Edit D:\app\Administrator\product\11.2.0\dbhome_1\ide\src\javax\ide\net\VirtualFileSystemHelper.java
/* * 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.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.UnknownServiceException; import java.util.ArrayList; import java.util.StringTokenizer; /** * The {@link VirtualFileSystemHelper} class specifies the * {@link VirtualFileSystem} operations that may have scheme-specific * handling. By default, the {@link VirtualFileSystem} delegates its * operations to {@link VirtualFileSystemHelper}. However, a subclass of * {@link VirtualFileSystemHelper} can be registered with the * {@link VirtualFileSystem} to handle the {@link VirtualFileSystem} operations * for a particular scheme. A helper class is registered through the * {@link VirtualFileSystem#registerHelper(String, VirtualFileSystemHelper)} * method.<P> * * <EM>Special implementation note</EM>: classes that extend * {@link VirtualFileSystemHelper} must be completely thread-safe because a * single instance of each registered helper is held by the * {@link VirtualFileSystem} and reused for all threads. * * @see VirtualFileSystem */ public class VirtualFileSystemHelper { //-------------------------------------------------------------------------- // constructors... //-------------------------------------------------------------------------- protected VirtualFileSystemHelper() { // NOP. } //-------------------------------------------------------------------------- // VirtualFileSystemHelper public API... //-------------------------------------------------------------------------- /** * Returns a canonical form of the {@link URI}, if one is available. * <P> * * The default implementation just returns the specified {@link URI} * as-is. */ public URI canonicalize( URI uri ) throws IOException { return uri; } /** * Tests whether the application can read the resource at the * specified {@link URI}. * * @return <CODE>true</CODE> if and only if the specified * {@link URI} points to a resource that exists <EM>and</EM> can be * read by the application; <CODE>false</CODE> otherwise. */ public boolean canRead( URI uri ) { return false; } /** * Tests whether the application can modify the resource at the * specified {@link URI}. * * @return <CODE>true</CODE> if and only if the specified * {@link URI} points to a file that exists <EM>and</EM> the * application is allowed to write to the file; <CODE>false</CODE> * otherwise. */ public boolean canWrite( URI uri ) { return false; } /** * 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 <CODE>false</CODE>. * * @return <CODE>true</CODE> if the resource at the specified {@link URI} * exists or can be created; <CODE>false</CODE> otherwise. */ public boolean canCreate( URI uri ) { return true; } /** * Tests whether the specified {@link URI} is valid. If the resource * pointed by the {@link URI} exists the method returns <CODE>true</CODE>. * If the resource does not exist, the method tests that all components * of the path can be created. * * @return <CODE>true</CODE> if the {@link URI} is valid. */ public boolean isValid( URI uri ) { if ( exists( uri ) ) { return true; } return canCreate( uri ); } /** * Takes the given {@link URI} and checks if its {@link #toString()} * representation ends with the specified <CODE>oldSuffix</CODE>. If * it does, the suffix is replaced with <CODE>newSuffix</CODE>. 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 <CODE>oldSuffix</CODE>, then the <CODE>newSuffix</CODE> * is simply appended to the end of the original {@link URI}. */ public URI convertSuffix( URI uri, String oldSuffix, String newSuffix ) { final String path = uri.getPath(); final String newPath; if ( path.endsWith( oldSuffix ) ) { final int suffixIndex = path.length() - oldSuffix.length(); newPath = path.substring( 0, suffixIndex ) + newSuffix; } else { newPath = path + newSuffix; } return replacePathPart( uri, newPath ); } /** * Deletes the content pointed to by the specified {@link URI}. If * the content 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).<P> * * The default implementation simply returns <CODE>false</CODE> * without doing anything. * * @return <CODE>true</CODE> if and only if the file or directory * is successfully deleted; <CODE>false</CODE> otherwise. */ public boolean delete( URI uri ) { return false; } /** * This method ensures that the specified {@link URI} ends with the * specified <CODE>suffix</CODE>. 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".<P> * * 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.<P> * * The default implementation first checks with {@link * #hasSuffix(URI, String)} to see if the {@link URI} already ends * with the specified suffix. If not, the suffix is simply appended * to the path part of the {@link URI}, and the new {@link URI} is * returned. * * @return An {@link URI}, based on the specified {@link URI}, whose * path part ends with the specified suffix. * * @exception NullPointerException if either the specified {@link * URI} or <CODE>suffix</CODE> is <CODE>null</CODE>. The caller is * responsible for checking that they are not <CODE>null</CODE>. */ public URI ensureSuffix( URI uri, String suffix ) { if ( hasSuffix( uri, suffix ) ) { return uri; } final String path = uri.getPath(); return replacePathPart( uri, path + suffix ); } /** * Compares the specified {@link URI} objects to determine whether * they point to the same resource. This method returns * <CODE>true</CODE> if the {@link URI}s point to the same resource * and returns <CODE>false</CODE> if the {@link URI}s do not point * to the same resource.<P> * * This method and all subclass implementations can assume that both * {@link URI} parameters are not <CODE>null</CODE>. The * {@link VirtualFileSystem#equals(URI, URI)} method is responsible for * checking that the two {@link URI}s are not <CODE>null</CODE>.<P> * * It can also be assumed that both {@link URI} parameters have * the same scheme and that the scheme is appropriate for this * <CODE>VirtualFileSystemHelper</CODE>. This determination is also * the responsibility of {@link VirtualFileSystem#equals(URI, URI)}.<P> * * The default implementation for this method delegates to * {@link URI#equals(Object)}. */ public boolean equals( URI uri1, URI uri2 ) { return uri1.equals( 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. * * The default implementation simply returns <CODE>false</CODE> * without doing anything. * * @return <CODE>true</CODE> if and only if a resource already exists * at the specified {@link URI} location; <CODE>false</CODE> * otherwise. */ public boolean exists( URI uri ) { return false; } /** * 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: * * <BLOCKQUOTE><CODE> * scheme://userinfo@host:1010/dir1/dir2/file.ext?query#fragment * </CODE></BLOCKQUOTE> * * the returned value is "<CODE>file.ext</CODE>" (without the * quotes).<P> * * @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. */ public String getFileName( URI uri ) { if ( uri == null ) { return ""; //NOTRANS } final String path = uri.getPath(); if ( path == null || path.length() == 0 ) { return ""; //NOTRANS } if ( path.equals( "/" ) ) //NOTRANS { return "/"; //NOTRANS } final int lastSep = path.lastIndexOf( '/' ); //NOTRANS if ( lastSep == path.length() - 1 ) { final int lastSep2 = path.lastIndexOf( '/', lastSep - 1 ); //NOTRANS return path.substring( lastSep2 + 1, lastSep ); } else { return path.substring( lastSep + 1 ); } } /** * Returns the number of bytes contained in the resource that the * specified {@link URI} points to. If the length cannot be * determined, <CODE>-1</CODE> is returned.<P> * * The default implementation returns -1. * * @return the size in bytes of the document at the specified * {@link URI}. */ public long getLength( URI uri ) { return -1; } /** * 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: * * <BLOCKQUOTE><CODE> * scheme://userinfo@host:1010/dir1/dir2/file.ext1.ext2?query#fragment * </CODE></BLOCKQUOTE> * * the returned value is "<CODE>file</CODE>" (without the quotes).<P> * * 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}.<P> * * The default implementation first calls {@link #getFileName(URI)} to * get the file name part. Then all characters starting with the * first occurrence of '.' are removed. The remaining string is then * returned. */ public String getName( URI uri ) { final String fileName = getFileName( uri ); final int firstDot = fileName.indexOf( '.' ); return firstDot > 0 ? fileName.substring( 0, firstDot ) : fileName; } /** * Returns the {@link URI} representing the parent directory of * the specified {@link URI}. If there is no parent directory, * then <CODE>null</CODE> is returned.<P> * * The default implementation returns the value of invoking * <CODE>uri.resolve( ".." )</CODE>. */ public URI getParent( URI uri ) { return uri != null ? uri.resolve( ".." ) : null; // NOTRANS } /** * 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.<P> * * The default implementation delegates to {@link URI#getPath()}. */ public String getPath( URI uri ) { return uri.getPath(); } /** * Returns the path part of the {@link URI} without the last file * extension. To clarify, the following examples demonstrate the * different cases: * * <TABLE BORDER COLS=2 WIDTH="100%"> * <TR> * <TD><CENTER>Path part of input {@link URI}</CENTER></TD> * <TD><CENTER>Output {@link String}</CENTER</TD> * </TR> * <TR> * <TD><CODE>/dir/file.ext</CODE></TD> * <TD><CODE>/dir/file</CODE></TD> * <TR> * <TR> * <TD><CODE>/dir/file.ext1.ext2</CODE></TD> * <TD><CODE>/dir/file.ext1</CODE></TD> * <TR> * <TR> * <TD><CODE>/dir1.ext1/dir2.ext2/file.ext1.ext2</CODE></TD> * <TD><CODE>/dir1.ext1/dir2.ext2/file.ext1</CODE></TD> * <TR> * <TR> * <TD><CODE>/file.ext</CODE></TD> * <TD><CODE>/file</CODE></TD> * <TR> * <TR> * <TD><CODE>/dir.ext/file</CODE></TD> * <TD><CODE>/dir.ext/file</CODE></TD> * <TR> * <TR> * <TD><CODE>/dir/file</CODE></TD> * <TD><CODE>/dir/file</CODE></TD> * <TR> * <TR> * <TD><CODE>/file</CODE></TD> * <TD><CODE>/file</CODE></TD> * <TR> * <TR> * <TD><CODE>/.ext</CODE></TD> * <TD><CODE>/</CODE></TD> * <TR> * </TABLE> * * The default implementation gets the path from {@link * #getPath(URI)} and then trims off all of the characters beginning * with the last "." in the path, if and only if the last "." comes * after the last "/" in the path. If the last "." comes before * the last "/" or if there is no "." at all, then the entire path * is returned. */ public String getPathNoExt( URI uri ) { final String path = getPath( uri ); final int lastSlash = path.lastIndexOf( "/" ); //NOTRANS final int lastDot = path.lastIndexOf( "." ); //NOTRANS if ( lastDot <= lastSlash ) { // When the lastDot < lastSlash, it means that one of the // directories has an extension, but the filename itself has // no extension. In this case, returning the whole path is // the correct behavior. // // The only time that lastDot and lastSlash can be equal occurs // when both of them are -1. In that case, returning the whole // path is the correct behavior. return path; } // At this point, we know that lastDot must be non-negative, so // we can return the whole path string up to the last dot. return path.substring( 0, lastDot ); } /** * 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} implementor.<P> * * The default implementation returns <CODE>uri.toString()</CODE>. * If the {@link URI} is <CODE>null</CODE>, the empty string is * returned. * * @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. */ public String getPlatformPathName( URI uri ) { return uri != null ? uri.toString() : ""; //NOTRANS } /** * 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.<P> * * Examples: * <UL> * <LI>file:/home/jsr198/foo.txt returns ".txt" * <LI>file:/home/jsr198/foo.txt.bak returns ".bak" * <LI>file:/home/jsr198/foo returns "" * <LI>file:/home/jsr198/foo. returns "." * <LI>file:/home/jsr198/foo/ returns "" * <LI>file:/home/jsr198.1/foo returns "" * <LI>file:/home/jsr198.1/foo.txt returns ".txt" * </UL> */ public String getSuffix( URI uri ) { final String path = uri.getPath(); final int lastDot = path.lastIndexOf( '.' ); final int lastSlash = path.lastIndexOf( '/' ); return ( lastDot >= 0 && lastDot > lastSlash ) ? path.substring( lastDot ) : ""; //NOTRANS } /** * Returns <CODE>true</CODE> if the path part of the {@link URI} * ends with the given <CODE>suffix</CODE> 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 <CODE>suffix</CODE> parameter must begin with a '.' * character to ensure that you get the right return value. */ public boolean hasSuffix( URI uri, String suffix ) { final String path = uri.getPath(); return path.endsWith( suffix ); } /** * Returns <CODE>true</CODE> if <CODE>uri1</CODE> represents a * a directory and <CODE>uri2</CODE> points to a location within * <CODE>uri1</CODE>'s directory tree. */ public boolean isBaseURIFor( URI uri1, URI uri2 ) { if ( !isDirectoryPath( uri1 ) ) { return false; } final String uri1String = uri1.toString(); final String uri2String = uri2.toString(); return uri2String.startsWith( uri1String ); } /** * Tests whether the location indicated by the {@link URI} is * a directory.<P> * * The default implementation always returns <CODE>false</CODE>. * * @return <CODE>true</CODE> if and only if the location indicated * by the {@link URI} exists <EM>and</EM> is a directory; * <CODE>false</CODE> otherwise. */ public boolean isDirectory( URI uri ) { return false; } /** * Tests whether the location indicated by the {@link URI} * represents a directory path. The directory path specified by * the {@link URI} need not exist.<P> * * 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.<P> * * The default implementation returns <CODE>true</CODE> if the path * part of the {@link URI} ends with a '/' and the query and ref * parts of the {@link URI} are null. * * @return <CODE>true</CODE> if the location indicated by the * {@link URI} represents a directory path; the directory path need * not exist. */ public boolean isDirectoryPath( URI uri ) { return ( uri != null && uri.getPath().endsWith( "/" ) && //NOTRANS uri.getQuery() == null && uri.getFragment() == null ); } /** * Tests whether the resource indiciated by the {@link URI} is a * hidden file. The exact definition of <EM>hidden</EM> 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.<P> * * The default implementation always returns <CODE>false</CODE>. */ public boolean isHidden( URI uri ) { return false; } /** * Returns <CODE>true</CODE> if the resource is read-only. A return * value of <CODE>false</CODE> 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 <CODE>true</CODE>.<P> * * The default implementation always returns <CODE>true</CODE>. This * means that all resources are considered read-only unless a * scheme-specific {@link VirtualFileSystemHelper} is registered for the * specified {@link URI} and is able to determine that the resource * underlying the specified {@link URI} is not read-only. */ public boolean isReadOnly( URI uri ) { return true; } /** * Tests whether the resource indiciated by the {@link URI} is * a regular file. A <EM>regular</EM> is a file that is not a * directory and, in addition, satisfies other system-dependent * criteria.<P> * * The default implementation returns the value of * <CODE>exists( uri ) && !isDirectory( uri )</CODE>. * * @return <CODE>true</CODE> if and only if the resource * indicated by the {@link URI} exists <EM>and</EM> is a normal * file. */ public boolean isRegularFile( URI uri ) { return exists( uri ) && !isDirectory( uri ); } /** * Returns the last modified time of the resource pointed to by the * {@link URI}. The returned <CODE>long</CODE> is the number of * milliseconds since the epoch (00:00:00 GMT Jan 1, 1970). If no * timestamp is available or if the {@link URI} passed in is * <CODE>null</CODE>, <CODE>-1</CODE> is returned.<P> * * The default implementation returns -1. * * @return The last modified time of the document pointed to by the * specified {@link URI}. */ public long lastModified( URI uri ) { return -1; } /** * Returns an array of {@link URI}s naming files and directories in * the directory indicated by the {@link URI}. If the specified * {@link URI} does not represent a directory, then this method * returns <CODE>null</CODE>. 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 occur in any particular order.<P> * * The default implementation always returns an empty {@link URI} * array. * * @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 <CODE>null</CODE> * if the {@link URI} does not represent a directory or if an * I/O error occurs. */ public URI[] list( URI uri ) { return new URI[0]; } /** * Returns an array of {@link URI}s naming files and directories in * the directory 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 <CODE>null</CODE>. * 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.<P> * * If the specified {@link URIFilter} is <CODE>null</CODE> then * no filtering behavior is done.<P> * * The default implementation calls {@link #list(URI)} first and * then applies the {@link URIFilter} to the resulting list. * * @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 <CODE>null</CODE> if the * {@link URI} does not represent a directory or if an I/O error * occurs. */ public URI[] list( URI uri, URIFilter filter ) { final URI[] list = list( uri ); if ( list == null ) { return null; } if ( filter == null ) { return list; } final ArrayList filteredList = new ArrayList(); for ( int i = list.length - 1; i >= 0; i-- ) { final URI fileURI = list[i]; if ( filter.accept( fileURI ) ) { filteredList.add( fileURI ); } } return (URI[]) filteredList.toArray( new URI[filteredList.size()] ); } /** * Lists the root "file systems" that are supported by this helper. The * returned URIs are used by file chooser dialogs to list all of the * roots that are available for the user to browse. If no root file * systems are supported, this method must return <CODE>null</CODE> or * an empty URI array. If the returned array is not empty, then each * URI contained in it must represent a directory and must not be null. * <P> * * The default implementation always returns <CODE>null</CODE>. */ public URI[] listRoots() { return null; } /** * Creates the directory indicated by the {@link URI}.<P> * * The default implementation always returns <CODE>false</CODE>. * * @return <CODE>true</CODE> if and only if the directory was * created; <CODE>false</CODE> otherwise. */ public boolean mkdir( URI uri ) { return false; } /** * 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 * <CODE>true</CODE> if the directory was created along with all * necessary parent directories or if the directories already * exist; it returns <CODE>false</CODE> otherwise. * * @return <CODE>true</CODE> if all directories were created * successfully or exist; <CODE>false</CODE> if there was a * failure somewhere. * Note that even if <CODE>false</CODE> is returned, some directories * may still have been created. */ public boolean mkdirs( URI uri ) { return false; } /** * Creates a new empty temporary file in the specified directory using the * given prefix and suffix strings to generate its name. * * Subclasses must implement this method given that default implementation * does nothing and returns null. * * @param prefix The prefix string to be used in generating the file's name; * must be at least three characters long * * @param suffix The directory in which the file is to be created, or * null if the default temporary-file directory is to 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 <CODE>URI</CODE> to the temporary file. */ public URI createTempFile( String prefix, String suffix, URI directory ) throws IOException { return null; } /** * Opens an {@link InputStream} on the specified {@link URI}.<P> * * The default implementation throws {@link UnknownServiceException}. * * @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}. */ public InputStream openInputStream( URI uri ) throws IOException { throw new UnknownServiceException(); } /** * 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.<P> * * The default implementation throws {@link UnknownServiceException}. * * @param uri An {@link OutputStream} is opened on the given * {@link URI}. The operation is scheme-dependent. * * @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}. */ public OutputStream openOutputStream( URI uri ) throws IOException { throw new UnknownServiceException(); } /** * Renames the resource indicated by the first {@link URI} to the * name indicated by the second {@link URI}.<P> * * The default implementation simply returns <CODE>false</CODE> * without doing anything. * * If either {@link URI} parameter is <CODE>null</CODE> or if both * of the specified {@link URI} parameters refer to the same * resource, then the rename is not attempted and failure is * returned.<P> * * If the specified {@link URI} parameters do not have the same * scheme, then the <CODE>VirtualFileSystem</CODE> 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.<P> * * 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 * <CODE>null</CODE>, do not refer to the same resource, and have * the same scheme.<P> * * 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 <CODE>true</CODE> if and only if the resource is * successfully renamed; <CODE>false</CODE> otherwise. * * @see VirtualFileSystem#renameTo(URI, URI) */ public boolean renameTo( URI oldURI, URI newURI ) { return false; } /** * Sets the last-modified timestamp of the resource indicated by * the {@link URI} to the time specified by <CODE>time</CODE>. * 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.<P> * * The default implementation always returns <CODE>false</CODE> * without doing anything. */ public boolean setLastModified( URI uri, long time ) { return false; } /** * Sets the read-only status of the resource indicated by the * {@link URI} according to the specified <CODE>readOnly</CODE> * flag. The return value indicates whether or not the setting * of the read-only flag succeeded.<P> * * The default implementation always returns <CODE>false</CODE> * without doing anything. */ public boolean setReadOnly( URI uri, boolean readOnly ) { return false; } /** * Returns a displayable form of the complete {@link URI}.<P> * * The default implementation delegates to {@link URI#toString()}. */ public String toDisplayString( URI uri ) { return uri == null ? "" : uri.toString(); //NOTRANS } /** * This method attempts all possible ways of deriving a * <EM>relative URI reference</EM> as described in * <A HREF="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</A> * using the <CODE>uri</CODE> parameter as the {@link URI} * whose relative URI reference is to be determined and the * <CODE>base</CODE> parameter as the {@link URI} that serves as the * base document for the <CODE>uri</CODE> pararmeter. If it is not * possible to produce a relative URI reference because the two * {@link URI}s are too different, then a full, absolute * reference for the <CODE>uri</CODE> parameter is returned.<P> * * Whatever value is returned by this method, it can be used in * conjunction with the <CODE>base</CODE> {@link URI} to * reconstruct the fully-qualified {@link URI} by using one of the * {@link URI} constructors that takes a context {@link URI} plus * a {@link String} spec (i.e. the {@link String} returned by this * method).<P> * * Both the <CODE>uri</CODE> and <CODE>base</CODE> parameters should * point to documents and be absolute {@link URI}s. Specifically, * the <CODE>base</CODE> parameter does not need to be modified to * represent the base directory if the <CODE>base</CODE> parameter * already points to a document that is in the directory to which * the <CODE>uri</CODE> parameter will be made relative. This * relationship between <CODE>uri</CODE> and <CODE>base</CODE> is * exactly how relative references are treated within HTML documents. * Relative references in an HTML page are resolved against the HTML * page's base URI. The base URI is the HTML page itself, not the * directory that contains it.<P> * * If either the <CODE>uri</CODE> or <CODE>base</CODE> parameter * needs to represent a directory rather than a file, they must end * with a "/" in the path part of the {@link URI}, such as: * <BLOCKQUOTE> * <CODE>http://host.com/root/my_directory/</CODE> * </BLOCKQUOTE> * * <P>The algorithm used by this method to determine the relative * reference closely follows the recommendations made in * <A HREF="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</A>. The * following steps are performed, in order, to determine the * relative reference: * <OL> * <LI>The scheme parts are checked first. If they do not * match exactly, then an absolute reference is returned. * <LI>The authority parts are checked next. If they do not * match exactly, then an absolute reference is returned. * <LI>If the scheme and authority parts match exactly, then * it is possible to calculate a relative reference. The * path parts are then compared element-by-element to * determine the relative path, using the following steps, * in order: * <OL> * <LI>If no path elements are in common, then an absolute * path is used and relative-path determination stops. * <LI>Otherwise, any path parts that are in common are * omitted from the relative path. Comparison of path * elements when the scheme is "file" is done using * instance of {@link java.io.File} so that, for example, * on Win32 the comparison is case-<EM>insensitive</EM>, * whereas on Unix the comparison is * case-<EM>sensitive</EM>. When the scheme is not * "file", comparison is always case-sensitive. * <LI>If, after matching as many path elements as possible, * there are still path elements remaining in the base * {@link URI} (except for the document name itself), * then a "../" sequence is prepended to the resulting * relative path for each base path element that was not * consumed while matching path elements. * <LI>If not all of the path elements in <CODE>uri</CODE> * were consumed, then those path elements are appended * to the resulting relative path as well. If the first * remaining path element in <CODE>uri</CODE> contains * a ':' character and there is no "../" sequence was * prepended to the relative reference, then a "./" * sequence is prepended to prevent the ':' character * from being interpreted as a scheme delimiter (this * is a special case in <A * HREF="http://www.ietf.org/rfc/rfc2396.txt">RFC * 2396</A>). * </OL> * </OL> * * After the path part has been processed, no further processing * is done. In particular, the query part and path part of the * <CODE>uri</CODE> are not appended.<P> * * This method is implemented using the <EM>template method</EM> * design pattern, so it is possible for subclasses to override just * part of the algorithm in order to handle scheme-specific * details. */ public String toRelativeSpec( URI uri, URI base ) { return toRelativeSpec( uri, base, false ); } /** * Variant of {@link #toRelativeSpec(URI, URI)} that has a flag * that indicates whether the base {@link URI} should be fully * consumed in the process of calculating the relative spec.<P> * * If <CODE>mustConsumeBase</CODE> is <CODE>true</CODE>, then * this method will return a non-<CODE>null</CODE> relative * spec if and only if the base {@link URI} was fully consumed * in the process of calculating the relative spec. Otherwise, * if any part of the base {@link URI} remained, then this * method returns <CODE>null</CODE>.<P> * * If <CODE>mustConsumeBase</CODE> is <CODE>false</CODE>, then * this method will return a non-<CODE>null</CODE> relative * spec regardless of how much of the base {@link URI} is * consumed during the determination. */ public String toRelativeSpec( URI uri, URI base, boolean mustConsumeBase ) { // The first step is to check that the scheme parts are // identical. If they are not identical, then the returned // reference should just be absolute. if ( !haveSameScheme( uri, base ) || !haveSameAuthority( uri, base ) ) { return mustConsumeBase ? null : uri.toString(); } final StringBuffer relativeURI = new StringBuffer(); final boolean baseFullyConsumed = appendRelativePath( uri, base, relativeURI, mustConsumeBase ); if ( mustConsumeBase && !baseFullyConsumed ) { return null; } return relativeURI.toString(); } /** * This method gets the base directory fully containing the relative path. * * The <CODE>uri</CODE> should be absolute and point to a directory. * It must end with a "/" in the path part of the {@link URI}, such as: * <BLOCKQUOTE> * <CODE>http://host.com/root/my_directory/</CODE> * </BLOCKQUOTE> * If the <CODE>uri</CODE> does not end with a "/", it will be assumed * that the <CODE>uri</CODE> points to a document. The document name will * then be stripped in order to determine the parent directory. * * The <CODE>relativeSpec</CODE> parameter should be a relative path. * If the <CODE>relativeSpec</CODE> does not end with a "/", it will be * assumed that the <CODE>relativeSpec</CODE> points to a document. * The document name will then be stripped in order to determine the * parent directory. * * For example, if the <CODE>uri</CODE> points to: * <BLOCKQUOTE> * <CODE>file://c:/root/dir1/dir2/dir3/</CODE> * </BLOCKQUOTE> * and the <CODE>relativeSpec</CODE> is: * <BLOCKQUOTE> * <CODE>dir2/dir3</CODE> * </BLOCKQUOTE> * The returned value would be: * <BLOCKQUOTE> * <CODE>file://c:/root/dir1/</CODE> * </BLOCKQUOTE> * * If the <CODE>relativeSpec</CODE> path elements are not fully * contained in the last part of the <CODE>uri</CODE> path the * value returned is the uri itself if the uri path ends with a * "/" or the uri parent otherwise. */ public URI getBaseParent( URI uri, String relativeSpec ) { String basePath = uri.getPath(); final int basePathIndex = basePath.lastIndexOf( '/' ); //NOTRANS // If the base path ends with a "/" get the parent uri. if ( basePathIndex < basePath.length() - 1 ) { uri = getParent(uri); basePath = uri.getPath(); } final String baseDir = basePath.substring( 0, basePathIndex ); final int relPathIndex = relativeSpec.lastIndexOf( '/' ); // If the relative path does not containe a "/" we assume we // are dealing with a document whose base parent directory // is just the specified uri. if ( relPathIndex < 0 ) { return uri; } final String relDir = relativeSpec.substring( 0, relativeSpec.lastIndexOf( '/' ) ); //NOTRANS final StringTokenizer relTokenizer = new StringTokenizer( relDir, "/" ); //NOTRANS String relToken = relTokenizer.nextToken(); final StringTokenizer baseTokenizer = new StringTokenizer( baseDir, "/" ); //NOTRANS int ctr = 0; boolean foundBasePath = false; while ( baseTokenizer.hasMoreTokens() ) { final String baseToken = baseTokenizer.nextToken(); if ( areEqualPathElems( relToken, baseToken ) ) { final int baseCount = baseTokenizer.countTokens(); final int relCount = relTokenizer.countTokens(); if ( baseCount == relCount ) { if ( relCount != 0 ) { relToken = relTokenizer.nextToken(); ctr++; } else { foundBasePath = true; break; } } } else if ( ctr != 0 ) { ctr = 0; break; } } if ( foundBasePath ) { for ( int i = ctr; i >= 0; i-- ) { uri = getParent( uri ); } } return uri; } /** * Get an {@link URL} from an {@link URI}. This method just calls the * {@link URI#toURL} method. */ public URL toURL( URI uri ) throws MalformedURLException { return uri.toURL(); } //-------------------------------------------------------------------------- // helpers for equals //-------------------------------------------------------------------------- /** * Returns <code>true</code> if the URIs user infos are equal. */ protected boolean haveSameUserInfo( URI uri1, URI uri2 ) { return areEqual( uri1.getUserInfo(), uri2.getUserInfo() ); } /** * Returns <code>true</code> if the URIs hosts are equal. */ protected boolean haveSameHost( URI uri1, URI uri2 ) { return areEqual( uri1.getHost(), uri2.getHost() ); } /** * Returns <code>true</code> if the URIs paths are equal. */ protected boolean haveSamePath( URI uri1, URI uri2 ) { return areEqual( uri1.getPath(), uri2.getPath() ); } /** * Returns <code>true</code> if the URIs queries are equal. */ protected boolean haveSameQuery( URI uri1, URI uri2 ) { return areEqual( uri1.getQuery(), uri2.getQuery() ); } /** * Returns <code>true</code> if the URIs refs are equal. */ protected boolean haveSameRef( URI uri1, URI uri2 ) { return areEqual( uri1.getFragment(), uri2.getFragment() ); } /** * Returns <code>true</code> if the URIs ports are equal. */ protected boolean haveSamePort( URI uri1, URI uri2 ) { return uri1.getPort() == uri2.getPort(); } /** * Compares the two string for equality. */ protected final boolean areEqual( String s1, String s2 ) { return s1 == s2 || ( s1 != null && s1.equals( s2 ) ); } //-------------------------------------------------------------------------- // template method helpers for toRelativeSpec(...) //-------------------------------------------------------------------------- /** * This is a helper for the {@link #toRelativeSpec(URI, URI)} method, * which uses the <EM>template method</EM> design pattern.<P> * * By default, the <CODE>uri</CODE> and <CODE>base</CODE> parameters * must have identical schemes as a prerequisite to being able to * produce a relative {@link URI} spec. */ protected boolean haveSameScheme( URI uri, URI base ) { if ( uri == null || base == null ) { return false; } final String uriScheme = uri.getScheme(); final String baseScheme = base.getScheme(); return uriScheme.equals( baseScheme ); } /** * This is a helper for the {@link #toRelativeSpec(URI, URI)} method, * which uses the <EM>template method</EM> design pattern.<P> * * The "authority" part is a combination of the user info, hostname, * and port number. The full syntax in the {@link URI} string is: * <BLOCKQUOTE> * <CODE>userinfo@hostname:port</CODE> * </BLOCKQUOTE> * * It may appear in an {@link URI} such as: * <BLOCKQUOTE> * <CODE>ftp://jsr198eg@ide.com:21/builds/ri.zip</CODE> * </BLOCKQUOTE> * * The authority part may be <CODE>null</CODE>, if the {@link URI} * scheme does not require one.<P> * * By default, the <CODE>uri</CODE> and <CODE>base</CODE> parameters * must have identical authority strings as a prerequisite to being * able to produce a relative {@link URI} spec. */ protected boolean haveSameAuthority( URI uri, URI base ) { if ( uri == base ) { return true; } else if ( uri == null || base == null ) { return false; } final String uriAuthority = uri.getAuthority(); final String baseAuthority = base.getAuthority(); if ( uriAuthority == null ) { return baseAuthority == null; } else if ( baseAuthority != null ) { return uriAuthority.equals( baseAuthority ); } else { return false; } } /** * This is a helper for the {@link #toRelativeSpec(URI, URI)} method, * which uses the <EM>template method</EM> design pattern.<P> * * @return <CODE>true</CODE> if the entire base {@link URI} was * consumed in the process of determining the relative path; * <CODE>false</CODE> otherwise (i.e. not all of the base {@link URI} * was consumed). */ protected boolean appendRelativePath( URI uri, URI base, StringBuffer relativeURI, boolean mustConsumeBase ) { // By this point, it's known that the scheme and authority parts // of the URIs match, so that it is possible to generate a relative // URI spec that omits the scheme and authority parts. The // process of converting the path part to a relative form begins // here. final String uriPath = uri.getPath(); final int uriLastSlash = uriPath.lastIndexOf( '/' ); // Chop off the file name from the uri parameter so that its // filename can't match a directory in the base URI that happens to // have the same name. final String uriDir = uriPath.substring( 0, uriLastSlash ); final String uriFileName = uriPath.substring( uriLastSlash + 1 ); final StringTokenizer uriTokenizer = new StringTokenizer( uriDir, "/" ); //NOTRANS final String basePath = base.getPath(); final String baseDir = basePath.substring( 0, basePath.lastIndexOf( '/' ) ); //NOTRANS final StringTokenizer baseTokenizer = new StringTokenizer( baseDir, "/" ); //NOTRANS final int numBaseTokens = baseTokenizer.countTokens(); // Iterate through the parts of the uriDir and baseDir, until either // a non-matching part is found or either uriDir or baseDir runs out // of tokens. int numMatches = 0; String uriToken = null; while ( uriTokenizer.hasMoreTokens() && baseTokenizer.hasMoreTokens() ) { uriToken = uriTokenizer.nextToken(); final String baseToken = baseTokenizer.nextToken(); if ( areEqualPathElems( uriToken, baseToken ) ) { numMatches++; uriToken = null; continue; } break; } final boolean baseFullyConsumed = ( numBaseTokens == numMatches ); if ( mustConsumeBase && !baseFullyConsumed ) { // Abort processing and just return false. return false; } if ( numMatches == 0 ) { // If there are no matching parts in uriDir and baseDir at all, // then the absolute path should be used in the relative URI spec. // This covers the drive-letter case on Win32. relativeURI.append( uriPath ); } else { // If there were some matches, first prepend one or more "../" // sequences to the resulting relative URI spec if not all of // the baseDir tokens were consumed. final int numDotDotsNeeded = numBaseTokens - numMatches; for ( int i = numDotDotsNeeded; i > 0; i-- ) { relativeURI.append( "../" ); // NOTRANS } if ( uriToken != null && uriToken.length() > 0 ) { if ( numDotDotsNeeded == 0 && uriToken.indexOf( ':' ) >= 0 ) //NOTRANS { // This is a special case in RFC 2396. If the relative path // contains a ':' in the first part of the path, then a // "./" sequence needs to be prepended to prevent the ':' // from being interpreted as delimiting the scheme. The // "./" does not need to be prepended if any "../" sequences // have alread been prepended. RFC 2396 states that a ':' // can appear in the path part only after the first "/" // character. relativeURI.append( "./" ); // NOTRANS //NOTRANS } relativeURI.append( uriToken ).append( '/' ); //NOTRANS } // Append any other remaining path elements from the uri // parameter. while ( uriTokenizer.hasMoreTokens() ) { relativeURI.append( uriTokenizer.nextToken() ).append( '/' ); //NOTRANS } // Must append the filename too! It was chopped off during the // processing of path elements to prevent the filename from // matching a directory name in the base URI. relativeURI.append( uriFileName ); } return baseFullyConsumed; } /** * This is a helper for the * {@link #appendRelativePath(URI, URI, StringBuffer, boolean)} method, * which uses the <EM>template method</EM> design pattern.<P> * * The two {@link String}s that are passed in represent elements * of the path parts of the <CODE>uri</CODE> and <CODE>base</CODE> * parameters that are passed into * {@link #appendRelativePath(URI, URI, StringBuffer, boolean)}.<P> * * By default, path elements are compared exactly in a * case-sensitive manner using regular {@link String} comparison. */ protected boolean areEqualPathElems( String uriElem, String baseElem ) { return ( uriElem.equals( baseElem ) ); } private URI replacePathPart( URI uri, String newPath ) { try { return new URI( uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(), newPath, uri.getQuery(), uri.getFragment() ); } catch ( Exception e ) { e.printStackTrace(); return null; } } }
Ms-Dos/Windows
Unix
Write backup
jsp File Browser version 1.2 by
www.vonloesch.de