View Javadoc
1   /*
2    * #%L
3    * settings4j
4    * ===============================================================
5    * Copyright (C) 2008 - 2015 Brabenetz Harald, Austria
6    * ===============================================================
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * 
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package org.settings4j.contentresolver;
21  
22  import java.io.File;
23  import java.io.IOException;
24  
25  import org.apache.commons.io.FileUtils;
26  import org.settings4j.ContentResolver;
27  
28  /**
29   * {@link ContentResolver} implementation to read content from the File System.
30   * <p>
31   * The optional Path Prefix is "file:".
32   * </p>
33   * <p>
34   * Absolute Windows paths contains a <b>":"</b>.<br>
35   * Absolute Unix paths starts with <b>"/"</b>.<br>
36   * Other Paths are relative and uses the {@link #getRootFolder()} as root. Which is per default <code>new File(".")</code>.<br>
37   * </p>
38   *
39   * @author Harald.Brabenetz
40   */
41  public class FSContentResolver implements ContentResolver {
42  
43      /** General Logger for this Class. */
44      private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(FSContentResolver.class);
45  
46      /** Pseudo URL prefix for loading from the class path: "classpath:". */
47      public static final String FILE_URL_PREFIX = "file:";
48  
49      private File rootFolder;
50  
51      @Override
52      public void addContentResolver(final ContentResolver contentResolver) {
53          throw new UnsupportedOperationException("FSContentResolver cannot add other ContentResolvers");
54      }
55  
56      @Override
57      // SuppressWarnings PMD.ReturnEmptyArrayRatherThanNull: returning null for this byte-Arrays is OK.
58      @SuppressWarnings("PMD.ReturnEmptyArrayRatherThanNull")
59      public byte[] getContent(final String key) {
60          String normalizedKey = key;
61          if (normalizedKey.startsWith(FILE_URL_PREFIX)) {
62              normalizedKey = normalizedKey.substring(FILE_URL_PREFIX.length());
63          }
64  
65          if (isUnixRoot(normalizedKey) || isWindowsRoot(normalizedKey)) {
66              // try to read it as full qualified path.
67              final byte[] content = getContent(new File(normalizedKey));
68              if (content != null) {
69                  return content;
70              }
71          }
72  
73          final byte[] content = getContent(new File(getRootFolder(), normalizedKey));
74          if (content != null) {
75              return content;
76          }
77          return null;
78      }
79  
80      private byte[] getContent(final File file) {
81          byte[] content = null;
82          if (file.exists()) {
83              try {
84                  content = FileUtils.readFileToByteArray(file);
85              } catch (final IOException e) {
86                  LOG.info(e.getMessage(), e);
87              }
88          }
89          return content;
90      }
91  
92  
93      /**
94       * @param key The Settings4j Key.
95       * @param value The value to Store.
96       * @throws IOException if an error occured.
97       */
98      public void setContent(final String key, final byte[] value) throws IOException {
99  
100         final String normalizedKey;
101         if (key.startsWith(FILE_URL_PREFIX)) {
102             normalizedKey = key.substring(FILE_URL_PREFIX.length());
103         } else {
104             normalizedKey = key;
105         }
106 
107         if (isUnixRoot(normalizedKey) || isWindowsRoot(normalizedKey)) {
108             // Unix-Root
109             throw new IllegalArgumentException(String.format(
110                 "The FSContentResolver can only store content relative to '%s' and not an absolute URL like '%s'.",
111                 getRootFolder().getCanonicalPath(), key));
112         }
113 
114         final File file = new File(getRootFolder(), normalizedKey);
115         LOG.debug("Store content in: {}", file.getAbsolutePath());
116 
117         FileUtils.writeByteArrayToFile(file, value);
118     }
119 
120     private boolean isWindowsRoot(final String normalizedKey) {
121         return normalizedKey.indexOf(':') >= 0;
122     }
123 
124     private boolean isUnixRoot(final String normalizedKey) {
125         return normalizedKey.startsWith("/");
126     }
127 
128     /**
129      * return the root of this FileSystem ContenResolver.
130      * <p>
131      * if no one is set, the "." will be returned.
132      * </p>
133      *
134      * @return the root of this FileSystem ContenResolver.
135      */
136     public File getRootFolder() {
137         if (this.rootFolder == null) {
138             this.rootFolder = new File(".");
139             LOG.info("FSContentResolver.rootFolder is null. The RootPath Folder will be used: {}", this.rootFolder.getAbsolutePath());
140         }
141         return this.rootFolder;
142     }
143 
144     /**
145      * @param rootFolderPath the root folder Path.
146      */
147     public void setRootFolderPath(final String rootFolderPath) {
148         final File newRootFolder = new File(rootFolderPath);
149         if (!newRootFolder.exists()) {
150             try {
151                 FileUtils.forceMkdir(newRootFolder);
152                 this.rootFolder = newRootFolder;
153                 LOG.info("Unable to create RootFolder for FSConntentResolver: {}", newRootFolder.getAbsolutePath());
154             } catch (final IOException e) {
155                 LOG.warn("cannot create rootFolder: {}!", rootFolderPath, e);
156                 throw new IllegalArgumentException(String.format("Unable to create RootFolder: '%s'!", rootFolderPath), e);
157             }
158         } else {
159             this.rootFolder = newRootFolder;
160         }
161     }
162 }