/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.commons.vfs2.provider.ram;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.vfs2.Capability;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.provider.AbstractFileName;
import org.apache.commons.vfs2.provider.AbstractFileSystem;

A RAM File System.
/** * A RAM File System. */
public class RamFileSystem extends AbstractFileSystem implements Serializable { private static final int BUFFER_SIZE = 512;
serialVersionUID format is YYYYMMDD for the date of the last binary change.
/** * serialVersionUID format is YYYYMMDD for the date of the last binary change. */
private static final long serialVersionUID = 20101208L;
Cache of RAM File Data
/** * Cache of RAM File Data */
private final Map<FileName, RamFileData> cache;
Params:
  • rootName – The root file name.
  • fileSystemOptions – The FileSystem options.
/** * @param rootName The root file name. * @param fileSystemOptions The FileSystem options. */
protected RamFileSystem(final FileName rootName, final FileSystemOptions fileSystemOptions) { super(rootName, null, fileSystemOptions); this.cache = Collections.synchronizedMap(new HashMap<FileName, RamFileData>()); // create root final RamFileData rootData = new RamFileData(rootName); rootData.setType(FileType.FOLDER); rootData.setLastModified(System.currentTimeMillis()); this.cache.put(rootName, rootData); } /* * (non-Javadoc) * * @see org.apache.commons.vfs2.provider.AbstractFileSystem#createFile(org.apache.commons.vfs2.FileName) */ @Override protected FileObject createFile(final AbstractFileName name) throws Exception { return new RamFileObject(name, this); } /* * (non-Javadoc) * * @see org.apache.commons.vfs2.provider.AbstractFileSystem#addCapabilities(java.util.Collection) */ @Override protected void addCapabilities(final Collection<Capability> caps) { caps.addAll(RamFileProvider.capabilities); }
Params:
  • name – The name of the file.
Returns:children The names of the children.
/** * @param name The name of the file. * @return children The names of the children. */
String[] listChildren(final FileName name) { final RamFileData data = this.cache.get(name); if (data == null || !data.getType().hasChildren()) { return null; } final Collection<RamFileData> children = data.getChildren(); String[] names; synchronized (children) { names = new String[children.size()]; int pos = 0; final Iterator<RamFileData> iter = children.iterator(); while (iter.hasNext()) { final RamFileData childData = iter.next(); names[pos] = childData.getName().getBaseName(); pos++; } } return names; }
Delete a file
Params:
  • file –
Throws:
/** * Delete a file * * @param file * @throws FileSystemException */
void delete(final RamFileObject file) throws FileSystemException { // root is read only check FileSystemException.requireNonNull(file.getParent(), "unable to delete root"); // Remove reference from cache this.cache.remove(file.getName()); // Notify the parent final RamFileObject parent = (RamFileObject) this.resolveFile(file.getParent().getName()); parent.getData().removeChild(file.getData()); parent.close(); // Close the file file.getData().clear(); file.close(); }
Saves a file
Params:
  • file –
Throws:
/** * Saves a file * * @param file * @throws FileSystemException */
void save(final RamFileObject file) throws FileSystemException { // Validate name if (file.getData().getName() == null) { throw new FileSystemException(new IllegalStateException("The data has no name. " + file)); } // Add to the parent if (file.getName().getDepth() > 0) { final RamFileData parentData = this.cache.get(file.getParent().getName()); // Only if not already added if (!parentData.hasChildren(file.getData())) { final RamFileObject parent = (RamFileObject) file.getParent(); parent.getData().addChild(file.getData()); parent.close(); } } // Store in cache cache.put(file.getName(), file.getData()); file.getData().updateLastModified(); file.close(); }
Params:
  • from – The original file.
  • to – The new file.
Throws:
/** * @param from The original file. * @param to The new file. * @throws FileSystemException if an error occurs. */
void rename(final RamFileObject from, final RamFileObject to) throws FileSystemException { if (!this.cache.containsKey(from.getName())) { throw new FileSystemException("File does not exist: " + from.getName()); } // Copy data to.getData().setContent(from.getData().getContent()); to.getData().setLastModified(from.getData().getLastModified()); to.getData().setType(from.getData().getType()); this.save(to); this.delete(from); } public void attach(final RamFileObject fo) { if (fo.getName() == null) { throw new IllegalArgumentException("Null argument"); } RamFileData data = this.cache.get(fo.getName()); if (data == null) { data = new RamFileData(fo.getName()); } fo.setData(data); }
Import a Tree.
Params:
  • file – The File
Throws:
/** * Import a Tree. * * @param file The File * @throws FileSystemException if an error occurs. */
public void importTree(final File file) throws FileSystemException { final FileObject fileFo = getFileSystemManager().toFileObject(file); this.toRamFileObject(fileFo, fileFo); }
Import the given file with the name relative to the given root
Params:
  • fo –
  • root –
Throws:
/** * Import the given file with the name relative to the given root * * @param fo * @param root * @throws FileSystemException */
void toRamFileObject(final FileObject fo, final FileObject root) throws FileSystemException { final RamFileObject memFo = (RamFileObject) this .resolveFile(fo.getName().getPath().substring(root.getName().getPath().length())); if (fo.getType().hasChildren()) { // Create Folder memFo.createFolder(); // Import recursively final FileObject[] fos = fo.getChildren(); for (final FileObject child : fos) { this.toRamFileObject(child, root); } } else if (fo.isFile()) { // Read bytes try { final InputStream is = fo.getContent().getInputStream(); try { final OutputStream os = new BufferedOutputStream(memFo.getOutputStream(), BUFFER_SIZE); int i; while ((i = is.read()) != -1) { os.write(i); } os.close(); } finally { try { is.close(); } catch (final IOException ignored) { /* ignore on close exception. */ } // TODO: close os } } catch (final IOException e) { throw new FileSystemException(e.getClass().getName() + " " + e.getMessage()); } } else { throw new FileSystemException("File is not a folder nor a file " + memFo); } }
Returns:Returns the size of the FileSystem
/** * @return Returns the size of the FileSystem */
long size() { long size = 0; synchronized (cache) { final Iterator<RamFileData> iter = cache.values().iterator(); while (iter.hasNext()) { final RamFileData data = iter.next(); size += data.size(); } } return size; }
Close the RAMFileSystem.
/** * Close the RAMFileSystem. */
@Override public void close() { this.cache.clear(); super.close(); } }