View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.transaction.file;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.commons.transaction.TransactionException;
31  import org.apache.commons.transaction.resource.ResourceException;
32  import org.apache.commons.transaction.resource.ResourceManager;
33  import org.apache.commons.transaction.resource.StreamableResource;
34  import org.apache.commons.transaction.util.FileHelper;
35  
36  /**
37   * Default file system implementation of a
38   * {@link ResourceManager resource manager}.
39   * 
40   * <p>
41   * Only two {@link StreamableResource#getProperty(String) properties} are
42   * supported for reading: "lastModified" and "length" . None are supported for
43   * {@link StreamableResource#setProperty(String, Object) setting} or
44   * {@link StreamableResource#readLock() removing}.
45   * 
46   * <p>
47   * This implementation is <b>NOT</b> <em>thread-safe</em>. Use
48   * {@link TxFileResourceManager} if you require a <em>thread-safe</em>
49   * implementation.
50   */
51  public class FileResourceManager implements ResourceManager<FileResourceManager.FileResource> {
52  
53      private Log logger = LogFactory.getLog(getClass());
54  
55      protected String rootPath;
56  
57      public FileResourceManager(String rootPath) {
58          try {
59              File file = new File(rootPath);
60              file.mkdirs();
61              this.rootPath = file.getCanonicalPath();
62          } catch (IOException e) {
63              throw new TransactionException(e);
64          }
65      }
66  
67      public FileResourceManager.FileResource getResource(String path) throws ResourceException {
68          return new FileResource(path);
69      }
70  
71      public String getRootPath() {
72          return rootPath;
73      }
74  
75      protected static class FileResource implements StreamableResource {
76  
77          private final File file;
78  
79          private final String canonicalPath;
80  
81          private final String name;
82  
83          protected static File getFileForResource(StreamableResource resource)
84                  throws ResourceException {
85              if (!(resource instanceof FileResource)) {
86                  throw new ResourceException(
87                          "Destination must be of created by FileResourceManager only!");
88  
89              }
90              return ((FileResource) resource).getFile();
91          }
92  
93          public FileResource(String path) throws ResourceException {
94              this(new File(path.trim()));
95          }
96  
97          public FileResource(File file) throws ResourceException {
98              this.file = file;
99              try {
100                 this.canonicalPath = file.getCanonicalPath();
101             } catch (IOException e) {
102                 throw new ResourceException(e);
103             }
104             this.name = file.getName();
105         }
106 
107         public void createAsDirectory() throws ResourceException {
108             if (!file.exists() && !file.mkdirs()) {
109                 throw new ResourceException(ResourceException.Code.COULD_NOT_CREATE,
110                         "Could not create directory");
111             }
112 
113         }
114 
115         public void createAsFile() throws ResourceException {
116             try {
117                 if (!file.createNewFile()) {
118                     throw new ResourceException(ResourceException.Code.COULD_NOT_CREATE,
119                             "Could not create file");
120                 }
121             } catch (IOException e) {
122                 throw new ResourceException(e);
123             }
124         }
125 
126         public void delete() throws ResourceException {
127             if (exists()) {
128                 if (!isDirectory()) {
129                     if (!getFile().delete())
130                         throw new ResourceException(ResourceException.Code.COULD_NOT_DELETE,
131                                 "Could not create file");
132                 } else {
133                     FileHelper.removeRecursive(getFile());
134                 }
135             }
136         }
137 
138         public boolean exists() {
139             return file.exists();
140         }
141 
142         public List<? extends FileResource> getChildren() throws ResourceException {
143             List<FileResource> result = new ArrayList<FileResource>();
144             File[] files = file.listFiles();
145             for (File file : files) {
146                 result.add(create(file));
147             }
148             return result;
149         }
150 
151         public FileResource getParent() throws ResourceException {
152             // FIXME: Is reasonable, but would require reference to enclosing
153             // class
154             /*
155              * if (getPath().equals(getRootPath())) return null;
156              */
157             File parent = file.getParentFile();
158             if (parent == null)
159                 return null;
160             return create(parent);
161         }
162 
163         public String getPath() {
164             return canonicalPath;
165         }
166 
167         public boolean isDirectory() {
168             return file.isDirectory();
169         }
170 
171         public boolean isFile() {
172             return file.isFile();
173         }
174 
175         public void move(StreamableResource destination) throws ResourceException {
176             if (!prepareMoveorCopy(destination))
177                 moveOrCopySaneCheck(destination);
178             try {
179                 if (isFile()) {
180                     FileHelper.move(file, getFileForResource(destination));
181                 } else {
182                     FileHelper.moveRecursive(file, getFileForResource(destination));
183                 }
184             } catch (IOException e) {
185                 throw new ResourceException(e);
186             }
187         }
188 
189         public void copy(StreamableResource destination) throws ResourceException {
190             if (!prepareMoveorCopy(destination))
191                 moveOrCopySaneCheck(destination);
192             try {
193                 if (isFile()) {
194                     FileHelper.copy(file, getFileForResource(destination));
195                 } else {
196                     FileHelper.copyRecursive(file, getFileForResource(destination));
197                 }
198             } catch (IOException e) {
199                 throw new ResourceException(e);
200             }
201         }
202 
203         protected boolean prepareMoveorCopy(StreamableResource destination)
204                 throws ResourceException {
205             if (!destination.exists()) {
206                 if (isDirectory()) {
207                     destination.createAsDirectory();
208                 } else {
209                     destination.createAsFile();
210                 }
211                 return true;
212             }
213             return false;
214         }
215 
216         protected void moveOrCopySaneCheck(StreamableResource destination) throws ResourceException {
217 
218             File from = getFile();
219             File to = getFileForResource(destination);
220             if (!from.isDirectory()) {
221                 if (to.isDirectory()) {
222                     throw new ResourceException(ResourceException.Code.CANT_MOVE_OR_COPY,
223                             "Could not move file to directory");
224                 }
225                 // still need to check, as it can also be a link
226             } else if (from.isDirectory()) {
227                 if (to.isFile()) {
228                     throw new ResourceException(ResourceException.Code.CANT_MOVE_OR_COPY,
229                             "Could not move directory to file");
230                 }
231             }
232         }
233 
234         public InputStream readStream() throws ResourceException {
235             try {
236                 FileInputStream is = new FileInputStream(file);
237                 return is;
238             } catch (IOException e) {
239                 throw new ResourceException(e);
240             }
241         }
242 
243         public OutputStream writeStream(boolean append) throws ResourceException {
244             try {
245                 FileOutputStream os = new FileOutputStream(file, append);
246                 return os;
247             } catch (IOException e) {
248                 throw new ResourceException(e);
249             }
250         }
251 
252         public void removeProperty(String name) {
253             throw new UnsupportedOperationException("You can not remove properties from files!");
254         }
255 
256         public void setProperty(String name, Object newValue) {
257             throw new UnsupportedOperationException("You can not set properties on files!");
258         }
259 
260         public Object getProperty(String name) {
261             if (name.equals("lastModified")) {
262                 return file.lastModified();
263             }
264             if (name.equals("length")) {
265                 return file.length();
266             }
267             return null;
268         }
269 
270         // XXX no op, only way to lock is using FileChannel#lock() and
271         // FileChannel#tryLock()
272         public void readLock() {
273         }
274 
275         // XXX no op, only way to lock is using FileChannel#lock() and
276         // FileChannel#tryLock()
277         public void writeLock() {
278         }
279 
280         protected File getFile() {
281             return file;
282         }
283 
284         protected FileResource create(File file) throws ResourceException {
285             return new FileResource(file);
286         }
287 
288         public FileResource getChild(String name) throws ResourceException {
289             File child = new File(file, name);
290             return create(child);
291         }
292 
293         public String getName() {
294             return name;
295         }
296 
297     }
298 }