From 52926715b4f4f53da4b63cf660a14f357d7a9b6e Mon Sep 17 00:00:00 2001 From: adammurdoch Date: Sat, 9 Mar 2002 10:31:31 +0000 Subject: [PATCH] VFS Tidy-ups: * Added FileObject.copy(). * Renamed task attributes file -> srcfile, tofile -> destfile, todir -> destdir. * Moved provider instantiation out of DefaultFileSystemManager, and into myrmidon-aware VfsManager. Providers are instantiated using the TypeManager. The list of providers isn't configurable yet. * Some support for %nn encoded URI (not quite complete). * Zip file system now handles zip files from any file system, not just local files. Still read-only at this stage. Uses a truely dodgy and very temporary replication mechanism. * Zip file system now handles relative paths in URI (e.g. zip:relpath.zip), that are resolved against the base dir. * Fixed bug in resolving names against the root file of a file system. * Changed behaviour of FileName.resolveName( ".." ) for the root file of a file system. * Added more test cases. * A bucketload of other minor changes. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271803 13f79535-47bb-0310-9956-ffa450edef68 --- proposal/myrmidon/build.xml | 3 + proposal/myrmidon/docs/todo.html | 19 +- proposal/myrmidon/docs/user.html | 3 +- .../org/apache/antlib/vfile/copy.ant | 2 +- .../apache/antlib/vfile/CopyFilesTask.java | 60 ++---- .../apache/antlib/vfile/DefaultFileSet.java | 9 + .../apache/antlib/vfile/ListFileSetTask.java | 26 ++- .../apache/antlib/vfile/Resources.properties | 1 - .../java/org/apache/aut/vfs/FileObject.java | 20 ++ .../org/apache/aut/vfs/FileSystemManager.java | 42 ++++- .../vfs/impl/DefaultFileSystemManager.java | 132 ++++++------- .../aut/vfs/impl/DefaultProviderContext.java | 66 +++++++ .../apache/aut/vfs/impl/Resources.properties | 2 + .../aut/vfs/provider/AbstractFileObject.java | 43 ++++- .../provider/AbstractFileSystemProvider.java | 76 ++++++-- .../aut/vfs/provider/FileSystemProvider.java | 15 +- .../provider/FileSystemProviderContext.java | 13 +- .../apache/aut/vfs/provider/ParsedUri.java | 4 +- .../aut/vfs/provider/Resources.properties | 4 + .../apache/aut/vfs/provider/UriParser.java | 173 ++++++++++++++++-- .../vfs/provider/ftp/FtpFileNameParser.java | 24 ++- .../provider/ftp/FtpFileSystemProvider.java | 19 +- .../provider/local/LocalFileNameParser.java | 17 +- .../local/LocalFileSystemProvider.java | 21 ++- .../vfs/provider/smb/SmbFileNameParser.java | 33 ++-- .../provider/smb/SmbFileSystemProvider.java | 19 +- .../aut/vfs/provider/zip/ParsedZipUri.java | 18 +- .../vfs/provider/zip/ZipFileNameParser.java | 76 ++++---- .../provider/zip/ZipFileSystemProvider.java | 78 ++++++-- .../framework/factories/Resources.properties | 3 +- .../framework/factories/VfsManager.java | 108 +++++++++++ .../factories/VfsManagerFactory.java | 3 +- .../myrmidon/src/manifest/core-services.xml | 7 +- .../aut/vfs/AbstractFileSystemTest.java | 113 +++++++++++- .../vfs/AbstractWritableFileSystemTest.java | 7 +- .../org/apache/aut/vfs/FtpFileSystemTest.java | 16 +- .../apache/aut/vfs/LocalFileSystemTest.java | 10 +- .../aut/vfs/NestedZipFileSystemTest.java | 41 +++++ .../org/apache/aut/vfs/SmbFileSystemTest.java | 13 +- .../org/apache/aut/vfs/ZipFileSystemTest.java | 8 +- .../aut/vfs/AbstractFileSystemTest.java | 113 +++++++++++- .../vfs/AbstractWritableFileSystemTest.java | 7 +- .../org/apache/aut/vfs/FtpFileSystemTest.java | 16 +- .../apache/aut/vfs/LocalFileSystemTest.java | 10 +- .../aut/vfs/NestedZipFileSystemTest.java | 41 +++++ .../org/apache/aut/vfs/SmbFileSystemTest.java | 13 +- .../org/apache/aut/vfs/ZipFileSystemTest.java | 8 +- proposal/myrmidon/src/xdocs/todo.xml | 19 +- proposal/myrmidon/src/xdocs/user.xml | 3 +- 49 files changed, 1227 insertions(+), 350 deletions(-) create mode 100644 proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultProviderContext.java create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManager.java create mode 100644 proposal/myrmidon/src/test/org/apache/aut/vfs/NestedZipFileSystemTest.java create mode 100644 proposal/myrmidon/src/testcases/org/apache/aut/vfs/NestedZipFileSystemTest.java diff --git a/proposal/myrmidon/build.xml b/proposal/myrmidon/build.xml index c63e4b46f..a05d8af2a 100644 --- a/proposal/myrmidon/build.xml +++ b/proposal/myrmidon/build.xml @@ -557,6 +557,9 @@ Legal: + + +

