/*
* Copyright 2005 by Oracle USA
* 500 Oracle Parkway, Redwood Shores, California, 94065, U.S.A.
* All rights reserved.
*/
package javax.ide.net;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import javax.ide.spi.ProviderNotFoundException;
import javax.ide.Service;
/**
* The VirtualFileSystem
class is responsible for encapsulating
* the notion of file system operations on content that is pointed to by
* an {@link URI}.
*
* The behavior of VirtualFileSystem
can be extended by
* subclasses of {@link VirtualFileSystemHelper}. An instance of
* VirtualFileSystemHelper
is registered with
* VirtualFileSystem
in association with a particular
* scheme. Scheme-specific behavior can thus be encapsulated by a
* specific implementation of VirtualFileSystemHelper
.
*
* IDE implementations do not need to register an implementation of this
* service. The default registered implementation delegates most of its
* operations to registered VirtualFileSystemHelpers.
*/
public class VirtualFileSystem extends Service
{
private static final int COPY_BUFFER_SIZE = 4096;
/**
* The "file" URI scheme.
*/
public static final String FILE_SCHEME = "file"; // NOTRANS
/**
* The "http" URI scheme.
*/
public static final String HTTP_SCHEME = "http"; // NOTRANS
/**
* The "jar" URI scheme.
*/
public static final String JAR_SCHEME = "jar"; // NOTRANS
private static final boolean _isCaseSensitive;
private final HashMap _helpers = new HashMap();
private final VirtualFileSystemHelper _defaultHelper =
new VirtualFileSystemHelper();
private final ArrayList _existsTests = new ArrayList( 3 );
static
{
// Determine whether the local file system is case-sensitive or not.
// This will affect how URIs are sorted in the UI.
final File f1 = new File( "A" );
final File f2 = new File( "a" );
_isCaseSensitive = !f1.equals( f2 );
}
//--------------------------------------------------------------------------
// extension API...
//--------------------------------------------------------------------------
/**
* Registers the specified {@link VirtualFileSystemHelper} as the object
* that can handle {@link VirtualFileSystem} operations for {@link URI}s
* of the specified scheme
.
*
* @param scheme the URI scheme to register a helper for. Must not be null
* or an empty String.
* @param helper the helper to register for the specified scheme. Must not
* be null.
*/
public void registerHelper( String scheme, VirtualFileSystemHelper helper )
{
if ( scheme == null )
{
throw new NullPointerException( "scheme must not be null" );
}
// Trim whitespace from the scheme name because it is not significant.
scheme = scheme.trim();
if ( scheme.length() == 0 )
{
throw new IllegalArgumentException( "cannot use empty string for scheme" );
}
if ( helper == null )
{
throw new NullPointerException( "helper must not be null" );
}
_helpers.put( scheme, helper );
}
/**
* Returns the {@link VirtualFileSystemHelper} class that is currently
* registered to handle operations related to the specified
* scheme
. If there is no registered helper, then a
* default helper is returned that can produce a default result.
*
* @param scheme the scheme to look up the helper for. Must not be null.
* @return the registered file system helper for the specified scheme, or
* a default helper if no helper is registered.
*/
public VirtualFileSystemHelper findHelper( String scheme )
{
if ( scheme == null )
{
throw new NullPointerException( "scheme must not be null" );
}
Object helper = _helpers.get( scheme );
return helper != null ? (VirtualFileSystemHelper) helper : _defaultHelper;
}
/**
* Returns the {@link VirtualFileSystemHelper} class that is currently
* registered to handle operations related to the specified
* {@link URI}. If there is no registered helper, then a default
* helper is returned that can produce a default result.
*
* @param uri a uri to find the helper for. May be null, in which case
* the default helper is returned.
* @return the helper for the scheme of the specified uri, or the
* default helper if the uri is null or no helper is registered for the
* scheme of the uri.
*/
public VirtualFileSystemHelper findHelper( URI uri )
{
if ( uri == null )
{
return _defaultHelper;
}
final String scheme = uri.getScheme();
return findHelper( scheme );
}
/**
* Add an implementation of the {@link URIExistsTest} interface.
* The existsTest
object will be called by the
* isBound()
method to determine if an {@link URI} is unique.
*
* @param existsTest the implementation of an existence test for uris. Must
* not be null.
*/
public void addExistsTest( URIExistsTest existsTest )
{
if ( existsTest == null )
{
throw new NullPointerException( "existsTest must not be null" );
}
_existsTests.add( existsTest );
}
//--------------------------------------------------------------------------
// VirtualFileSystem operations...
//--------------------------------------------------------------------------
/**
* Returns a canonical form of the {@link URI}, if one is available.
*
* @param uri the uri to canonicalize.
* @return a canonicalized form of the specified uri.
* @throws java.io.IOException if the uri could not be canonicalized.
* @see VirtualFileSystemHelper#canonicalize( URI )
*/
public URI canonicalize( URI uri ) throws IOException
{
return findHelper( uri ).canonicalize( uri );
}
/**
* Tests whether the application can read the resource at the
* specified {@link URI}.
*
* @param uri the uri to check.
* @return true
if and only if the specified
* {@link URI} points to a resource that exists and can be
* read by the application; false
otherwise.
* @see VirtualFileSystemHelper#canRead( URI )
*/
public boolean canRead( URI uri )
{
return findHelper( uri ).canRead( uri );
}
/**
* Tests whether the application can modify the resource at the
* specified {@link URI}.
*
* @param uri the uri to check.
* @return true
if and only if the specified
* {@link URI} points to a file that exists and the
* application is allowed to write to the file; false
* otherwise.
* @see VirtualFileSystemHelper#canWrite( URI )
*/
public boolean canWrite( URI uri )
{
return findHelper( uri ).canWrite( uri );
}
/**
* Tests whether the application can create the resource at the specified
* {@link URI}. This method tests that all components of the path can
* be created. If the resource pointed by the {@link URI} is read-only,
* this method returns false
.
*
* @param uri the uri to check.
* @return true
if the resource at the specified {@link URI}
* exists or can be created; false
otherwise.
* @see VirtualFileSystemHelper#canCreate( java.net.URI )
*/
public boolean canCreate( URI uri )
{
return findHelper( uri ).canCreate( uri );
}
/**
* Tests whether the specified {@link URI} is valid. If the resource
* pointed by the {@link URI} exists the method returns true
.
* If the resource does not exist, the method tests that all components
* of the path can be created.
*
* @param uri the uri to check.
* @return true
if the {@link URI} is valid.
* @see VirtualFileSystemHelper#isValid( java.net.URI )
*/
public boolean isValid( URI uri )
{
return findHelper( uri ).isValid( uri );
}
/**
* Takes the given {@link URI} and checks if its {@link #toString()}
* representation ends with the specified oldSuffix
. If
* it does, the suffix is replaced with newSuffix
. Both
* suffix parameters must include the leading dot ('.') if the dot is
* part of the suffix. If the specified {@link URI} does not end
* with the oldSuffix
, then the newSuffix
* is simply appended to the end of the original {@link URI}.
*
* @param uri the uri to check.
* @param oldSuffix the old suffix to check for.
* @param newSuffix the new suffix to use.
*
* @return a new uri with the old suffix replaced by the new suffix, or the
* new suffix appended if the original uri did not end with
* oldSuffix.
*
* @see VirtualFileSystemHelper#convertSuffix( URI, String, String )
*/
public URI convertSuffix( URI uri, String oldSuffix, String newSuffix )
{
return findHelper( uri ).convertSuffix( uri, oldSuffix, newSuffix );
}
/**
* Copies the contents at src
to dst
. If the
* destination directory does not exist, it will be created.
* IOException is thrown if:
*
in
to dst
.
*
* @param in an input stream to read data from. Must not be null.
* @param dst a uri to copy data to. Must not be null.
* @throws java.io.IOException if an error occurs reading or writing.
*/
public void copy( InputStream in, URI dst ) throws IOException
{
if ( in == null )
{
throw new NullPointerException( "in must not be null" );
}
if ( dst == null )
{
throw new NullPointerException( "dst must not be null" );
}
OutputStream out = null;
try
{
out = openOutputStream( dst );
mkdirs( getParent( dst ) );
copy( in, out );
}
finally
{
try { if ( in != null ) in.close(); } catch ( IOException e ) { e.printStackTrace(); }
try { if ( out != null ) out.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
/**
* Copies the contents of src
to dst
.
*
* @param src the uri of a resource to read data from. Must not be null.
* @param dst a file object to write data to. Must not be null.
* @throws java.io.IOException if an error occurs copying data.
*/
public void copy( URI src, File dst ) throws IOException
{
if ( src == null )
{
throw new NullPointerException( "src must not be null" );
}
if ( dst == null )
{
throw new NullPointerException( "dst must not be null" );
}
InputStream in = null;
OutputStream out = null;
try
{
in = openInputStream( src );
out = new FileOutputStream( dst );
dst.getParentFile().mkdirs();
copy( in, out );
}
finally
{
try { if ( in != null ) in.close(); } catch ( IOException e ) { e.printStackTrace(); }
try { if ( out != null ) out.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
/**
* Common code for copy routines. By convention, the streams are
* closed in the same method in which they were opened. Thus,
* this method does not close the streams when the copying is done.
*/
private static void copy( InputStream in, OutputStream out )
throws IOException
{
final byte[] buffer = new byte[ COPY_BUFFER_SIZE ];
while ( true )
{
final int bytesRead = in.read( buffer );
if ( bytesRead < 0 )
{
break;
}
out.write( buffer, 0, bytesRead );
}
}
/**
* Deletes the resource pointed to by the specified {@link URI}. If
* the resource is a file (or analogous to a file), then the file is
* removed from its directory (or container). If the content is a
* directory (or analogous to a directory), then the directory is
* removed only if it is empty (i.e. contains no other files or
* directories).
*
* @param uri the uri of the resource to delete.
* @return true
if and only if the file or directory
* is successfully deleted; false
otherwise.
* @see VirtualFileSystemHelper#delete( URI )
*/
public boolean delete( URI uri )
{
return findHelper( uri ).delete( uri );
}
/**
* This method ensures that the specified {@link URI} ends with the
* specified suffix
. The suffix does not necessarily
* have to start with a ".", so if a leading "." is required, the
* specified suffix must contain it -- e.g. ".java", ".class".
*
* If the {@link URI} already ends in the specified suffix, then
* the {@link URI} itself is returned. Otherwise, a new
* {@link URI} is created with the the specified suffix appended
* to the original {@link URI}'s path part, and the new {@link URI}
* is returned.
*
* @param uri the uri to check. Must not be null.
* @param suffix the suffix to ensure the specified uri has. Must not be
* null.
*
* @return An {@link URI}, based on the specified {@link URI}, whose
* path part ends with the specified suffix.
*/
public URI ensureSuffix( URI uri, String suffix )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
if ( suffix == null )
{
throw new NullPointerException( "suffix must not be null" );
}
return findHelper( uri ).ensureSuffix( uri, suffix );
}
/**
* Returns true
if both of the specified {@link URI}
* parameters point to the same {@link URI} instance or if
* both {@link URI} parameters have the same scheme and the
* scheme helper determines that the {@link URI} objects are
* equal.
*
* @param uri1 the first uri to compare.
* @param uri2 the second uri to compare.
*
* @return true if the two uris are both null or the same instance, or if
* the schemes are equal and the registered VirtualFileSystemHelper
* for the scheme returns true from
* {@link VirtualFileSystemHelper#equals( URI, URI ) equals(uri1,uri2)}.
* @see VirtualFileSystemHelper#equals( URI, URI )
*/
public boolean equals( URI uri1, URI uri2 )
{
if ( uri1 == uri2 )
{
return true;
}
else if ( !schemesAreEqual( uri1, uri2 ) )
{
return false;
}
return findHelper( uri1 ).equals( uri1, uri2 );
}
/**
* Tests whether a resource at the specified {@link URI} location
* currently exists. The test for existence only checks the actual
* location and does not check any in-memory caches. To employ
* additional existential tests that do check in-memory caches, see
* {@link #isBound(URI)}.
*
* @param uri the uri of a resource to check for existence. Must not be
* null.
* @return true
if and only if a resource already exists
* at the specified {@link URI} location; false
* otherwise.
* @see VirtualFileSystemHelper#exists( URI )
*/
public boolean exists( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).exists( uri );
}
/**
* Returns the name of the file contained by the {@link URI}, not
* including any scheme, authority, directory path, query, or
* fragment. This simply returns the simple filename. For example,
* if you pass in an {@link URI} whose string representation is:
*
*
* scheme://userinfo@host:1010/dir1/dir2/file.ext?query#fragment
*
*
* the returned value is "file.ext
" (without the
* quotes).
*
* @param uri the uri to get the file name of. Must not be null.
* @return The simple filename of the specified {@link URI}. This
* value should only be used for display purposes and not for opening
* streams or otherwise trying to locate the document.
* @see VirtualFileSystemHelper#getFileName( URI )
*/
public String getFileName( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).getFileName( uri );
}
/**
* Returns the number of bytes contained in the resource that the
* specified {@link URI} points to. If the length cannot be
* determined, -1
is returned.* * @param uri the uri of the resource to get the size of. Must not be null. * @return the size in bytes of the document at the specified * {@link URI}. * @see VirtualFileSystemHelper#getLength( URI ) */ public long getLength( URI uri ) { if ( uri == null ) { throw new NullPointerException( "uri must not be null" ); } return findHelper( uri ).getLength( uri ); } /** * Returns the name of the file contained by the {@link URI}, not * including any scheme, authority, directory path, file extension, * query, or fragment. This simply returns the simple filename. For * example, if you pass in an {@link URI} whose string representation * is: * *
* scheme://userinfo@host:1010/dir1/dir2/file.ext1.ext2?query#fragment
*
*
* the returned value is "file
" (without the quotes).* * The returned file name should only be used for display purposes * and not for opening streams or otherwise trying to locate the * resource indicated by the {@link URI}.
*
* @param uri the uri to get the name of. Must not be null.
* @return the simple name of the uri without an extension.
* @see VirtualFileSystemHelper#getName( URI )
*/
public String getName( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).getName( uri );
}
/**
* Returns the {@link URI} representing the parent of the specified
* {@link URI}. If there is no parent then null
is returned.
*
* @param uri the uri of the resource to get the parent of. Must not be
* null.
* @return the uri of the parent resource, or null if the specified resource
* has no parent.
*
* @see VirtualFileSystemHelper#getParent( URI )
*/
public URI getParent( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).getParent( uri );
}
/**
* Returns the path part of the {@link URI}. The returned string
* is acceptable to use in one of the {@link URIFactory} methods
* that takes a path.
* * This implementation delegates to {@link URI#getPath()}. * * @param uri the uri to get the path of. Must not be null. * @return the path of the specified uri. * * @see VirtualFileSystemHelper#getPath( URI ) */ public String getPath( URI uri ) { if ( uri == null ) { throw new NullPointerException( "uri must not be null" ); } return findHelper( uri ).getPath( uri ); } /** * Returns the path part of the {@link URI} without the last file * extension. To clarify, the following examples demonstrate the * different cases: * *
/dir/file.ext |
* /dir/file |
*
/dir/file.ext1.ext2 |
* /dir/file.ext1 |
*
/dir1.ext1/dir2.ext2/file.ext1.ext2 |
* /dir1.ext1/dir2.ext2/file.ext1 |
*
/file.ext |
* /file |
*
/dir.ext/file |
* /dir.ext/file |
*
/dir/file |
* /dir/file |
*
/file |
* /file |
*
/.ext |
* / |
*
* * Examples: *
true
if the path part of the {@link URI}
* ends with the given suffix
String. The suffix can
* be any String and doesn't necessarily have to be one that begins
* with a dot ('.'). If you are trying to test whether the path
* part of the {@link URI} ends with a particular file extension,
* then the suffix
parameter must begin with a '.'
* character to ensure that you get the right return value.
*
* @param uri the uri to check. Must not be null.
* @param suffix the suffix to check for. Must not be null.
* @return true if the specified suffix is present on the specified uri.
* @see VirtualFileSystemHelper#hasSuffix( URI, String )
*/
public boolean hasSuffix( URI uri, String suffix )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
if ( suffix == null )
{
throw new NullPointerException( "suffix must not be null" );
}
return findHelper( uri ).hasSuffix( uri, suffix );
}
/**
* Returns true
if uri1
represents a
* a directory and uri2
points to a location within
* uri1
's directory tree.
*
* @param uri1 the uri of a directory resource.
* @param uri2 the uri of a resource.
*
* @return true if uri2 is uri1 or points to a descendent resource of
* uri1. If either uri is null, returns false.
* @see VirtualFileSystemHelper#isBaseURIFor( URI, URI )
*/
public boolean isBaseURIFor( URI uri1, URI uri2 )
{
if ( uri1 == null || uri2 == null )
{
return false;
}
else if ( uri1 == uri2 )
{
return true;
}
else if ( !schemesAreEqual( uri1, uri2 ) )
{
return false;
}
return findHelper( uri1 ).isBaseURIFor( uri1, uri2 );
}
/**
* This method tests whether the specified {@link URI} is bound to
* an existing resource, which may reside in memory (not yet
* saved) or already exist at the {@link URI} location. This is
* similar to {@link #exists(URI)} but differs in that additional
* tests are applied that check whether the {@link URI} is bound
* to an in-memory object before the actual {@link URI} location is
* checked.* * More precisely, "bound" means either that an {@link URI} is being * used in such a way that a registered {@link URIExistsTest} is able * to detect the {@link URI}'s usage or that a document already * exists at the {@link URI} location as determined by {@link * #exists(URI)}).
*
* Checking for uniqueness of a newly generated {@link URI} is the
* primary use for this method.
*
* @param uri the uri to check, must not be null.
* @return true if the specified uri is bound.
*/
public boolean isBound( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
for ( Iterator iter = _existsTests.iterator(); iter.hasNext(); )
{
final URIExistsTest test = (URIExistsTest) iter.next();
if ( test.uriExists( uri ) )
{
return true;
}
}
return exists( uri );
}
/**
* Returns true
if the local file system is case
* sensitive. Returns false
if the local file system is
* not case sensitive.
*
* @return true if the local file system is case sensitive.
*/
public static boolean isLocalFileSystemCaseSensitive()
{
return _isCaseSensitive;
}
/**
* Tests whether the location indicated by the {@link URI} is
* a directory resource.
*
* @param uri the uri to check. Must not be null.
* @return true
if and only if the location indicated
* by the {@link URI} exists and is a directory;
* false
otherwise.
* @see VirtualFileSystemHelper#isDirectory( URI )
*/
public boolean isDirectory( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).isDirectory( uri );
}
/**
* Tests whether the location indicated by the {@link URI}
* represents a directory path. The directory path specified by
* the {@link URI} need not exist.
* * This method is intended to be a higher performance version of * the {@link #isDirectory(URI)} method. Implementations of this * method should attempt to ascertain whether the specified {@link * URI} represents a directory path by simply examining the {@link * URI} itself. Time consuming i/o operations should be * avoided.
*
* @param uri the uri to check. Must not be null.
* @return true
if the location indicated by the
* {@link URI} represents a directory path; the directory path need
* not exist.
*
* @see VirtualFileSystemHelper#isDirectoryPath( URI )
*/
public boolean isDirectoryPath( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).isDirectoryPath( uri );
}
/**
* Tests whether the resource indiciated by the {@link URI} is a
* hidden file. The exact definition of hidden is
* scheme-dependent and possibly system-dependent. On UNIX
* systems, a file is considered to be hidden if its name begins
* with a period character ('.'). On Win32 systems, a file is
* considered to be hidden if it has been marked as such in the
* file system.
*
* @param uri the uri to check. Must not be null.
* @return true if the uri represents a hidden resource.
*
* @see VirtualFileSystemHelper#isHidden( URI )
*/
public boolean isHidden( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).isHidden( uri );
}
/**
* Returns true
if the resource is read-only. A return
* value of false
means that trying to get an
* {@link OutputStream} or trying to write to an {@link OutputStream}
* based on the {@link URI} will cause an IOException to be thrown.
* If the read-only status cannot be determined for some reason,
* this method returns true
.
*
* @param uri the uri of the resource to check. Must not be null.
* @return true
if the document pointed to by the
* specified {@link URI} is read-only or if the read-only status
* cannot be determined; false
otherwise.
*
* @see VirtualFileSystemHelper#isReadOnly( URI )
*/
public boolean isReadOnly( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).isReadOnly( uri );
}
/**
* Tests whether the resource indiciated by the {@link URI} is
* a regular file. A regular is a file that is not a
* directory and, in addition, satisfies other system-dependent
* criteria.
*
* @param uri the uri of the resource to check. Must not be null.
* @return true
if and only if the resource
* indicated by the {@link URI} exists and is a normal
* file.
* @see VirtualFileSystemHelper#isRegularFile( URI )
*/
public boolean isRegularFile( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).isRegularFile( uri );
}
/**
* Returns true
if the specified {@link URI}
* corresponds to the root of a file system; false
* otherwise.
*
* @param uri the uri of a resource to check. Must not be null.
* @return true if the specified uri is a resource that is the
* root of a file system.
*/
public boolean isRoot( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
final URI[] roots = listRoots();
final int n = roots.length;
for ( int i = 0; i < n; i++ )
{
if ( equals( uri, roots[i] ) )
{
return true;
}
}
return false;
}
/**
* Returns the last modified time of the resource pointed to by the
* {@link URI}. The returned long
is the number of
* milliseconds since the epoch (00:00:00 GMT Jan 1, 1970). If no
* timestamp is available, -1
is returned.
*
* @param uri the uri of the resource to get the last modified time of. Must
* not be null.
* @return The last modified time of the resource pointed to by the
* specified {@link URI} in milliseconds since the epoch.
*
* @see VirtualFileSystemHelper#lastModified( URI )
*/
public long lastModified( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).lastModified( uri );
}
/**
* Returns an array of {@link URI}s identifying resources in
* the directory resource indicated by the {@link URI}. If the specified
* {@link URI} does not represent a directory, then this method
* returns null
. Otherwise, an array of {@link URI}s
* is returned, one for each file or directory in the directory.
* {@link URI}s representing the directory itself or its parent are
* not included in the result. There is no guarantee that the
* {@link URI}s will be returned in any particular order.
*
* @param uri the uri of a directory resource. Must not be null.
* @return An array of {@link URI}s naming the files and directories
* in the directory indicated by the {@link URI}. The array will
* be empty if the directory is empty. Returns null
* if the {@link URI} does not represent a directory or if an
* I/O error occurs.
*
* @see VirtualFileSystemHelper#list( URI )
*/
public URI[] list( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).list( uri );
}
/**
* Returns an array of {@link URI}s identifying resources in
* the directory resource indicated by the {@link URI}; the specified
* {@link URIFilter} is applied to determine which {@link URI}s will
* be returned. If the specified {@link URI} does not represent a
* directory, then this method returns null
.
* Otherwise, an array of {@link URI}s is returned, one for each file
* or directory in the directory that is accepted by the specified
* filter. {@link URI}s representing the directory itself or its
* parent are not included in the result. There is no guarantee that
* the {@link URI}s will occur in any particular order.
*
* If the specified {@link URIFilter} is null
then
* no filtering behavior is done.
*
* @param uri the uri of a directory resource. Must not be null.
* @param filter a filter to use when retrieving the child resources
* of the specified uri. May be null, in which case no filtering is done.
* @return An array of {@link URI}s naming the files and directories
* in the directory indicated by the {@link URI} that are accepted
* by the specified {@link URIFilter}. The array will be empty if
* the directory is empty. Returns null
if the
* {@link URI} does not represent a directory or if an I/O error
* occurs.
*
* @see VirtualFileSystemHelper#list( URI, URIFilter )
*/
public URI[] list( URI uri, URIFilter filter )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).list( uri, filter );
}
/**
* Returns an array of {@link URI}s that represent the root resources
* available. The determination of the roots is delegated to each
* registered {@link VirtualFileSystemHelper}.
*
* @return an array of root resources retrieved from each registered
* {@link VirtualFileSystemHelper}.
*/
public URI[] listRoots()
{
final ArrayList roots = new ArrayList( 40 );
final ArrayList helperKeys = new ArrayList( _helpers.keySet() );
Collections.sort( helperKeys );
for ( Iterator iter = helperKeys.iterator(); iter.hasNext(); )
{
final String scheme = iter.next().toString();
final VirtualFileSystemHelper helper =
(VirtualFileSystemHelper) _helpers.get( scheme );
final URI[] schemeRoots = helper.listRoots();
if ( schemeRoots != null )
{
roots.addAll( Arrays.asList( schemeRoots ) );
}
}
return (URI[]) roots.toArray( new URI[ roots.size() ] );
}
/**
* Creates the directory indicated by the {@link URI}.
*
* @param uri the uri of a potential directory resource. Must not be null.
* @return true
if and only if the directory was
* created; false
otherwise.
* @see VirtualFileSystemHelper#mkdir( URI )
*/
public boolean mkdir( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).mkdir( uri );
}
/**
* Creates the directory indicated by the specified {@link URI}
* including any necessary but nonexistent parent directories. Note
* that if this operation fails, it may have succeeded in creating
* some of the necessary parent directories. This method returns
* true
if the directory was created along with all
* necessary parent directories or if the directories already
* exist; it returns false
otherwise.
*
* @param uri the uri of a potential directory resource. Must not be null.
* @return true
if all directories were created
* successfully or exist; false
if there was a
* failure somewhere.
* Note that even if false
is returned, some directories
* may still have been created.
* @see VirtualFileSystemHelper#mkdirs( URI )
*/
public boolean mkdirs( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).mkdirs( uri );
}
/**
* Creates a new empty temporary file in the specified directory using the
* given prefix and suffix strings to generate its name.
*
* @param prefix The prefix string to be used in generating the file's name;
* must be at least three characters long
*
* @param suffix The suffix string to be used in generating the file's
* name; may be null
, in which case the
* suffix ".tmp"
will be used
*
* @param directory The directory in which the file is to be created,
* or null if the default temporary-file directory is to be used
*
* @return The URI
to the temporary file.
* @throws java.io.IOException if an error occurs creating the temporary
* file.
*
* @see VirtualFileSystemHelper#createTempFile( String, String, URI )
*/
public URI createTempFile( String prefix,
String suffix,
URI directory ) throws IOException
{
if ( prefix == null || prefix.length() < 3 )
{
throw new IllegalArgumentException(
"prefix must be at least three characters long" );
}
return ( directory != null
? findHelper( directory ).createTempFile( prefix, suffix, directory )
: findHelper( FILE_SCHEME ).createTempFile( prefix, suffix, null ) );
}
/**
* Opens an {@link InputStream} for the location indicated by the
* specified {@link URI}.
*
* @param uri An {@link InputStream} is opened on the given
* {@link URI}. Must not be null.
*
* @return The {@link InputStream} associated with the {@link URI}.
*
* @exception java.io.FileNotFoundException if the resource at the
* specified URI does not exist.
*
* @exception IOException if an I/O error occurs when trying to open
* the {@link InputStream}.
*
* @exception java.net.UnknownServiceException (a runtime exception) if
* the scheme does not support opening an {@link InputStream}.
*
* @see VirtualFileSystemHelper#openInputStream( URI )
*/
public InputStream openInputStream( URI uri ) throws IOException
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).openInputStream( uri );
}
/**
* Opens an {@link OutputStream} on the {@link URI}. If the file
* does not exist, the file should be created. If the directory
* path to the file does not exist, all necessary directories
* should be created.
*
* @param uri An {@link OutputStream} is opened on the given
* {@link URI}. Must not be null.
*
* @return The {@link OutputStream} associated with the {@link URI}.
*
* @exception IOException if an I/O error occurs when trying to open
* the {@link OutputStream}.
*
* @exception java.net.UnknownServiceException (a runtime exception)
* if the scheme does not support opening an {@link OutputStream}.
*
* @see VirtualFileSystemHelper#openOutputStream( URI )
*/
public OutputStream openOutputStream( URI uri ) throws IOException
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).openOutputStream( uri );
}
/**
* Renames the resource indicated by the first {@link URI} to the
* name indicated by the second {@link URI}.
*
* If either {@link URI} parameter is null
or if both
* of the specified {@link URI} parameters refer to the same
* resource, then the rename is not attempted and failure is
* returned.
*
* If the specified {@link URI} parameters do not have the same
* scheme, then the VirtualFileSystem
handles the rename
* by first copying the resource to the destination with {@link
* VirtualFileSystem#copy(URI, URI)} and then deleting the original
* resource with {@link VirtualFileSystem#delete(URI)}; if either
* operation fails, then failure is returned.
*
* Otherwise, the scheme helper is called to perform the actual
* rename operation. Scheme helper implementations may therefore
* assume that both {@link URI} parameters are not
* null
, do not refer to the same resource, and have
* the same scheme.
*
* If the original {@link URI} refers to a nonexistent resource,
* then the scheme helper implementations should return failure.
* It is left up to the scheme helper implementations to decide
* whether to overwrite the destination or return failure if the
* destination {@link URI} refers to an existing resource.
*
* @param oldURI the {@link URI} of the original resource
* @param newURI the desired {@link URI} for the renamed resource
*
* @return true
if and only if the resource is
* successfully renamed; false
otherwise.
*/
public boolean renameTo( URI oldURI, URI newURI )
{
if ( oldURI == null || newURI == null )
{
return false;
}
else if ( oldURI == newURI || oldURI.equals( newURI ) )
{
return false;
}
else if ( !schemesAreEqual( oldURI, newURI ) )
{
try
{
copy( oldURI, newURI );
}
catch ( IOException e )
{
return false;
}
return delete( oldURI );
}
return findHelper( oldURI ).renameTo( oldURI, newURI );
}
/**
* Sets the last-modified timestamp of the resource indicated by
* the {@link URI} to the time specified by time
.
* The time is specified in the number of milliseconds since
* the epoch (00:00:00 GMT Jan 1, 1970). The return value
* indicates whether or not the setting of the timestamp
* succeeded.
*
* @param uri the uri of the resource to set the last modified timesamp of.
* Must not be null.
* @param time a last modified timestamp in milliseconds since the epoch.
*
* @return true if the last modified time of the specified resource was
* successful.
*
* @see VirtualFileSystemHelper#setLastModified( URI, long )
*/
public boolean setLastModified( URI uri, long time )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).setLastModified( uri, time );
}
/**
* Sets the read-only status of the resource indicated by the
* {@link URI} according to the specified readOnly
* flag. The return value indicates whether or not the setting
* of the read-only flag succeeded.
*
* @param uri the uri of a resource to set the read only flag of. Must not
* be null.
* @param readOnly whether the specified resource should be read only.
*
* @return true if the read only flag on the specified resource was
* successfully set.
*
* @see VirtualFileSystemHelper#setReadOnly( URI, boolean )
*/
public boolean setReadOnly( URI uri, boolean readOnly )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).setReadOnly( uri, readOnly );
}
/**
* Returns a displayable form of the complete {@link URI}.
*
* @param uri the uri of a resource. Must not be null.
* @return a human-readable string representing the resource.
*
* @see VirtualFileSystemHelper#toDisplayString( URI )
*/
public String toDisplayString( URI uri )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
return findHelper( uri ).toDisplayString( uri );
}
/**
* Converts a uri to a relative spec.
*
* @param uri the uri to convert. Must not be null.
* @param base the base uri.
* @return the relative spec of uri
* @see VirtualFileSystemHelper#toRelativeSpec( URI, URI )
*/
public String toRelativeSpec( URI uri, URI base )
{
if ( uri == null )
{
throw new NullPointerException( "uri must not be null" );
}
if ( base == null )
{
throw new NullPointerException( "base must not be null" );
}
return findHelper( uri ).toRelativeSpec( uri, base );
}
/**
* Converts a uri to a relative spec.
*
* @param uri the uri to convert. Must not be null.
* @param base the base uri.
* @param mustConsumeBase If mustConsumeBase
is
* false
, then
* this method will return a non-null
relative
* spec regardless of how much of the base {@link URI} is
* consumed during the determination.
* @return the relative spec of uri
* @see VirtualFileSystemHelper#toRelativeSpec( URI, URI )
*/
public String toRelativeSpec( URI uri, URI base, boolean mustConsumeBase )
{
return findHelper( uri ).toRelativeSpec( uri, base, mustConsumeBase );
}
/**
* This method gets the base directory fully containing the relative path.
*
* @param uri the uri to get the base directory for.
* @param relativeSpec a relative path.
* @return the base directory fully containing the relative path.
* @see VirtualFileSystemHelper#getBaseParent(URI, String)
*/
public URI getBaseParent( URI uri, String relativeSpec )
{
return findHelper( uri ).getBaseParent( uri, relativeSpec );
}
/**
* Get a {@link URL} from a {@link URI}.
*
* @param uri the URI to convert to a URL.
* @return a url representation of the uri.
*
* @throws MalformedURLException if the uri could not be converted into
* a URL.
*/
public URL toURL( URI uri ) throws MalformedURLException
{
return findHelper( uri ).toURL( uri );
}
//--------------------------------------------------------------------------
// implementation details...
//--------------------------------------------------------------------------
/**
* Compares the schemes of the specified {@link URI} parameters
* for equality. The schemes are considered to be unequal if
* either {@link URI} is null
, even when both {@link
* URI} parameters are null
.
*/
private static boolean schemesAreEqual( URI uri1, URI uri2 )
{
if ( uri1 == null || uri2 == null )
{
return false;
}
final String p1 = uri1.getScheme();
final String p2 = uri2.getScheme();
return p1.equals( p2 );
}
/**
* Gets the VirtualFileSystem implementation for this IDE.
*
* @return the virtual file system implementation for this ide.
*/
public static VirtualFileSystem getVirtualFileSystem()
{
try
{
return (VirtualFileSystem) getService( VirtualFileSystem.class );
}
catch ( ProviderNotFoundException lnfe )
{
lnfe.printStackTrace();
throw new IllegalStateException( "No virtual file system" );
}
}
public VirtualFileSystem(){}
}