Edit D:\app\Administrator\product\11.2.0\dbhome_1\ide\src\javax\ide\net\URIFactory.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.File; import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Iterator; /** * This class contains methods which create new instances of * {@link URI}. In order for {@link URI}s to be used effectively as * keys in a hashtable, the URI must be created in a very consistent * manner. Therefore, when creating a new instance of {@link URI}, it * is strongly recommended that you use one of the methods in this class * rather than calling the {@link URI} constructor directly. This will * help prevent subtle bugs that can come up when two {@link URI} * instances that should be equal aren't equal (resulting in caching * bugs) because of a difference in some detail of the URI that affects * the result of the {@link Object#equals(Object)} method but doesn't * affect the location pointed to by the {@link URI} (which means that * code other than the caching will actually continue to work).<P> * * Additionally, by using the methods in this class to create instances * of {@link URI}, dependencies on {@link URI} can be tracked more * easily. * */ public final class URIFactory { public static final String JAR_URI_SEPARATOR = "!/"; // NOTRANS /** * This is a callback interface used by the {@link URIFactory} * while it is in the process of producing a new unique * {@link java.net.URI URI}. */ public interface NameGenerator { /** * This method is called by {@link URIFactory} from one of its * <CODE>newUniqueURI()</CODE> methods to obtain a relative * file name. The name is usually just a simple file name without any * preceeding directory names, that will be used in the process of * generating a unique {@link java.net.URI}.<P> * * The {@link URIFactory} is responsible for assembling a complete * <CODE>URI</CODE> by combining a base <CODE>URI</CODE> with the * relative file name returned by <CODE>nextName()</CODE>. The * {@link URIFactory} is also responsible for checking that the * newly created <CODE>URI</CODE> is unique among files on disk * and within the IDE's caches. If the new <CODE>URI</CODE> is not * unique, then {@link URIFactory} will issue another call to * <CODE>nextName()</CODE> to get a new name. This process is * repeated until either a unique <CODE>URI</CODE> is produced, or * the {@link URIFactory} "times out" on the * <CODE>NameGenerator</CODE> implementation after a very large * number of iterations fails to produce a unique <CODE>URI</CODE>. * <P> * * Therefore to interact properly with {@link URIFactory}, the * <CODE>nextName()</CODE> implementation must return a different * name each time it is invoked. More specifically, a particular * instance of <CODE>NameGenerator</CODE> should not return any * name more than once from its <CODE>nextName()</CODE> method. * Of course, this restriction does not apply across different * instances of <CODE>NameGenerator</CODE>.<P> * * The exact means by which a new name is produced is not specified * and is left to the specific <CODE>NameGenerator</CODE> classes. * However, the <CODE>nextName()</CODE> method should not attempt to * create an <CODE>URI</CODE> and check for its uniqueness, as this * may lead to problems in the future when the {@link URIFactory} and * {@link VirtualFileSystem} classes are enhanced. For example, if * individual <CODE>NameGenerator</CODE> implementations are * attempting to determine uniqueness, bugs may surface later if the * IDE's algorithm for determining uniqueness changes. How the IDE * determines <CODE>URI</CODE>uniqueness is not documented and should * be considered an implementation detail of the IDE framework. */ public String nextName(); } //-------------------------------------------------------------------------- // non-sanitizing factory methods... //-------------------------------------------------------------------------- /** * Creates a new {@link URI} that is the combination of the * specified base {@link URI} and the relative spec string. The * base {@link URI} is treated as a directory, whether or not the * {@link URI} ends with the "/" character, and the relative spec * is always treated as relative, even if it begins with a "/".<P> * * Non-sanitizing. */ public static URI newURI( URI baseURI, String relativeSpec ) { final String newPath = resolveRelative( baseURI.getPath(), relativeSpec ); if ( isJarURI( baseURI ) ) { if ( newPath.indexOf( JAR_URI_SEPARATOR ) < 0 ) { // Then this means that the relative spec must have contined // some ".." sequences and cause the URI to ascend into the // jar file's path itself. return newJarFileURIImpl( newPath ); } } return URIFactory.replacePathPart( baseURI, newPath ); } /** * Creates a new {@link URI} that is the combination of the * specified base {@link URI} and the relative spec string. The * base {@link URI} is treated as a directory whether or not it * ends with the "/" character. The returned {@link URI} will * return with the "/" character in the path part.<P> * * Non-sanitizing. */ public static URI newDirURI( URI baseURI, String relativeSpec ) { return relativeSpec.endsWith( "/" ) ? //NOTRANS newURI( baseURI, relativeSpec ) : newURI( baseURI, relativeSpec + "/" ); //NOTRANS } /** * Standard way of specifying a scheme with a file path. The file * path is used in the {@link URI} verbatim, without any changes to * the file separator character or any other characters. For an {@link URI} whose scheme is "file", the * {@link #newFileURI(String)} factory method should be used instead. * <P> * * Non-sanitizing. */ public static URI newURI( String scheme, String path ) { return newURI( scheme, null, null, -1, path, null, null ); } /** * Creates a new {@link URI} that is the combination of the * specified <code>scheme</code> and the directory path. The directory * path is used in the {@link URI} verbatim, without any changes to * the file separator character or any other characters. * The returned {@link URI} will return with the "/" character in the * path part.<P> * * Non-sanitizing. */ public static URI newDirURI( String scheme, String dirPath ) { return dirPath.endsWith( "/" ) ? //NOTRANS newURI( scheme, dirPath ) : newURI( scheme, dirPath + "/" ); //NOTRANS } /** * Creates a new unique URI using the scheme of the specified * <code>baseURI</code>. The <code>nameGen</code> object is called to * generate a unique name that will be appended to the base uri. * * Non-sanitizing. */ public static URI newUniqueURI( URI baseURI, NameGenerator nameGen ) { while ( true ) { final String name = nameGen.nextName(); final URI uri = newURI( baseURI, name ); if ( uri == null ) { return null; } // This will get expensive if many iterations are required to get // a unique URI, especially if the URI points to a resource that // requires network access. if ( !VirtualFileSystem.getVirtualFileSystem().isBound( uri ) ) { return uri; } } } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the scheme part of the {@link URI} * has been replaced with the specified <CODE>newscheme</CODE>.<P> * * Non-sanitizing. */ public static URI replaceSchemePart( URI uri, String newScheme ) { final String userinfo = uri.getUserInfo(); final String host = uri.getHost(); final int port = uri.getPort(); final String path = uri.getPath(); final String query = uri.getQuery(); final String fragment = uri.getFragment(); return newURI( newScheme, userinfo, host, port, path, query, fragment ); } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the port part of the {@link URI} * has been replaced with the specified <CODE>newPort</CODE>.<P> * * Non-sanitizing. */ public static URI replacePortPart( URI uri, int newPort ) { final String scheme = uri.getScheme(); final String userinfo = uri.getUserInfo(); final String host = uri.getHost(); final String path = uri.getPath(); final String query = uri.getQuery(); final String fragment = uri.getFragment(); return newURI( scheme, userinfo, host, newPort, path, query, fragment ); } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the host part of the {@link URI} * has been replaced with the specified <CODE>newHost</CODE>.<P> * * Non-sanitizing. */ public static URI replaceHostPart( URI uri, String newHost ) { final String scheme = uri.getScheme(); final String userinfo = uri.getUserInfo(); final int port = uri.getPort(); final String path = uri.getPath(); final String query = uri.getQuery(); final String fragment = uri.getFragment(); return newURI( scheme, userinfo, newHost, port, path, query, fragment ); } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the path part of {@link URI} has been * replaced with the specified <CODE>newPath</CODE>.<P> * * Non-sanitizing. */ public static URI replacePathPart( URI uri, String newPath ) { final String scheme = uri.getScheme(); final String userinfo = uri.getUserInfo(); final String host = uri.getHost(); final int port = uri.getPort(); final String query = uri.getQuery(); final String fragment = uri.getFragment(); return newURI( scheme, userinfo, host, port, newPath, query, fragment ); } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the fragment part of the {@link URI} * has been replaced with the specified <CODE>newRef</CODE>.<P> * * Non-sanitizing. */ public static URI replaceFragmentPart( URI uri, String newFragment ) { final String scheme = uri.getScheme(); final String userinfo = uri.getUserInfo(); final String host = uri.getHost(); final int port = uri.getPort(); final String path = uri.getPath(); final String query = uri.getQuery(); return newURI( scheme, userinfo, host, port, path, query, newFragment ); } /** * Returns a new {@link URI} that is identical to the specified * {@link URI} except that the query part of the {@link URI} * has been replaced with the specified <CODE>newQuery</CODE>.<P> * * Non-sanitizing. */ public static URI replaceQueryPart( URI uri, String newQuery ) { final String scheme = uri.getScheme(); final String userinfo = uri.getUserInfo(); final String host = uri.getHost(); final int port = uri.getPort(); final String path = uri.getPath(); final String fragment = uri.getFragment(); return newURI( scheme, userinfo, host, port, path, newQuery, fragment ); } //-------------------------------------------------------------------------- // factory methods taking string specifications... //-------------------------------------------------------------------------- /*- * NOTE: This implementation has known bugs. To avoid these bugs, * you should strongly consider using any of the other URIFactory * methods that do not require parsing a uriSpec string. * * Non-sanitizing. */ public static URI newURI( String uriSpec ) { return newURI( uriSpec, false, false ); } /*- * Do not make this public yet. */ static URI newURI( String uriSpec, boolean forceDir, boolean assumeFile ) { if ( uriSpec == null ) { return null; } if ( forceDir && !uriSpec.endsWith( "/" ) ) //NOTRANS { uriSpec += "/"; //NOTRANS } final int uriSpecLen = uriSpec.length(); if ( uriSpecLen > 0 ) { if ( uriSpec.charAt( 0 ) == File.separatorChar || ( uriSpecLen > 1 && uriSpec.charAt( 1 ) == ':' ) || ( uriSpec.indexOf( ':' ) < 0 && assumeFile ) ) { return newFileURI( uriSpec ); } } if ( uriSpec.toLowerCase().startsWith( "file:" ) ) // NOTRANS { return newFileURI( uriSpec.substring( 5 ) ); } else { try { // -- Bugs here if # or ? appear in the URI string. // -- Need to use a customized URI parser to convert // -- the string into an URI. This will do for now, // -- since # and ? are infrequently used in URIs. //return new URI( URLEncoder.encode( uriSpec, "UTF-8" ) ); return new URI( uriSpec ); } // catch ( UnsupportedEncodingException ue ) // { // // } catch ( URISyntaxException e ) { // Silent. The return value will be null, which the caller // should interpret to mean that no valid URI was specified. } } return null; } //-------------------------------------------------------------------------- // sanitizing factory methods... //-------------------------------------------------------------------------- /** * Creates a new {@link URI} using the "<CODE>file</CODE>" scheme. * The specified <CODE>filePath</CODE> can be expressed in the * notation of the platform that the Java VM is currently running on, * or it can be expressed using the forward slash character ("/") as * its file separator character, which is the standard file separator * for {@link URI}s. Note that technically, the forward slash * character is the only officially recognized hierarchy separator * character for an URI. * * Sanitizing. */ public static URI newFileURI( String filePath ) { if ( filePath == null ) { return null; } return newFileURI( new File( filePath ) ); } /** * This method converts a {@link File} instance into an {@link URI} * instance using an algorithm that is consistent with the other * factory methods in <CODE>URIFactory</CODE>.<P> * * Sanitizing. * * @return An {@link URI} corresponding to the given {@link File}. * The {@link URI} is produced using a mechanism that ensures * uniformity of the {@link URI} format across platforms. */ public static URI newFileURI( File file ) { if ( file == null ) { return null; } URI uri = file.toURI(); if ( file.isDirectory() ) { String path = uri.getPath(); if ( !path.endsWith( "/" ) ) { path = path + "/"; try { uri = new URI( uri.getScheme(), uri.getAuthority(), path, uri.getQuery(), uri.getFragment() ); } catch ( URISyntaxException e ) { throw new AssertionError( e ); } } } return uri; } /** * Creates a new {@link URI} with the "file" scheme that is for the * specified directory. Leading and trailing "/" characters are * added if they are missing. If the specified <CODE>dirPath</CODE> * is <CODE>null</CODE>, then the returned {@link URI} is * <CODE>null</CODE>.<P> * * Sanitizing. */ public static URI newDirURI( String dirPath ) { if ( dirPath == null ) { return null; } String path = sanitizePath( dirPath ); if ( !path.endsWith( "/" ) ) //NOTRANS { path = path + "/"; //NOTRANS } return newURI( VirtualFileSystem.FILE_SCHEME, path ); } /** * Creates a new {@link URI} with the "file" scheme that is for the * specified directory. Leading and trailing "/" characters are * added if they are missing. This method does not check whether the * specified {@link File} is actually a directory on disk; it just * assumes that it is. If the specified <CODE>dirPath</CODE> is * <CODE>null</CODE>, then the returned {@link URI} is * <CODE>null</CODE>.<P> * * Sanitizing. */ public static URI newDirURI( File dir ) { return dir != null ? newDirURI( dir.getAbsolutePath() ) : null; } //-------------------------------------------------------------------------- // jar URI factory methods... //-------------------------------------------------------------------------- /** * Builds an {@link URI} using the "<CODE>jar</CODE>" scheme based * on the specified archive {@link File} and the entry name passed * in. The entry name is relative to the root of the jar file, so * it should not begin with a slash. The entry name may be the * empty string or null, which means that the returned {@link URI} * should represent the jar file itself. * * Sanitizing for archiveFile; non-sanitizing for entryName. */ public static URI newJarURI( File archiveFile, String entryName ) { final URI archiveURI = newFileURI( archiveFile ); return newJarURI( archiveURI, entryName ); } /** * Returns <CODE>true</CODE> if the specified {@link URI} has * the "jar" scheme. Returns <CODE>false</CODE> if the specified * {@link URI} is <CODE>null</CODE> or has a scheme other than * "jar". */ public static boolean isJarURI( URI jarURI ) { return jarURI != null ? jarURI.getScheme().equals( "jar" ) : false; // NOTRANS } /** * Determine if a given URL represents an jar or zip file. The method * does a simple check to determine if the pathname ends with * .jar or .zip. */ public static boolean isArchive( String pathname ) { final int lastDot = pathname.lastIndexOf( '.' ); if ( lastDot < 0 ) { return false; } final String ext = pathname.substring( lastDot ).toLowerCase(); return ext.equals( ".jar" ) || ext.equals( ".zip" ); // NOTRANS } /** * Builds an {@link URI} using the "<CODE>jar</CODE>" scheme based * on the specified archive {@link URI} and the entry name passed in. * The entry name is relative to the root of the jar file, so it * should not begin with a slash. The entry name may be the empty * string or null, which means that the returned {@link URI} * should represent the jar file itself.<P> * * Non-sanitizing for both archiveURI and entryName. */ public static URI newJarURI( URI archiveURI, String entryName ) { if ( isJarURI( archiveURI ) ) { // If the specified URI is already a "jar" URI, we don't want to // put another "jar:" scheme in front of it. Instead, we just // want to append the entry name to the existing jar URI. First // we need to verify that the "!/" delimiter is already there. // Then we force the ending "/" onto the base URI, if it didn't // already have it (it really should). Then the entry name is // appended. final String path = archiveURI.getPath(); final int bangSlash = path.indexOf( JAR_URI_SEPARATOR ); if ( bangSlash < 0 ) { throw new IllegalArgumentException( "Bad jar uri: " + archiveURI ); // NOTRANS } final StringBuffer newPath = new StringBuffer( path ); if ( !path.endsWith( "/" ) ) //NOTRANS { newPath.append( '/' ); //NOTRANS } if ( entryName != null ) { newPath.append( entryName ); } return replacePathPart( archiveURI, newPath.toString() ); } else { try { final StringBuffer path = new StringBuffer( URLDecoder.decode( archiveURI.toString(), "UTF-8" ) ); path.insert( 0, '/' ); path.append( JAR_URI_SEPARATOR ); if ( entryName != null ) { path.append( entryName ); } return newURI( VirtualFileSystem.JAR_SCHEME, path.toString() ); } catch ( UnsupportedEncodingException uee ) { uee.printStackTrace(); assert false; } return null; } } //-------------------------------------------------------------------------- // direct access factory methods... //-------------------------------------------------------------------------- /** * Creates a new {@link URI} whose parts have the exact values that * are specified. <EM>In general, you should avoid calling this * method directly.</EM><P> * * This method is the ultimate place where all of the other * <CODE>URIFactory</CODE> methods end up when creating an * {@link URI}. * * Non-sanitizing. */ public static URI newURI( String scheme, String userinfo, String host, int port, String path, String query, String fragment ) { try { return new URI( scheme, userinfo, host, port, path, query, fragment ); } catch ( Exception e ) { e.printStackTrace(); return null; } } /** * Creates a new {@link URI} form an {@link URL}. * @param url The URL from which URI is derived. * @return New URI. */ public static URI newURI( URL url ) { // the URI() constructor does not work well with jar: URLs. Basically, // URI likes jar:/file:/path/to/file.jar!/entry/file.txt // URL likes jar:file:/path/to/file.jar!/entry/file.txt String path = url.getPath(); if ( "jar".equalsIgnoreCase( url.getProtocol() ) ) { path = "/" + path; } return newURI( url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), path, url.getQuery(), url.getRef() ); } //-------------------------------------------------------------------------- // implementation details... //-------------------------------------------------------------------------- /** * This "sanitizes" the specified string path by converting all * {@link File#separatorChar} characters to forward slash ('/'). * Also, a leading forward slash is prepended if the path does * not begin with one. */ private static String sanitizePath( String path ) { if ( File.separatorChar != '/' ) { path = path.replace( File.separatorChar, '/' ); } if ( !path.startsWith( "/" ) ) //NOTRANS { path = "/" + path; //NOTRANS } // bug 6994276 - replicates logic in java.io.File.toURI() if ( path.startsWith( "//" ) ) { path = "//" + path; } return path; } private static String resolveRelative( String basePath, String relPath ) { // Concatenate the base path and relative spec together, // eliminating any occurrences of "." or ".." in the relative // spec. If "." or ".." occur in the baseURI, they are treated // as literal names of directories. // // Note that the tokenization is done here directly for performance // reasons rather than through a StringTokenizer. // The basePath tokenization is set to return the "/" tokens // as well. This is needed to detect a UNC path, which begins // with two slashes. final ArrayList pathElems = new ArrayList(); for ( int pos = 0 ;; ) { final int newPos = basePath.indexOf( '/', pos ); final boolean done = newPos == -1; final String substr = done ? basePath.substring( pos ) : basePath.substring( pos, newPos ); if ( substr.length() > 0 || newPos == pos + 1 ) { pathElems.add( substr ); } if ( done ) { break; } pos = newPos + 1; } // The relPath tokenization is not currently configured to return // the "/" tokens, so there is an asymmetry here wrt basePath. // There isn't a problem with this right now because file systems // treat multiple slashes in the middle of the path as being a // single delimiter, but there may be a very special-case problem // with some schemes if there is a dependency on the occurrence // of multiple slashes in the path part of the URI. boolean lastElemIsRelativeDir = false; for ( int pos = 0 ;; ) { final int newPos = relPath.indexOf( '/', pos ); final boolean done = newPos == -1; final String substr = done ? relPath.substring( pos ) : relPath.substring( pos, newPos ); if ( substr.length() > 0 ) { if ( substr.equals( ".." ) ) // NOTRANS { final int n = pathElems.size(); if ( n > 0 ) { pathElems.remove( n - 1 ); } lastElemIsRelativeDir = true; } else if ( substr.equals( "." ) ) //NOTRANS { lastElemIsRelativeDir = true; } else { pathElems.add( substr ); lastElemIsRelativeDir = false; } } if ( done ) { break; } pos = newPos + 1; } // Put the path elements together to form the new path specification. final StringBuffer newPath = new StringBuffer(); if ( basePath.startsWith( "//" ) ) //NOTRANS { newPath.append( "//" ); //NOTRANS } else if ( basePath.startsWith( "/" ) ) //NOTRANS { newPath.append( '/' ); //NOTRANS } for ( Iterator iter = pathElems.iterator(); iter.hasNext(); ) { newPath.append( iter.next().toString() ).append( '/' ); //NOTRANS } if ( !lastElemIsRelativeDir && !relPath.endsWith( "/" ) && //NOTRANS relPath.length() != 0 ) { final int length = newPath.length(); if ( length > 0 ) { newPath.setLength( length - 1 ); } } return newPath.toString(); } private static URI newJarFileURIImpl( String uriStr ) { try { // No choice here -- must use the URI constructor directly // (instead of using the preferred approach of going through // URIFactory) because we have no way of knowing what's in // the URI string. There may be problems on some JDK // implementations if the jar/zip file resides on a path that // has '#', '?', or whitespace in the name. That's because // Sun's JDK has a number of bugs in the way it handles URIs. return new URI( uriStr ); } catch ( URISyntaxException e ) { e.printStackTrace(); return null; } } /** * Private constructor prevents instantiation. */ private URIFactory() { // NOP. } }
Ms-Dos/Windows
Unix
Write backup
jsp File Browser version 1.2 by
www.vonloesch.de