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.vfs2.provider.ram;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.Serializable;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.commons.vfs2.Capability;
28  import org.apache.commons.vfs2.FileContent;
29  import org.apache.commons.vfs2.FileName;
30  import org.apache.commons.vfs2.FileObject;
31  import org.apache.commons.vfs2.FileSystemException;
32  import org.apache.commons.vfs2.FileSystemOptions;
33  import org.apache.commons.vfs2.FileType;
34  import org.apache.commons.vfs2.provider.AbstractFileName;
35  import org.apache.commons.vfs2.provider.AbstractFileSystem;
36  
37  /**
38   * A RAM File System.
39   */
40  public class RamFileSystem extends AbstractFileSystem implements Serializable {
41  
42      /**
43       * serialVersionUID format is YYYYMMDD for the date of the last binary change.
44       */
45      private static final long serialVersionUID = 20101208L;
46  
47      /**
48       * Cache of RAM File Data
49       */
50      private final Map<FileName, RamFileData> cache;
51  
52      /**
53       * @param rootName The root file name.
54       * @param fileSystemOptions The FileSystem options.
55       */
56      protected RamFileSystem(final FileName rootName, final FileSystemOptions fileSystemOptions) {
57          super(rootName, null, fileSystemOptions);
58          this.cache = Collections.synchronizedMap(new HashMap<>());
59          // create root
60          final RamFileDatader/ram/RamFileData.html#RamFileData">RamFileData rootData = new RamFileData(rootName);
61          rootData.setType(FileType.FOLDER);
62          rootData.setLastModified(System.currentTimeMillis());
63          this.cache.put(rootName, rootData);
64      }
65  
66      /*
67       * (non-Javadoc)
68       *
69       * @see org.apache.commons.vfs2.provider.AbstractFileSystem#createFile(org.apache.commons.vfs2.FileName)
70       */
71      @Override
72      protected FileObject createFile(final AbstractFileName name) throws Exception {
73          return new RamFileObject(name, this);
74      }
75  
76      /*
77       * (non-Javadoc)
78       *
79       * @see org.apache.commons.vfs2.provider.AbstractFileSystem#addCapabilities(java.util.Collection)
80       */
81      @Override
82      protected void addCapabilities(final Collection<Capability> caps) {
83          caps.addAll(RamFileProvider.capabilities);
84      }
85  
86      /**
87       * @param name The name of the file.
88       * @return children The names of the children.
89       */
90      String[] listChildren(final FileName name) {
91          final RamFileData data = this.cache.get(name);
92          if (data == null || !data.getType().hasChildren()) {
93              return null;
94          }
95          final Collection<RamFileData> children = data.getChildren();
96  
97          synchronized (children) {
98              return children.stream().map(childData -> childData.getName().getBaseName()).toArray(String[]::new);
99          }
100     }
101 
102     /**
103      * Delete a file
104      *
105      * @param file the {@link RamFileObject} file to delete.
106      * @throws FileSystemException Thrown for file system errors.
107      */
108     void delete(final RamFileObject file) throws FileSystemException {
109         // root is read only check
110         FileSystemException.requireNonNull(file.getParent(), "unable to delete root");
111 
112         // Remove reference from cache
113         this.cache.remove(file.getName());
114         // Notify the parent
115         final RamFileObject./../../../org/apache/commons/vfs2/provider/ram/RamFileObject.html#RamFileObject">RamFileObject parent = (RamFileObject) this.resolveFile(file.getParent().getName());
116         parent.getData().removeChild(file.getData());
117         parent.close();
118         // Close the file
119         file.getData().clear();
120         file.close();
121     }
122 
123     /**
124      * Saves a file
125      *
126      * @param file the {@link RamFileObject} file to save.
127      * @throws FileSystemException Thrown for file system errors.
128      */
129     void save(final RamFileObject file) throws FileSystemException {
130 
131         // Validate name
132         if (file.getData().getName() == null) {
133             throw new FileSystemException(new IllegalStateException("The data has no name. " + file));
134         }
135 
136         // Add to the parent
137         if (file.getName().getDepth() > 0) {
138             final RamFileData parentData = this.cache.get(file.getParent().getName());
139             // Only if not already added
140             if (!parentData.hasChildren(file.getData())) {
141                 final RamFileObject./../../../org/apache/commons/vfs2/provider/ram/RamFileObject.html#RamFileObject">RamFileObject parent = (RamFileObject) file.getParent();
142                 parent.getData().addChild(file.getData());
143                 parent.close();
144             }
145         }
146         // Store in cache
147         cache.put(file.getName(), file.getData());
148         file.getData().updateLastModified();
149         file.close();
150     }
151 
152     /**
153      * @param from The original file.
154      * @param to The new file.
155      * @throws FileSystemException if an error occurs.
156      */
157     void rename(final RamFileObjectider/ram/RamFileObject.html#RamFileObject">RamFileObject from, final RamFileObject to) throws FileSystemException {
158         if (!this.cache.containsKey(from.getName())) {
159             throw new FileSystemException("File does not exist: " + from.getName());
160         }
161         // Copy data
162 
163         to.getData().setContent(from.getData().getContent());
164         to.getData().setLastModified(from.getData().getLastModified());
165         to.getData().setType(from.getData().getType());
166 
167         this.save(to);
168         this.delete(from);
169     }
170 
171     public void attach(final RamFileObject fo) {
172         if (fo.getName() == null) {
173             throw new IllegalArgumentException("Null argument");
174         }
175         RamFileData data = this.cache.get(fo.getName());
176         if (data == null) {
177             data = new RamFileData(fo.getName());
178         }
179         fo.setData(data);
180     }
181 
182     /**
183      * Import a Tree.
184      *
185      * @param file The File
186      * @throws FileSystemException if an error occurs.
187      */
188     public void importTree(final File file) throws FileSystemException {
189         final FileObject fileFo = getFileSystemManager().toFileObject(file);
190         this.toRamFileObject(fileFo, fileFo);
191     }
192 
193     /**
194      * Import the given file with the name relative to the given root
195      *
196      * @param fo the source {@link FileObject} file to import.
197      * @param root the {@link FileObject} root.
198      * @throws FileSystemException Thrown for file system errors.
199      */
200     private void toRamFileObject(final FileObject/FileObject.html#FileObject">FileObject fo, final FileObject root) throws FileSystemException {
201         final RamFileObject../../../../org/apache/commons/vfs2/provider/ram/RamFileObject.html#RamFileObject">RamFileObject memFo = (RamFileObject) this
202                 .resolveFile(fo.getName().getPath().substring(root.getName().getPath().length()));
203         if (fo.getType().hasChildren()) {
204             // Create Folder
205             memFo.createFolder();
206             // Import recursively
207             final FileObject[] fos = fo.getChildren();
208             for (final FileObject child : fos) {
209                 this.toRamFileObject(child, root);
210             }
211         } else if (fo.isFile()) {
212             // Copy bytes
213             try (final FileContent content = fo.getContent()) {
214                 content.write(memFo);
215             } catch (final IOException e) {
216                 throw new FileSystemException(e.getClass().getName() + " " + e.getMessage());
217             }
218         } else {
219             throw new FileSystemException("File is not a folder nor a file " + memFo);
220         }
221     }
222 
223     /**
224      * @return Returns the size of the FileSystem
225      */
226     long size() {
227         long size = 0;
228         synchronized (cache) {
229             for (final RamFileData data : cache.values()) {
230                 size += data.size();
231             }
232         }
233         return size;
234     }
235 
236     /**
237      * Close the RAMFileSystem.
238      */
239     @Override
240     public void close() {
241         this.cache.clear();
242         super.close();
243     }
244 }