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 |