<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
      "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">

<chapter id="vfs">
   <title>VFS Configuration and Usage</title>
   <abstract>
      <simpara>The virtual file system module provides a read-only
      abstraction for a file system accessed using a root URI/URL.
      </simpara>
   </abstract>

   <sect1>
      <title>Overview</title>
      <simpara>The virtual file system module provides a read-only
         abstraction for a file system accessed using a root URI/URL.
         The main VFS classes include:
      </simpara>
      <itemizedlist>
         <listitem>
            <simpara>org.jboss.virtual.VFS - A factory class for creating and
            finding VirtualFiles.
            </simpara>
         </listitem>
         <listitem>
            <simpara>org.jboss.virtual.VirtualFile - the encapsulation of an
            entry in a virtual file system.
            </simpara>
         </listitem>
         <listitem>
            <simpara>org.jboss.virtual.VirtualFileFilter/VirtualFileFilterWithAttributes
             - filters that can be used to restrict the VirtualFiles matching
             a search.
            </simpara>
         </listitem>
         <listitem>
            <simpara>org.jboss.virtual.VisitorAttributes - attributes that control
               how a visitation of a VFS root is performed.
            </simpara>
         </listitem>
         <listitem>
            <simpara>org.jboss.virtual.VirtualFileVisitor - a callback interface
               used with the VFS/VirtualFile.vist methods.
            </simpara>
         </listitem>
         <listitem>
            <simpara>
               org.jboss.virtual.plugins.vfs.helpers.SuffixMatchFilter - a
               VirtualFileFilter implementation that accepts any file that ends
               with one of the filter suffixes.
            </simpara>
         </listitem>
      </itemizedlist>
      <sect2>
         <title>VFS Examples</title>
         <example>
            <title>Getting a VFS from a root URL</title>
            <programlisting>
               URL rootURL = ...;
               VFS vfs = VFS.getVFS(rootURL);
               VirtualFile jar = vfs.findChild("outer.jar");               
            </programlisting>
         </example>
         <example>
            <title>Getting a VFS from a root URI</title>
            <programlisting>
               URI rootURI = ...;
               VFS vfs = VFS.getVFS(rootURI);
               VirtualFile jar = vfs.findChild("outer.jar");               
            </programlisting>
         </example>
         <example>
            <title>Accessing a jar manifest</title>
            <programlisting>
               URI rootURI = ...;
               VFS vfs = VFS.getVFS(rootURI);
               VirtualFile jar = vfs.findChild("outer.jar");               
               VirtualFile metaInf = jar.findChild("META-INF/MANIFEST.MF");
               InputStream mfIS = metaInf.openStream();
               Manifest mf = new Manifest(mfIS);
               mfIS.close();
               Attributes mainAttrs = mf.getMainAttributes();
               String version = mainAttrs.getValue(Attributes.Name.SPECIFICATION_VERSION);
            </programlisting>
         </example>
         <example>
            <title>Finding all .class files under a VFS root</title>
            <programlisting><![CDATA[
               URI rootURI = ...;
               VFS vfs = VFS.getVFS(rootURI);
               SuffixMatchFilter classVisitor = new SuffixMatchFilter(".class", VisitorAttributes.RECURSE);
               List<VirtualFile> classes = vfs.getChildren(classVisitor);
               int count = 0;
               for (VirtualFile cf : classes)
               {
               ...
               }                  
            ]]></programlisting>
         </example>
      </sect2>
      <sect2>
         <title>org.jboss.virtual Classes</title>
         <example>
            <title>org.jboss.virtual.VFS</title>
            <programlisting><![CDATA[
public class VFS
{
   /**
    * Get the virtual file system for a root uri
    * 
    * @param rootURI the root URI
    * @return the virtual file system
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL is null
    */
   public static VFS getVFS(URI rootURI) throws IOException
   {
   }

   /**
    * Get the root virtual file
    * 
    * @param rootURI the root uri
    * @return the virtual file
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL
    */
   public static VirtualFile getRoot(URI rootURI) throws IOException
   {
   }

   /**
    * Get a virtual file
    * 
    * @param rootURI the root uri
    * @param name the path name
    * @return the virtual file
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL or name is null
    */
   public static VirtualFile getVirtualFile(URI rootURI, String name) throws IOException
   {
   }

   /**
    * Get the virtual file system for a root url
    * 
    * @param rootURL the root url
    * @return the virtual file system
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL is null
    */
   public static VFS getVFS(URL rootURL) throws IOException
   {
   }

   /**
    * Get the root virtual file
    * 
    * @param rootURL the root url
    * @return the virtual file
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL
    */
   public static VirtualFile getRoot(URL rootURL) throws IOException
   {
   }

   /**
    * Get a virtual file
    * 
    * @param rootURL the root url
    * @param name the path name
    * @return the virtual file
    * @throws IOException if there is a problem accessing the VFS
    * @throws IllegalArgumentException if the rootURL or name is null
    */
   public static VirtualFile getVirtualFile(URL rootURL, String name) throws IOException
   {
   }

   /**
    * Get the root file of this VFS
    * 
    * @return the root
    * @throws IOException for any problem accessing the VFS
    */
   public VirtualFile getRoot() throws IOException
   {
   }
   
   /**
    * Find a child from the root
    * 
    * @param path the child path
    * @return the child
    * @throws IOException for any problem accessing the VFS (including the child does not exist)
    * @throws IllegalArgumentException if the path is null
    */
   public VirtualFile findChild(String path) throws IOException
   {
   }
   
   /**
    * Find a child from the root
    * 
    * @Deprecated use {@link #findChild(String)}
    * @param path the child path
    * @return the child
    * @throws IOException for any problem accessing the VFS (including the child does not exist)
    * @throws IllegalArgumentException if the path is null
    */
   @Deprecated
   public VirtualFile findChildFromRoot(String path) throws IOException
   {
   }
   
   /**
    * Get the children
    * 
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the root is a leaf node
    */
   public List<VirtualFile> getChildren() throws IOException
   {
   }

   /**
    * Get the children
    * 
    * @param filter to filter the children
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the root is a leaf node
    */
   public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
   {
   }
   
   /**
    * Get all the children recursively<p>
    * 
    * This always uses {@link VisitorAttributes#RECURSE}
    * 
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the root is a leaf node
    */
   public List<VirtualFile> getChildrenRecursively() throws IOException
   {
   }
   
   /**
    * Get all the children recursively<p>
    * 
    * This always uses {@link VisitorAttributes#RECURSE}
    * 
    * @param filter to filter the children
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the root is a leaf node
    */
   public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
   {
   }
   
   /**
    * Visit the virtual file system from the root
    * 
    * @param visitor the visitor
    * @throws IOException for any problem accessing the VFS
    * @throws IllegalArgumentException if the visitor is null
    * @throws IllegalStateException if the root is a leaf node
    */
   public void visit(VirtualFileVisitor visitor) throws IOException
   {
      ...
   }

}
         ]]></programlisting>
         </example>
         <example>
            <title>org.jboss.virtual.VirtualFile</title>
            <programlisting><![CDATA[
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.jboss.util.collection.WeakSet;
import org.jboss.virtual.plugins.vfs.helpers.FilterVirtualFileVisitor;
import org.jboss.virtual.plugins.vfs.helpers.MatchAllVirtualFileFilter;
import org.jboss.virtual.spi.VFSContext;
import org.jboss.virtual.spi.VirtualFileHandler;

/**
 * A virtual file as seen by the user
 *
 * @author Scott.Stark@jboss.org
 * @author adrian@jboss.org
 * @version $Revision: 44334 $
 */
public class VirtualFile implements Serializable
{
   private static final long serialVersionUID = 1L;

   /** The virtual file handler */
   private final VirtualFileHandler handler;

   /** Whether we are closed */
   private AtomicBoolean closed = new AtomicBoolean(false);

   /** The open streams */
   private transient final Set<InputStream> streams = Collections.synchronizedSet(new WeakSet());

   /**
    * Create a new VirtualFile.
    *
    * @param handler the handler
    * @throws IllegalArgumentException if the handler is null
    */
   public VirtualFile(VirtualFileHandler handler)
   {
...
   }

   /**
    * Get the virtual file handler
    *
    * @return the handler
    * @throws IllegalStateException if the file is closed
    */
   public VirtualFileHandler getHandler()
   {
...
   }

   /**
    * Get the simple VF name (X.java)
    *
    * @return the simple file name
    * @throws IllegalStateException if the file is closed
    */
   public String getName()
   {
...
   }

   /**
    * Get the VFS relative path name (org/jboss/X.java)
    *
    * @return the VFS relative path name
    * @throws IllegalStateException if the file is closed
    */
   public String getPathName()
   {
...
   }

   /**
    * Get the VF URL (file://root/org/jboss/X.java)
    *
    * @return the full URL to the VF in the VFS.
    * @throws MalformedURLException if a url cannot be parsed
    * @throws URISyntaxException if a uri cannot be parsed
    * @throws IllegalStateException if the file is closed
    */
   public URL toURL() throws MalformedURLException, URISyntaxException
   {
...
   }

   /**
    * Get the VF URI (file://root/org/jboss/X.java)
    *
    * @return the full URI to the VF in the VFS.
    * @throws URISyntaxException if a uri cannot be parsed
    * @throws IllegalStateException if the file is closed
    * @throws MalformedURLException for a bad url
    */
   public URI toURI() throws MalformedURLException, URISyntaxException
   {
...
   }

   /**
    * When the file was last modified
    *
    * @return the last modified time
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public long getLastModified() throws IOException
   {
...
   }

   /**
    * Returns true if the file has been modified since this method was last called
    * Last modified time is initialized at handler instantiation.
    *
    * @return
    * @throws IOException
    */
   public boolean hasBeenModified() throws IOException
   {
...
   }

   /**
    * Get the size
    *
    * @return the size
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public long getSize() throws IOException
   {
...
   }

   /**
    * Tests whether the underlying implementation file still exists.
    * @return true if the file exists, false otherwise.
    * @throws IOException - thrown on failure to detect existence.
    */
   public boolean exists() throws IOException
   {
...
   }

   /**
    * Whether it is a simple leaf of the VFS,
    * i.e. whether it can contain other files
    *
    * @return true if a simple file.
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public boolean isLeaf() throws IOException
   {
...
   }

   /**
    * Whether it is hidden
    *
    * @return true when hidden
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public boolean isHidden() throws IOException
   {
...
   }

   /**
    * Access the file contents.
    *
    * @return an InputStream for the file contents.
    * @throws IOException for any error accessing the file system
    * @throws IllegalStateException if the file is closed
    */
   public InputStream openStream() throws IOException
   {
...
   }

   /**
    * Close the streams
    */
   public void closeStreams()
   {
...
   }

   /**
    * Close the file resources (stream, etc.)
    */
   public void close()
   {
...
   }

   /**
    * Get the VFS instance for this virtual file
    *
    * @return the VFS
    * @throws IllegalStateException if the file is closed
    */
   public VFS getVFS()
   {
...
   }

   /**
    * Get the parent
    *
    * @return the parent or null if there is no parent
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public VirtualFile getParent() throws IOException
   {
...
   }

   /**
    * Get the children
    *
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public List<VirtualFile> getChildren() throws IOException
   {
      return getChildren(null);
   }

   /**
    * Get the children
    *
    * @param filter to filter the children
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed or it is a leaf node
    */
   public List<VirtualFile> getChildren(VirtualFileFilter filter) throws IOException
   {
...
   }

   /**
    * Get all the children recursively<p>
    *
    * This always uses {@link VisitorAttributes#RECURSE}
    *
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed
    */
   public List<VirtualFile> getChildrenRecursively() throws IOException
   {
      return getChildrenRecursively(null);
   }

   /**
    * Get all the children recursively<p>
    *
    * This always uses {@link VisitorAttributes#RECURSE}
    *
    * @param filter to filter the children
    * @return the children
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalStateException if the file is closed or it is a leaf node
    */
   public List<VirtualFile> getChildrenRecursively(VirtualFileFilter filter) throws IOException
   {
...
   }

   /**
    * Visit the virtual file system
    *
    * @param visitor the visitor
    * @throws IOException for any problem accessing the virtual file system
    * @throws IllegalArgumentException if the visitor is null
    * @throws IllegalStateException if the file is closed or it is a leaf node
    */
   public void visit(VirtualFileVisitor visitor) throws IOException
   {
...
   }

   /**
    * Find a child
    *
    * @param path the path
    * @return the child
    * @throws IOException for any problem accessing the VFS (including the child does not exist)
    * @throws IllegalArgumentException if the path is null
    * @throws IllegalStateException if the file is closed or it is a leaf node
    */
   public VirtualFile findChild(String path) throws IOException
   {
...
   }

}
            ]]></programlisting>
         </example>
         <example>
            <title>org.jboss.virtual.VisitorAttributes</title>
            <programlisting><![CDATA[
/**
 * Attributes used when visiting a virtual file system
 * 
 * @author <a href="adrian@jboss.com">Adrian Brock</a>
 * @author Scott.Stark@jboss.org
 * @version $Revision: 1.1 $
 */
public class VisitorAttributes
{
   /** A VirtualFileFilter than accepts any file */
   public static final AcceptAnyFilter RECURSE_ALL = new AcceptAnyFilter();

   /** The default attributes - visit nothing both leaves, non-leaves, no recursion */
   public static final VisitorAttributes DEFAULT = new ImmutableVisitorAttributes();

   /** Visit leaves only and do not recurse non-leaf files */
   public static final VisitorAttributes LEAVES_ONLY = new ImmutableVisitorAttributes(true, null);

   /** Recurse and visit all non-leaf files */
   public static final VisitorAttributes RECURSE = new ImmutableVisitorAttributes(false, RECURSE_ALL);

   /** Recurse all non-leaf files but only visit leaves */
   public static final VisitorAttributes RECURSE_LEAVES_ONLY = new ImmutableVisitorAttributes(true, RECURSE_ALL);
   
   /** Whether to include the root */
   private boolean includeRoot;

   /** Whether to only visit leaves */
   private boolean leavesOnly;

   /** Whether to ignore individual file errors */
   private boolean ignoreErrors;

   /** Whether to include hidden files */
   private boolean includeHidden;

   /** A filter used to control whether a non-leaf is recursive visited */
   private VirtualFileFilter recurseFilter;

   /**
    * Whether to visit leaves only<p>
    * 
    * Default: false
    * 
    * @return the visit leaves only.
    */
   public boolean isLeavesOnly()
   {
      return leavesOnly;
   }

   /**
    * Set the leaves only.
    * 
    * @param leavesOnly the leaves only
    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
    */
   public void setLeavesOnly(boolean leavesOnly)
   {
      this.leavesOnly = leavesOnly;
   }

   /**
    * Whether to recurse into the non-leaf file<p>. If there is a recurse
    * filter then the result will by its accepts(file) value.
    * 
    * Default: false
    * 
    * @param file the file
    * @return the recurse flag.
    */
   public boolean isRecurse(VirtualFile file)
   {
      boolean recurse = false;
      if( recurseFilter != null )
         recurse = recurseFilter.accepts(file);
      return recurse;
   }

   /**
    * Get the recurse filter.
    * @return the current recurse filter.
    */
   public VirtualFileFilter getRecurseFilter()
   {
      return recurseFilter;
   }

   /**
    * Set the recurse filter.
    * 
    * @param filter - the recurse filter.
    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
    */
   public void setRecurseFilter(VirtualFileFilter filter)
   {
      this.recurseFilter = filter;
   }

   /**
    * Whether to include the root of the visit<p>
    * 
    * Default: false
    * 
    * @return the includeRoot.
    */
   public boolean isIncludeRoot()
   {
      return includeRoot;
   }

   /**
    * Set the includeRoot.
    * 
    * @param includeRoot the includeRoot.
    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
    */
   public void setIncludeRoot(boolean includeRoot)
   {
      this.includeRoot = includeRoot;
   }

   /**
    * Whether to ignore individual errors<p>
    * 
    * Default: false
    * 
    * @return the ignoreErrors.
    */
   public boolean isIgnoreErrors()
   {
      return ignoreErrors;
   }

   /**
    * Set the ignoreErrors.
    * 
    * @param ignoreErrors the ignoreErrors.
    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
    */
   public void setIgnoreErrors(boolean ignoreErrors)
   {
      this.ignoreErrors = ignoreErrors;
   }

   /**
    * Whether to include hidden files<p>
    * 
    * Default: false
    * 
    * @return the includeHidden.
    */
   public boolean isIncludeHidden()
   {
      return includeHidden;
   }

   /**
    * Set the includeHidden.
    * 
    * @param includeHidden the includeHidden.
    * @throws IllegalStateException if you attempt to modify one of the preconfigured static values of this class
    */
   public void setIncludeHidden(boolean includeHidden)
   {
      this.includeHidden = includeHidden;
   }

}

            ]]></programlisting>            
         </example>
      </sect2>
   </sect1>

   <sect1>
      <title>Configuration</title>
      <para>TODO:jboss-vfs.jar ...</para>
   </sect1>


</chapter>
