/* * 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: *

* * @param src the uri of the resource to copy from. Must not be null. * @param dst the uri of the resource to copy to. Must not be null. * @throws java.io.IOException if an error occurs copying the resource from * the old uri to the new uri. */ public void copy( URI src, URI dst ) throws IOException { if ( src == null ) { throw new NullPointerException( "src uri must not be null" ); } if ( dst == null ) { throw new NullPointerException( "dst uri must not be null" ); } InputStream in = null; OutputStream out = null; try { in = openInputStream( src ); out = openOutputStream( dst ); if (!mkdirs( getParent( dst ) )) { throw new IOException( "Failed to create parent directories for "+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 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: * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Path part of input {@link URI}
Output {@link String} *
/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/
* * @param uri the uri to get the path of without extension. Must not be null. * @return the path of the specified uri without its extension. * * @see VirtualFileSystemHelper#getPathNoExt( URI ) */ public String getPathNoExt( URI uri ) { if ( uri == null ) { throw new NullPointerException( "uri must not be null" ); } return findHelper( uri ).getPathNoExt( uri ); } /** * Returns the platform-dependent String representation of the * {@link URI}; the returned string should be considered acceptable * for users to read. In general, the returned string should omit * as many parts of the {@link URI} as possible. For the "file" * scheme, therefore, the platform pathname should just be the * pathname alone (no scheme) using the appropriate file separator * character for the current platform. For other schemes, it may * be necessary to reformat the {@link URI} string into a more * human-readable form. That decision is left to each * {@link VirtualFileSystemHelper} implementation. * * @param uri the uri of the resource to get the platform path name of. * Must not be null. * @return The path portion of the specified {@link URI} in * platform-dependent notation. This value should only be used for * display purposes and not for opening streams or otherwise trying * to locate the document. * * @see VirtualFileSystemHelper#getPlatformPathName( URI ) */ public String getPlatformPathName( URI uri ) { if ( uri == null ) { throw new NullPointerException( "uri must not be null" ); } return findHelper( uri ).getPlatformPathName( uri ); } /** * If a dot ('.') occurs in the filename part of the path part of * the {@link URI}, then all of the text starting at the last dot is * returned, including the dot. If the last dot is also the last * character in the path, then the dot by itself is returned. If * there is no dot in the file name (even if a dot occurs elsewhere * in the path), then the empty string is returned.

* * Examples: *

* * @param uri the uri to get the suffix of. Must not be null. * @return the suffix of the specified uri. * @see VirtualFileSystemHelper#getSuffix( URI ) */ public String getSuffix( URI uri ) { if ( uri == null ) { throw new NullPointerException( "uri must not be null" ); } return findHelper( uri ).getSuffix( uri ); } /** * Returns 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(){} }