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.impl;
18  
19  import java.util.Collection;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.apache.commons.vfs2.Capability;
24  import org.apache.commons.vfs2.FileName;
25  import org.apache.commons.vfs2.FileObject;
26  import org.apache.commons.vfs2.FileSystemException;
27  import org.apache.commons.vfs2.FileSystemOptions;
28  import org.apache.commons.vfs2.FileType;
29  import org.apache.commons.vfs2.NameScope;
30  import org.apache.commons.vfs2.provider.AbstractFileName;
31  import org.apache.commons.vfs2.provider.AbstractFileSystem;
32  import org.apache.commons.vfs2.provider.DelegateFileObject;
33  
34  /**
35   * A logical file system, made up of set of junctions, or links, to files from other file systems.
36   * <p>
37   * TODO - Handle nested junctions.
38   * </p>
39   */
40  public class VirtualFileSystem extends AbstractFileSystem {
41      private final Map<FileName, FileObject> junctions = new HashMap<>();
42  
43      public VirtualFileSystem(final AbstractFileName rootName, final FileSystemOptions fileSystemOptions) {
44          super(rootName, null, fileSystemOptions);
45      }
46  
47      /**
48       * Adds the capabilities of this file system.
49       */
50      @Override
51      protected void addCapabilities(final Collection<Capability> caps) {
52          // TODO - this isn't really true
53          caps.add(Capability.ATTRIBUTES);
54          caps.add(Capability.CREATE);
55          caps.add(Capability.DELETE);
56          caps.add(Capability.GET_TYPE);
57          caps.add(Capability.JUNCTIONS);
58          caps.add(Capability.GET_LAST_MODIFIED);
59          caps.add(Capability.SET_LAST_MODIFIED_FILE);
60          caps.add(Capability.SET_LAST_MODIFIED_FOLDER);
61          caps.add(Capability.LIST_CHILDREN);
62          caps.add(Capability.READ_CONTENT);
63          caps.add(Capability.SIGNING);
64          caps.add(Capability.WRITE_CONTENT);
65          caps.add(Capability.APPEND_CONTENT);
66      }
67  
68      /**
69       * Creates a file object. This method is called only if the requested file is not cached.
70       */
71      @Override
72      protected FileObject createFile(final AbstractFileName name) throws Exception {
73          // Find the file that the name points to
74          final FileName junctionPoint = getJunctionForFile(name);
75          final FileObject file;
76          if (junctionPoint != null) {
77              // Resolve the real file
78              final FileObject junctionFile = junctions.get(junctionPoint);
79              final String relName = junctionPoint.getRelativeName(name);
80              file = junctionFile.resolveFile(relName, NameScope.DESCENDENT_OR_SELF);
81          } else {
82              file = null;
83          }
84  
85          // Return a wrapper around the file
86          return new DelegateFileObject(name, this, file);
87      }
88  
89      /**
90       * Adds a junction to this file system.
91       *
92       * @param junctionPoint The location of the junction.
93       * @param targetFile The target file to base the junction on.
94       * @throws FileSystemException if an error occurs.
95       */
96      @Override
97      public void addJunction(final String junctionPoint, final FileObject targetFile) throws FileSystemException {
98          final FileName junctionName = getFileSystemManager().resolveName(getRootName(), junctionPoint);
99  
100         // Check for nested junction - these are not supported yet
101         if (getJunctionForFile(junctionName) != null) {
102             throw new FileSystemException("vfs.impl/nested-junction.error", junctionName);
103         }
104 
105         try {
106             // Add to junction table
107             junctions.put(junctionName, targetFile);
108 
109             // Attach to file
110             final DelegateFileObject/apache/commons/vfs2/provider/DelegateFileObject.html#DelegateFileObject">DelegateFileObject junctionFile = (DelegateFileObject) getFileFromCache(junctionName);
111             if (junctionFile != null) {
112                 junctionFile.setFile(targetFile);
113             }
114 
115             // Create ancestors of junction point
116             FileName childName = junctionName;
117             boolean done = false;
118             for (AbstractFileName/org/apache/commons/vfs2/provider/AbstractFileName.html#AbstractFileName">AbstractFileName parentName = (AbstractFileName) childName.getParent(); !done
119                     && parentName != null; childName = parentName, parentName = (AbstractFileName) parentName
120                             .getParent()) {
121                 DelegateFileObject./../org/apache/commons/vfs2/provider/DelegateFileObject.html#DelegateFileObject">DelegateFileObject file = (DelegateFileObject) getFileFromCache(parentName);
122                 if (file == null) {
123                     file = new DelegateFileObject(parentName, this, null);
124                     putFileToCache(file);
125                 } else {
126                     done = file.exists();
127                 }
128 
129                 // As this is the parent of our junction it has to be a folder
130                 file.attachChild(childName, FileType.FOLDER);
131             }
132 
133             // TODO - attach all cached children of the junction point to their real file
134         } catch (final Exception e) {
135             throw new FileSystemException("vfs.impl/create-junction.error", junctionName, e);
136         }
137     }
138 
139     /**
140      * Removes a junction from this file system.
141      *
142      * @param junctionPoint The junction to remove.
143      * @throws FileSystemException if an error occurs.
144      */
145     @Override
146     public void removeJunction(final String junctionPoint) throws FileSystemException {
147         final FileName junctionName = getFileSystemManager().resolveName(getRootName(), junctionPoint);
148         junctions.remove(junctionName);
149 
150         // TODO - remove from parents of junction point
151         // TODO - detach all cached children of the junction point from their real file
152     }
153 
154     /**
155      * Locates the junction point for the junction containing the given file.
156      *
157      * @param name The FileName.
158      * @return the FileName where the junction occurs.
159      */
160     private FileNameileName">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 (final FileName junctionPoint : junctions.keySet()) {
168             if (junctionPoint.isDescendent(name)) {
169                 return junctionPoint;
170             }
171         }
172 
173         // None
174         return null;
175     }
176 
177     @Override
178     public void close() {
179         super.close();
180         junctions.clear();
181     }
182 }