001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.vfs.impl;
018:
019: import org.apache.commons.vfs.Capability;
020: import org.apache.commons.vfs.FileName;
021: import org.apache.commons.vfs.FileObject;
022: import org.apache.commons.vfs.FileSystemException;
023: import org.apache.commons.vfs.FileSystemOptions;
024: import org.apache.commons.vfs.FileType;
025: import org.apache.commons.vfs.NameScope;
026: import org.apache.commons.vfs.provider.AbstractFileSystem;
027: import org.apache.commons.vfs.provider.DelegateFileObject;
028:
029: import java.util.Collection;
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.Map;
033:
034: /**
035: * A logical file system, made up of set of junctions, or links, to files from
036: * other file systems.
037: *
038: * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
039: * @version $Revision: 480428 $ $Date: 2006-11-28 22:15:24 -0800 (Tue, 28 Nov 2006) $
040: * @todo Handle nested junctions.
041: */
042: public class VirtualFileSystem extends AbstractFileSystem {
043: private final Map junctions = new HashMap();
044:
045: public VirtualFileSystem(final FileName rootName,
046: final FileSystemOptions fileSystemOptions) {
047: super (rootName, null, fileSystemOptions);
048: }
049:
050: /**
051: * Adds the capabilities of this file system.
052: */
053: protected void addCapabilities(final Collection caps) {
054: // TODO - this isn't really true
055: caps.add(Capability.ATTRIBUTES);
056: caps.add(Capability.CREATE);
057: caps.add(Capability.DELETE);
058: caps.add(Capability.GET_TYPE);
059: caps.add(Capability.JUNCTIONS);
060: caps.add(Capability.GET_LAST_MODIFIED);
061: caps.add(Capability.SET_LAST_MODIFIED_FILE);
062: caps.add(Capability.SET_LAST_MODIFIED_FOLDER);
063: caps.add(Capability.LIST_CHILDREN);
064: caps.add(Capability.READ_CONTENT);
065: caps.add(Capability.SIGNING);
066: caps.add(Capability.WRITE_CONTENT);
067: caps.add(Capability.APPEND_CONTENT);
068: }
069:
070: /**
071: * Creates a file object. This method is called only if the requested
072: * file is not cached.
073: */
074: protected FileObject createFile(final FileName name)
075: throws Exception {
076: // Find the file that the name points to
077: final FileName junctionPoint = getJunctionForFile(name);
078: final FileObject file;
079: if (junctionPoint != null) {
080: // Resolve the real file
081: final FileObject junctionFile = (FileObject) junctions
082: .get(junctionPoint);
083: final String relName = junctionPoint.getRelativeName(name);
084: file = junctionFile.resolveFile(relName,
085: NameScope.DESCENDENT_OR_SELF);
086: } else {
087: file = null;
088: }
089:
090: // Return a wrapper around the file
091: return new DelegateFileObject(name, this , file);
092: }
093:
094: /**
095: * Adds a junction to this file system.
096: */
097: public void addJunction(final String junctionPoint,
098: final FileObject targetFile) throws FileSystemException {
099: final FileName junctionName = getFileSystemManager()
100: .resolveName(getRootName(), junctionPoint);
101:
102: // Check for nested junction - these are not supported yet
103: if (getJunctionForFile(junctionName) != null) {
104: throw new FileSystemException(
105: "vfs.impl/nested-junction.error", junctionName);
106: }
107:
108: try {
109: // Add to junction table
110: junctions.put(junctionName, targetFile);
111:
112: // Attach to file
113: final DelegateFileObject junctionFile = (DelegateFileObject) getFileFromCache(junctionName);
114: if (junctionFile != null) {
115: junctionFile.setFile(targetFile);
116: }
117:
118: // Create ancestors of junction point
119: FileName childName = junctionName;
120: boolean done = false;
121: for (FileName parentName = childName.getParent(); !done
122: && parentName != null; childName = parentName, parentName = parentName
123: .getParent()) {
124: DelegateFileObject file = (DelegateFileObject) getFileFromCache(parentName);
125: if (file == null) {
126: file = new DelegateFileObject(parentName, this ,
127: null);
128: putFileToCache(file);
129: } else {
130: done = file.exists();
131: }
132:
133: // As this is the parent of our junction it has to be a folder
134: file.attachChild(childName, FileType.FOLDER);
135: }
136:
137: // TODO - attach all cached children of the junction point to their real file
138: } catch (final Exception e) {
139: throw new FileSystemException(
140: "vfs.impl/create-junction.error", junctionName, e);
141: }
142: }
143:
144: /**
145: * Removes a junction from this file system.
146: */
147: public void removeJunction(final String junctionPoint)
148: throws FileSystemException {
149: final FileName junctionName = getFileSystemManager()
150: .resolveName(getRootName(), junctionPoint);
151: junctions.remove(junctionName);
152:
153: // TODO - remove from parents of junction point
154: // TODO - detach all cached children of the junction point from their real file
155: }
156:
157: /**
158: * Locates the junction point for the junction containing the given file.
159: */
160: private FileName getJunctionForFile(final FileName name) {
161: if (junctions.containsKey(name)) {
162: // The name points to the junction point directly
163: return name;
164: }
165:
166: // Find matching junction
167: for (Iterator iterator = junctions.keySet().iterator(); iterator
168: .hasNext();) {
169: final FileName junctionPoint = (FileName) iterator.next();
170: if (junctionPoint.isDescendent(name)) {
171: return junctionPoint;
172: }
173: }
174:
175: // None
176: return null;
177: }
178: }
|