* Added FileSelector, which allows files to be chosen when doing recursive operations. Added a couple of implementations. Added a selector parameter to FileObject.delete() and copy(). * Added FileObject.replicateFile(), which converts a FileObject into a local File. * Moved replication code out of the Zip provider, into a shared FileReplicator component. The implemenation is pretty brain-dead, but at very least should properly clean up temporary files in ant_vfs_cache. Also, local files will no longer be replicated, but used directly. * Added FileName.getRelativeName(), and NameScope.DESCENDENT_OR_SELF. * Now handles providers which are LogEnabled and Disposable. * Made the local file provider pluggable. * Providers are now responsible for thier own caching. * FTP and Zip providers clean up properly. Fixed FTP directory delete. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@272262 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -682,7 +682,7 @@ Legal: | |||||
| <!-- Pass config to the tests --> | <!-- Pass config to the tests --> | ||||
| <sysproperty key="test.basedir" value="${test.working.dir}"/> | <sysproperty key="test.basedir" value="${test.working.dir}"/> | ||||
| <sysproperty key="test.smb.uri" value="smb://${vfs.user}:${vfs.password}@${vfs.host}/${vfs.user}/vfs"/> | <sysproperty key="test.smb.uri" value="smb://${vfs.user}:${vfs.password}@${vfs.host}/${vfs.user}/vfs"/> | ||||
| <sysproperty key="test.ftp.uri" value="ftp://${vfs.user}:${vfs.password}@${vfs.host}/home/${vfs.user}/vfs"/> | |||||
| <sysproperty key="test.ftp.uri" value="ftp://${vfs.user}:${vfs.password}@${vfs.host}/vfs"/> | |||||
| <batchtest> | <batchtest> | ||||
| <fileset dir="${test.classes}"> | <fileset dir="${test.classes}"> | ||||
| @@ -13,6 +13,7 @@ import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.FileType; | import org.apache.aut.vfs.FileType; | ||||
| import org.apache.aut.vfs.NameScope; | import org.apache.aut.vfs.NameScope; | ||||
| import org.apache.aut.vfs.FileConstants; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.myrmidon.api.AbstractTask; | import org.apache.myrmidon.api.AbstractTask; | ||||
| @@ -114,7 +115,7 @@ public class CopyFilesTask | |||||
| } | } | ||||
| getContext().verbose( "copy " + m_srcFile + " to " + m_destFile ); | getContext().verbose( "copy " + m_srcFile + " to " + m_destFile ); | ||||
| m_destFile.copy( m_srcFile ); | |||||
| m_destFile.copyFrom( m_srcFile, FileConstants.SELECT_SELF ); | |||||
| } | } | ||||
| // Copy the contents of the filesets across | // Copy the contents of the filesets across | ||||
| @@ -142,7 +143,7 @@ public class CopyFilesTask | |||||
| // Copy the file across | // Copy the file across | ||||
| getContext().verbose( "copy " + srcFile + " to " + destFile ); | getContext().verbose( "copy " + srcFile + " to " + destFile ); | ||||
| destFile.copy( srcFile ); | |||||
| destFile.copyFrom( srcFile, FileConstants.SELECT_SELF ); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -0,0 +1,36 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * A {@link FileSelector} which selects everything. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class AllFileSelector | |||||
| implements FileSelector | |||||
| { | |||||
| /** | |||||
| * Determines if a file or folder should be selected. | |||||
| */ | |||||
| public boolean includeFile( final FileSelectInfo fileInfo ) | |||||
| throws FileSystemException | |||||
| { | |||||
| return true; | |||||
| } | |||||
| /** | |||||
| * Determines whether a folder should be traversed. | |||||
| */ | |||||
| public boolean traverseDescendents( final FileSelectInfo fileInfo ) | |||||
| throws FileSystemException | |||||
| { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,46 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * Several constants for use in the VFS API. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface FileConstants | |||||
| { | |||||
| /** | |||||
| * A {@link FileSelector} which selects only the base file/folder. | |||||
| */ | |||||
| FileSelector SELECT_SELF = new FileDepthSelector( 0, 0 ); | |||||
| /** | |||||
| * A {@link FileSelector} which selects the base file/folder and its | |||||
| * direct children. | |||||
| */ | |||||
| FileSelector SELECT_SELF_AND_CHILDREN = new FileDepthSelector( 0, 1 ); | |||||
| /** | |||||
| * A {@link FileSelector} which selects only the direct children | |||||
| * of the base folder. | |||||
| */ | |||||
| FileSelector SELECT_CHILDREN = new FileDepthSelector( 1, 1 ); | |||||
| /** | |||||
| * A {@link FileSelector} which selects all the descendents of the | |||||
| * base folder, but does not select the base folder itself. | |||||
| */ | |||||
| FileSelector EXCLUDE_SELF = new FileDepthSelector( 1, Integer.MAX_VALUE ); | |||||
| /** | |||||
| * A {@link FileSelector} which selects the base file/folder, plus all | |||||
| * its descendents. | |||||
| */ | |||||
| FileSelector SELECT_ALL = new AllFileSelector(); | |||||
| } | |||||
| @@ -25,7 +25,8 @@ import java.io.OutputStream; | |||||
| * | * | ||||
| * @see FileObject#getContent | * @see FileObject#getContent | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public interface FileContent | public interface FileContent | ||||
| { | { | ||||
| @@ -0,0 +1,46 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * A {@link FileSelector} which selects all files in a particular depth range. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class FileDepthSelector | |||||
| implements FileSelector | |||||
| { | |||||
| private final int m_minDepth; | |||||
| private final int m_maxDepth; | |||||
| public FileDepthSelector( int minDepth, int maxDepth ) | |||||
| { | |||||
| m_minDepth = minDepth; | |||||
| m_maxDepth = maxDepth; | |||||
| } | |||||
| /** | |||||
| * Determines if a file or folder should be selected. | |||||
| */ | |||||
| public boolean includeFile( final FileSelectInfo fileInfo ) | |||||
| throws FileSystemException | |||||
| { | |||||
| final int depth = fileInfo.getDepth(); | |||||
| return m_minDepth <= depth && depth <= m_maxDepth; | |||||
| } | |||||
| /** | |||||
| * Determines whether a folder should be traversed. | |||||
| */ | |||||
| public boolean traverseDescendents( final FileSelectInfo fileInfo ) | |||||
| throws FileSystemException | |||||
| { | |||||
| return fileInfo.getDepth() < m_maxDepth; | |||||
| } | |||||
| } | |||||
| @@ -13,13 +13,14 @@ package org.apache.aut.vfs; | |||||
| * | * | ||||
| * @see FileObject | * @see FileObject | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public interface FileName | public interface FileName | ||||
| { | { | ||||
| /** | /** | ||||
| * Returns the base name of the file. The base name of a file is the | |||||
| * last element of its name. For example the base name of | |||||
| * Returns the base name of this file. The base name is the last element | |||||
| * of the file name. For example the base name of | |||||
| * <code>/somefolder/somefile</code> is <code>somefile</code>. | * <code>/somefolder/somefile</code> is <code>somefile</code>. | ||||
| * | * | ||||
| * <p>The root file of a file system has an empty base name. | * <p>The root file of a file system has an empty base name. | ||||
| @@ -27,23 +28,23 @@ public interface FileName | |||||
| String getBaseName(); | String getBaseName(); | ||||
| /** | /** | ||||
| * Returns the absolute path of the file, within its file system. This | |||||
| * Returns the absolute path of this file, within its file system. This | |||||
| * path is normalised, so that <code>.</code> and <code>..</code> elements | * path is normalised, so that <code>.</code> and <code>..</code> elements | ||||
| * have been removed. Also, the path only contains <code>/</code> as its | * have been removed. Also, the path only contains <code>/</code> as its | ||||
| * separator character. The path always starts with <code>/</code> | * separator character. The path always starts with <code>/</code> | ||||
| * | * | ||||
| * <p>The root of a file system has <code>/</code> as its path. | |||||
| * <p>The root of a file system has <code>/</code> as its absolute path. | |||||
| */ | */ | ||||
| String getPath(); | String getPath(); | ||||
| /** | /** | ||||
| * Returns the absolute URI of the file. | |||||
| * Returns the absolute URI of this file. | |||||
| */ | */ | ||||
| String getURI(); | String getURI(); | ||||
| /** | /** | ||||
| * Returns the name of the parent of the file. The root of a file system | |||||
| * has no parent. | |||||
| * Returns the file name of the parent of this file. The root of a | |||||
| * file system has no parent. | |||||
| * | * | ||||
| * @return | * @return | ||||
| * A {@link FileName} object representing the parent name. Returns | * A {@link FileName} object representing the parent name. Returns | ||||
| @@ -52,35 +53,49 @@ public interface FileName | |||||
| FileName getParent(); | FileName getParent(); | ||||
| /** | /** | ||||
| * Resolves a name, relative to the file. Equivalent to calling | |||||
| * Resolves a name, relative to this file name. Equivalent to calling | |||||
| * <code>resolveName( path, NameScope.FILE_SYSTEM )</code>. | * <code>resolveName( path, NameScope.FILE_SYSTEM )</code>. | ||||
| * | * | ||||
| * @param path | |||||
| * The path to resolve. | |||||
| * @param name | |||||
| * The name to resolve. | |||||
| * | * | ||||
| * @return | * @return | ||||
| * A {@link FileName} object representing the resolved name. | |||||
| * A {@link FileName} object representing the resolved file name. | |||||
| * | * | ||||
| * @throws FileSystemException | * @throws FileSystemException | ||||
| * If the name is invalid. | * If the name is invalid. | ||||
| */ | */ | ||||
| FileName resolveName( String path ) throws FileSystemException; | |||||
| FileName resolveName( String name ) throws FileSystemException; | |||||
| /** | /** | ||||
| * Resolves a name, relative to the file. Refer to {@link NameScope} | |||||
| * Resolves a name, relative to this file name. Refer to {@link NameScope} | |||||
| * for a description of how names are resolved. | * for a description of how names are resolved. | ||||
| * | * | ||||
| * @param name | * @param name | ||||
| * The path to resolve. | |||||
| * The name to resolve. | |||||
| * | * | ||||
| * @param scope | * @param scope | ||||
| * The scope to use when resolving the name. | * The scope to use when resolving the name. | ||||
| * | * | ||||
| * @return | * @return | ||||
| * A {@link FileName} object representing the resolved name. | |||||
| * A {@link FileName} object representing the resolved file name. | |||||
| * | * | ||||
| * @throws FileSystemException | * @throws FileSystemException | ||||
| * If the name is invalid. | * If the name is invalid. | ||||
| */ | */ | ||||
| FileName resolveName( String name, NameScope scope ) throws FileSystemException; | FileName resolveName( String name, NameScope scope ) throws FileSystemException; | ||||
| /** | |||||
| * Converts a file name to a relative name, relative to this file name. | |||||
| * | |||||
| * @param name | |||||
| * The name to convert to a relative path. | |||||
| * | |||||
| * @return | |||||
| * The relative name. | |||||
| * | |||||
| * @throws FileSystemException | |||||
| * On error. | |||||
| */ | |||||
| String getRelativeName( FileName name ) throws FileSystemException; | |||||
| } | } | ||||
| @@ -7,6 +7,8 @@ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs; | package org.apache.aut.vfs; | ||||
| import java.io.File; | |||||
| /** | /** | ||||
| * This interface represents a file, and is used to access the content and | * This interface represents a file, and is used to access the content and | ||||
| * structure of the file. | * structure of the file. | ||||
| @@ -53,7 +55,8 @@ package org.apache.aut.vfs; | |||||
| * @see FileContent | * @see FileContent | ||||
| * @see FileName | * @see FileName | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public interface FileObject | public interface FileObject | ||||
| { | { | ||||
| @@ -154,17 +157,19 @@ public interface FileObject | |||||
| FileObject resolveFile( String path ) throws FileSystemException; | FileObject resolveFile( String path ) throws FileSystemException; | ||||
| /** | /** | ||||
| * Deletes this file, and all children. Does nothing if the file | |||||
| * Deletes this file, and all descendents. Does nothing if the file | |||||
| * does not exist. | * does not exist. | ||||
| * | * | ||||
| * <p>This method is not transactional. If it fails and throws an | * <p>This method is not transactional. If it fails and throws an | ||||
| * exception, some of this file's descendents may have been deleted. | |||||
| * exception, this file will potentially only be partially deleted. | |||||
| * | |||||
| * @param selector The selector to use to select which files to delete. | |||||
| * | * | ||||
| * @throws FileSystemException | * @throws FileSystemException | ||||
| * If this file or one of its descendents is read-only, or on error | * If this file or one of its descendents is read-only, or on error | ||||
| * deleting this file or one of its descendents. | * deleting this file or one of its descendents. | ||||
| */ | */ | ||||
| void delete() throws FileSystemException; | |||||
| void delete( FileSelector selector ) throws FileSystemException; | |||||
| /** | /** | ||||
| * Creates this file, if it does not exist. Also creates any ancestor | * Creates this file, if it does not exist. Also creates any ancestor | ||||
| @@ -182,18 +187,42 @@ public interface FileObject | |||||
| void create( FileType type ) throws FileSystemException; | void create( FileType type ) throws FileSystemException; | ||||
| /** | /** | ||||
| * Copies the content of another file to this file. | |||||
| * Copies another file, and all its descendents, to this file. | |||||
| * | * | ||||
| * If this file does not exist, it is created. Its parent folder is also | * 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. | |||||
| * created, if necessary. If this file does exist, it is deleted first. | |||||
| * | |||||
| * <p>This method is not transactional. If it fails and throws an | |||||
| * exception, this file will potentially only be partially copied. | |||||
| * | |||||
| * @param srcFile The source file to copy. | |||||
| * @param selector The selector to use to select which files to copy. | |||||
| * | |||||
| * @throws FileSystemException | |||||
| * If this file is read-only, or if the source file does not exist, | |||||
| * or on error copying the file. | |||||
| */ | |||||
| void copyFrom( FileObject srcFile, FileSelector selector ) throws FileSystemException; | |||||
| /** | |||||
| * Creates a temporary local copy of this file, and its descendents. If | |||||
| * this file is a local file, a copy is not made. | |||||
| * | |||||
| * <p>Note that the local copy may include additonal files, that were | |||||
| * not selected by the given selector. | |||||
| * | |||||
| * @todo Add options to indicate whether the caller is happy to deal with | |||||
| * extra files being present locally (eg if the file has been | |||||
| * replicated previously), or whether the caller expects only | |||||
| * the selected files to be present. | |||||
| * | * | ||||
| * @param file The file to copy the content from. | |||||
| * @param selector the selector to use to select the files to replicate. | |||||
| * @return The local copy of this file. | |||||
| * | * | ||||
| * @throws FileSystemException | * @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. | |||||
| * If this file does not exist, or on error replicating the file. | |||||
| */ | */ | ||||
| void copy( FileObject file ) throws FileSystemException; | |||||
| File replicateFile( FileSelector selector ) throws FileSystemException; | |||||
| /** | /** | ||||
| * Returns this file's content. The {@link FileContent} returned by this | * Returns this file's content. The {@link FileContent} returned by this | ||||
| @@ -0,0 +1,33 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * Information about a file, that is used to select files during the | |||||
| * traversal of a hierarchy. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface FileSelectInfo | |||||
| { | |||||
| /** | |||||
| * Returns the base folder of the traversal. | |||||
| */ | |||||
| FileObject getBaseFolder(); | |||||
| /** | |||||
| * Returns the file (or folder) to be considered. | |||||
| */ | |||||
| FileObject getFile(); | |||||
| /** | |||||
| * Returns the depth of the file relative to the base folder. | |||||
| */ | |||||
| int getDepth(); | |||||
| } | |||||
| @@ -0,0 +1,38 @@ | |||||
| /* | |||||
| * 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; | |||||
| /** | |||||
| * This interface is used to select files when traversing a file hierarchy. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface FileSelector | |||||
| { | |||||
| /** | |||||
| * Determines if a file or folder should be selected. | |||||
| * | |||||
| * @param fileInfo the file or folder to select. | |||||
| * @return true if the file should be selected. | |||||
| */ | |||||
| boolean includeFile( FileSelectInfo fileInfo ) | |||||
| throws FileSystemException; | |||||
| /** | |||||
| * Determines whether a folder should be traversed. If this method returns | |||||
| * true, {@link #includeFile} is called for each of the children of | |||||
| * the folder, and each of the child folders is recursively traversed. | |||||
| * | |||||
| * @param fileInfo the file or folder to select. | |||||
| * | |||||
| * @return true if the folder should be traversed. | |||||
| */ | |||||
| boolean traverseDescendents( FileSelectInfo fileInfo ) | |||||
| throws FileSystemException; | |||||
| } | |||||
| @@ -10,7 +10,8 @@ package org.apache.aut.vfs; | |||||
| /** | /** | ||||
| * Thrown for file system errors. | * Thrown for file system errors. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class FileSystemException | public class FileSystemException | ||||
| extends Exception | extends Exception | ||||
| @@ -49,7 +49,9 @@ import java.io.File; | |||||
| * | * | ||||
| * </ul> | * </ul> | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | |||||
| * @ant:role shorthand="file-system-manager" | * @ant:role shorthand="file-system-manager" | ||||
| */ | */ | ||||
| public interface FileSystemManager | public interface FileSystemManager | ||||
| @@ -128,7 +130,7 @@ public interface FileSystemManager | |||||
| /** | /** | ||||
| * Creates a layered file system. A layered file system is a file system | * 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 | |||||
| * that is created from the contents of another file, such as a zip | |||||
| * or tar file. | * or tar file. | ||||
| * | * | ||||
| * @param provider | * @param provider | ||||
| @@ -5,7 +5,8 @@ | |||||
| * version 1.1, a copy of which has been included with this distribution in | * version 1.1, a copy of which has been included with this distribution in | ||||
| * the LICENSE.txt file. | * the LICENSE.txt file. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs; | package org.apache.aut.vfs; | ||||
| @@ -11,7 +11,8 @@ package org.apache.aut.vfs; | |||||
| * An enumerated type for file name scope, used when resolving a name relative | * An enumerated type for file name scope, used when resolving a name relative | ||||
| * to a file. | * to a file. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public final class NameScope | public final class NameScope | ||||
| { | { | ||||
| @@ -29,6 +30,14 @@ public final class NameScope | |||||
| */ | */ | ||||
| public static final NameScope DESCENDENT = new NameScope( "descendent" ); | public static final NameScope DESCENDENT = new NameScope( "descendent" ); | ||||
| /** | |||||
| * Resolve against the descendents of the base file. The name is resolved | |||||
| * as described by {@link #FILE_SYSTEM}. However, an exception is thrown | |||||
| * if the resolved file is not a descendent of the base file, or the base | |||||
| * files itself. | |||||
| */ | |||||
| public static final NameScope DESCENDENT_OR_SELF = new NameScope( "descendent_or_self" ); | |||||
| /** | /** | ||||
| * Resolve against files in the same file system as the base file. | * Resolve against files in the same file system as the base file. | ||||
| * | * | ||||
| @@ -46,7 +55,7 @@ public final class NameScope | |||||
| */ | */ | ||||
| public static final NameScope FILE_SYSTEM = new NameScope( "filesystem" ); | public static final NameScope FILE_SYSTEM = new NameScope( "filesystem" ); | ||||
| private String m_name; | |||||
| private final String m_name; | |||||
| private NameScope( final String name ) | private NameScope( final String name ) | ||||
| { | { | ||||
| @@ -0,0 +1,98 @@ | |||||
| /* | |||||
| * 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.io.File; | |||||
| import java.util.ArrayList; | |||||
| import org.apache.aut.vfs.FileConstants; | |||||
| import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSelector; | |||||
| import org.apache.aut.vfs.FileSystemException; | |||||
| import org.apache.aut.vfs.provider.FileReplicator; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| /** | |||||
| * A simple file replicator. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultFileReplicator | |||||
| extends AbstractLogEnabled | |||||
| implements FileReplicator, Disposable | |||||
| { | |||||
| private static final Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultFileReplicator.class ); | |||||
| private final DefaultFileSystemManager m_manager; | |||||
| private final File m_tempDir; | |||||
| private final ArrayList m_copies = new ArrayList(); | |||||
| private long m_filecount; | |||||
| public DefaultFileReplicator( final DefaultFileSystemManager manager ) | |||||
| { | |||||
| m_manager = manager; | |||||
| m_tempDir = new File( "ant_vfs_cache" ).getAbsoluteFile(); | |||||
| } | |||||
| /** | |||||
| * Deletes the temporary files. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| while( m_copies.size() > 0 ) | |||||
| { | |||||
| final FileObject file = (FileObject)m_copies.remove( 0 ); | |||||
| try | |||||
| { | |||||
| file.delete( FileConstants.SELECT_ALL ); | |||||
| } | |||||
| catch( final FileSystemException e ) | |||||
| { | |||||
| final String message = REZ.getString( "delete-temp.warn", file.getName() ); | |||||
| getLogger().warn( message, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a local copy of the file, and all its descendents. | |||||
| */ | |||||
| public File replicateFile( final FileObject srcFile, | |||||
| final FileSelector selector ) | |||||
| throws FileSystemException | |||||
| { | |||||
| // TODO - this is awful | |||||
| // Create a unique-ish file name | |||||
| final String basename = m_filecount + "_" + srcFile.getName().getBaseName(); | |||||
| m_filecount++; | |||||
| final File file = new File( m_tempDir, basename ); | |||||
| try | |||||
| { | |||||
| // Copy from the source file | |||||
| final FileObject destFile = m_manager.convert( file ); | |||||
| destFile.copyFrom( srcFile, selector ); | |||||
| // Keep track of the copy | |||||
| m_copies.add( destFile ); | |||||
| } | |||||
| catch( final FileSystemException e ) | |||||
| { | |||||
| final String message = REZ.getString( "replicate-file.error", srcFile.getName(), file ); | |||||
| throw new FileSystemException( message, e ); | |||||
| } | |||||
| return file; | |||||
| } | |||||
| } | |||||
| @@ -9,48 +9,50 @@ package org.apache.aut.vfs.impl; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.util.HashMap; | import java.util.HashMap; | ||||
| import java.util.HashSet; | |||||
| import java.util.Iterator; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.Set; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.FileSystemManager; | import org.apache.aut.vfs.FileSystemManager; | ||||
| import org.apache.aut.vfs.provider.FileReplicator; | |||||
| import org.apache.aut.vfs.provider.FileSystemProvider; | import org.apache.aut.vfs.provider.FileSystemProvider; | ||||
| import org.apache.aut.vfs.provider.LocalFileSystemProvider; | |||||
| import org.apache.aut.vfs.provider.UriParser; | import org.apache.aut.vfs.provider.UriParser; | ||||
| import org.apache.aut.vfs.provider.local.LocalFileSystemProvider; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| import org.apache.avalon.framework.logger.Logger; | |||||
| /** | /** | ||||
| * A default file system manager implementation. | * A default file system manager implementation. | ||||
| * | * | ||||
| * @todo - Extract an AbstractFileSystemManager super-class from this class. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | ||||
| * @version $Revision$ $Date$ | * @version $Revision$ $Date$ | ||||
| */ | */ | ||||
| public class DefaultFileSystemManager | public class DefaultFileSystemManager | ||||
| implements FileSystemManager | |||||
| extends AbstractLogEnabled | |||||
| implements FileSystemManager, Disposable | |||||
| { | { | ||||
| private static final Resources REZ | private static final Resources REZ | ||||
| = ResourceManager.getPackageResources( DefaultFileSystemManager.class ); | = ResourceManager.getPackageResources( DefaultFileSystemManager.class ); | ||||
| /** The default provider. */ | |||||
| private final LocalFileSystemProvider m_localFileProvider; | |||||
| /** The provider for local files. */ | |||||
| private LocalFileSystemProvider m_localFileProvider; | |||||
| /** The file replicator to use. */ | |||||
| private final DefaultFileReplicator m_fileReplicator = new DefaultFileReplicator( this ); | |||||
| /** Mapping from URI scheme to FileSystemProvider. */ | /** Mapping from URI scheme to FileSystemProvider. */ | ||||
| private final Map m_providers = new HashMap(); | private final Map m_providers = new HashMap(); | ||||
| /** The provider context. */ | |||||
| private final DefaultProviderContext m_context = new DefaultProviderContext( this ); | |||||
| /** The base file to use for relative URI. */ | /** The base file to use for relative URI. */ | ||||
| private FileObject m_baseFile; | private FileObject m_baseFile; | ||||
| public DefaultFileSystemManager() | |||||
| { | |||||
| // Create the local provider | |||||
| m_localFileProvider = new LocalFileSystemProvider(); | |||||
| m_providers.put( "file", m_localFileProvider ); | |||||
| m_localFileProvider.setContext( m_context ); | |||||
| } | |||||
| /** | /** | ||||
| * Registers a file system provider. | * Registers a file system provider. | ||||
| */ | */ | ||||
| @@ -58,7 +60,7 @@ public class DefaultFileSystemManager | |||||
| final FileSystemProvider provider ) | final FileSystemProvider provider ) | ||||
| throws FileSystemException | throws FileSystemException | ||||
| { | { | ||||
| addProvider( new String[] { urlScheme }, provider ); | |||||
| addProvider( new String[]{urlScheme}, provider ); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -71,7 +73,7 @@ public class DefaultFileSystemManager | |||||
| // Check for duplicates | // Check for duplicates | ||||
| for( int i = 0; i < urlSchemes.length; i++ ) | for( int i = 0; i < urlSchemes.length; i++ ) | ||||
| { | { | ||||
| final String scheme = urlSchemes[i ]; | |||||
| final String scheme = urlSchemes[ i ]; | |||||
| if( m_providers.containsKey( scheme ) ) | if( m_providers.containsKey( scheme ) ) | ||||
| { | { | ||||
| final String message = REZ.getString( "multiple-providers-for-scheme.error", scheme ); | final String message = REZ.getString( "multiple-providers-for-scheme.error", scheme ); | ||||
| @@ -80,7 +82,8 @@ public class DefaultFileSystemManager | |||||
| } | } | ||||
| // Contextualise | // Contextualise | ||||
| provider.setContext( m_context ); | |||||
| setupLogger( provider ); | |||||
| provider.setContext( new DefaultProviderContext( this ) ); | |||||
| // Add to map | // Add to map | ||||
| for( int i = 0; i < urlSchemes.length; i++ ) | for( int i = 0; i < urlSchemes.length; i++ ) | ||||
| @@ -88,14 +91,55 @@ public class DefaultFileSystemManager | |||||
| final String scheme = urlSchemes[ i ]; | final String scheme = urlSchemes[ i ]; | ||||
| m_providers.put( scheme, provider ); | m_providers.put( scheme, provider ); | ||||
| } | } | ||||
| if( provider instanceof LocalFileSystemProvider ) | |||||
| { | |||||
| m_localFileProvider = (LocalFileSystemProvider)provider; | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * Closes all file systems created by this file system manager. | |||||
| * Returns the file replicator. | |||||
| * | |||||
| * @return The file replicator. Never returns null. | |||||
| */ | */ | ||||
| public void close() | |||||
| public FileReplicator getReplicator() | |||||
| throws FileSystemException | |||||
| { | { | ||||
| // TODO - implement this | |||||
| return m_fileReplicator; | |||||
| } | |||||
| /** | |||||
| * Enable logging. | |||||
| */ | |||||
| public void enableLogging( final Logger logger ) | |||||
| { | |||||
| super.enableLogging( logger ); | |||||
| setupLogger( m_fileReplicator ); | |||||
| } | |||||
| /** | |||||
| * Closes all files created by this manager, and cleans up any temporary | |||||
| * files. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| // Dispose the providers (making sure we only dispose each provider | |||||
| // once | |||||
| final Set providers = new HashSet(); | |||||
| providers.addAll( m_providers.values() ); | |||||
| for( Iterator iterator = providers.iterator(); iterator.hasNext(); ) | |||||
| { | |||||
| Object provider = iterator.next(); | |||||
| if( provider instanceof Disposable ) | |||||
| { | |||||
| Disposable disposable = (Disposable)provider; | |||||
| disposable.dispose(); | |||||
| } | |||||
| } | |||||
| m_providers.clear(); | |||||
| m_fileReplicator.dispose(); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -111,7 +155,7 @@ public class DefaultFileSystemManager | |||||
| */ | */ | ||||
| public void setBaseFile( final File baseFile ) throws FileSystemException | public void setBaseFile( final File baseFile ) throws FileSystemException | ||||
| { | { | ||||
| m_baseFile = m_localFileProvider.findLocalFile( baseFile.getAbsolutePath() ); | |||||
| m_baseFile = getLocalFileProvider().findLocalFile( baseFile ); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -136,7 +180,7 @@ public class DefaultFileSystemManager | |||||
| public FileObject resolveFile( final File baseFile, final String uri ) | public FileObject resolveFile( final File baseFile, final String uri ) | ||||
| throws FileSystemException | throws FileSystemException | ||||
| { | { | ||||
| final FileObject baseFileObj = m_localFileProvider.findLocalFile( baseFile ); | |||||
| final FileObject baseFileObj = getLocalFileProvider().findLocalFile( baseFile ); | |||||
| return resolveFile( baseFileObj, uri ); | return resolveFile( baseFileObj, uri ); | ||||
| } | } | ||||
| @@ -162,19 +206,20 @@ public class DefaultFileSystemManager | |||||
| final String decodedUri = UriParser.decode( uri ); | final String decodedUri = UriParser.decode( uri ); | ||||
| // Handle absolute file names | // Handle absolute file names | ||||
| if( m_localFileProvider.isAbsoluteLocalName( decodedUri ) ) | |||||
| if( m_localFileProvider != null | |||||
| && m_localFileProvider.isAbsoluteLocalName( decodedUri ) ) | |||||
| { | { | ||||
| return m_localFileProvider.findLocalFile( decodedUri ); | return m_localFileProvider.findLocalFile( decodedUri ); | ||||
| } | } | ||||
| // Assume a bad scheme | |||||
| if( scheme != null ) | if( scheme != null ) | ||||
| { | { | ||||
| // Assume a bad scheme | |||||
| final String message = REZ.getString( "unknown-scheme.error", scheme, uri ); | final String message = REZ.getString( "unknown-scheme.error", scheme, uri ); | ||||
| throw new FileSystemException( message ); | throw new FileSystemException( message ); | ||||
| } | } | ||||
| // Use the supplied base file | |||||
| // Assume a relative name - use the supplied base file | |||||
| if( baseFile == null ) | if( baseFile == null ) | ||||
| { | { | ||||
| final String message = REZ.getString( "find-rel-file.error", uri ); | final String message = REZ.getString( "find-rel-file.error", uri ); | ||||
| @@ -189,7 +234,7 @@ public class DefaultFileSystemManager | |||||
| public FileObject convert( final File file ) | public FileObject convert( final File file ) | ||||
| throws FileSystemException | throws FileSystemException | ||||
| { | { | ||||
| return m_localFileProvider.findLocalFile( file ); | |||||
| return getLocalFileProvider().findLocalFile( file ); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -207,4 +252,18 @@ public class DefaultFileSystemManager | |||||
| } | } | ||||
| return provider.createFileSystem( scheme, file ); | return provider.createFileSystem( scheme, file ); | ||||
| } | } | ||||
| /** | |||||
| * Locates the local file provider. | |||||
| */ | |||||
| private LocalFileSystemProvider getLocalFileProvider() | |||||
| throws FileSystemException | |||||
| { | |||||
| if( m_localFileProvider == null ) | |||||
| { | |||||
| final String message = REZ.getString( "no-local-file-provider.error" ); | |||||
| throw new FileSystemException( message ); | |||||
| } | |||||
| return m_localFileProvider; | |||||
| } | |||||
| } | } | ||||
| @@ -7,11 +7,9 @@ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs.impl; | 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.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.provider.FileSystem; | |||||
| import org.apache.aut.vfs.provider.FileReplicator; | |||||
| import org.apache.aut.vfs.provider.FileSystemProviderContext; | import org.apache.aut.vfs.provider.FileSystemProviderContext; | ||||
| /** | /** | ||||
| @@ -25,12 +23,6 @@ final class DefaultProviderContext | |||||
| { | { | ||||
| private final DefaultFileSystemManager m_manager; | 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 ) | public DefaultProviderContext( final DefaultFileSystemManager manager ) | ||||
| { | { | ||||
| m_manager = manager; | m_manager = manager; | ||||
| @@ -46,21 +38,10 @@ final class DefaultProviderContext | |||||
| } | } | ||||
| /** | /** | ||||
| * Locates a cached file system by root URI. | |||||
| * Locates a file replicator for the provider to use. | |||||
| */ | */ | ||||
| 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 | |||||
| public FileReplicator getReplicator() throws FileSystemException | |||||
| { | { | ||||
| // TODO - should really check that there's not one already cached | |||||
| m_fileSystems.put( rootURI, fs ); | |||||
| return m_manager.getReplicator(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -2,4 +2,7 @@ | |||||
| unknown-scheme.error=Unknown scheme "{0}" in URI "{1}". | 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. | 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}". | multiple-providers-for-scheme.error=Multiple file system providers registered for URL scheme "{0}". | ||||
| unknown-provider.error=Unknown file system provider "{0}". | |||||
| unknown-provider.error=No file system provider is registered for URI scheme "{0}". | |||||
| no-local-file-provider.error=Could not find a file system provider which can handle local files. | |||||
| replicate-file.error=Could not replicate "{0}" to "{1}". | |||||
| delete-temp.warn=Could not clean up temporary file "{0}". | |||||
| @@ -7,15 +7,16 @@ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs.provider; | package org.apache.aut.vfs.provider; | ||||
| import java.io.File; | |||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.HashSet; | |||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Set; | |||||
| import org.apache.aut.vfs.FileConstants; | |||||
| import org.apache.aut.vfs.FileContent; | import org.apache.aut.vfs.FileContent; | ||||
| import org.apache.aut.vfs.FileName; | import org.apache.aut.vfs.FileName; | ||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSelector; | |||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.FileType; | import org.apache.aut.vfs.FileType; | ||||
| import org.apache.aut.vfs.NameScope; | import org.apache.aut.vfs.NameScope; | ||||
| @@ -26,7 +27,11 @@ import org.apache.avalon.excalibur.io.IOUtil; | |||||
| /** | /** | ||||
| * A partial file object implementation. | * A partial file object implementation. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @todo Chop this class up - move all the protected methods to several | |||||
| * interfaces, so that structure and content can be separately overridden. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public abstract class AbstractFileObject | public abstract class AbstractFileObject | ||||
| implements FileObject | implements FileObject | ||||
| @@ -98,7 +103,7 @@ public abstract class AbstractFileObject | |||||
| * <ul> | * <ul> | ||||
| * <li>{@link #isReadOnly} returns false. | * <li>{@link #isReadOnly} returns false. | ||||
| * <li>{@link #doGetType} does not return null. | * <li>{@link #doGetType} does not return null. | ||||
| * <li>If this file is a folder, it has no children. | |||||
| * <li>This file has no children. | |||||
| * </ul> | * </ul> | ||||
| */ | */ | ||||
| protected void doDelete() throws Exception | protected void doDelete() throws Exception | ||||
| @@ -122,6 +127,15 @@ public abstract class AbstractFileObject | |||||
| throw new FileSystemException( message ); | throw new FileSystemException( message ); | ||||
| } | } | ||||
| /** | |||||
| * Creates a local copy of this file. | |||||
| */ | |||||
| protected File doReplicateFile( final FileSelector selector ) throws FileSystemException | |||||
| { | |||||
| final FileReplicator replicator = m_fs.getContext().getReplicator(); | |||||
| return replicator.replicateFile( this, selector ); | |||||
| } | |||||
| /** | /** | ||||
| * Called when the children of this file change. | * Called when the children of this file change. | ||||
| */ | */ | ||||
| @@ -321,9 +335,9 @@ public abstract class AbstractFileObject | |||||
| * absolute path, which is resolved relative to the file system | * absolute path, which is resolved relative to the file system | ||||
| * that contains this file. | * that contains this file. | ||||
| */ | */ | ||||
| public FileObject resolveFile( String path ) throws FileSystemException | |||||
| public FileObject resolveFile( final String path ) throws FileSystemException | |||||
| { | { | ||||
| FileName name = m_name.resolveName( path ); | |||||
| final FileName name = m_name.resolveName( path ); | |||||
| return m_fs.findFile( name ); | return m_fs.findFile( name ); | ||||
| } | } | ||||
| @@ -356,7 +370,7 @@ public abstract class AbstractFileObject | |||||
| /** | /** | ||||
| * Deletes this file, and all children. | * Deletes this file, and all children. | ||||
| */ | */ | ||||
| public void delete() throws FileSystemException | |||||
| public void delete( final FileSelector selector ) throws FileSystemException | |||||
| { | { | ||||
| attach(); | attach(); | ||||
| if( m_type == null ) | if( m_type == null ) | ||||
| @@ -365,51 +379,27 @@ public abstract class AbstractFileObject | |||||
| return; | return; | ||||
| } | } | ||||
| // Recursively delete this file and all its children | |||||
| List queue = new ArrayList(); | |||||
| Set expanded = new HashSet(); | |||||
| queue.add( this ); | |||||
| // Locate all the files to delete | |||||
| ArrayList files = new ArrayList(); | |||||
| findFiles( selector, true, files ); | |||||
| // Recursively delete each file | |||||
| // TODO - recover from errors | |||||
| while( queue.size() > 0 ) | |||||
| // Delete 'em | |||||
| final int count = files.size(); | |||||
| for( int i = 0; i < count; i++ ) | |||||
| { | { | ||||
| AbstractFileObject file = (AbstractFileObject)queue.get( 0 ); | |||||
| final AbstractFileObject file = (AbstractFileObject)files.get( i ); | |||||
| file.attach(); | file.attach(); | ||||
| if( file.m_type == null ) | |||||
| { | |||||
| // Shouldn't happen | |||||
| queue.remove( 0 ); | |||||
| } | |||||
| else if( file.m_type == FileType.FILE ) | |||||
| { | |||||
| // Delete the file | |||||
| file.deleteSelf(); | |||||
| queue.remove( 0 ); | |||||
| } | |||||
| else if( expanded.contains( file ) ) | |||||
| // If the file is a folder, make sure all its children have been deleted | |||||
| if( file.m_type == FileType.FOLDER && file.getChildren().length != 0 ) | |||||
| { | { | ||||
| // Have already deleted all the children of this folder - | |||||
| // delete it | |||||
| file.deleteSelf(); | |||||
| queue.remove( 0 ); | |||||
| // Skip | |||||
| continue; | |||||
| } | } | ||||
| else | |||||
| { | |||||
| // Delete the folder's children | |||||
| FileObject[] children = file.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| FileObject child = children[ i ]; | |||||
| queue.add( 0, child ); | |||||
| } | |||||
| expanded.add( file ); | |||||
| } | |||||
| } | |||||
| // Update parent's child list | |||||
| notifyParent(); | |||||
| // Delete the file | |||||
| file.deleteSelf(); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -467,19 +457,88 @@ public abstract class AbstractFileObject | |||||
| updateType(); | updateType(); | ||||
| } | } | ||||
| /** | |||||
| * Copies another file to this file. | |||||
| */ | |||||
| public void copyFrom( final FileObject file, final FileSelector selector ) | |||||
| throws FileSystemException | |||||
| { | |||||
| if( !file.exists() ) | |||||
| { | |||||
| final String message = REZ.getString( "copy-missing-file.error", file.getName() ); | |||||
| throw new FileSystemException( message ); | |||||
| } | |||||
| if( isReadOnly() ) | |||||
| { | |||||
| final String message = REZ.getString( "copy-read-only.error", file.getType(), file.getName(), m_name ); | |||||
| throw new FileSystemException( message ); | |||||
| } | |||||
| // Locate the files to copy across | |||||
| final ArrayList files = new ArrayList(); | |||||
| ( (AbstractFileObject)file ).findFiles( selector, false, files ); | |||||
| // Copy everything across | |||||
| final int count = files.size(); | |||||
| for( int i = 0; i < count; i++ ) | |||||
| { | |||||
| final FileObject srcFile = (FileObject)files.get( i ); | |||||
| // Determine the destination file | |||||
| final String relPath = file.getName().getRelativeName( srcFile.getName() ); | |||||
| final FileObject destFile = resolveFile( relPath, NameScope.DESCENDENT_OR_SELF ); | |||||
| // Clean up the destination file, if necessary | |||||
| if( destFile.exists() && destFile.getType() != srcFile.getType() ) | |||||
| { | |||||
| // The destination file exists, and is not of the same type, | |||||
| // so delete it | |||||
| // TODO - add a pluggable policy for deleting and overwriting existing files | |||||
| destFile.delete( FileConstants.SELECT_ALL ); | |||||
| } | |||||
| // Copy across | |||||
| if( srcFile.getType() == FileType.FILE ) | |||||
| { | |||||
| copyContent( srcFile, destFile ); | |||||
| } | |||||
| else | |||||
| { | |||||
| destFile.create( FileType.FOLDER ); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Creates a temporary local copy of this file, and its descendents. | |||||
| */ | |||||
| public File replicateFile( final FileSelector selector ) | |||||
| throws FileSystemException | |||||
| { | |||||
| if( !exists() ) | |||||
| { | |||||
| final String message = REZ.getString( "copy-missing-file.error", m_name ); | |||||
| throw new FileSystemException( message ); | |||||
| } | |||||
| return doReplicateFile( selector ); | |||||
| } | |||||
| /** | /** | ||||
| * Copies the content of another file to this file. | * Copies the content of another file to this file. | ||||
| */ | */ | ||||
| public void copy( final FileObject file ) throws FileSystemException | |||||
| private static void copyContent( final FileObject srcFile, | |||||
| final FileObject destFile ) | |||||
| throws FileSystemException | |||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| final InputStream instr = file.getContent().getInputStream(); | |||||
| final InputStream instr = srcFile.getContent().getInputStream(); | |||||
| try | try | ||||
| { | { | ||||
| // Create the output strea via getContent(), to pick up the | |||||
| // Create the output stream via getContent(), to pick up the | |||||
| // validation it does | // validation it does | ||||
| final OutputStream outstr = getContent().getOutputStream(); | |||||
| final OutputStream outstr = destFile.getContent().getOutputStream(); | |||||
| try | try | ||||
| { | { | ||||
| IOUtil.copy( instr, outstr ); | IOUtil.copy( instr, outstr ); | ||||
| @@ -496,7 +555,7 @@ public abstract class AbstractFileObject | |||||
| } | } | ||||
| catch( final Exception exc ) | catch( final Exception exc ) | ||||
| { | { | ||||
| final String message = REZ.getString( "copy-file.error", file.getName(), m_name ); | |||||
| final String message = REZ.getString( "copy-file.error", srcFile.getName(), destFile.getName() ); | |||||
| throw new FileSystemException( message, exc ); | throw new FileSystemException( message, exc ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -678,4 +737,69 @@ public abstract class AbstractFileObject | |||||
| m_children = null; | m_children = null; | ||||
| onChildrenChanged(); | onChildrenChanged(); | ||||
| } | } | ||||
| /** | |||||
| * Traverses the descendents of this file, and builds a list of selected | |||||
| * files. | |||||
| */ | |||||
| void findFiles( final FileSelector selector, | |||||
| final boolean depthwise, | |||||
| final List selected ) throws FileSystemException | |||||
| { | |||||
| if( exists() ) | |||||
| { | |||||
| // Traverse starting at this file | |||||
| final DefaultFileSelectorInfo info = new DefaultFileSelectorInfo(); | |||||
| info.setBaseFolder( this ); | |||||
| info.setDepth( 0 ); | |||||
| info.setFile( this ); | |||||
| traverse( info, selector, depthwise, selected ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Traverses a file. | |||||
| */ | |||||
| private void traverse( final DefaultFileSelectorInfo fileInfo, | |||||
| final FileSelector selector, | |||||
| final boolean depthwise, | |||||
| final List selected ) | |||||
| throws FileSystemException | |||||
| { | |||||
| // Check the file itself | |||||
| final boolean includeFile = selector.includeFile( fileInfo ); | |||||
| final FileObject file = fileInfo.getFile(); | |||||
| // Add the file if not doing depthwise traversal | |||||
| if( !depthwise && includeFile ) | |||||
| { | |||||
| selected.add( file ); | |||||
| } | |||||
| // If the file is a folder, traverse it | |||||
| if( file.getType() == FileType.FOLDER && selector.traverseDescendents( fileInfo ) ) | |||||
| { | |||||
| final int curDepth = fileInfo.getDepth(); | |||||
| fileInfo.setDepth( curDepth + 1 ); | |||||
| // Traverse the children | |||||
| final FileObject[] children = file.getChildren(); | |||||
| for( int i = 0; i < children.length; i++ ) | |||||
| { | |||||
| final FileObject child = children[ i ]; | |||||
| fileInfo.setFile( child ); | |||||
| traverse( fileInfo, selector, depthwise, selected ); | |||||
| } | |||||
| fileInfo.setFile( file ); | |||||
| fileInfo.setDepth( curDepth ); | |||||
| } | |||||
| // Add the file if doing depthwise traversal | |||||
| if( depthwise && includeFile ) | |||||
| { | |||||
| selected.add( file ); | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -12,45 +12,67 @@ import java.util.Map; | |||||
| import org.apache.aut.vfs.FileName; | import org.apache.aut.vfs.FileName; | ||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| /** | /** | ||||
| * A partial file system implementation. | * A partial file system implementation. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public abstract class AbstractFileSystem implements FileSystem | |||||
| public abstract class AbstractFileSystem | |||||
| extends AbstractLogEnabled | |||||
| implements FileSystem, Disposable | |||||
| { | { | ||||
| private FileObject m_root; | private FileObject m_root; | ||||
| private FileName m_rootName; | |||||
| private final FileName m_rootName; | |||||
| private final FileSystemProviderContext m_context; | |||||
| /** Map from absolute file path to FileObject. */ | |||||
| private Map m_files = new HashMap(); | |||||
| /** Map from FileName to FileObject. */ | |||||
| private final Map m_files = new HashMap(); | |||||
| protected AbstractFileSystem( FileName rootName ) | |||||
| protected AbstractFileSystem( final FileSystemProviderContext context, | |||||
| final FileName rootName ) | |||||
| { | { | ||||
| m_rootName = rootName; | m_rootName = rootName; | ||||
| m_context = context; | |||||
| } | |||||
| public void dispose() | |||||
| { | |||||
| // Clean-up | |||||
| m_files.clear(); | |||||
| } | } | ||||
| /** | /** | ||||
| * Creates a file object. This method is called only if the requested | * Creates a file object. This method is called only if the requested | ||||
| * file is not cached. | * file is not cached. | ||||
| */ | */ | ||||
| protected abstract FileObject createFile( FileName name ) throws FileSystemException; | |||||
| protected abstract FileObject createFile( final FileName name ) throws FileSystemException; | |||||
| /** | /** | ||||
| * Adds a file object to the cache. | * Adds a file object to the cache. | ||||
| */ | */ | ||||
| protected void putFile( FileObject file ) | |||||
| protected void putFile( final FileObject file ) | |||||
| { | { | ||||
| m_files.put( file.getName().getPath(), file ); | |||||
| m_files.put( file.getName(), file ); | |||||
| } | } | ||||
| /** | /** | ||||
| * Returns a cached file. | * Returns a cached file. | ||||
| */ | */ | ||||
| protected FileObject getFile( FileName name ) | |||||
| protected FileObject getFile( final FileName name ) | |||||
| { | |||||
| return (FileObject)m_files.get( name ); | |||||
| } | |||||
| /** | |||||
| * Returns the context fir this file system. | |||||
| */ | |||||
| public FileSystemProviderContext getContext() | |||||
| { | { | ||||
| return (FileObject)m_files.get( name.getPath() ); | |||||
| return m_context; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -68,24 +90,24 @@ public abstract class AbstractFileSystem implements FileSystem | |||||
| /** | /** | ||||
| * Finds a file in this file system. | * Finds a file in this file system. | ||||
| */ | */ | ||||
| public FileObject findFile( String nameStr ) throws FileSystemException | |||||
| public FileObject findFile( final String nameStr ) throws FileSystemException | |||||
| { | { | ||||
| // Resolve the name, and create the file | // Resolve the name, and create the file | ||||
| FileName name = m_rootName.resolveName( nameStr ); | |||||
| final FileName name = m_rootName.resolveName( nameStr ); | |||||
| return findFile( name ); | return findFile( name ); | ||||
| } | } | ||||
| /** | /** | ||||
| * Finds a file in this file system. | * Finds a file in this file system. | ||||
| */ | */ | ||||
| public FileObject findFile( FileName name ) throws FileSystemException | |||||
| public FileObject findFile( final FileName name ) throws FileSystemException | |||||
| { | { | ||||
| // TODO - assert that name is from this file system | // TODO - assert that name is from this file system | ||||
| FileObject file = (FileObject)m_files.get( name.getPath() ); | |||||
| FileObject file = (FileObject)m_files.get( name ); | |||||
| if( file == null ) | if( file == null ) | ||||
| { | { | ||||
| file = createFile( name ); | file = createFile( name ); | ||||
| m_files.put( name.getPath(), file ); | |||||
| m_files.put( name, file ); | |||||
| } | } | ||||
| return file; | return file; | ||||
| } | } | ||||
| @@ -7,24 +7,37 @@ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs.provider; | package org.apache.aut.vfs.provider; | ||||
| import java.util.HashMap; | |||||
| import java.util.Iterator; | |||||
| import java.util.Map; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.logger.AbstractLogEnabled; | |||||
| /** | /** | ||||
| * A partial file system provider implementation. | * A partial file system provider implementation. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public abstract class AbstractFileSystemProvider | public abstract class AbstractFileSystemProvider | ||||
| implements FileSystemProvider | |||||
| extends AbstractLogEnabled | |||||
| implements FileSystemProvider, Disposable | |||||
| { | { | ||||
| private static final Resources REZ = | private static final Resources REZ = | ||||
| ResourceManager.getPackageResources( AbstractFileSystemProvider.class ); | ResourceManager.getPackageResources( AbstractFileSystemProvider.class ); | ||||
| private FileSystemProviderContext m_context; | private FileSystemProviderContext m_context; | ||||
| /** | |||||
| * The cached file systems. This is a mapping from root URI to | |||||
| * FileSystem object. | |||||
| */ | |||||
| private final Map m_fileSystems = new HashMap(); | |||||
| /** | /** | ||||
| * Returns the context for this provider. | * Returns the context for this provider. | ||||
| */ | */ | ||||
| @@ -42,6 +55,23 @@ public abstract class AbstractFileSystemProvider | |||||
| m_context = context; | m_context = context; | ||||
| } | } | ||||
| /** | |||||
| * Closes the file systems created by this provider. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| for( Iterator iterator = m_fileSystems.values().iterator(); iterator.hasNext(); ) | |||||
| { | |||||
| FileSystem fileSystem = (FileSystem)iterator.next(); | |||||
| if( fileSystem instanceof Disposable ) | |||||
| { | |||||
| Disposable disposable = (Disposable)fileSystem; | |||||
| disposable.dispose(); | |||||
| } | |||||
| } | |||||
| m_fileSystems.clear(); | |||||
| } | |||||
| /** | /** | ||||
| * Locates a file object, by absolute URI. | * Locates a file object, by absolute URI. | ||||
| * | * | ||||
| @@ -65,7 +95,6 @@ public abstract class AbstractFileSystemProvider | |||||
| // Locate the file | // Locate the file | ||||
| return findFile( parsedUri ); | return findFile( parsedUri ); | ||||
| } | } | ||||
| /** | /** | ||||
| @@ -76,12 +105,13 @@ public abstract class AbstractFileSystemProvider | |||||
| { | { | ||||
| // Check in the cache for the file system | // Check in the cache for the file system | ||||
| final String rootUri = parsedUri.getRootUri(); | final String rootUri = parsedUri.getRootUri(); | ||||
| FileSystem fs = m_context.getFileSystem( rootUri ); | |||||
| FileSystem fs = (FileSystem)m_fileSystems.get( rootUri ); | |||||
| if( fs == null ) | if( fs == null ) | ||||
| { | { | ||||
| // Need to create the file system, and cache it | // Need to create the file system, and cache it | ||||
| fs = createFileSystem( parsedUri ); | fs = createFileSystem( parsedUri ); | ||||
| m_context.putFileSystem( rootUri, fs ); | |||||
| setupLogger( fs ); | |||||
| m_fileSystems.put( rootUri, fs ); | |||||
| } | } | ||||
| // Locate the file | // Locate the file | ||||
| @@ -21,7 +21,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | /** | ||||
| * The content of a file. | * The content of a file. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class DefaultFileContent | public class DefaultFileContent | ||||
| implements FileContent | implements FileContent | ||||
| @@ -14,7 +14,8 @@ import org.apache.aut.vfs.NameScope; | |||||
| /** | /** | ||||
| * A default file name implementation. | * A default file name implementation. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class DefaultFileName implements FileName | public class DefaultFileName implements FileName | ||||
| { | { | ||||
| @@ -127,4 +128,12 @@ public class DefaultFileName implements FileName | |||||
| } | } | ||||
| return m_uri; | return m_uri; | ||||
| } | } | ||||
| /** | |||||
| * Converts a file name to a relative name, relative to this file name. | |||||
| */ | |||||
| public String getRelativeName( final FileName name ) throws FileSystemException | |||||
| { | |||||
| return m_parser.makeRelative( m_absPath, name.getPath() ); | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,55 @@ | |||||
| /* | |||||
| * 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.provider; | |||||
| import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSelectInfo; | |||||
| /** | |||||
| * A default {@link FileSelectInfo} implementation. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| class DefaultFileSelectorInfo | |||||
| implements FileSelectInfo | |||||
| { | |||||
| private FileObject m_baseFolder; | |||||
| private FileObject m_file; | |||||
| private int m_depth; | |||||
| public FileObject getBaseFolder() | |||||
| { | |||||
| return m_baseFolder; | |||||
| } | |||||
| public void setBaseFolder( final FileObject baseFolder ) | |||||
| { | |||||
| m_baseFolder = baseFolder; | |||||
| } | |||||
| public FileObject getFile() | |||||
| { | |||||
| return m_file; | |||||
| } | |||||
| public void setFile( final FileObject file ) | |||||
| { | |||||
| m_file = file; | |||||
| } | |||||
| public int getDepth() | |||||
| { | |||||
| return m_depth; | |||||
| } | |||||
| public void setDepth( final int depth ) | |||||
| { | |||||
| m_depth = depth; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,36 @@ | |||||
| /* | |||||
| * 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.provider; | |||||
| import java.io.File; | |||||
| import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSelector; | |||||
| import org.apache.aut.vfs.FileSystemException; | |||||
| /** | |||||
| * Responsible for making local replicas of files. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface FileReplicator | |||||
| { | |||||
| /** | |||||
| * Creates a local copy of the file, and all its descendents. | |||||
| * | |||||
| * @param srcFile The file to copy. | |||||
| * @param selector Selects the files to copy. | |||||
| * | |||||
| * @return The local copy of the source file. | |||||
| * | |||||
| * @throws FileSystemException | |||||
| * If the source files does not exist, or on error copying. | |||||
| */ | |||||
| File replicateFile( FileObject srcFile, FileSelector selector ) | |||||
| throws FileSystemException; | |||||
| } | |||||
| @@ -14,7 +14,8 @@ import org.apache.aut.vfs.FileSystemException; | |||||
| /** | /** | ||||
| * A file system. | * A file system. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public interface FileSystem | public interface FileSystem | ||||
| { | { | ||||
| @@ -25,6 +25,9 @@ public interface FileSystemProvider | |||||
| /** | /** | ||||
| * Sets the context for this file system provider. This method is called | * Sets the context for this file system provider. This method is called | ||||
| * before any of the other provider methods. | * before any of the other provider methods. | ||||
| * | |||||
| * @todo - move this to a lifecycle interface (this interface is accessable to | |||||
| * other providers, so need to prevent this being called). | |||||
| */ | */ | ||||
| void setContext( FileSystemProviderContext context ); | void setContext( FileSystemProviderContext context ); | ||||
| @@ -29,12 +29,7 @@ public interface FileSystemProviderContext | |||||
| throws FileSystemException; | throws FileSystemException; | ||||
| /** | /** | ||||
| * Locates a cached file system by root URI. | |||||
| * Locates a file replicator for the provider to use. | |||||
| */ | */ | ||||
| FileSystem getFileSystem( String rootURI ); | |||||
| /** | |||||
| * Registers a file system for caching. | |||||
| */ | |||||
| void putFileSystem( String rootURI, FileSystem fs ) throws FileSystemException; | |||||
| FileReplicator getReplicator() throws FileSystemException; | |||||
| } | } | ||||
| @@ -0,0 +1,43 @@ | |||||
| /* | |||||
| * 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.provider; | |||||
| import java.io.File; | |||||
| import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSystemException; | |||||
| /** | |||||
| * A file system provider which handles local file systems. | |||||
| * | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface LocalFileSystemProvider | |||||
| extends FileSystemProvider | |||||
| { | |||||
| /** | |||||
| * Determines if a name is an absolute file name. | |||||
| * | |||||
| * @todo Move this to a general file name parser interface. | |||||
| * | |||||
| * @param name The name to test. | |||||
| */ | |||||
| boolean isAbsoluteLocalName( final String name ); | |||||
| /** | |||||
| * Finds a local file, from its local name. | |||||
| */ | |||||
| FileObject findLocalFile( final String name ) | |||||
| throws FileSystemException; | |||||
| /** | |||||
| * Finds a local file. | |||||
| */ | |||||
| FileObject findLocalFile( final File file ) | |||||
| throws FileSystemException; | |||||
| } | |||||
| @@ -10,7 +10,8 @@ package org.apache.aut.vfs.provider; | |||||
| /** | /** | ||||
| * A data container for information parsed from an absolute URI. | * A data container for information parsed from an absolute URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ParsedUri | public class ParsedUri | ||||
| { | { | ||||
| @@ -18,6 +18,8 @@ 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-in-use.error=Could not write to "{0}" because it is already in use. | ||||
| write.error=Could not write to "{0}". | write.error=Could not write to "{0}". | ||||
| copy-file.error=Could not copy "{0}" to "{1}". | copy-file.error=Could not copy "{0}" to "{1}". | ||||
| copy-read-only.error=Could not copy {0} "{1}" to "{2}" because the destination file is read-only. | |||||
| copy-missing-file.error=Could not copy "{0}" because is does not exist. | |||||
| # DefaultFileContent | # DefaultFileContent | ||||
| get-size-no-exist.error=Could not determine the size of file "{0}" because it does not exist. | get-size-no-exist.error=Could not determine the size of file "{0}" because it does not exist. | ||||
| @@ -17,7 +17,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | /** | ||||
| * A name parser which parses absolute URIs. See RFC 2396 for details. | * A name parser which parses absolute URIs. See RFC 2396 for details. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class UriParser | public class UriParser | ||||
| { | { | ||||
| @@ -452,6 +453,17 @@ public class UriParser | |||||
| throw new FileSystemException( message ); | throw new FileSystemException( message ); | ||||
| } | } | ||||
| } | } | ||||
| else if( scope == NameScope.DESCENDENT_OR_SELF ) | |||||
| { | |||||
| final int baseLen = baseFile.length(); | |||||
| if( !resolvedPath.startsWith( baseFile ) | |||||
| || ( resolvedPath.length() != baseLen | |||||
| && resolvedPath.charAt( baseLen ) != m_separatorChar ) ) | |||||
| { | |||||
| final String message = REZ.getString( "invalid-descendent-name.error", path ); | |||||
| throw new FileSystemException( message ); | |||||
| } | |||||
| } | |||||
| else if( scope != NameScope.FILE_SYSTEM ) | else if( scope != NameScope.FILE_SYSTEM ) | ||||
| { | { | ||||
| throw new IllegalArgumentException(); | throw new IllegalArgumentException(); | ||||
| @@ -482,6 +494,67 @@ public class UriParser | |||||
| return path.substring( 0, idx ); | return path.substring( 0, idx ); | ||||
| } | } | ||||
| /** | |||||
| * Converts an absolute path into a relative path. | |||||
| * | |||||
| * @param basePath The base path. | |||||
| * @param path The path to convert. | |||||
| */ | |||||
| public String makeRelative( final String basePath, final String path ) | |||||
| { | |||||
| // Calculate the common prefix | |||||
| final int basePathLen = basePath.length(); | |||||
| final int pathLen = path.length(); | |||||
| // Deal with root | |||||
| if( basePathLen == 1 && pathLen == 1 ) | |||||
| { | |||||
| return "."; | |||||
| } | |||||
| else if( basePathLen == 1 ) | |||||
| { | |||||
| return path.substring( 1 ); | |||||
| } | |||||
| final int maxlen = Math.min( basePathLen, pathLen ); | |||||
| int pos = 0; | |||||
| for( ; pos < maxlen && basePath.charAt( pos ) == path.charAt( pos ); pos++ ) | |||||
| { | |||||
| } | |||||
| if( pos == basePathLen && pos == pathLen ) | |||||
| { | |||||
| // Same names | |||||
| return "."; | |||||
| } | |||||
| else if( pos == basePathLen && pos < pathLen && path.charAt( pos ) == m_separatorChar ) | |||||
| { | |||||
| // A descendent of the base path | |||||
| return path.substring( pos + 1 ); | |||||
| } | |||||
| // Strip the common prefix off the path | |||||
| final StringBuffer buffer = new StringBuffer(); | |||||
| if( pathLen > 1 && ( pos < pathLen || basePath.charAt( pos ) != m_separatorChar ) ) | |||||
| { | |||||
| // Not a direct ancestor, need to back up | |||||
| pos = basePath.lastIndexOf( m_separatorChar, pos ); | |||||
| buffer.append( path.substring( pos ) ); | |||||
| } | |||||
| // Prepend a '../' for each element in the base path past the common | |||||
| // prefix | |||||
| buffer.insert( 0, ".." ); | |||||
| pos = basePath.indexOf( m_separatorChar, pos + 1 ); | |||||
| while( pos != -1 ) | |||||
| { | |||||
| buffer.insert( 0, "../" ); | |||||
| pos = basePath.indexOf( m_separatorChar, pos + 1 ); | |||||
| } | |||||
| return buffer.toString(); | |||||
| } | |||||
| /** | /** | ||||
| * Normalises a path. Does the following: | * Normalises a path. Does the following: | ||||
| * <ul> | * <ul> | ||||
| @@ -13,7 +13,8 @@ import org.apache.aut.vfs.provider.UriParser; | |||||
| /** | /** | ||||
| * A parser for FTP URI. | * A parser for FTP URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class FtpFileNameParser extends UriParser | public class FtpFileNameParser extends UriParser | ||||
| { | { | ||||
| @@ -7,6 +7,7 @@ | |||||
| */ | */ | ||||
| package org.apache.aut.vfs.provider.ftp; | package org.apache.aut.vfs.provider.ftp; | ||||
| import com.oroinc.net.ftp.FTPClient; | |||||
| import com.oroinc.net.ftp.FTPFile; | import com.oroinc.net.ftp.FTPFile; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| @@ -20,7 +21,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | /** | ||||
| * An FTP file. | * An FTP file. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| class FtpFileObject | class FtpFileObject | ||||
| extends AbstractFileObject | extends AbstractFileObject | ||||
| @@ -160,7 +162,17 @@ class FtpFileObject | |||||
| */ | */ | ||||
| protected void doDelete() throws Exception | protected void doDelete() throws Exception | ||||
| { | { | ||||
| if( !m_ftpFs.getClient().deleteFile( getName().getPath() ) ) | |||||
| final FTPClient ftpClient = m_ftpFs.getClient(); | |||||
| boolean ok; | |||||
| if( m_fileInfo.isDirectory() ) | |||||
| { | |||||
| ok = ftpClient.removeDirectory( getName().getPath() ); | |||||
| } | |||||
| else | |||||
| { | |||||
| ok = ftpClient.deleteFile( getName().getPath() ); | |||||
| } | |||||
| if( !ok ) | |||||
| { | { | ||||
| final String message = REZ.getString( "delete-file.error", getName() ); | final String message = REZ.getString( "delete-file.error", getName() ); | ||||
| throw new FileSystemException( message ); | throw new FileSystemException( message ); | ||||
| @@ -15,13 +15,15 @@ import org.apache.aut.vfs.FileName; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.provider.AbstractFileSystem; | import org.apache.aut.vfs.provider.AbstractFileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystemProviderContext; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| /** | /** | ||||
| * An FTP file system. | * An FTP file system. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| class FtpFileSystem | class FtpFileSystem | ||||
| extends AbstractFileSystem | extends AbstractFileSystem | ||||
| @@ -31,13 +33,14 @@ class FtpFileSystem | |||||
| private FTPClient m_client; | private FTPClient m_client; | ||||
| public FtpFileSystem( final FileName rootName, | |||||
| public FtpFileSystem( final FileSystemProviderContext context, | |||||
| final FileName rootName, | |||||
| final String hostname, | final String hostname, | ||||
| final String username, | final String username, | ||||
| final String password ) | final String password ) | ||||
| throws FileSystemException | throws FileSystemException | ||||
| { | { | ||||
| super( rootName ); | |||||
| super( context, rootName ); | |||||
| try | try | ||||
| { | { | ||||
| m_client = new FTPClient(); | m_client = new FTPClient(); | ||||
| @@ -64,26 +67,39 @@ class FtpFileSystem | |||||
| throw new FileSystemException( message ); | throw new FileSystemException( message ); | ||||
| } | } | ||||
| } | } | ||||
| catch( Exception exc ) | |||||
| catch( final Exception exc ) | |||||
| { | { | ||||
| try | |||||
| { | |||||
| // Clean up | |||||
| if( m_client.isConnected() ) | |||||
| { | |||||
| m_client.disconnect(); | |||||
| } | |||||
| } | |||||
| catch( IOException e ) | |||||
| { | |||||
| // Ignore | |||||
| } | |||||
| closeConnection(); | |||||
| final String message = REZ.getString( "connect.error", hostname ); | final String message = REZ.getString( "connect.error", hostname ); | ||||
| throw new FileSystemException( message, exc ); | throw new FileSystemException( message, exc ); | ||||
| } | } | ||||
| } | |||||
| // TODO - close connection | |||||
| public void dispose() | |||||
| { | |||||
| // Clean up the connection | |||||
| super.dispose(); | |||||
| closeConnection(); | |||||
| } | |||||
| /** | |||||
| * Cleans up the connection to the server. | |||||
| */ | |||||
| private void closeConnection() | |||||
| { | |||||
| try | |||||
| { | |||||
| // Clean up | |||||
| if( m_client.isConnected() ) | |||||
| { | |||||
| m_client.disconnect(); | |||||
| } | |||||
| } | |||||
| catch( final IOException e ) | |||||
| { | |||||
| final String message = REZ.getString( "close-connection.error" ); | |||||
| getLogger().warn( message, e ); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -91,6 +107,7 @@ class FtpFileSystem | |||||
| */ | */ | ||||
| public FTPClient getClient() | public FTPClient getClient() | ||||
| { | { | ||||
| // TODO - connect on demand, and garbage collect connections | |||||
| return m_client; | return m_client; | ||||
| } | } | ||||
| @@ -18,7 +18,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| /** | /** | ||||
| * A provider for FTP file systems. | * A provider for FTP file systems. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | * | ||||
| * @ant.type type="file-system" name="ftp" | * @ant.type type="file-system" name="ftp" | ||||
| */ | */ | ||||
| @@ -60,6 +61,6 @@ public class FtpFileSystemProvider extends AbstractFileSystemProvider | |||||
| } | } | ||||
| // Create the file system | // Create the file system | ||||
| return new FtpFileSystem( rootName, ftpUri.getHostName(), username, password ); | |||||
| return new FtpFileSystem( getContext(), rootName, ftpUri.getHostName(), username, password ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| /** | /** | ||||
| * A parsed FTP URI. | * A parsed FTP URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ParsedFtpUri extends ParsedUri | public class ParsedFtpUri extends ParsedUri | ||||
| { | { | ||||
| @@ -6,4 +6,5 @@ finish-put.error=Could not put FTP file "{0}". | |||||
| connect-rejected.error=Connection to FTP server on "{0}" rejected. | connect-rejected.error=Connection to FTP server on "{0}" rejected. | ||||
| login.error=Could not login to FTP server on "{0}" as user "{1}". | login.error=Could not login to FTP server on "{0}" as user "{1}". | ||||
| set-binary.error=Could not switch to binary transfer mode. | set-binary.error=Could not switch to binary transfer mode. | ||||
| connect.error=Could not connect to FTP server on "{0}". | |||||
| connect.error=Could not connect to FTP server on "{0}". | |||||
| close-connection.error=Could not close connection to FTP server. | |||||
| @@ -14,7 +14,7 @@ import org.apache.aut.vfs.FileSystemException; | |||||
| import org.apache.aut.vfs.provider.AbstractFileSystemProvider; | import org.apache.aut.vfs.provider.AbstractFileSystemProvider; | ||||
| import org.apache.aut.vfs.provider.DefaultFileName; | import org.apache.aut.vfs.provider.DefaultFileName; | ||||
| import org.apache.aut.vfs.provider.FileSystem; | import org.apache.aut.vfs.provider.FileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystemProvider; | |||||
| import org.apache.aut.vfs.provider.LocalFileSystemProvider; | |||||
| import org.apache.aut.vfs.provider.ParsedUri; | import org.apache.aut.vfs.provider.ParsedUri; | ||||
| /** | /** | ||||
| @@ -22,13 +22,17 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| * | * | ||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | ||||
| * @version $Revision$ $Date$ | * @version $Revision$ $Date$ | ||||
| * | |||||
| * @ant.type type="file-system" name="file" | |||||
| * | |||||
| */ | */ | ||||
| public class LocalFileSystemProvider extends AbstractFileSystemProvider | |||||
| implements FileSystemProvider | |||||
| public class DefaultLocalFileSystemProvider | |||||
| extends AbstractFileSystemProvider | |||||
| implements LocalFileSystemProvider | |||||
| { | { | ||||
| private final LocalFileNameParser m_parser; | private final LocalFileNameParser m_parser; | ||||
| public LocalFileSystemProvider() | |||||
| public DefaultLocalFileSystemProvider() | |||||
| { | { | ||||
| if( Os.isFamily( Os.OS_FAMILY_WINDOWS ) ) | if( Os.isFamily( Os.OS_FAMILY_WINDOWS ) ) | ||||
| { | { | ||||
| @@ -96,6 +100,6 @@ public class LocalFileSystemProvider extends AbstractFileSystemProvider | |||||
| // Create the file system | // 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 ); | |||||
| return new LocalFileSystem( getContext(), rootName, rootFile ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -14,6 +14,7 @@ import java.io.InputStream; | |||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import org.apache.aut.vfs.FileName; | import org.apache.aut.vfs.FileName; | ||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSelector; | |||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.FileType; | import org.apache.aut.vfs.FileType; | ||||
| import org.apache.aut.vfs.provider.AbstractFileObject; | import org.apache.aut.vfs.provider.AbstractFileObject; | ||||
| @@ -94,7 +95,7 @@ final class LocalFile | |||||
| /** | /** | ||||
| * Deletes this file, and all children. | * Deletes this file, and all children. | ||||
| */ | */ | ||||
| public void doDelete() | |||||
| protected void doDelete() | |||||
| throws Exception | throws Exception | ||||
| { | { | ||||
| if( !m_file.delete() ) | if( !m_file.delete() ) | ||||
| @@ -143,4 +144,13 @@ final class LocalFile | |||||
| { | { | ||||
| return m_file.length(); | return m_file.length(); | ||||
| } | } | ||||
| /** | |||||
| * Creates a temporary local copy of this file, and its descendents. | |||||
| */ | |||||
| protected File doReplicateFile( final FileSelector selector ) | |||||
| throws FileSystemException | |||||
| { | |||||
| return m_file; | |||||
| } | |||||
| } | } | ||||
| @@ -13,6 +13,7 @@ import org.apache.aut.vfs.FileSystemException; | |||||
| import org.apache.aut.vfs.provider.AbstractFileSystem; | import org.apache.aut.vfs.provider.AbstractFileSystem; | ||||
| import org.apache.aut.vfs.provider.DefaultFileName; | import org.apache.aut.vfs.provider.DefaultFileName; | ||||
| import org.apache.aut.vfs.provider.FileSystem; | import org.apache.aut.vfs.provider.FileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystemProviderContext; | |||||
| /** | /** | ||||
| * A local file system. | * A local file system. | ||||
| @@ -24,19 +25,21 @@ class LocalFileSystem extends AbstractFileSystem implements FileSystem | |||||
| { | { | ||||
| private String m_rootFile; | private String m_rootFile; | ||||
| public LocalFileSystem( DefaultFileName rootName, String rootFile ) | |||||
| public LocalFileSystem( final FileSystemProviderContext context, | |||||
| final DefaultFileName rootName, | |||||
| final String rootFile ) | |||||
| { | { | ||||
| super( rootName ); | |||||
| super( context, rootName ); | |||||
| m_rootFile = rootFile; | m_rootFile = rootFile; | ||||
| } | } | ||||
| /** | /** | ||||
| * Creates a file object. | * Creates a file object. | ||||
| */ | */ | ||||
| protected FileObject createFile( FileName name ) throws FileSystemException | |||||
| protected FileObject createFile( final FileName name ) throws FileSystemException | |||||
| { | { | ||||
| // Create the file | // Create the file | ||||
| String fileName = m_rootFile + name.getPath(); | |||||
| final String fileName = m_rootFile + name.getPath(); | |||||
| return new LocalFile( this, fileName, name ); | return new LocalFile( this, fileName, name ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| /** | /** | ||||
| * A parsed SMB URI. | * A parsed SMB URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ParsedSmbUri extends ParsedUri | public class ParsedSmbUri extends ParsedUri | ||||
| { | { | ||||
| @@ -16,7 +16,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | /** | ||||
| * A parser for SMB URI. | * A parser for SMB URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class SmbFileNameParser | public class SmbFileNameParser | ||||
| extends UriParser | extends UriParser | ||||
| @@ -23,7 +23,8 @@ import org.apache.avalon.excalibur.i18n.Resources; | |||||
| /** | /** | ||||
| * A file in an SMB file system. | * A file in an SMB file system. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class SmbFileObject | public class SmbFileObject | ||||
| extends AbstractFileObject | extends AbstractFileObject | ||||
| @@ -12,25 +12,28 @@ import org.apache.aut.vfs.FileObject; | |||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.provider.AbstractFileSystem; | import org.apache.aut.vfs.provider.AbstractFileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystem; | import org.apache.aut.vfs.provider.FileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystemProviderContext; | |||||
| /** | /** | ||||
| * A SMB file system. | * A SMB file system. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class SmbFileSystem extends AbstractFileSystem implements FileSystem | public class SmbFileSystem extends AbstractFileSystem implements FileSystem | ||||
| { | { | ||||
| public SmbFileSystem( FileName rootName ) | |||||
| public SmbFileSystem( final FileSystemProviderContext context, | |||||
| final FileName rootName ) | |||||
| { | { | ||||
| super( rootName ); | |||||
| super( context, rootName ); | |||||
| } | } | ||||
| /** | /** | ||||
| * Creates a file object. | * Creates a file object. | ||||
| */ | */ | ||||
| protected FileObject createFile( FileName name ) throws FileSystemException | |||||
| protected FileObject createFile( final FileName name ) throws FileSystemException | |||||
| { | { | ||||
| String fileName = name.getURI(); | |||||
| final String fileName = name.getURI(); | |||||
| return new SmbFileObject( fileName, name, this ); | return new SmbFileObject( fileName, name, this ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -19,7 +19,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| /** | /** | ||||
| * A provider for SMB (Samba, Windows share) file systems. | * A provider for SMB (Samba, Windows share) file systems. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | * | ||||
| * @ant.type type="file-system" name="smb" | * @ant.type type="file-system" name="smb" | ||||
| */ | */ | ||||
| @@ -45,6 +46,6 @@ public class SmbFileSystemProvider extends AbstractFileSystemProvider implements | |||||
| { | { | ||||
| final ParsedSmbUri smbUri = (ParsedSmbUri)uri; | final ParsedSmbUri smbUri = (ParsedSmbUri)uri; | ||||
| final FileName rootName = new DefaultFileName( m_parser, smbUri.getRootUri(), "/" ); | final FileName rootName = new DefaultFileName( m_parser, smbUri.getRootUri(), "/" ); | ||||
| return new SmbFileSystem( rootName ); | |||||
| return new SmbFileSystem( getContext(), rootName ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -13,7 +13,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| /** | /** | ||||
| * A parsed Zip URI. | * A parsed Zip URI. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ParsedZipUri extends ParsedUri | public class ParsedZipUri extends ParsedUri | ||||
| { | { | ||||
| @@ -1 +1,2 @@ | |||||
| open-zip-file.error=Could not open Zip file "{0}". | open-zip-file.error=Could not open Zip file "{0}". | ||||
| close-zip-file.error=Could not close Zip file "{0}". | |||||
| @@ -13,12 +13,13 @@ import org.apache.aut.vfs.provider.UriParser; | |||||
| /** | /** | ||||
| * A parser for Zip file names. | * A parser for Zip file names. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ZipFileNameParser | public class ZipFileNameParser | ||||
| extends UriParser | extends UriParser | ||||
| { | { | ||||
| private static final char[] ZIP_URL_RESERVED_CHARS = { '!' }; | |||||
| private static final char[] ZIP_URL_RESERVED_CHARS = {'!'}; | |||||
| /** | /** | ||||
| * Parses an absolute URI, splitting it into its components. | * Parses an absolute URI, splitting it into its components. | ||||
| @@ -19,7 +19,8 @@ import org.apache.aut.vfs.provider.AbstractFileObject; | |||||
| /** | /** | ||||
| * A file in a Zip file system. | * A file in a Zip file system. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| class ZipFileObject extends AbstractFileObject implements FileObject | class ZipFileObject extends AbstractFileObject implements FileObject | ||||
| { | { | ||||
| @@ -18,15 +18,19 @@ import org.apache.aut.vfs.FileSystemException; | |||||
| import org.apache.aut.vfs.provider.AbstractFileSystem; | import org.apache.aut.vfs.provider.AbstractFileSystem; | ||||
| import org.apache.aut.vfs.provider.DefaultFileName; | import org.apache.aut.vfs.provider.DefaultFileName; | ||||
| import org.apache.aut.vfs.provider.FileSystem; | import org.apache.aut.vfs.provider.FileSystem; | ||||
| import org.apache.aut.vfs.provider.FileSystemProviderContext; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| /** | /** | ||||
| * A read-only file system for Zip/Jar files. | * A read-only file system for Zip/Jar files. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | */ | ||||
| public class ZipFileSystem extends AbstractFileSystem implements FileSystem | |||||
| public class ZipFileSystem | |||||
| extends AbstractFileSystem | |||||
| implements FileSystem | |||||
| { | { | ||||
| private static final Resources REZ = | private static final Resources REZ = | ||||
| ResourceManager.getPackageResources( ZipFileSystem.class ); | ResourceManager.getPackageResources( ZipFileSystem.class ); | ||||
| @@ -34,9 +38,11 @@ public class ZipFileSystem extends AbstractFileSystem implements FileSystem | |||||
| private File m_file; | private File m_file; | ||||
| private ZipFile m_zipFile; | private ZipFile m_zipFile; | ||||
| public ZipFileSystem( DefaultFileName rootName, File file ) throws FileSystemException | |||||
| public ZipFileSystem( final FileSystemProviderContext context, | |||||
| final DefaultFileName rootName, | |||||
| final File file ) throws FileSystemException | |||||
| { | { | ||||
| super( rootName ); | |||||
| super( context, rootName ); | |||||
| m_file = file; | m_file = file; | ||||
| // Open the Zip file | // Open the Zip file | ||||
| @@ -101,6 +107,22 @@ public class ZipFileSystem extends AbstractFileSystem implements FileSystem | |||||
| } | } | ||||
| } | } | ||||
| public void dispose() | |||||
| { | |||||
| super.dispose(); | |||||
| // Release the zip file | |||||
| try | |||||
| { | |||||
| m_zipFile.close(); | |||||
| } | |||||
| catch( final IOException e ) | |||||
| { | |||||
| final String message = REZ.getString( "close-zip-file.error", m_file ); | |||||
| getLogger().warn( message, e ); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Creates a file object. | * Creates a file object. | ||||
| */ | */ | ||||
| @@ -8,7 +8,7 @@ | |||||
| package org.apache.aut.vfs.provider.zip; | package org.apache.aut.vfs.provider.zip; | ||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.IOException; | |||||
| import org.apache.aut.vfs.FileConstants; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.provider.AbstractFileSystemProvider; | import org.apache.aut.vfs.provider.AbstractFileSystemProvider; | ||||
| @@ -21,7 +21,8 @@ import org.apache.aut.vfs.provider.ParsedUri; | |||||
| * A file system provider for Zip/Jar files. Provides read-only file | * A file system provider for Zip/Jar files. Provides read-only file | ||||
| * systems, for local Zip files only. | * systems, for local Zip files only. | ||||
| * | * | ||||
| * @author Adam Murdoch | |||||
| * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a> | |||||
| * @version $Revision$ $Date$ | |||||
| * | * | ||||
| * @ant.type type="file-system" name="zip" | * @ant.type type="file-system" name="zip" | ||||
| */ | */ | ||||
| @@ -80,25 +81,12 @@ public class ZipFileSystemProvider | |||||
| final ParsedZipUri zipUri = (ParsedZipUri)uri; | final ParsedZipUri zipUri = (ParsedZipUri)uri; | ||||
| final FileObject file = zipUri.getZipFile(); | 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 ); | |||||
| // Make a local copy of the file | |||||
| final File zipFile = file.replicateFile( FileConstants.SELECT_SELF ); | |||||
| // Create the file system | // Create the file system | ||||
| DefaultFileName name = new DefaultFileName( m_parser, zipUri.getRootUri(), "/" ); | DefaultFileName name = new DefaultFileName( m_parser, zipUri.getRootUri(), "/" ); | ||||
| return new ZipFileSystem( name, destFile ); | |||||
| return new ZipFileSystem( getContext(), name, zipFile ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -12,7 +12,6 @@ import org.apache.aut.vfs.impl.DefaultFileSystemManager; | |||||
| import org.apache.aut.vfs.provider.FileSystemProvider; | import org.apache.aut.vfs.provider.FileSystemProvider; | ||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.avalon.framework.activity.Disposable; | |||||
| import org.apache.avalon.framework.activity.Initializable; | import org.apache.avalon.framework.activity.Initializable; | ||||
| import org.apache.avalon.framework.service.ServiceException; | import org.apache.avalon.framework.service.ServiceException; | ||||
| import org.apache.avalon.framework.service.ServiceManager; | import org.apache.avalon.framework.service.ServiceManager; | ||||
| @@ -28,7 +27,7 @@ import org.apache.myrmidon.interfaces.type.TypeManager; | |||||
| */ | */ | ||||
| public class VfsManager | public class VfsManager | ||||
| extends DefaultFileSystemManager | extends DefaultFileSystemManager | ||||
| implements Serviceable, Initializable, Disposable | |||||
| implements Serviceable, Initializable | |||||
| { | { | ||||
| private static final Resources REZ | private static final Resources REZ | ||||
| = ResourceManager.getPackageResources( VfsManager.class ); | = ResourceManager.getPackageResources( VfsManager.class ); | ||||
| @@ -53,6 +52,7 @@ public class VfsManager | |||||
| // TODO - make this list configurable | // TODO - make this list configurable | ||||
| // Required providers | // Required providers | ||||
| addProvider( factory, new String[]{"file"}, "file", false ); | |||||
| addProvider( factory, new String[]{"zip", "jar"}, "zip", false ); | addProvider( factory, new String[]{"zip", "jar"}, "zip", false ); | ||||
| // Optional providers | // Optional providers | ||||
| @@ -60,15 +60,6 @@ public class VfsManager | |||||
| addProvider( factory, new String[]{"ftp"}, "ftp", true ); | addProvider( factory, new String[]{"ftp"}, "ftp", true ); | ||||
| } | } | ||||
| /** | |||||
| * Disposes this service. | |||||
| */ | |||||
| public void dispose() | |||||
| { | |||||
| // Clean-up | |||||
| close(); | |||||
| } | |||||
| /** | /** | ||||
| * Registers a file system provider. | * Registers a file system provider. | ||||
| */ | */ | ||||
| @@ -16,6 +16,8 @@ import java.util.List; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import org.apache.aut.vfs.impl.DefaultFileSystemManager; | import org.apache.aut.vfs.impl.DefaultFileSystemManager; | ||||
| import org.apache.aut.vfs.provider.AbstractFileObject; | import org.apache.aut.vfs.provider.AbstractFileObject; | ||||
| import org.apache.aut.vfs.provider.LocalFileSystemProvider; | |||||
| import org.apache.aut.vfs.provider.local.DefaultLocalFileSystemProvider; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileType; | import org.apache.aut.vfs.FileType; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| @@ -59,15 +61,15 @@ public abstract class AbstractFileSystemTestCase | |||||
| { | { | ||||
| // Build the expected structure | // Build the expected structure | ||||
| final FileInfo base = new FileInfo( "test", FileType.FOLDER ); | final FileInfo base = new FileInfo( "test", FileType.FOLDER ); | ||||
| base.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||||
| base.addChild( new FileInfo( "empty.txt", FileType.FILE ) ); | |||||
| base.addChild( new FileInfo( "emptydir", FileType.FOLDER ) ); | |||||
| base.addChild( "file1.txt", FileType.FILE ); | |||||
| base.addChild( "empty.txt", FileType.FILE ); | |||||
| base.addChild( "emptydir", FileType.FOLDER ); | |||||
| final FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | final FileInfo dir = new FileInfo( "dir1", FileType.FOLDER ); | ||||
| base.addChild( dir ); | base.addChild( dir ); | ||||
| dir.addChild( new FileInfo( "file1.txt", FileType.FILE ) ); | |||||
| dir.addChild( new FileInfo( "file2.txt", FileType.FILE ) ); | |||||
| dir.addChild( new FileInfo( "file3.txt", FileType.FILE ) ); | |||||
| dir.addChild( "file1.txt", FileType.FILE ); | |||||
| dir.addChild( "file2.txt", FileType.FILE ); | |||||
| dir.addChild( "file3.txt", FileType.FILE ); | |||||
| return base; | return base; | ||||
| } | } | ||||
| @@ -83,6 +85,8 @@ public abstract class AbstractFileSystemTestCase | |||||
| { | { | ||||
| // Create the file system manager | // Create the file system manager | ||||
| m_manager = new DefaultFileSystemManager(); | m_manager = new DefaultFileSystemManager(); | ||||
| m_manager.enableLogging( getLogger() ); | |||||
| m_manager.addProvider( "file", new DefaultLocalFileSystemProvider() ); | |||||
| // Locate the base folder | // Locate the base folder | ||||
| m_baseFolder = getBaseFolder(); | m_baseFolder = getBaseFolder(); | ||||
| @@ -100,7 +104,7 @@ public abstract class AbstractFileSystemTestCase | |||||
| */ | */ | ||||
| protected void tearDown() throws Exception | protected void tearDown() throws Exception | ||||
| { | { | ||||
| m_manager.close(); | |||||
| m_manager.dispose(); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -465,6 +469,70 @@ public abstract class AbstractFileSystemTestCase | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Tests conversion from absolute to relative names. | |||||
| */ | |||||
| public void testAbsoluteNameConvert() throws Exception | |||||
| { | |||||
| final FileName baseName = m_baseFolder.getName(); | |||||
| String path = "/test1/test2"; | |||||
| FileName name = baseName.resolveName( path ); | |||||
| assertEquals( path, name.getPath() ); | |||||
| // Try child and descendent names | |||||
| testRelName( name, "child" ); | |||||
| testRelName( name, "child1/child2" ); | |||||
| // Try own name | |||||
| testRelName( name, "." ); | |||||
| // Try parent, and root | |||||
| testRelName( name, ".." ); | |||||
| testRelName( name, "../.." ); | |||||
| // Try sibling and descendent of sibling | |||||
| testRelName( name, "../sibling" ); | |||||
| testRelName( name, "../sibling/child" ); | |||||
| // Try siblings with similar names | |||||
| testRelName( name, "../test2_not" ); | |||||
| testRelName( name, "../test2_not/child" ); | |||||
| testRelName( name, "../test" ); | |||||
| testRelName( name, "../test/child" ); | |||||
| // Try unrelated | |||||
| testRelName( name, "../../unrelated" ); | |||||
| testRelName( name, "../../test" ); | |||||
| testRelName( name, "../../test/child" ); | |||||
| // Test against root | |||||
| path = "/"; | |||||
| name = baseName.resolveName( path ); | |||||
| assertEquals( path, name.getPath() ); | |||||
| // Try child and descendent names (against root) | |||||
| testRelName( name, "child" ); | |||||
| testRelName( name, "child1/child2" ); | |||||
| // Try own name (against root) | |||||
| testRelName( name, "." ); | |||||
| } | |||||
| /** | |||||
| * Checks that a file name converts to an expected relative path | |||||
| */ | |||||
| private void testRelName( final FileName baseName, | |||||
| final String relPath ) | |||||
| throws Exception | |||||
| { | |||||
| final FileName expectedName = baseName.resolveName( relPath ); | |||||
| // Convert to relative path, and check | |||||
| final String actualRelPath = baseName.getRelativeName( expectedName ); | |||||
| assertEquals( relPath, actualRelPath ); | |||||
| } | |||||
| /** | /** | ||||
| * Walks the base folder structure, asserting it contains exactly the | * Walks the base folder structure, asserting it contains exactly the | ||||
| * expected files and folders. | * expected files and folders. | ||||
| @@ -496,9 +564,9 @@ public abstract class AbstractFileSystemTestCase | |||||
| final FileInfo info = (FileInfo)queueExpected.remove( 0 ); | final FileInfo info = (FileInfo)queueExpected.remove( 0 ); | ||||
| // Check the type is correct | // Check the type is correct | ||||
| assertSame( file.getType(), info._type ); | |||||
| assertSame( file.getType(), info.m_type ); | |||||
| if( info._type == FileType.FILE ) | |||||
| if( info.m_type == FileType.FILE ) | |||||
| { | { | ||||
| continue; | continue; | ||||
| } | } | ||||
| @@ -508,13 +576,13 @@ public abstract class AbstractFileSystemTestCase | |||||
| // Make sure all children were found | // Make sure all children were found | ||||
| assertNotNull( children ); | assertNotNull( children ); | ||||
| assertEquals( "count children of \"" + file.getName() + "\"", info._children.size(), children.length ); | |||||
| assertEquals( "count children of \"" + file.getName() + "\"", info.m_children.size(), children.length ); | |||||
| // Recursively check each child | // Recursively check each child | ||||
| for( int i = 0; i < children.length; i++ ) | for( int i = 0; i < children.length; i++ ) | ||||
| { | { | ||||
| final FileObject child = children[ i ]; | final FileObject child = children[ i ]; | ||||
| final FileInfo childInfo = (FileInfo)info._children.get( child.getName().getBaseName() ); | |||||
| final FileInfo childInfo = (FileInfo)info.m_children.get( child.getName().getBaseName() ); | |||||
| // Make sure the child is expected | // Make sure the child is expected | ||||
| assertNotNull( childInfo ); | assertNotNull( childInfo ); | ||||
| @@ -776,20 +844,36 @@ public abstract class AbstractFileSystemTestCase | |||||
| */ | */ | ||||
| protected static final class FileInfo | protected static final class FileInfo | ||||
| { | { | ||||
| String _baseName; | |||||
| FileType _type; | |||||
| Map _children = new HashMap(); | |||||
| String m_baseName; | |||||
| FileType m_type; | |||||
| Map m_children = new HashMap(); | |||||
| public FileInfo( final String name, final FileType type ) | |||||
| { | |||||
| m_baseName = name; | |||||
| m_type = type; | |||||
| } | |||||
| public FileInfo( String name, FileType type ) | |||||
| /** Adds a child. */ | |||||
| public void addChild( final FileInfo child ) | |||||
| { | { | ||||
| _baseName = name; | |||||
| _type = type; | |||||
| m_children.put( child.m_baseName, child ); | |||||
| } | } | ||||
| /** Adds a child. */ | /** Adds a child. */ | ||||
| public void addChild( FileInfo child ) | |||||
| public void addChild( final String baseName, final FileType type ) | |||||
| { | |||||
| addChild( new FileInfo( baseName, type ) ); | |||||
| } | |||||
| /** Adds a bunch of children. */ | |||||
| public void addChildren( final String[] baseNames, final FileType type ) | |||||
| { | { | ||||
| _children.put( child._baseName, child ); | |||||
| for( int i = 0; i < baseNames.length; i++ ) | |||||
| { | |||||
| String baseName = baseNames[i ]; | |||||
| addChild( new FileInfo( baseName, type ) ); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -14,6 +14,7 @@ import org.apache.aut.vfs.test.AbstractFileSystemTestCase; | |||||
| import org.apache.aut.vfs.FileObject; | import org.apache.aut.vfs.FileObject; | ||||
| import org.apache.aut.vfs.FileType; | import org.apache.aut.vfs.FileType; | ||||
| import org.apache.aut.vfs.FileSystemException; | import org.apache.aut.vfs.FileSystemException; | ||||
| import org.apache.aut.vfs.FileConstants; | |||||
| /** | /** | ||||
| * File system test that check that a file system can be modified. | * File system test that check that a file system can be modified. | ||||
| @@ -41,7 +42,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| FileObject scratchFolder = getWriteFolder(); | FileObject scratchFolder = getWriteFolder(); | ||||
| // Make sure the test folder is empty | // Make sure the test folder is empty | ||||
| scratchFolder.delete(); | |||||
| scratchFolder.delete( FileConstants.EXCLUDE_SELF ); | |||||
| scratchFolder.create( FileType.FOLDER ); | scratchFolder.create( FileType.FOLDER ); | ||||
| return scratchFolder; | return scratchFolder; | ||||
| @@ -59,6 +60,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| assertTrue( !folder.exists() ); | assertTrue( !folder.exists() ); | ||||
| folder.create( FileType.FOLDER ); | folder.create( FileType.FOLDER ); | ||||
| assertTrue( folder.exists() ); | assertTrue( folder.exists() ); | ||||
| assertSame( FileType.FOLDER, folder.getType() ); | |||||
| assertEquals( 0, folder.getChildren().length ); | assertEquals( 0, folder.getChildren().length ); | ||||
| // Create a descendant, where the intermediate folders don't exist | // Create a descendant, where the intermediate folders don't exist | ||||
| @@ -68,11 +70,13 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| assertTrue( !folder.getParent().getParent().exists() ); | assertTrue( !folder.getParent().getParent().exists() ); | ||||
| folder.create( FileType.FOLDER ); | folder.create( FileType.FOLDER ); | ||||
| assertTrue( folder.exists() ); | assertTrue( folder.exists() ); | ||||
| assertSame( FileType.FOLDER, folder.getType() ); | |||||
| assertEquals( 0, folder.getChildren().length ); | assertEquals( 0, folder.getChildren().length ); | ||||
| assertTrue( folder.getParent().exists() ); | assertTrue( folder.getParent().exists() ); | ||||
| assertTrue( folder.getParent().getParent().exists() ); | assertTrue( folder.getParent().getParent().exists() ); | ||||
| // Test creating a folder that already exists | // Test creating a folder that already exists | ||||
| assertTrue( folder.exists() ); | |||||
| folder.create( FileType.FOLDER ); | folder.create( FileType.FOLDER ); | ||||
| } | } | ||||
| @@ -88,6 +92,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| file.create( FileType.FILE ); | file.create( FileType.FILE ); | ||||
| assertTrue( file.exists() ); | assertTrue( file.exists() ); | ||||
| assertSame( FileType.FILE, file.getType() ); | |||||
| assertEquals( 0, file.getContent().getSize() ); | assertEquals( 0, file.getContent().getSize() ); | ||||
| // Create a descendant, where the intermediate folders don't exist | // Create a descendant, where the intermediate folders don't exist | ||||
| @@ -97,11 +102,13 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| assertTrue( !file.getParent().getParent().exists() ); | assertTrue( !file.getParent().getParent().exists() ); | ||||
| file.create( FileType.FILE ); | file.create( FileType.FILE ); | ||||
| assertTrue( file.exists() ); | assertTrue( file.exists() ); | ||||
| assertSame( FileType.FILE, file.getType() ); | |||||
| assertEquals( 0, file.getContent().getSize() ); | assertEquals( 0, file.getContent().getSize() ); | ||||
| assertTrue( file.getParent().exists() ); | assertTrue( file.getParent().exists() ); | ||||
| assertTrue( file.getParent().getParent().exists() ); | assertTrue( file.getParent().getParent().exists() ); | ||||
| // Test creating a file that already exists | // Test creating a file that already exists | ||||
| assertTrue( file.exists() ); | |||||
| file.create( FileType.FILE ); | file.create( FileType.FILE ); | ||||
| } | } | ||||
| @@ -125,7 +132,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| try | try | ||||
| { | { | ||||
| folder.create( FileType.FILE ); | folder.create( FileType.FILE ); | ||||
| assertTrue( false ); | |||||
| fail(); | |||||
| } | } | ||||
| catch( FileSystemException exc ) | catch( FileSystemException exc ) | ||||
| { | { | ||||
| @@ -135,7 +142,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| try | try | ||||
| { | { | ||||
| file.create( FileType.FOLDER ); | file.create( FileType.FOLDER ); | ||||
| assertTrue( false ); | |||||
| fail(); | |||||
| } | } | ||||
| catch( FileSystemException exc ) | catch( FileSystemException exc ) | ||||
| { | { | ||||
| @@ -146,7 +153,7 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| try | try | ||||
| { | { | ||||
| folder2.create( FileType.FOLDER ); | folder2.create( FileType.FOLDER ); | ||||
| assertTrue( false ); | |||||
| fail(); | |||||
| } | } | ||||
| catch( FileSystemException exc ) | catch( FileSystemException exc ) | ||||
| { | { | ||||
| @@ -168,13 +175,13 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| // Delete a file | // Delete a file | ||||
| FileObject file = folder.resolveFile( "file1.txt" ); | FileObject file = folder.resolveFile( "file1.txt" ); | ||||
| assertTrue( file.exists() ); | assertTrue( file.exists() ); | ||||
| file.delete(); | |||||
| file.delete( FileConstants.SELECT_ALL ); | |||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| // Delete an empty folder | // Delete an empty folder | ||||
| file = folder.resolveFile( "emptydir" ); | file = folder.resolveFile( "emptydir" ); | ||||
| assertTrue( file.exists() ); | assertTrue( file.exists() ); | ||||
| file.delete(); | |||||
| file.delete( FileConstants.SELECT_ALL ); | |||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| // Recursive delete | // Recursive delete | ||||
| @@ -182,14 +189,14 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| FileObject file2 = file.resolveFile( "dir2/file2.txt" ); | FileObject file2 = file.resolveFile( "dir2/file2.txt" ); | ||||
| assertTrue( file.exists() ); | assertTrue( file.exists() ); | ||||
| assertTrue( file2.exists() ); | assertTrue( file2.exists() ); | ||||
| file.delete(); | |||||
| file.delete( FileConstants.SELECT_ALL ); | |||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| assertTrue( !file2.exists() ); | assertTrue( !file2.exists() ); | ||||
| // Delete a file that does not exist | // Delete a file that does not exist | ||||
| file = folder.resolveFile( "some-folder/some-file" ); | file = folder.resolveFile( "some-folder/some-file" ); | ||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| file.delete(); | |||||
| file.delete( FileConstants.SELECT_ALL ); | |||||
| assertTrue( !file.exists() ); | assertTrue( !file.exists() ); | ||||
| } | } | ||||
| @@ -226,17 +233,17 @@ public abstract class AbstractWritableFileSystemTestCase | |||||
| assertSameFileSet( names, folder.getChildren() ); | assertSameFileSet( names, folder.getChildren() ); | ||||
| // Delete a child folder | // Delete a child folder | ||||
| folder.resolveFile( "dir1" ).delete(); | |||||
| folder.resolveFile( "dir1" ).delete( FileConstants.SELECT_ALL ); | |||||
| names.remove( "dir1" ); | names.remove( "dir1" ); | ||||
| assertSameFileSet( names, folder.getChildren() ); | assertSameFileSet( names, folder.getChildren() ); | ||||
| // Delete a child file | // Delete a child file | ||||
| folder.resolveFile( "file1.html" ).delete(); | |||||
| folder.resolveFile( "file1.html" ).delete( FileConstants.SELECT_ALL ); | |||||
| names.remove( "file1.html" ); | names.remove( "file1.html" ); | ||||
| assertSameFileSet( names, folder.getChildren() ); | assertSameFileSet( names, folder.getChildren() ); | ||||
| // Recreate the folder | // Recreate the folder | ||||
| folder.delete(); | |||||
| folder.delete( FileConstants.SELECT_ALL ); | |||||
| folder.create( FileType.FOLDER ); | folder.create( FileType.FOLDER ); | ||||
| assertEquals( 0, folder.getChildren().length ); | assertEquals( 0, folder.getChildren().length ); | ||||
| } | } | ||||
| @@ -174,12 +174,6 @@ public abstract class AbstractMyrmidonTest | |||||
| */ | */ | ||||
| protected void assertSameMessage( final String[] messages, final Throwable throwable ) | protected void assertSameMessage( final String[] messages, final Throwable throwable ) | ||||
| { | { | ||||
| //System.out.println( "exception:" ); | |||||
| //for( Throwable t = throwable; t != null; t = ExceptionUtil.getCause( t, true ) ) | |||||
| //{ | |||||
| // System.out.println( " " + t.getMessage() ); | |||||
| //} | |||||
| Throwable current = throwable; | Throwable current = throwable; | ||||
| for( int i = 0; i < messages.length; i++ ) | for( int i = 0; i < messages.length; i++ ) | ||||
| { | { | ||||
| @@ -10,6 +10,7 @@ package org.apache.myrmidon; | |||||
| import java.io.File; | import java.io.File; | ||||
| import org.apache.myrmidon.frontends.EmbeddedAnt; | import org.apache.myrmidon.frontends.EmbeddedAnt; | ||||
| import org.apache.myrmidon.listeners.ProjectListener; | import org.apache.myrmidon.listeners.ProjectListener; | ||||
| import org.apache.avalon.framework.ExceptionUtil; | |||||
| /** | /** | ||||
| * A base class for test cases which need to execute projects. | * A base class for test cases which need to execute projects. | ||||
| @@ -72,28 +73,35 @@ public class AbstractProjectTest | |||||
| final ProjectListener listener ) | final ProjectListener listener ) | ||||
| throws Exception | throws Exception | ||||
| { | { | ||||
| // Create the project and workspace | |||||
| final EmbeddedAnt embeddor = new EmbeddedAnt(); | final EmbeddedAnt embeddor = new EmbeddedAnt(); | ||||
| embeddor.setHomeDirectory( getInstallDirectory() ); | |||||
| embeddor.enableLogging( getLogger() ); | |||||
| embeddor.setSharedClassLoader( getClass().getClassLoader() ); | |||||
| embeddor.setProjectFile( projectFile.getAbsolutePath() ); | |||||
| embeddor.setProjectListener( null ); | |||||
| // Add a listener to make sure all is good | |||||
| final TrackingProjectListener tracker = new TrackingProjectListener(); | final TrackingProjectListener tracker = new TrackingProjectListener(); | ||||
| embeddor.addProjectListener( tracker ); | |||||
| // Add supplied listener | |||||
| if( listener != null ) | |||||
| try | |||||
| { | { | ||||
| embeddor.addProjectListener( listener ); | |||||
| } | |||||
| // Configure embeddor | |||||
| embeddor.setHomeDirectory( getInstallDirectory() ); | |||||
| embeddor.enableLogging( getLogger() ); | |||||
| embeddor.setSharedClassLoader( getClass().getClassLoader() ); | |||||
| embeddor.setProjectFile( projectFile.getAbsolutePath() ); | |||||
| embeddor.setProjectListener( null ); | |||||
| // Add a listener to make sure all is good | |||||
| embeddor.addProjectListener( tracker ); | |||||
| // Now execute the target | |||||
| embeddor.executeTargets( new String[] { targetName } ); | |||||
| // Add supplied listener | |||||
| if( listener != null ) | |||||
| { | |||||
| embeddor.addProjectListener( listener ); | |||||
| } | |||||
| // Now execute the target | |||||
| embeddor.executeTargets( new String[] { targetName } ); | |||||
| } | |||||
| finally | |||||
| { | |||||
| embeddor.stop(); | |||||
| } | |||||
| embeddor.stop(); | |||||
| // Make sure all expected events were delivered | // Make sure all expected events were delivered | ||||
| tracker.assertComplete(); | tracker.assertComplete(); | ||||
| @@ -335,7 +335,7 @@ public class DefaultClassLoaderManagerTestCase | |||||
| * add some classes to common loader only. | * add some classes to common loader only. | ||||
| * | * | ||||
| * unknown extension | * unknown extension | ||||
| * multiple versions of extensions | |||||
| * multiple versions of the same extension | |||||
| * extn with requirement on itself | * extn with requirement on itself | ||||
| * | * | ||||
| * jar with 1 and 2 extns: | * jar with 1 and 2 extns: | ||||