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.vfs.provider.ram;
18  
19  import java.io.BufferedOutputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.io.Serializable;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.Map;
30  
31  import org.apache.commons.vfs.FileName;
32  import org.apache.commons.vfs.FileObject;
33  import org.apache.commons.vfs.FileSystemException;
34  import org.apache.commons.vfs.FileSystemOptions;
35  import org.apache.commons.vfs.FileType;
36  import org.apache.commons.vfs.provider.AbstractFileSystem;
37  
38  /***
39   * A RAM File System
40   */
41  public class RamFileSystem extends AbstractFileSystem implements Serializable
42  {
43  	/***
44  	 * Cache of RAM File Data
45  	 */
46  	private Map cache;
47  
48  	/***
49  	 * @param rootName
50  	 * @param fileSystemOptions
51  	 */
52  	protected RamFileSystem(FileName rootName,
53  			FileSystemOptions fileSystemOptions)
54  	{
55  		super(rootName, null, fileSystemOptions);
56  		this.cache = Collections.synchronizedMap(new HashMap());
57          // create root
58          RamFileData rootData = new RamFileData(rootName) ;
59          rootData.setType(FileType.FOLDER);
60          rootData.setLastModified(System.currentTimeMillis());
61          this.cache.put(rootName, rootData);
62  	}
63  
64  	/*
65  	 * (non-Javadoc)
66  	 * 
67  	 * @see org.apache.commons.vfs.provider.AbstractFileSystem#createFile(org.apache.commons.vfs.FileName)
68  	 */
69  	protected FileObject createFile(FileName name) throws Exception
70  	{
71  		RamFileObject file = new RamFileObject(name, this);
72  		return file;
73  	}
74  
75  	/*
76  	 * (non-Javadoc)
77  	 * 
78  	 * @see org.apache.commons.vfs.provider.AbstractFileSystem#addCapabilities(java.util.Collection)
79  	 */
80  	protected void addCapabilities(Collection caps)
81  	{
82  		caps.addAll(RamFileProvider.capabilities);
83  	}
84  
85  	/***
86  	 * @param name
87  	 * @return children
88  	 */
89  	String[] listChildren(FileName name)
90  	{
91          RamFileData data = (RamFileData) this.cache.get(name);
92  		Collection children = data.getChildren();
93          
94          String[] names = new String[children.size()];
95          
96          int pos = 0 ;
97          Iterator iter = children.iterator() ;
98          while (iter.hasNext()) 
99          {
100             RamFileData childData = (RamFileData) iter.next();
101             names[pos] = childData.getName().getBaseName();
102             pos++;
103         }
104         
105 		return names;
106 	}
107 
108 	/***
109 	 * Delete a file
110 	 * 
111 	 * @param file
112 	 * @throws FileSystemException
113 	 */
114 	void delete(RamFileObject file) throws FileSystemException
115 	{
116 	    // root is read only check
117         if (file.getParent()==null) {
118             throw new FileSystemException("unable to delete root");
119         }
120         
121 		// Remove reference from cache
122 		this.cache.remove(file.getName());
123 		// Notify the parent
124         RamFileObject parent = (RamFileObject) this.resolveFile(file
125                 .getParent().getName());
126         parent.getData().removeChild(file.getData());
127 		parent.close();
128 		// Close the file
129 		file.getData().clear();
130 		file.close();
131 	}
132 
133 	/***
134 	 * Saves a file
135 	 * 
136 	 * @param file
137 	 * @throws FileSystemException
138 	 */
139 	void save(final RamFileObject file) throws FileSystemException
140 	{
141 
142 		// Validate name
143 		if (file.getData().getName() == null)
144 		{
145 			throw new FileSystemException(new IllegalStateException(
146 					"The data has no name. " + file));
147 		}
148 
149 		// Add to the parent
150 		if (file.getName().getDepth() > 0)
151 		{
152 			RamFileData parentData = (RamFileData) this.cache.get(file
153 					.getParent().getName());
154 			// Only if not already added
155 			if (!parentData.hasChildren(file.getData()))
156 			{
157 				RamFileObject parent = (RamFileObject) file.getParent();
158 				parent.getData().addChild(file.getData());
159 				parent.close();
160 			}
161 		}
162 		// Store in cache
163 		cache.put(file.getName(), file.getData());
164 		file.getData().updateLastModified();
165 		file.close();
166 	}
167 
168 	/***
169 	 * @param from
170 	 * @param to
171 	 * @throws FileSystemException
172 	 */
173 	void rename(RamFileObject from, RamFileObject to)
174 			throws FileSystemException
175 	{
176 		if (!this.cache.containsKey(from.getName()))
177 		{
178 			throw new FileSystemException("File does not exist: "
179 					+ from.getName());
180 		}
181 		// Copy data
182 
183 		to.getData().setBuffer(from.getData().getBuffer());
184 		to.getData().setLastModified(from.getData().getLastModified());
185 		to.getData().setType(from.getData().getType());
186 
187 		this.save(to);
188 		this.delete(from);
189 	}
190 
191 	public void attach(RamFileObject fo)
192 	{
193 		if (fo.getName() == null)
194 		{
195 			throw new IllegalArgumentException("Null argument");
196 		}
197 		RamFileData data = (RamFileData) this.cache.get(fo.getName());
198 		if (data == null)
199 		{
200 			data = new RamFileData(fo.getName());
201 		}
202 		fo.setData(data);
203 	}
204 
205 	/***
206 	 * Import a Tree
207 	 * 
208 	 * @param file
209 	 * @throws FileSystemException
210 	 */
211 	public void importTree(File file) throws FileSystemException
212 	{
213 		FileObject fileFo = getFileSystemManager().toFileObject(file);
214 		this.toRamFileObject(fileFo, fileFo);
215 	}
216 
217 	/***
218 	 * Import the given file with the name relative to the given root
219 	 * 
220 	 * @param fo
221 	 * @param root
222 	 * @throws FileSystemException
223 	 */
224 	void toRamFileObject(FileObject fo, FileObject root)
225 			throws FileSystemException
226 	{
227 		RamFileObject memFo = (RamFileObject) this.resolveFile(fo.getName()
228 				.getPath().substring(root.getName().getPath().length()));
229 		if (fo.getType().hasChildren())
230 		{
231 			// Create Folder
232 			memFo.createFolder();
233 			// Import recursively
234 			FileObject[] fos = fo.getChildren();
235 			for (int i = 0; i < fos.length; i++)
236 			{
237 				FileObject child = fos[i];
238 				this.toRamFileObject(child, root);
239 			}
240 		}
241 		else if (fo.getType().equals(FileType.FILE))
242 		{
243 			// Read bytes
244 			try
245 			{
246 				InputStream is = fo.getContent().getInputStream();
247 				try
248 				{
249 					OutputStream os = new BufferedOutputStream(memFo
250 							.getOutputStream(), 512);
251 					int i;
252 					while ((i = is.read()) != -1)
253 					{
254 						os.write(i);
255 					}
256 					os.flush();
257 					os.close();
258 				}
259 				finally
260 				{
261 					try
262 					{
263 						is.close();
264 					}
265 					catch (IOException e)
266 					{
267 						// ignore on close exception
268 						;
269 					}
270 				}
271 			}
272 			catch (IOException e)
273 			{
274 				throw new FileSystemException(e.getClass().getName() + " "
275 						+ e.getMessage());
276 			}
277 		}
278 		else
279 		{
280 			throw new FileSystemException("File is not a folder nor a file "
281 					+ memFo);
282 		}
283 	}
284 
285 	/***
286 	 * @return Returns the size of the FileSystem
287 	 */
288 	int size()
289 	{
290 		int size = 0;
291 		Iterator iter = cache.values().iterator();
292 		while (iter.hasNext())
293 		{
294 			RamFileData data = (RamFileData) iter.next();
295 			size += data.size();
296 		}
297 		return size;
298 	}
299 
300 	/***
301 	 * Close the RAMFileSystem
302 	 */
303 	public void close()
304 	{
305 		this.cache = null;
306 		super.close();
307 	}
308 }