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