The VFS needs plenty of work:

    -
  • Move and copy files/folders.
  • +
  • Move files/folders.
  • +
  • Recursive folders copy.
  • Search through a file hierarchy, using Ant-style wildcards.
  • Search through a file hierarchy, using a Selector interface.
  • The in-memory caching mechanism is pretty rudimentary at this stage. It needs work to make it size capped. In addition, some mechanism needs to be provided to release and refresh cached info.
  • +
  • Convert files/folders into local files, for handing off + to external commands, or legacy tasks.
  • +
  • Refactor the replication mechanism out of ZipFileSystemProvder, + and make more general pluggable.
  • Capabilities discovery.
  • Attributes and attribute schema.
  • +
  • Handle file canonicalisation better (for cases like case-insensitive + file systems, symbolic links, name encoding, etc).
  • File system layering. That is, the ability for a file system to sit on top of another file system, or a file from another file system (e.g. Zip/Jar/Tar file systems, gzip/encoding file systems, virtual file @@ -300,10 +307,6 @@

    A completely unordered list of items, big and small:

    • Search through the code for 'TODO' items and fix them.
    • -
    • Tidy-up CLIMain so that it calls System.exit() with a non-zero exit code, - if the build fails.
    • -
    • Tidy-up the 'build failed' message, so that the stack trace is only - printed out if the log level is verbose/debug.
    • Allow service factories to be configured from the contents of the ant-services.xml descriptor.
    • Route external process stdout and stderr through the logger.
    • @@ -314,11 +317,10 @@
    • Fire ProjectListener events projectStarted() and projectFinished() events on start and finish of referenced projects, adding indicator methods to ProjectEvent.
    • -
    • Convert PropertyUtil to a non-static PropertyResolver service.
    • Validate project and target names in DefaultProjectBuilder - reject dodgy - names like "," or "", or " ". Probably want to exclude names that start or + names like "," or "", or " ". Probably want to reject names that start or end with white-space (though internal whitespace is probably fine). We also - want to reserve certain punctuation characters like . , : ? [ ] { }, etc for + want to reserve certain punctuation characters like , : ? $ [ ] { } < >, etc for future use.
    • Similarly, validate property names, using the same rules.
    • Detect duplicate type names.
    • @@ -330,6 +332,7 @@ an antlib.
    • Split up <is-set> condition into is-set and is-true conditions.
    • Allow the <if> task to take any condition implementation.
    • +
    • Add an else block to the <if> task.
    • Unit tests.
    diff --git a/proposal/myrmidon/docs/user.html b/proposal/myrmidon/docs/user.html index db73fe914..1f7701ea6 100644 --- a/proposal/myrmidon/docs/user.html +++ b/proposal/myrmidon/docs/user.html @@ -125,7 +125,8 @@ files are found in the lib directory:

    - jcifs.samba.org + jcifs.samba.org. +

    Note: there are problems using the 0.6.1 release. Try 0.6.0 instead.

    diff --git a/proposal/myrmidon/etc/testcases/org/apache/antlib/vfile/copy.ant b/proposal/myrmidon/etc/testcases/org/apache/antlib/vfile/copy.ant index 8b68c7057..18ea5067c 100644 --- a/proposal/myrmidon/etc/testcases/org/apache/antlib/vfile/copy.ant +++ b/proposal/myrmidon/etc/testcases/org/apache/antlib/vfile/copy.ant @@ -1,7 +1,7 @@ - + diff --git a/proposal/myrmidon/src/java/org/apache/antlib/vfile/CopyFilesTask.java b/proposal/myrmidon/src/java/org/apache/antlib/vfile/CopyFilesTask.java index 1a3fdcf6a..5ebcb253e 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/vfile/CopyFilesTask.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/vfile/CopyFilesTask.java @@ -7,8 +7,6 @@ */ package org.apache.antlib.vfile; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; import org.apache.aut.vfs.FileObject; @@ -41,7 +39,7 @@ public class CopyFilesTask /** * Sets the source file. */ - public void setFile( final FileObject file ) + public void setSrcfile( final FileObject file ) { m_srcFile = file; } @@ -49,7 +47,7 @@ public class CopyFilesTask /** * Sets the destination file. */ - public void setTofile( final FileObject file ) + public void setDestfile( final FileObject file ) { m_destFile = file; } @@ -57,11 +55,19 @@ public class CopyFilesTask /** * Sets the destination directory. */ - public void setTodir( final FileObject file ) + public void setDestdir( final FileObject file ) { m_destDir = file; } + /** + * Sets the source directory. + */ + public void setSrcdir( final FileObject dir ) + { + add( new DefaultFileSet( dir ) ); + } + /** * Adds a source file set. */ @@ -107,7 +113,8 @@ public class CopyFilesTask m_destFile = m_destDir.resolveFile( m_srcFile.getName().getBaseName() ); } - copyFile( m_srcFile, m_destFile ); + getLogger().info( "copy " + m_srcFile + " to " + m_destFile ); + m_destFile.copy( m_srcFile ); } // Copy the contents of the filesets across @@ -134,7 +141,8 @@ public class CopyFilesTask final FileObject destFile = m_destDir.resolveFile( path, NameScope.DESCENDENT ); // Copy the file across - copyFile( srcFile, destFile ); + getLogger().info( "copy " + srcFile + " to " + destFile ); + destFile.copy( srcFile ); } } } @@ -144,42 +152,4 @@ public class CopyFilesTask } } - /** - * Copies a file. - */ - private void copyFile( final FileObject srcFile, final FileObject destFile ) - throws TaskException - { - getLogger().info( "copy " + srcFile + " to " + destFile ); - - try - { - // TODO - move copy behind FileObject interface - InputStream instr = srcFile.getContent().getInputStream(); - try - { - OutputStream outstr = destFile.getContent().getOutputStream(); - byte[] buffer = new byte[ 4096 ]; - while( true ) - { - int nread = instr.read( buffer ); - if( nread == -1 ) - { - break; - } - outstr.write( buffer, 0, nread ); - } - outstr.close(); - } - finally - { - instr.close(); - } - } - catch( Exception exc ) - { - final String message = REZ.getString( "copyfilestask.copy-file.error", srcFile, destFile ); - throw new TaskException( message, exc ); - } - } } diff --git a/proposal/myrmidon/src/java/org/apache/antlib/vfile/DefaultFileSet.java b/proposal/myrmidon/src/java/org/apache/antlib/vfile/DefaultFileSet.java index e8cbf469b..78f94e72c 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/vfile/DefaultFileSet.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/vfile/DefaultFileSet.java @@ -36,6 +36,15 @@ public class DefaultFileSet private FileObject m_dir; private final AndFileSelector m_selector = new AndFileSelector(); + public DefaultFileSet() + { + } + + public DefaultFileSet( final FileObject dir ) + { + m_dir = dir; + } + /** * Sets the root directory. */ diff --git a/proposal/myrmidon/src/java/org/apache/antlib/vfile/ListFileSetTask.java b/proposal/myrmidon/src/java/org/apache/antlib/vfile/ListFileSetTask.java index fa64e9862..bd2ff212c 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/vfile/ListFileSetTask.java +++ b/proposal/myrmidon/src/java/org/apache/antlib/vfile/ListFileSetTask.java @@ -7,6 +7,7 @@ */ package org.apache.antlib.vfile; +import java.util.ArrayList; import org.apache.aut.vfs.FileObject; import org.apache.myrmidon.api.AbstractTask; import org.apache.myrmidon.api.TaskException; @@ -22,11 +23,11 @@ import org.apache.myrmidon.api.TaskException; public class ListFileSetTask extends AbstractTask { - private FileSet m_fileSet; + private final ArrayList m_fileSets = new ArrayList(); - public void set( final FileSet fileSet ) + public void add( final FileSet fileSet ) { - m_fileSet = fileSet; + m_fileSets.add( fileSet ); } /** @@ -35,14 +36,19 @@ public class ListFileSetTask public void execute() throws TaskException { - FileSetResult result = m_fileSet.getResult( getContext() ); - final FileObject[] files = result.getFiles(); - final String[] paths = result.getPaths(); - for( int i = 0; i < files.length; i++ ) + final int count = m_fileSets.size(); + for( int i = 0; i < count; i++ ) { - final FileObject file = files[ i ]; - final String path = paths[ i ]; - getLogger().info( path + " = " + file ); + final FileSet fileSet = (FileSet)m_fileSets.get(i ); + FileSetResult result = fileSet.getResult( getContext() ); + final FileObject[] files = result.getFiles(); + final String[] paths = result.getPaths(); + for( int j = 0; j < files.length; j++ ) + { + final FileObject file = files[ j ]; + final String path = paths[ j ]; + getLogger().info( path + " = " + file ); + } } } } diff --git a/proposal/myrmidon/src/java/org/apache/antlib/vfile/Resources.properties b/proposal/myrmidon/src/java/org/apache/antlib/vfile/Resources.properties index 2f0741bb0..b0eb4863c 100644 --- a/proposal/myrmidon/src/java/org/apache/antlib/vfile/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/antlib/vfile/Resources.properties @@ -6,6 +6,5 @@ fileset.list-files.error=Could not list the files in folder "{0}". copyfilestask.no-source.error=No source files specified for {0} task. copyfilestask.no-destination.error=No destination file or directory specified for {0} task. copyfilestask.no-destination.error=No destination directory specified for {0} task. -copyfilestask.copy-file.error=Could not copy "{0}" to "{1}". filteredfilelist.no-selector.error=No filter criteria specified. diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/FileObject.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/FileObject.java index fc5a720ef..42210e513 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/FileObject.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/FileObject.java @@ -181,6 +181,20 @@ public interface FileObject */ void create( FileType type ) throws FileSystemException; + /** + * Copies the content of another file to this file. + * + * If this file does not exist, it is created. Its parent folder is also + * created, if necessary. If this file does exist, its content is replaced. + * + * @param file The file to copy the content from. + * + * @throws FileSystemException + * If this file is read-only, or is a folder, or if the supplied file + * is not a file, or on error copying the content. + */ + void copy( FileObject file ) throws FileSystemException; + /** * Returns this file's content. The {@link FileContent} returned by this * method can be used to read and write the content of the file. @@ -189,6 +203,12 @@ public interface FileObject * the returned {@link FileContent} can be used to create the file * by writing its content. * + * @todo Do not throw an exception if this file is a folder. Instead, + * throw the exceptions when (if) any methods on the returned object + * are called. This is to hand 2 cases: when the folder is deleted + * and recreated as a file, and to allow attributes of the folder + * to be set (last modified time, permissions, etc). + * * @return * This file's content. * diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/FileSystemManager.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/FileSystemManager.java index 1c43a9f73..19768527c 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/FileSystemManager.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/FileSystemManager.java @@ -71,7 +71,8 @@ public interface FileSystemManager * @throws FileSystemException * On error parsing the file name. */ - FileObject resolveFile( String name ) throws FileSystemException; + FileObject resolveFile( String name ) + throws FileSystemException; /** * Locates a file by name. The name is resolved as described @@ -90,7 +91,8 @@ public interface FileSystemManager * @throws FileSystemException * On error parsing the file name. */ - FileObject resolveFile( FileObject baseFile, String name ) throws FileSystemException; + FileObject resolveFile( FileObject baseFile, String name ) + throws FileSystemException; /** * Locates a file by name. See {@link #resolveFile(FileObject, String)} @@ -106,5 +108,39 @@ public interface FileSystemManager * On error parsing the file name. * */ - FileObject resolveFile( File baseFile, String name ) throws FileSystemException; + FileObject resolveFile( File baseFile, String name ) + throws FileSystemException; + + /** + * Converts a local file into a {@link FileObject}. + * + * @param file + * The file to convert. + * + * @return + * The {@link FileObject} that represents the local file. + * + * @throws FileSystemException + * On error converting the file. + */ + FileObject convert( File file ) + throws FileSystemException; + + /** + * Creates a layered file system. A layered file system is a file system + * that is created from the contents of another file file, such as a zip + * or tar file. + * + * @param provider + * The name of the file system provider to use. This name is + * the same as the scheme used in URI to identify the provider. + * + * @param file + * The file to use to create the file system. + * + * @throws FileSystemException + * On error creating the file system. + */ + FileObject createFileSystem( String provider, FileObject file ) + throws FileSystemException; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultFileSystemManager.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultFileSystemManager.java index a13539905..f3b3aebd9 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultFileSystemManager.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultFileSystemManager.java @@ -9,14 +9,11 @@ package org.apache.aut.vfs.impl; import java.io.File; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.FileSystemException; import org.apache.aut.vfs.FileSystemManager; -import org.apache.aut.vfs.provider.FileSystem; import org.apache.aut.vfs.provider.FileSystemProvider; -import org.apache.aut.vfs.provider.FileSystemProviderContext; import org.apache.aut.vfs.provider.UriParser; import org.apache.aut.vfs.provider.local.LocalFileSystemProvider; import org.apache.avalon.excalibur.i18n.ResourceManager; @@ -25,7 +22,8 @@ import org.apache.avalon.excalibur.i18n.Resources; /** * A default file system manager implementation. * - * @author Adam Murdoch + * @author Adam Murdoch + * @version $Revision$ $Date$ */ public class DefaultFileSystemManager implements FileSystemManager @@ -40,69 +38,55 @@ public class DefaultFileSystemManager private final Map m_providers = new HashMap(); /** The provider context. */ - private final ProviderContextImpl m_context = new ProviderContextImpl(); + private final DefaultProviderContext m_context = new DefaultProviderContext( this ); /** The base file to use for relative URI. */ private FileObject m_baseFile; - /** - * The cached file systems. This is a mapping from root URI to - * FileSystem object. - */ - private final Map m_fileSystems = new HashMap(); - - public DefaultFileSystemManager() throws Exception + public DefaultFileSystemManager() { // Create the local provider m_localFileProvider = new LocalFileSystemProvider(); m_providers.put( "file", m_localFileProvider ); + m_localFileProvider.setContext( m_context ); + } - // TODO - make this list configurable - // Create the providers - - FileSystemProvider provider = createProvider( "org.apache.aut.vfs.provider.zip.ZipFileSystemProvider" ); - if( provider != null ) - { - m_providers.put( "zip", provider ); - m_providers.put( "jar", provider ); - } - - provider = createProvider( "org.apache.aut.vfs.provider.smb.SmbFileSystemProvider" ); - if( provider != null ) - { - m_providers.put( "smb", provider ); - } - - provider = createProvider( "org.apache.aut.vfs.provider.ftp.FtpFileSystemProvider" ); - if( provider != null ) - { - m_providers.put( "ftp", provider ); - } - - // Contextualise the providers - for( Iterator iterator = m_providers.values().iterator(); iterator.hasNext(); ) - { - provider = (FileSystemProvider)iterator.next(); - provider.setContext( m_context ); - } + /** + * Registers a file system provider. + */ + public void addProvider( final String urlScheme, + final FileSystemProvider provider ) + throws FileSystemException + { + addProvider( new String[] { urlScheme }, provider ); } /** - * Creates a provider instance, returns null if the provider class is - * not found. + * Registers a file system provider. */ - private FileSystemProvider createProvider( final String className ) - throws Exception + public void addProvider( final String[] urlSchemes, + final FileSystemProvider provider ) + throws FileSystemException { - try + // Check for duplicates + for( int i = 0; i < urlSchemes.length; i++ ) { - // TODO - wrap exceptions - return (FileSystemProvider)Class.forName( className ).newInstance(); + final String scheme = urlSchemes[i ]; + if( m_providers.containsKey( scheme ) ) + { + final String message = REZ.getString( "multiple-providers-for-scheme.error", scheme ); + throw new FileSystemException( message ); + } } - catch( ClassNotFoundException e ) + + // Contextualise + provider.setContext( m_context ); + + // Add to map + for( int i = 0; i < urlSchemes.length; i++ ) { - // This is fine, for now - return null; + final String scheme = urlSchemes[ i ]; + m_providers.put( scheme, provider ); } } @@ -152,7 +136,7 @@ public class DefaultFileSystemManager public FileObject resolveFile( final File baseFile, final String uri ) throws FileSystemException { - final FileObject baseFileObj = m_localFileProvider.findFileByLocalName( baseFile ); + final FileObject baseFileObj = m_localFileProvider.findLocalFile( baseFile ); return resolveFile( baseFileObj, uri ); } @@ -170,14 +154,17 @@ public class DefaultFileSystemManager final FileSystemProvider provider = (FileSystemProvider)m_providers.get( scheme ); if( provider != null ) { - return provider.findFile( uri ); + return provider.findFile( baseFile, uri ); } } + // Decode the URI (remove %nn encodings) + final String decodedUri = UriParser.decode( uri ); + // Handle absolute file names - if( m_localFileProvider.isAbsoluteLocalName( uri ) ) + if( m_localFileProvider.isAbsoluteLocalName( decodedUri ) ) { - return m_localFileProvider.findLocalFile( uri ); + return m_localFileProvider.findLocalFile( decodedUri ); } // Assume a bad scheme @@ -193,32 +180,31 @@ public class DefaultFileSystemManager final String message = REZ.getString( "find-rel-file.error", uri ); throw new FileSystemException( message ); } - return baseFile.resolveFile( uri ); + return baseFile.resolveFile( decodedUri ); } /** - * A provider context implementation. + * Converts a local file into a {@link FileObject}. */ - private final class ProviderContextImpl - implements FileSystemProviderContext + public FileObject convert( final File file ) + throws FileSystemException { - /** - * Locates a cached file system by root URI. - */ - public FileSystem getFileSystem( final String rootURI ) - { - // TODO - need to have a per-fs uri comparator - return (FileSystem)m_fileSystems.get( rootURI ); - } + return m_localFileProvider.findLocalFile( file ); + } - /** - * Registers a file system for caching. - */ - public void putFileSystem( final String rootURI, final FileSystem fs ) - throws FileSystemException + /** + * Creates a layered file system. + */ + public FileObject createFileSystem( final String scheme, + final FileObject file ) + throws FileSystemException + { + FileSystemProvider provider = (FileSystemProvider)m_providers.get( scheme ); + if( provider == null ) { - // TODO - should really check that there's not one already cached - m_fileSystems.put( rootURI, fs ); + final String message = REZ.getString( "unknown-provider.error", scheme ); + throw new FileSystemException( message ); } + return provider.createFileSystem( scheme, file ); } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultProviderContext.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultProviderContext.java new file mode 100644 index 000000000..9cb6ac6b8 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/DefaultProviderContext.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.aut.vfs.impl; + +import java.util.HashMap; +import java.util.Map; +import org.apache.aut.vfs.FileObject; +import org.apache.aut.vfs.FileSystemException; +import org.apache.aut.vfs.provider.FileSystem; +import org.apache.aut.vfs.provider.FileSystemProviderContext; + +/** + * A provider context implementation. + * + * @author Adam Murdoch + * @version $Revision$ $Date$ + */ +final class DefaultProviderContext + implements FileSystemProviderContext +{ + private final DefaultFileSystemManager m_manager; + + /** + * The cached file systems. This is a mapping from root URI to + * FileSystem object. + */ + private final Map m_fileSystems = new HashMap(); + + public DefaultProviderContext( final DefaultFileSystemManager manager ) + { + m_manager = manager; + } + + /** + * Locate a file by name. + */ + public FileObject resolveFile( final FileObject baseFile, final String name ) + throws FileSystemException + { + return m_manager.resolveFile( baseFile, name ); + } + + /** + * Locates a cached file system by root URI. + */ + public FileSystem getFileSystem( final String rootURI ) + { + // TODO - need to have a per-fs uri comparator + return (FileSystem)m_fileSystems.get( rootURI ); + } + + /** + * Registers a file system for caching. + */ + public void putFileSystem( final String rootURI, final FileSystem fs ) + throws FileSystemException + { + // TODO - should really check that there's not one already cached + m_fileSystems.put( rootURI, fs ); + } +} diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/Resources.properties b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/Resources.properties index 201aa219e..6d9077083 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/impl/Resources.properties @@ -1,3 +1,5 @@ # DefaultFileSystemManager unknown-scheme.error=Unknown scheme "{0}" in URI "{1}". find-rel-file.error=Could not find file with URI "{0}" because it is a relative path, and no base URI was provided. +multiple-providers-for-scheme.error=Multiple file system providers registered for URL scheme "{0}". +unknown-provider.error=Unknown file system provider "{0}". \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileObject.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileObject.java index 60c5aaff5..cedc0b453 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileObject.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileObject.java @@ -21,6 +21,7 @@ import org.apache.aut.vfs.FileType; import org.apache.aut.vfs.NameScope; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.excalibur.io.IOUtil; /** * A partial file object implementation. @@ -349,7 +350,7 @@ public abstract class AbstractFileObject } // Update cached info - updateType( null ); + updateType(); } /** @@ -463,7 +464,41 @@ public abstract class AbstractFileObject } // Update cached info - updateType( type ); + updateType(); + } + + /** + * Copies the content of another file to this file. + */ + public void copy( final FileObject file ) throws FileSystemException + { + try + { + final InputStream instr = file.getContent().getInputStream(); + try + { + // Create the output strea via getContent(), to pick up the + // validation it does + final OutputStream outstr = getContent().getOutputStream(); + try + { + IOUtil.copy( instr, outstr ); + } + finally + { + IOUtil.shutdownStream( outstr ); + } + } + finally + { + IOUtil.shutdownStream( instr ); + } + } + catch( final Exception exc ) + { + final String message = REZ.getString( "copy-file.error", file.getName(), m_name ); + throw new FileSystemException( message, exc ); + } } /** @@ -598,14 +633,14 @@ public abstract class AbstractFileObject */ public void endOutput() throws Exception { - updateType( FileType.FILE ); + updateType(); doEndOutput(); } /** * Update cached info when this file's type changes. */ - private void updateType( FileType type ) + private void updateType() { // Notify parent that its child list may no longer be valid notifyParent(); diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileSystemProvider.java index 2d3955162..f3e6e0d92 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/AbstractFileSystemProvider.java @@ -23,13 +23,21 @@ public abstract class AbstractFileSystemProvider private final static Resources REZ = ResourceManager.getPackageResources( AbstractFileSystemProvider.class ); - protected FileSystemProviderContext m_context; + private FileSystemProviderContext m_context; + + /** + * Returns the context for this provider. + */ + protected FileSystemProviderContext getContext() + { + return m_context; + } /** * Sets the context for this file system provider. This method is called * before any of the other provider methods. */ - public void setContext( FileSystemProviderContext context ) + public void setContext( final FileSystemProviderContext context ) { m_context = context; } @@ -40,13 +48,14 @@ public abstract class AbstractFileSystemProvider * @param uri * The absolute URI of the file to find. */ - public FileObject findFile( String uri ) throws FileSystemException + public FileObject findFile( final FileObject baseFile, + final String uri ) throws FileSystemException { // Parse the URI - ParsedUri parsedURI = null; + ParsedUri parsedUri = null; try { - parsedURI = parseURI( uri ); + parsedUri = parseUri( baseFile, uri ); } catch( FileSystemException exc ) { @@ -54,31 +63,70 @@ public abstract class AbstractFileSystemProvider throw new FileSystemException( message, exc ); } + // Locate the file + return findFile( parsedUri ); + + } + + /** + * Locates a file from its parsed URI. + */ + private FileObject findFile( final ParsedUri parsedUri ) + throws FileSystemException + { // Check in the cache for the file system - FileSystem fs = m_context.getFileSystem( parsedURI.getRootURI() ); + final String rootUri = parsedUri.getRootUri(); + FileSystem fs = m_context.getFileSystem( rootUri ); if( fs == null ) { - // Need to create the file system - fs = createFileSystem( parsedURI ); - m_context.putFileSystem( parsedURI.getRootURI(), fs ); + // Need to create the file system, and cache it + fs = createFileSystem( parsedUri ); + m_context.putFileSystem( rootUri, fs ); } // Locate the file - return fs.findFile( parsedURI.getPath() ); + return fs.findFile( parsedUri.getPath() ); + } + + /** + * Creates a layered file system. + */ + public FileObject createFileSystem( final String scheme, final FileObject file ) + throws FileSystemException + { + // TODO - this is a pretty shonky model for layered FS; need to revise + + // Build the URI + final ParsedUri uri = buildUri( scheme, file ); + + // Locate the file + return findFile( uri ); } /** * Parses a URI into its components. The returned value is used to - * locate the file system in the cache (using the root prefix), and is - * passed to {@link #createFileSystem} to create the file system. + * locate the file system in the cache (using the root prefix). * *

    The provider can annotate this object with any additional * information it requires to create a file system from the URI. */ - protected abstract ParsedUri parseURI( String uri ) throws FileSystemException; + protected abstract ParsedUri parseUri( final FileObject baseFile, final String uri ) + throws FileSystemException; + + /** + * Builds the URI for the root of a layered file system. + */ + protected ParsedUri buildUri( final String scheme, + final FileObject file ) + throws FileSystemException + { + final String message = REZ.getString( "not-layered-fs.error" ); + throw new FileSystemException( message ); + } /** * Creates the filesystem. */ - protected abstract org.apache.aut.vfs.provider.FileSystem createFileSystem( ParsedUri uri ) throws FileSystemException; + protected abstract FileSystem createFileSystem( final ParsedUri uri ) + throws FileSystemException; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProvider.java index 80afef499..53166a947 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProvider.java @@ -12,6 +12,11 @@ import org.apache.aut.vfs.FileSystemException; /** * A file system provider, or factory. + * + * @author Adam Murdoch + * @version $Revision$ $Date$ + * + * @ant:role shorthand="file-system" */ public interface FileSystemProvider { @@ -24,8 +29,16 @@ public interface FileSystemProvider /** * Locates a file object, by absolute URI. * + * @param baseFile + * The base file to use for resolving the individual parts of + * a compound URI. * @param uri * The absolute URI of the file to find. */ - FileObject findFile( String uri ) throws FileSystemException; + FileObject findFile( FileObject baseFile, String uri ) throws FileSystemException; + + /** + * Creates a layered file system. + */ + FileObject createFileSystem( String scheme, FileObject file ) throws FileSystemException; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProviderContext.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProviderContext.java index 6062df4b3..1fb092d11 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProviderContext.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/FileSystemProviderContext.java @@ -7,16 +7,27 @@ */ package org.apache.aut.vfs.provider; +import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.FileSystemException; +import org.apache.aut.vfs.FileSystemManager; /** * Used for a file system provider to access the services it needs, such * as the file system cache or other file system providers. * - * @author Adam Murdoch + * @author Adam Murdoch + * @version $Revision$ $Date$ */ public interface FileSystemProviderContext { + /** + * Locate a file by name. See + * {@link FileSystemManager#resolveFile(FileObject, String)} for a + * description of how this works. + */ + FileObject resolveFile( FileObject baseFile, String name ) + throws FileSystemException; + /** * Locates a cached file system by root URI. */ diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ParsedUri.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ParsedUri.java index 2116d998d..70b7efd66 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ParsedUri.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ParsedUri.java @@ -34,13 +34,13 @@ public class ParsedUri } /** Returns the root URI, used to identify the file system. */ - public String getRootURI() + public String getRootUri() { return m_rootURI; } /** Sets the root URI. */ - public void setRootURI( String rootPrefix ) + public void setRootUri( String rootPrefix ) { m_rootURI = rootPrefix; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/Resources.properties b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/Resources.properties index 82b2cd6dd..16911ce1a 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/Resources.properties @@ -17,6 +17,7 @@ write-read-only.error=Could not write to "{0}" because it is read-only. write-folder.error=Could not write to "{0}" because it is a folder. write-in-use.error=Could not write to "{0}" because it is already in use. write.error=Could not write to "{0}". +copy-file.error=Could not copy "{0}" to "{1}". # DefaultFileContent get-size-no-exist.error=Could not determine the size of file "{0}" because it does not exist. @@ -30,6 +31,7 @@ close-outstr.error=Could not close file output stream. # AbstractFileSystemProvider invalid-absolute-uri.error=Invalid absolute URI "{0}". +not-layered-fs.error=File system is not a layered file system. # UriParser missing-double-slashes.error=Expecting // to follow the scheme in URI "{0}". @@ -38,3 +40,5 @@ missing-port.error=Port number is missing from URI "{0}". missing-hostname-path-sep.error=Expecting / to follow the hostname in URI "{0}". invalid-childname.error=Invalid file base-name "{0}". invalid-descendent-name.error=Invalid descendent file name "{0}". +invalid-escape-sequence.error=Invalid URI escape sequence "{0}". +invalid-relative-path.error=Invalid relative file name. \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/UriParser.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/UriParser.java index a45cba92c..8b6c85e17 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/UriParser.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/UriParser.java @@ -84,14 +84,41 @@ public class UriParser * Parses an absolute URI, splitting it into its components. This * implementation assumes a "generic URI", as defined by RFC 2396. See * {@link #parseGenericUri} for more info. - * - *

    Sub-classes should override this method. */ public ParsedUri parseUri( final String uriStr ) throws FileSystemException { - final ParsedUri retval = new ParsedUri(); - parseGenericUri( uriStr, retval ); - return retval; + // Parse the URI + final ParsedUri uri = new ParsedUri(); + parseGenericUri( uriStr, uri ); + + // Build the root URI + final StringBuffer rootUri = new StringBuffer(); + appendRootUri( uri, rootUri ); + uri.setRootUri( rootUri.toString() ); + + return uri; + } + + /** + * Assembles a generic URI, appending to the supplied StringBuffer. + */ + protected void appendRootUri( final ParsedUri uri, final StringBuffer rootUri ) + { + rootUri.append( uri.getScheme() ); + rootUri.append( "://" ); + final String userInfo = uri.getUserInfo(); + if( userInfo != null && userInfo.length() != 0 ) + { + rootUri.append( userInfo ); + rootUri.append( "@" ); + } + rootUri.append( uri.getHostName() ); + final String port = uri.getPort(); + if( port != null && port.length() > 0 ) + { + rootUri.append( ":" ); + rootUri.append( port ); + } } /** @@ -119,7 +146,8 @@ public class UriParser // Extract the scheme and authority parts extractToPath( uriStr, name, uri ); - // Normalise the file name + // Decode and normalise the file name + decode( name, 0, name.length() ); normalisePath( name ); uri.setPath( name.toString() ); @@ -128,7 +156,7 @@ public class UriParser rootUri.append( uri.getScheme() ); rootUri.append( "://" ); rootUri.append( uri.getHostName() ); - uri.setRootURI( rootUri.toString() ); + uri.setRootUri( rootUri.toString() ); } /** @@ -404,9 +432,9 @@ public class UriParser if( scope == NameScope.CHILD ) { final int baseLen = baseFile.length(); - if( ! resolvedPath.startsWith( baseFile ) + if( !resolvedPath.startsWith( baseFile ) || resolvedPath.length() == baseLen - || resolvedPath.charAt( baseLen ) != m_separatorChar + || ( baseLen > 1 && resolvedPath.charAt( baseLen ) != m_separatorChar ) || resolvedPath.indexOf( m_separatorChar, baseLen + 1 ) != -1 ) { final String message = REZ.getString( "invalid-childname.error", path ); @@ -416,9 +444,9 @@ public class UriParser else if( scope == NameScope.DESCENDENT ) { final int baseLen = baseFile.length(); - if( ! resolvedPath.startsWith( baseFile ) + if( !resolvedPath.startsWith( baseFile ) || resolvedPath.length() == baseLen - || resolvedPath.charAt( baseLen ) != m_separatorChar ) + || ( baseLen > 1 && resolvedPath.charAt( baseLen ) != m_separatorChar ) ) { final String message = REZ.getString( "invalid-descendent-name.error", path ); throw new FileSystemException( message ); @@ -463,7 +491,8 @@ public class UriParser *

  • Removes trailing separator. *
*/ - public void normalisePath( final StringBuffer path ) throws FileSystemException + public void normalisePath( final StringBuffer path ) + throws FileSystemException { if( path.length() == 0 ) { @@ -515,14 +544,20 @@ public class UriParser path.charAt( startElem + 1 ) == '.' ) { // A '..' element - remove the previous element - if( startElem > startFirstElem ) + if( startElem == startFirstElem ) { - int pos = startElem - 2; - for( ; pos >= 0 && path.charAt( pos ) != m_separatorChar; pos -- ) - { - } - startElem = pos + 1; + // Previous element is missing + final String message = REZ.getString( "invalid-relative-path.error" ); + throw new FileSystemException( message ); } + + // Find start of previous element + int pos = startElem - 2; + for( ; pos >= 0 && path.charAt( pos ) != m_separatorChar; pos-- ) + { + } + startElem = pos + 1; + path.delete( startElem, endElem + 1 ); maxlen = path.length(); continue; @@ -595,7 +630,8 @@ public class UriParser * @return * The scheme name. Returns null if there is no scheme. */ - protected static String extractScheme( final String uri, final StringBuffer buffer ) + public static String extractScheme( final String uri, + final StringBuffer buffer ) { if( buffer != null ) { @@ -642,4 +678,103 @@ public class UriParser // No scheme in URI return null; } + + /** + * Removes %nn encodings from a string. + */ + public static String decode( final String encodedStr ) + throws FileSystemException + { + final StringBuffer buffer = new StringBuffer( encodedStr ); + decode( buffer, 0, buffer.length() ); + return buffer.toString(); + } + + /** + * Removes %nn encodings from a string. + */ + public static void decode( final StringBuffer buffer, + final int offset, + final int length ) + throws FileSystemException + { + int index = offset; + int count = length; + for( ; count > 0; count--, index++ ) + { + final char ch = buffer.charAt( index ); + if( ch != '%' ) + { + continue; + } + if( count < 3 ) + { + final String message = REZ.getString( "invalid-escape-sequence.error", buffer.substring( index, index + count ) ); + throw new FileSystemException( message ); + } + + // Decode + int dig1 = Character.digit( buffer.charAt( index + 1 ), 16 ); + int dig2 = Character.digit( buffer.charAt( index + 2 ), 16 ); + if( dig1 == -1 || dig2 == -1 ) + { + final String message = REZ.getString( "invalid-escape-sequence.error", buffer.substring( index, index + 3 ) ); + throw new FileSystemException( message ); + } + char value = (char)( dig1 << 4 | dig2 ); + + // Replace + buffer.setCharAt( index, value ); + buffer.delete( index + 1, index + 3 ); + count -= 2; + } + } + + /** + * Encodes and appends a string to a StringBuffer. + */ + public static void appendEncoded( final StringBuffer buffer, + final String unencodedValue, + final char[] reserved ) + { + final int offset = buffer.length(); + buffer.append( unencodedValue ); + encode( buffer, offset, unencodedValue.length(), reserved ); + } + + /** + * Encodes a set of reserved characters in a StringBuffer, using the URI + * %nn encoding. Always encodes % characters. + */ + public static void encode( final StringBuffer buffer, + final int offset, + final int length, + final char[] reserved ) + { + int index = offset; + int count = length; + for( ; count > 0; index++, count-- ) + { + final char ch = buffer.charAt( index ); + boolean match = ( ch == '%' ); + for( int i = 0; !match && i < reserved.length; i++ ) + { + if( ch == reserved[ i ] ) + { + match = true; + } + } + if( match ) + { + // Encode + char[] digits = { + Character.forDigit( ( ( ch >> 4 ) & 0xF ), 16 ), + Character.forDigit( ( ch & 0xF ), 16 ) + }; + buffer.setCharAt( index, '%' ); + buffer.insert( index + 1, digits ); + index += 2; + } + } + } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileNameParser.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileNameParser.java index eb9b7e7b1..5b2f4f12e 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileNameParser.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileNameParser.java @@ -8,7 +8,6 @@ package org.apache.aut.vfs.provider.ftp; import org.apache.aut.vfs.FileSystemException; -import org.apache.aut.vfs.provider.ParsedUri; import org.apache.aut.vfs.provider.UriParser; /** @@ -21,15 +20,27 @@ public class FtpFileNameParser extends UriParser /** * Parses an absolute URI, splitting it into its components. */ - public ParsedUri parseUri( String uriStr ) throws FileSystemException + public ParsedFtpUri parseFtpUri( final String uriStr ) + throws FileSystemException { - ParsedFtpUri uri = new ParsedFtpUri(); + final ParsedFtpUri uri = new ParsedFtpUri(); // FTP URI are generic URI (as per RFC 2396) parseGenericUri( uriStr, uri ); + // Adjust the hostname to lower-case + final String hostname = uri.getHostName().toLowerCase(); + uri.setHostName( hostname ); + + // Drop the port if it is 21 + final String port = uri.getPort(); + if( port != null && port.equals( "21" ) ) + { + uri.setPort( null ); + } + // Split up the userinfo into a username and password - String userInfo = uri.getUserInfo(); + final String userInfo = uri.getUserInfo(); if( userInfo != null ) { int idx = userInfo.indexOf( ':' ); @@ -46,6 +57,11 @@ public class FtpFileNameParser extends UriParser } } + // Now build the root URI + final StringBuffer rootUri = new StringBuffer(); + appendRootUri( uri, rootUri ); + uri.setRootUri( rootUri.toString() ); + return uri; } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileSystemProvider.java index 18670c235..4684abec2 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/ftp/FtpFileSystemProvider.java @@ -8,39 +8,44 @@ package org.apache.aut.vfs.provider.ftp; import org.apache.aut.vfs.FileName; +import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.FileSystemException; import org.apache.aut.vfs.provider.AbstractFileSystemProvider; import org.apache.aut.vfs.provider.DefaultFileName; import org.apache.aut.vfs.provider.FileSystem; import org.apache.aut.vfs.provider.ParsedUri; -import org.apache.aut.vfs.provider.UriParser; /** * A provider for FTP file systems. * * @author Adam Murdoch + * + * @ant:type type="file-system" name="ftp" */ public class FtpFileSystemProvider extends AbstractFileSystemProvider { - private UriParser m_parser = new FtpFileNameParser(); + private final FtpFileNameParser m_parser = new FtpFileNameParser(); /** * Parses a URI into its components. */ - protected ParsedUri parseURI( String uri ) throws FileSystemException + protected ParsedUri parseUri( final FileObject baseFile, + final String uri ) + throws FileSystemException { - return m_parser.parseUri( uri ); + return m_parser.parseFtpUri( uri ); } /** * Creates the filesystem. */ - protected FileSystem createFileSystem( ParsedUri uri ) throws FileSystemException + protected FileSystem createFileSystem( final ParsedUri uri ) + throws FileSystemException { - ParsedFtpUri ftpUri = (ParsedFtpUri)uri; + final ParsedFtpUri ftpUri = (ParsedFtpUri)uri; // Build the root name - FileName rootName = new DefaultFileName( m_parser, ftpUri.getRootURI(), "/" ); + final FileName rootName = new DefaultFileName( m_parser, ftpUri.getRootUri(), "/" ); // Determine the username and password to use String username = ftpUri.getUserName(); diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileNameParser.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileNameParser.java index d55db0f27..5ac42a39d 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileNameParser.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileNameParser.java @@ -50,21 +50,22 @@ abstract class LocalFileNameParser * * @param uriStr The URI. */ - public ParsedUri parseUri( final String uriStr ) + public ParsedUri parseFileUri( final String uriStr ) throws FileSystemException { - StringBuffer name = new StringBuffer(); - ParsedFileUri uri = new ParsedFileUri(); + final StringBuffer name = new StringBuffer(); + final ParsedFileUri uri = new ParsedFileUri(); // Extract the scheme - String scheme = extractScheme( uriStr, name ); + final String scheme = extractScheme( uriStr, name ); uri.setScheme( scheme ); - // Adjust the separators + // Remove encoding, and adjust the separators + decode( name, 0, name.length() ); fixSeparators( name ); // Extract the root prefix - String rootFile = extractRootPrefix( uriStr, name ); + final String rootFile = extractRootPrefix( uriStr, name ); uri.setRootFile( rootFile ); // Normalise the path @@ -72,11 +73,11 @@ abstract class LocalFileNameParser uri.setPath( name.toString() ); // Build the root URI - StringBuffer rootUri = new StringBuffer(); + final StringBuffer rootUri = new StringBuffer(); rootUri.append( scheme ); rootUri.append( "://" ); rootUri.append( rootFile ); - uri.setRootURI( rootUri.toString() ); + uri.setRootUri( rootUri.toString() ); return uri; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileSystemProvider.java index 694f3a0a8..be00f376d 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/local/LocalFileSystemProvider.java @@ -51,20 +51,22 @@ public class LocalFileSystemProvider extends AbstractFileSystemProvider /** * Finds a local file, from its local name. */ - public FileObject findLocalFile( final String name ) throws FileSystemException + public FileObject findLocalFile( final String name ) + throws FileSystemException { // TODO - tidy this up, no need to turn the name into an absolute URI, // and then straight back again - return findFile( "file:" + name ); + return findFile( null, "file:" + name ); } /** * Finds a local file. */ - public FileObject findFileByLocalName( final File file ) throws FileSystemException + public FileObject findLocalFile( final File file ) + throws FileSystemException { // TODO - tidy this up, should build file object straight from the file - return findFile( "file:" + file.getAbsolutePath() ); + return findFile( null, "file:" + file.getAbsolutePath() ); } /** @@ -75,22 +77,25 @@ public class LocalFileSystemProvider extends AbstractFileSystemProvider *

The provider can annotate this object with any additional * information it requires to create a file system from the URI. */ - protected ParsedUri parseURI( final String uri ) throws FileSystemException + protected ParsedUri parseUri( final FileObject baseFile, + final String uri ) + throws FileSystemException { - return m_parser.parseUri( uri ); + return m_parser.parseFileUri( uri ); } /** * Creates the filesystem. */ - protected FileSystem createFileSystem( final ParsedUri uri ) throws FileSystemException + protected FileSystem createFileSystem( final ParsedUri uri ) + throws FileSystemException { // Build the name of the root file. final ParsedFileUri fileUri = (ParsedFileUri)uri; final String rootFile = fileUri.getRootFile(); // Create the file system - final DefaultFileName rootName = new DefaultFileName( m_parser, fileUri.getRootURI(), "/" ); + final DefaultFileName rootName = new DefaultFileName( m_parser, fileUri.getRootUri(), "/" ); return new LocalFileSystem( rootName, rootFile ); } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileNameParser.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileNameParser.java index 2f2a5e788..2f0248854 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileNameParser.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileNameParser.java @@ -27,19 +27,27 @@ public class SmbFileNameParser /** * Parses an absolute URI, splitting it into its components. */ - public ParsedUri parseUri( String uriStr ) throws FileSystemException + public ParsedUri parseSmbUri( final String uriStr ) + throws FileSystemException { - ParsedSmbUri uri = new ParsedSmbUri(); - StringBuffer name = new StringBuffer(); + final ParsedSmbUri uri = new ParsedSmbUri(); + final StringBuffer name = new StringBuffer(); // Extract the scheme and authority parts extractToPath( uriStr, name, uri ); - // Normalise paths + // Convert the hostname to lowercase + final String hostname = uri.getHostName().toLowerCase(); + uri.setHostName( hostname ); + + // TODO - drop the default port + + // Decode and adjust separators + decode( name, 0, name.length() ); fixSeparators( name ); // Extract the share - String share = extractFirstElement( name ); + final String share = extractFirstElement( name ); if( share == null ) { final String message = REZ.getString( "missing-share-name.error", uriStr ); @@ -47,23 +55,18 @@ public class SmbFileNameParser } uri.setShare( share ); + // Normalise the path + normalisePath( name ); + // Set the path uri.setPath( name.toString() ); // Set the root URI StringBuffer rootUri = new StringBuffer(); - rootUri.append( uri.getScheme() ); - rootUri.append( "://" ); - String userInfo = uri.getUserInfo(); - if( userInfo != null ) - { - rootUri.append( userInfo ); - rootUri.append( '@' ); - } - rootUri.append( uri.getHostName() ); + appendRootUri( uri, rootUri ); rootUri.append( '/' ); rootUri.append( share ); - uri.setRootURI( rootUri.toString() ); + uri.setRootUri( rootUri.toString() ); return uri; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileSystemProvider.java index f9e7eb276..ba62eec70 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/smb/SmbFileSystemProvider.java @@ -8,6 +8,7 @@ package org.apache.aut.vfs.provider.smb; import org.apache.aut.vfs.FileName; +import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.FileSystemException; import org.apache.aut.vfs.provider.AbstractFileSystemProvider; import org.apache.aut.vfs.provider.DefaultFileName; @@ -19,27 +20,31 @@ import org.apache.aut.vfs.provider.ParsedUri; * A provider for SMB (Samba, Windows share) file systems. * * @author Adam Murdoch + * + * @ant:type type="file-system" name="smb" */ public class SmbFileSystemProvider extends AbstractFileSystemProvider implements FileSystemProvider { - SmbFileNameParser m_parser = new SmbFileNameParser(); + private final SmbFileNameParser m_parser = new SmbFileNameParser(); /** * Parses a URI into its components. */ - protected ParsedUri parseURI( String uri ) throws FileSystemException + protected ParsedUri parseUri( final FileObject baseFile, + final String uri ) + throws FileSystemException { - return m_parser.parseUri( uri ); + return m_parser.parseSmbUri( uri ); } /** * Creates the filesystem. */ - protected FileSystem createFileSystem( ParsedUri uri ) throws FileSystemException + protected FileSystem createFileSystem( final ParsedUri uri ) + throws FileSystemException { - ParsedSmbUri smbUri = (ParsedSmbUri)uri; - - FileName rootName = new DefaultFileName( m_parser, smbUri.getRootURI(), "/" ); + final ParsedSmbUri smbUri = (ParsedSmbUri)uri; + final FileName rootName = new DefaultFileName( m_parser, smbUri.getRootUri(), "/" ); return new SmbFileSystem( rootName ); } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ParsedZipUri.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ParsedZipUri.java index 0dda462ae..9bc36d0c8 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ParsedZipUri.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ParsedZipUri.java @@ -7,6 +7,7 @@ */ package org.apache.aut.vfs.provider.zip; +import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.provider.ParsedUri; /** @@ -16,14 +17,25 @@ import org.apache.aut.vfs.provider.ParsedUri; */ public class ParsedZipUri extends ParsedUri { - private String m_zipFile; + private String m_zipFileName; + private FileObject m_zipFile; - public String getZipFile() + public String getZipFileName() + { + return m_zipFileName; + } + + public void setZipFileName( final String zipFileName ) + { + m_zipFileName = zipFileName; + } + + public FileObject getZipFile() { return m_zipFile; } - public void setZipFile( String zipFile ) + public void setZipFile( final FileObject zipFile ) { m_zipFile = zipFile; } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileNameParser.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileNameParser.java index 7f804efd7..caeab439c 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileNameParser.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileNameParser.java @@ -8,7 +8,6 @@ package org.apache.aut.vfs.provider.zip; import org.apache.aut.vfs.FileSystemException; -import org.apache.aut.vfs.provider.ParsedUri; import org.apache.aut.vfs.provider.UriParser; /** @@ -16,66 +15,77 @@ import org.apache.aut.vfs.provider.UriParser; * * @author Adam Murdoch */ -public class ZipFileNameParser extends UriParser +public class ZipFileNameParser + extends UriParser { + private static final char[] ZIP_URL_RESERVED_CHARS = { '!' }; + /** * Parses an absolute URI, splitting it into its components. * - * @param name + * @param uriStr * The URI. */ - public ParsedUri parseUri( String uriStr ) throws FileSystemException + public ParsedZipUri parseZipUri( final String uriStr ) + throws FileSystemException { - StringBuffer name = new StringBuffer(); - ParsedZipUri uri = new ParsedZipUri(); + final StringBuffer name = new StringBuffer(); + final ParsedZipUri uri = new ParsedZipUri(); // Extract the scheme - String scheme = extractScheme( uriStr, name ); + final String scheme = extractScheme( uriStr, name ); uri.setScheme( scheme ); // Extract the Zip file name - String zipName = extractZipName( name ); - uri.setZipFile( zipName ); - - // Adjust the separators - fixSeparators( name ); + final String zipName = extractZipName( name ); + uri.setZipFileName( zipName ); - // Normalise the file name + // Decode and normalise the file name + decode( name, 0, name.length() ); normalisePath( name ); uri.setPath( name.toString() ); - // Build root URI - StringBuffer rootUri = new StringBuffer(); - rootUri.append( scheme ); + return uri; + } + + /** + * Assembles a root URI from the components of a parsed URI. + */ + public String buildRootUri( final ParsedZipUri uri ) + { + final StringBuffer rootUri = new StringBuffer(); + rootUri.append( uri.getScheme() ); rootUri.append( ":" ); - rootUri.append( zipName ); + appendEncoded( rootUri, uri.getZipFile().getName().getURI(), ZIP_URL_RESERVED_CHARS ); rootUri.append( "!" ); - uri.setRootURI( rootUri.toString() ); - - return uri; + return rootUri.toString(); } /** * Pops the root prefix off a URI, which has had the scheme removed. */ - protected String extractZipName( StringBuffer uri ) throws FileSystemException + private String extractZipName( final StringBuffer uri ) + throws FileSystemException { // Looking for ! - // TODO - how does '!' in the file name get escaped? int maxlen = uri.length(); - for( int pos = 0; pos < maxlen; pos++ ) + int pos = 0; + for( ; pos < maxlen && uri.charAt( pos ) != '!'; pos++ ) + { + } + + // Extract the name + String prefix = uri.substring( 0, pos ); + if( pos < maxlen ) + { + uri.delete( 0, pos + 1 ); + } + else { - if( uri.charAt( pos ) == '!' ) - { - String prefix = uri.substring( 0, pos ); - uri.delete( 0, pos + 1 ); - return prefix; - } + uri.setLength( 0 ); } - // Assume the URI is the Jar file name - String prefix = uri.toString(); - uri.setLength( 0 ); - return prefix; + // Decode the name + return decode( prefix ); } } diff --git a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileSystemProvider.java b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileSystemProvider.java index 21f540646..f1ab31d82 100644 --- a/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileSystemProvider.java +++ b/proposal/myrmidon/src/java/org/apache/aut/vfs/provider/zip/ZipFileSystemProvider.java @@ -8,6 +8,8 @@ package org.apache.aut.vfs.provider.zip; import java.io.File; +import java.io.IOException; +import org.apache.aut.vfs.FileObject; import org.apache.aut.vfs.FileSystemException; import org.apache.aut.vfs.provider.AbstractFileSystemProvider; import org.apache.aut.vfs.provider.DefaultFileName; @@ -20,31 +22,83 @@ import org.apache.aut.vfs.provider.ParsedUri; * systems, for local Zip files only. * * @author Adam Murdoch + * + * @ant:type type="file-system" name="zip" */ -public class ZipFileSystemProvider extends AbstractFileSystemProvider +public class ZipFileSystemProvider + extends AbstractFileSystemProvider implements FileSystemProvider { - private ZipFileNameParser m_parser = new ZipFileNameParser(); + private final ZipFileNameParser m_parser = new ZipFileNameParser(); /** * Parses a URI into its components. */ - protected ParsedUri parseURI( String uri ) throws FileSystemException + protected ParsedUri parseUri( final FileObject baseFile, + final String uriStr ) + throws FileSystemException { - return m_parser.parseUri( uri ); + // Parse the URI + final ParsedZipUri uri = m_parser.parseZipUri( uriStr ); + + // Make the URI canonical + + // Resolve the Zip file name + final String fileName = uri.getZipFileName(); + final FileObject file = getContext().resolveFile( baseFile, fileName ); + uri.setZipFile( file ); + + // Rebuild the root URI + final String rootUri = m_parser.buildRootUri( uri ); + uri.setRootUri( rootUri ); + + return uri; + } + + /** + * Builds the URI for the root of a layered file system. + */ + protected ParsedUri buildUri( final String scheme, + final FileObject file ) + throws FileSystemException + { + ParsedZipUri uri = new ParsedZipUri(); + uri.setScheme( scheme ); + uri.setZipFile( file ); + final String rootUri = m_parser.buildRootUri( uri ); + uri.setRootUri( rootUri ); + uri.setPath( "/" ); + return uri; } /** * Creates the filesystem. */ - protected FileSystem createFileSystem( ParsedUri uri ) throws FileSystemException + protected FileSystem createFileSystem( final ParsedUri uri ) + throws FileSystemException { - // Locate the Zip file - ParsedZipUri zipUri = (ParsedZipUri)uri; - String fileName = zipUri.getZipFile(); - // TODO - use the context to resolve zip file to a FileObject - File file = new File( fileName ).getAbsoluteFile(); - DefaultFileName name = new DefaultFileName( m_parser, zipUri.getRootURI(), "/" ); - return new ZipFileSystem( name, file ); + final ParsedZipUri zipUri = (ParsedZipUri)uri; + final FileObject file = zipUri.getZipFile(); + + // TODO - temporary hack; need to use a converter + File destFile = null; + try + { + final File cacheDir = new File( "ant_vfs_cache" ); + cacheDir.mkdirs(); + destFile = File.createTempFile( "cache_", "_" + file.getName().getBaseName(), cacheDir ); + destFile.deleteOnExit(); + } + catch( IOException e ) + { + throw new FileSystemException( "Could not replicate file", e ); + } + FileObject destFileObj = getContext().resolveFile( null, destFile.getAbsolutePath() ); + destFileObj.copy( file ); + + // Create the file system + DefaultFileName name = new DefaultFileName( m_parser, zipUri.getRootUri(), "/" ); + return new ZipFileSystem( name, destFile ); } + } diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/Resources.properties index 9d1e2fbf5..22651c223 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/Resources.properties +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/Resources.properties @@ -1,2 +1,3 @@ missing-home-dir.error=Cannot locate antRun scripts: Property 'myrmidon.home' not specified -create-vfs-manager.error=Could not create the VFS manager. \ No newline at end of file +create-vfs-manager.error=Could not create the VFS manager. +create-provider.error=Could not create file system provider "{0}". \ No newline at end of file diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManager.java b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManager.java new file mode 100644 index 000000000..faa50d46c --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManager.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.framework.factories; + +import org.apache.aut.vfs.impl.DefaultFileSystemManager; +import org.apache.aut.vfs.provider.FileSystemProvider; +import org.apache.aut.vfs.FileSystemException; +import org.apache.avalon.framework.activity.Disposable; +import org.apache.avalon.framework.activity.Initializable; +import org.apache.avalon.framework.service.Serviceable; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.myrmidon.interfaces.type.TypeManager; +import org.apache.myrmidon.interfaces.type.TypeFactory; +import org.apache.myrmidon.interfaces.type.TypeException; + +/** + * The myrmidon FileSystemManager implementation. + * + * @author Adam Murdoch + * @version $Revision$ $Date$ + */ +public class VfsManager + extends DefaultFileSystemManager + implements Serviceable, Initializable, Disposable +{ + private final static Resources REZ + = ResourceManager.getPackageResources( VfsManager.class ); + + private TypeFactory m_typeFactory; + + /** + * Locate the services used by this service. + */ + public void service( final ServiceManager serviceManager ) throws ServiceException + { + final TypeManager typeManager = (TypeManager)serviceManager.lookup( TypeManager.ROLE ); + try + { + m_typeFactory = typeManager.getFactory( FileSystemProvider.class ); + } + catch( TypeException e ) + { + throw new ServiceException( e.getMessage(), e ); + } + } + + /** + * Initialises this service. + */ + public void initialize() throws Exception + { + // TODO - make this list configurable + + // Required providers + addProvider( new String[] { "zip", "jar" }, "zip", false ); + + // Optional providers + addProvider( new String[] { "smb" }, "smb", true ); + addProvider( new String[] { "ftp" }, "ftp", true ); + } + + /** + * Disposes this service. + */ + public void dispose() + { + // Clean-up + close(); + } + + /** + * Registers a file system provider. + */ + public void addProvider( final String[] urlSchemes, + final String providerName, + final boolean ignoreIfNotPresent ) + throws FileSystemException + { + // Create an instance + if( ignoreIfNotPresent && ! m_typeFactory.canCreate( providerName ) ) + { + return; + } + + final FileSystemProvider provider; + try + { + provider = (FileSystemProvider)m_typeFactory.create( providerName ); + } + catch( Exception e ) + { + final String message = REZ.getString( "create-provider.error", providerName ); + throw new FileSystemException( message, e ); + } + + // Register the provider + addProvider( urlSchemes, provider ); + } + +} diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManagerFactory.java b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManagerFactory.java index 4ff530dcb..bf4c941c5 100644 --- a/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManagerFactory.java +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/framework/factories/VfsManagerFactory.java @@ -8,7 +8,6 @@ package org.apache.myrmidon.framework.factories; import org.apache.aut.vfs.FileSystemManager; -import org.apache.aut.vfs.impl.DefaultFileSystemManager; import org.apache.avalon.excalibur.i18n.ResourceManager; import org.apache.avalon.excalibur.i18n.Resources; import org.apache.myrmidon.interfaces.service.AntServiceException; @@ -34,7 +33,7 @@ public class VfsManagerFactory { try { - return new DefaultFileSystemManager(); + return new VfsManager(); } catch( Exception e ) { diff --git a/proposal/myrmidon/src/manifest/core-services.xml b/proposal/myrmidon/src/manifest/core-services.xml index b2cfc8883..dd26e6334 100644 --- a/proposal/myrmidon/src/manifest/core-services.xml +++ b/proposal/myrmidon/src/manifest/core-services.xml @@ -1,9 +1,4 @@ - - - - - - + diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java index a48f7a139..1b93bbe03 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractFileSystemTest.java @@ -66,9 +66,9 @@ public abstract class AbstractFileSystemTest } /** - * Returns the URI for the base folder. + * Returns the base folder to run the tests against. */ - protected abstract String getBaseFolderURI() throws Exception; + protected abstract FileObject getBaseFolder() throws Exception; /** * Sets up the test @@ -79,7 +79,10 @@ public abstract class AbstractFileSystemTest m_manager = new DefaultFileSystemManager(); // Locate the base folder - m_baseFolder = m_manager.resolveFile( getBaseFolderURI() ); + m_baseFolder = getBaseFolder(); + + // Make some assumptions absout the name + assertTrue( ! m_baseFolder.getName().getPath().equals( "/" ) ); // Build the expected content of "file1.txt" final String eol = System.getProperty( "line.separator" ); @@ -123,6 +126,66 @@ public abstract class AbstractFileSystemTest assertSame( "file object", m_baseFolder.getParent(), file ); } + /** + * Tests encoding of relative URI. + */ + public void testRelativeUriEncoding() throws Exception + { + // Build base dir + m_manager.setBaseFile( m_baseFolder ); + final String path = m_baseFolder.getName().getPath(); + + // Encode "some file" + FileObject file = m_manager.resolveFile( "%73%6f%6d%65%20%66%69%6c%65" ); + assertEquals( path + "/some file", file.getName().getPath() ); + + // Encode "." + file = m_manager.resolveFile( "%2e" ); + assertEquals( path, file.getName().getPath() ); + + // Encode '%' + file = m_manager.resolveFile( "a%25" ); + assertEquals( path + "/a%", file.getName().getPath() ); + + // Encode / + file = m_manager.resolveFile( "dir%2fchild" ); + assertEquals( path + "/dir/child", file.getName().getPath() ); + + // Encode \ + file = m_manager.resolveFile( "dir%5cchild" ); + assertEquals( path + "/dir/child", file.getName().getPath() ); + + // Use "%" literal + try + { + m_manager.resolveFile( "%" ); + fail(); + } + catch( FileSystemException e ) + { + } + + // Not enough digits in encoded char + try + { + m_manager.resolveFile( "%5" ); + fail(); + } + catch( FileSystemException e ) + { + } + + // Invalid digit in encoded char + try + { + m_manager.resolveFile( "%q" ); + fail(); + } + catch( FileSystemException e ) + { + } + } + /** * Tests the root file name. */ @@ -176,7 +239,7 @@ public abstract class AbstractFileSystemTest final NameScope scope ) throws Exception { - // Make some assumptions about the name explicit + // Make some assumptions about the name assertTrue( !name.getPath().equals( "/" ) ); assertTrue( !name.getPath().endsWith( "/a" ) ); assertTrue( !name.getPath().endsWith( "/a/b" ) ); @@ -329,6 +392,46 @@ public abstract class AbstractFileSystemTest checkDescendentNames( baseName, NameScope.DESCENDENT ); } + /** + * Tests resolution of absolute names. + */ + public void testAbsoluteNames() throws Exception + { + // Test against the base folder + FileName name = m_baseFolder.getName(); + checkAbsoluteNames( name ); + + // Test against the root + name = m_baseFolder.getRoot().getName(); + checkAbsoluteNames( name ); + + // Test against some unknown file + name = name.resolveName( "a/b/unknown" ); + checkAbsoluteNames( name ); + } + + /** + * Tests resolution of absolute names. + */ + private void checkAbsoluteNames( final FileName name ) throws Exception + { + // Root + assertSameName( "/", name, "/" ); + assertSameName( "/", name, "//" ); + assertSameName( "/", name, "/." ); + assertSameName( "/", name, "/some file/.." ); + + // Some absolute names + assertSameName( "/a", name, "/a" ); + assertSameName( "/a", name, "/./a" ); + assertSameName( "/a", name, "/a/." ); + assertSameName( "/a/b", name, "/a/b" ); + + // Some bad names + assertBadName( name, "/..", NameScope.FILE_SYSTEM ); + assertBadName( name, "/a/../..", NameScope.FILE_SYSTEM ); + } + /** * Asserts that a particular relative name is invalid for a particular * scope. @@ -340,7 +443,7 @@ public abstract class AbstractFileSystemTest try { name.resolveName( relName, scope ); - fail(); + fail( "expected failure" ); } catch( FileSystemException e ) { diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractWritableFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractWritableFileSystemTest.java index 8243bb32e..ad57831aa 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractWritableFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/AbstractWritableFileSystemTest.java @@ -16,7 +16,8 @@ import java.util.Set; * * @author Adam Murdoch */ -public abstract class AbstractWritableFileSystemTest extends AbstractFileSystemTest +public abstract class AbstractWritableFileSystemTest + extends AbstractFileSystemTest { public AbstractWritableFileSystemTest( String name ) { @@ -26,14 +27,14 @@ public abstract class AbstractWritableFileSystemTest extends AbstractFileSystemT /** * Returns the URI for the area to do tests in. */ - protected abstract String getWriteFolderURI() throws Exception; + protected abstract FileObject getWriteFolder() throws Exception; /** * Sets up a scratch folder for the test to use. */ protected FileObject createScratchFolder() throws Exception { - FileObject scratchFolder = m_manager.resolveFile( getWriteFolderURI() ); + FileObject scratchFolder = getWriteFolder(); // Make sure the test folder is empty scratchFolder.delete(); diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/FtpFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/FtpFileSystemTest.java index dc12a0009..56a344802 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/FtpFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/FtpFileSystemTest.java @@ -7,12 +7,15 @@ */ package org.apache.aut.vfs; +import org.apache.aut.vfs.provider.ftp.FtpFileSystemProvider; + /** * Tests for FTP file systems. * * @author Adam Murdoch */ -public class FtpFileSystemTest extends AbstractWritableFileSystemTest +public class FtpFileSystemTest + extends AbstractWritableFileSystemTest { public FtpFileSystemTest( String name ) { @@ -22,16 +25,19 @@ public class FtpFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { - return System.getProperty( "test.ftp.uri" ) + "/read-tests"; + final String uri = System.getProperty( "test.ftp.uri" ) + "/read-tests"; + m_manager.addProvider( "ftp", new FtpFileSystemProvider() ); + return m_manager.resolveFile( uri ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() + protected FileObject getWriteFolder() throws Exception { - return System.getProperty( "test.ftp.uri" ) + "/write-tests"; + final String uri = System.getProperty( "test.ftp.uri" ) + "/write-tests"; + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/LocalFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/LocalFileSystemTest.java index ae74afe75..e0218041e 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/LocalFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/LocalFileSystemTest.java @@ -24,21 +24,19 @@ public class LocalFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() - throws Exception + protected FileObject getBaseFolder() throws Exception { final File testDir = getTestResource( "basedir" ); - return testDir.toURL().toString(); + return m_manager.convert( testDir ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() - throws Exception + protected FileObject getWriteFolder() throws Exception { final File testDir = getTestResource( "write-tests" ); - return testDir.toURL().toString(); + return m_manager.convert( testDir ); } /** diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/NestedZipFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/NestedZipFileSystemTest.java new file mode 100644 index 000000000..b5523a688 --- /dev/null +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/NestedZipFileSystemTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.aut.vfs; + +import org.apache.aut.vfs.provider.zip.ZipFileSystemProvider; + +/** + * Tests for the Zip file system, using a zip file nested inside another zip file. + * + * @author Adam Murdoch + */ +public class NestedZipFileSystemTest + extends AbstractReadOnlyFileSystemTest +{ + public NestedZipFileSystemTest( String name ) + { + super( name ); + } + + /** + * Returns the URI for the base folder. + */ + protected FileObject getBaseFolder() throws Exception + { + m_manager.addProvider( "zip", new ZipFileSystemProvider() ); + + // Locate the base Zip file + final String zipFilePath = getTestResource( "nested.zip" ).getAbsolutePath(); + String uri = "zip:" + zipFilePath + "!/test.zip"; + final FileObject zipFile = m_manager.resolveFile( uri ); + + // Now build the nested file system + final FileObject nestedFS = m_manager.createFileSystem( "zip", zipFile ); + return nestedFS.resolveFile( "/basedir" ); + } +} diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/SmbFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/SmbFileSystemTest.java index 308d92c65..c3ff819e7 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/SmbFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/SmbFileSystemTest.java @@ -7,6 +7,8 @@ */ package org.apache.aut.vfs; +import org.apache.aut.vfs.provider.smb.SmbFileSystemProvider; + /** * Tests for the SMB file system. * @@ -22,16 +24,19 @@ public class SmbFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { - return System.getProperty( "test.smb.uri" ) + "/read-tests"; + final String uri = System.getProperty( "test.smb.uri" ) + "/read-tests"; + m_manager.addProvider( "smb", new SmbFileSystemProvider() ); + return m_manager.resolveFile( uri ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() + protected FileObject getWriteFolder() throws Exception { - return System.getProperty( "test.smb.uri" ) + "/write-tests"; + final String uri = System.getProperty( "test.smb.uri" ) + "/write-tests"; + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/test/org/apache/aut/vfs/ZipFileSystemTest.java b/proposal/myrmidon/src/test/org/apache/aut/vfs/ZipFileSystemTest.java index 8755781c9..4c8b4af38 100644 --- a/proposal/myrmidon/src/test/org/apache/aut/vfs/ZipFileSystemTest.java +++ b/proposal/myrmidon/src/test/org/apache/aut/vfs/ZipFileSystemTest.java @@ -8,6 +8,7 @@ package org.apache.aut.vfs; import java.io.File; +import org.apache.aut.vfs.provider.zip.ZipFileSystemProvider; /** * Tests for the Zip file system. @@ -24,10 +25,11 @@ public class ZipFileSystemTest extends AbstractReadOnlyFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { File zipFile = getTestResource( "test.zip" ); - String uri = "zip:" + zipFile + "!basedir"; - return uri; + String uri = "zip:" + zipFile.getAbsolutePath() + "!basedir"; + m_manager.addProvider( "zip", new ZipFileSystemProvider() ); + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java index a48f7a139..1b93bbe03 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractFileSystemTest.java @@ -66,9 +66,9 @@ public abstract class AbstractFileSystemTest } /** - * Returns the URI for the base folder. + * Returns the base folder to run the tests against. */ - protected abstract String getBaseFolderURI() throws Exception; + protected abstract FileObject getBaseFolder() throws Exception; /** * Sets up the test @@ -79,7 +79,10 @@ public abstract class AbstractFileSystemTest m_manager = new DefaultFileSystemManager(); // Locate the base folder - m_baseFolder = m_manager.resolveFile( getBaseFolderURI() ); + m_baseFolder = getBaseFolder(); + + // Make some assumptions absout the name + assertTrue( ! m_baseFolder.getName().getPath().equals( "/" ) ); // Build the expected content of "file1.txt" final String eol = System.getProperty( "line.separator" ); @@ -123,6 +126,66 @@ public abstract class AbstractFileSystemTest assertSame( "file object", m_baseFolder.getParent(), file ); } + /** + * Tests encoding of relative URI. + */ + public void testRelativeUriEncoding() throws Exception + { + // Build base dir + m_manager.setBaseFile( m_baseFolder ); + final String path = m_baseFolder.getName().getPath(); + + // Encode "some file" + FileObject file = m_manager.resolveFile( "%73%6f%6d%65%20%66%69%6c%65" ); + assertEquals( path + "/some file", file.getName().getPath() ); + + // Encode "." + file = m_manager.resolveFile( "%2e" ); + assertEquals( path, file.getName().getPath() ); + + // Encode '%' + file = m_manager.resolveFile( "a%25" ); + assertEquals( path + "/a%", file.getName().getPath() ); + + // Encode / + file = m_manager.resolveFile( "dir%2fchild" ); + assertEquals( path + "/dir/child", file.getName().getPath() ); + + // Encode \ + file = m_manager.resolveFile( "dir%5cchild" ); + assertEquals( path + "/dir/child", file.getName().getPath() ); + + // Use "%" literal + try + { + m_manager.resolveFile( "%" ); + fail(); + } + catch( FileSystemException e ) + { + } + + // Not enough digits in encoded char + try + { + m_manager.resolveFile( "%5" ); + fail(); + } + catch( FileSystemException e ) + { + } + + // Invalid digit in encoded char + try + { + m_manager.resolveFile( "%q" ); + fail(); + } + catch( FileSystemException e ) + { + } + } + /** * Tests the root file name. */ @@ -176,7 +239,7 @@ public abstract class AbstractFileSystemTest final NameScope scope ) throws Exception { - // Make some assumptions about the name explicit + // Make some assumptions about the name assertTrue( !name.getPath().equals( "/" ) ); assertTrue( !name.getPath().endsWith( "/a" ) ); assertTrue( !name.getPath().endsWith( "/a/b" ) ); @@ -329,6 +392,46 @@ public abstract class AbstractFileSystemTest checkDescendentNames( baseName, NameScope.DESCENDENT ); } + /** + * Tests resolution of absolute names. + */ + public void testAbsoluteNames() throws Exception + { + // Test against the base folder + FileName name = m_baseFolder.getName(); + checkAbsoluteNames( name ); + + // Test against the root + name = m_baseFolder.getRoot().getName(); + checkAbsoluteNames( name ); + + // Test against some unknown file + name = name.resolveName( "a/b/unknown" ); + checkAbsoluteNames( name ); + } + + /** + * Tests resolution of absolute names. + */ + private void checkAbsoluteNames( final FileName name ) throws Exception + { + // Root + assertSameName( "/", name, "/" ); + assertSameName( "/", name, "//" ); + assertSameName( "/", name, "/." ); + assertSameName( "/", name, "/some file/.." ); + + // Some absolute names + assertSameName( "/a", name, "/a" ); + assertSameName( "/a", name, "/./a" ); + assertSameName( "/a", name, "/a/." ); + assertSameName( "/a/b", name, "/a/b" ); + + // Some bad names + assertBadName( name, "/..", NameScope.FILE_SYSTEM ); + assertBadName( name, "/a/../..", NameScope.FILE_SYSTEM ); + } + /** * Asserts that a particular relative name is invalid for a particular * scope. @@ -340,7 +443,7 @@ public abstract class AbstractFileSystemTest try { name.resolveName( relName, scope ); - fail(); + fail( "expected failure" ); } catch( FileSystemException e ) { diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractWritableFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractWritableFileSystemTest.java index 8243bb32e..ad57831aa 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractWritableFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/AbstractWritableFileSystemTest.java @@ -16,7 +16,8 @@ import java.util.Set; * * @author Adam Murdoch */ -public abstract class AbstractWritableFileSystemTest extends AbstractFileSystemTest +public abstract class AbstractWritableFileSystemTest + extends AbstractFileSystemTest { public AbstractWritableFileSystemTest( String name ) { @@ -26,14 +27,14 @@ public abstract class AbstractWritableFileSystemTest extends AbstractFileSystemT /** * Returns the URI for the area to do tests in. */ - protected abstract String getWriteFolderURI() throws Exception; + protected abstract FileObject getWriteFolder() throws Exception; /** * Sets up a scratch folder for the test to use. */ protected FileObject createScratchFolder() throws Exception { - FileObject scratchFolder = m_manager.resolveFile( getWriteFolderURI() ); + FileObject scratchFolder = getWriteFolder(); // Make sure the test folder is empty scratchFolder.delete(); diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/FtpFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/FtpFileSystemTest.java index dc12a0009..56a344802 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/FtpFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/FtpFileSystemTest.java @@ -7,12 +7,15 @@ */ package org.apache.aut.vfs; +import org.apache.aut.vfs.provider.ftp.FtpFileSystemProvider; + /** * Tests for FTP file systems. * * @author Adam Murdoch */ -public class FtpFileSystemTest extends AbstractWritableFileSystemTest +public class FtpFileSystemTest + extends AbstractWritableFileSystemTest { public FtpFileSystemTest( String name ) { @@ -22,16 +25,19 @@ public class FtpFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { - return System.getProperty( "test.ftp.uri" ) + "/read-tests"; + final String uri = System.getProperty( "test.ftp.uri" ) + "/read-tests"; + m_manager.addProvider( "ftp", new FtpFileSystemProvider() ); + return m_manager.resolveFile( uri ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() + protected FileObject getWriteFolder() throws Exception { - return System.getProperty( "test.ftp.uri" ) + "/write-tests"; + final String uri = System.getProperty( "test.ftp.uri" ) + "/write-tests"; + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/LocalFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/LocalFileSystemTest.java index ae74afe75..e0218041e 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/LocalFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/LocalFileSystemTest.java @@ -24,21 +24,19 @@ public class LocalFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() - throws Exception + protected FileObject getBaseFolder() throws Exception { final File testDir = getTestResource( "basedir" ); - return testDir.toURL().toString(); + return m_manager.convert( testDir ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() - throws Exception + protected FileObject getWriteFolder() throws Exception { final File testDir = getTestResource( "write-tests" ); - return testDir.toURL().toString(); + return m_manager.convert( testDir ); } /** diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/NestedZipFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/NestedZipFileSystemTest.java new file mode 100644 index 000000000..b5523a688 --- /dev/null +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/NestedZipFileSystemTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.aut.vfs; + +import org.apache.aut.vfs.provider.zip.ZipFileSystemProvider; + +/** + * Tests for the Zip file system, using a zip file nested inside another zip file. + * + * @author Adam Murdoch + */ +public class NestedZipFileSystemTest + extends AbstractReadOnlyFileSystemTest +{ + public NestedZipFileSystemTest( String name ) + { + super( name ); + } + + /** + * Returns the URI for the base folder. + */ + protected FileObject getBaseFolder() throws Exception + { + m_manager.addProvider( "zip", new ZipFileSystemProvider() ); + + // Locate the base Zip file + final String zipFilePath = getTestResource( "nested.zip" ).getAbsolutePath(); + String uri = "zip:" + zipFilePath + "!/test.zip"; + final FileObject zipFile = m_manager.resolveFile( uri ); + + // Now build the nested file system + final FileObject nestedFS = m_manager.createFileSystem( "zip", zipFile ); + return nestedFS.resolveFile( "/basedir" ); + } +} diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/SmbFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/SmbFileSystemTest.java index 308d92c65..c3ff819e7 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/SmbFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/SmbFileSystemTest.java @@ -7,6 +7,8 @@ */ package org.apache.aut.vfs; +import org.apache.aut.vfs.provider.smb.SmbFileSystemProvider; + /** * Tests for the SMB file system. * @@ -22,16 +24,19 @@ public class SmbFileSystemTest extends AbstractWritableFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { - return System.getProperty( "test.smb.uri" ) + "/read-tests"; + final String uri = System.getProperty( "test.smb.uri" ) + "/read-tests"; + m_manager.addProvider( "smb", new SmbFileSystemProvider() ); + return m_manager.resolveFile( uri ); } /** * Returns the URI for the area to do tests in. */ - protected String getWriteFolderURI() + protected FileObject getWriteFolder() throws Exception { - return System.getProperty( "test.smb.uri" ) + "/write-tests"; + final String uri = System.getProperty( "test.smb.uri" ) + "/write-tests"; + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/ZipFileSystemTest.java b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/ZipFileSystemTest.java index 8755781c9..4c8b4af38 100644 --- a/proposal/myrmidon/src/testcases/org/apache/aut/vfs/ZipFileSystemTest.java +++ b/proposal/myrmidon/src/testcases/org/apache/aut/vfs/ZipFileSystemTest.java @@ -8,6 +8,7 @@ package org.apache.aut.vfs; import java.io.File; +import org.apache.aut.vfs.provider.zip.ZipFileSystemProvider; /** * Tests for the Zip file system. @@ -24,10 +25,11 @@ public class ZipFileSystemTest extends AbstractReadOnlyFileSystemTest /** * Returns the URI for the base folder. */ - protected String getBaseFolderURI() + protected FileObject getBaseFolder() throws Exception { File zipFile = getTestResource( "test.zip" ); - String uri = "zip:" + zipFile + "!basedir"; - return uri; + String uri = "zip:" + zipFile.getAbsolutePath() + "!basedir"; + m_manager.addProvider( "zip", new ZipFileSystemProvider() ); + return m_manager.resolveFile( uri ); } } diff --git a/proposal/myrmidon/src/xdocs/todo.xml b/proposal/myrmidon/src/xdocs/todo.xml index cdb2890ce..d77ea4d34 100644 --- a/proposal/myrmidon/src/xdocs/todo.xml +++ b/proposal/myrmidon/src/xdocs/todo.xml @@ -37,15 +37,22 @@

The VFS needs plenty of work:

    -
  • Move and copy files/folders.
  • +
  • Move files/folders.
  • +
  • Recursive folders copy.
  • Search through a file hierarchy, using Ant-style wildcards.
  • Search through a file hierarchy, using a Selector interface.
  • The in-memory caching mechanism is pretty rudimentary at this stage. It needs work to make it size capped. In addition, some mechanism needs to be provided to release and refresh cached info.
  • +
  • Convert files/folders into local files, for handing off + to external commands, or legacy tasks.
  • +
  • Refactor the replication mechanism out of ZipFileSystemProvder, + and make more general pluggable.
  • Capabilities discovery.
  • Attributes and attribute schema.
  • +
  • Handle file canonicalisation better (for cases like case-insensitive + file systems, symbolic links, name encoding, etc).
  • File system layering. That is, the ability for a file system to sit on top of another file system, or a file from another file system (e.g. Zip/Jar/Tar file systems, gzip/encoding file systems, virtual file @@ -192,10 +199,6 @@
    • Search through the code for 'TODO' items and fix them.
    • -
    • Tidy-up CLIMain so that it calls System.exit() with a non-zero exit code, - if the build fails.
    • -
    • Tidy-up the 'build failed' message, so that the stack trace is only - printed out if the log level is verbose/debug.
    • Allow service factories to be configured from the contents of the ant-services.xml descriptor.
    • Route external process stdout and stderr through the logger.
    • @@ -206,11 +209,10 @@
    • Fire ProjectListener events projectStarted() and projectFinished() events on start and finish of referenced projects, adding indicator methods to ProjectEvent.
    • -
    • Convert PropertyUtil to a non-static PropertyResolver service.
    • Validate project and target names in DefaultProjectBuilder - reject dodgy - names like "," or "", or " ". Probably want to exclude names that start or + names like "," or "", or " ". Probably want to reject names that start or end with white-space (though internal whitespace is probably fine). We also - want to reserve certain punctuation characters like . , : ? [ ] { }, etc for + want to reserve certain punctuation characters like , : ? $ [ ] { } < >, etc for future use.
    • Similarly, validate property names, using the same rules.
    • Detect duplicate type names.
    • @@ -222,6 +224,7 @@ an antlib.
    • Split up <is-set> condition into is-set and is-true conditions.
    • Allow the <if> task to take any condition implementation.
    • +
    • Add an else block to the <if> task.
    • Unit tests.
    diff --git a/proposal/myrmidon/src/xdocs/user.xml b/proposal/myrmidon/src/xdocs/user.xml index 168f285e0..24c03506c 100644 --- a/proposal/myrmidon/src/xdocs/user.xml +++ b/proposal/myrmidon/src/xdocs/user.xml @@ -32,7 +32,8 @@ files are found in the lib directory:

    SMB VFS support (Samba, Windows shares) jcifs.jar - jcifs.samba.org + jcifs.samba.org. +

    Note: there are problems using the 0.6.1 release. Try 0.6.0 instead.

    FTP VFS support