/**************************************************************************** * * Copyright (c) 2008-2011, EBM WebSourcing * * This source code is available under agreement available at * http://www.petalslink.com/legal/licenses/petals-studio * * You should have received a copy of the agreement along with this program. * If not, write to EBM WebSourcing (4, rue Amelie - 31200 Toulouse, France). * *****************************************************************************/ package org.eclipse.bpel.common.wsdl.helpers; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.Date; import org.eclipse.bpel.common.wsdl.SoaWsdlCommonPlugin; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; /** * A set of helpers for URIs and URLs. * @author Vincent Zurczak - EBM WebSourcing */ public class UriAndUrlHelper { /** * Builds an URI from an URL (with an handle for URLs not compliant with RFC 2396). * @param url * @return */ public static URI urlToUri( URL url ) { URI uri; try { // Possible failing step. uri = url.toURI(); } catch( Exception e ) { // URL did not comply with RFC 2396 => illegal un-escaped characters. try { uri = new URI( url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); } catch( Exception e1 ) { // No automatic repair. throw new IllegalArgumentException( "Broken URL: " + url ); } } uri = uri.normalize(); return uri; } /** * Builds an URI from an URL string (with an handle for URLs not compliant with RFC 2396). * @param urlAsString * @return */ public static URI urlToUri( String urlAsString ) { try { URL url = new URL( urlAsString ); return urlToUri( url ); } catch( Exception e ) { // e.printStackTrace(); } throw new IllegalArgumentException( "Broken URL: " + urlAsString ); } /** * Extracts the file name from a URI or URL given as a string. * <p> * If the file name contains invalid characters, such as a question mark, * this methods modifies the file name so that is is a valid file name. * </p> * @param uriAsString the URI or URL given as a string * @return the file name (never null) */ public static String extractOrGenerateFileName( String uriAsString ) { String fileName = uriAsString; if( fileName.endsWith( "/" )) fileName = fileName.substring( 0, fileName.length() - 1 ); int index = fileName.lastIndexOf( '/' ); if( index != -1 ) fileName = fileName.substring( ++ index ); // Handle cases like "jsp?value=" String lowered = fileName.toLowerCase(); if( lowered.endsWith( "?wsdl" )) fileName = fileName.substring( 0, fileName.length() - 5 ) + ".wsdl"; else if( lowered.contains( "?wsdl=" )) fileName = fileName.replace( "?wsdl=", "" ) + ".wsdl"; else if( lowered.endsWith( "?xsd" )) fileName = fileName.substring( 0, fileName.length() - 5 ) + ".xsd"; else if( lowered.contains( "?xsd=" )) fileName = fileName.replace( "?xsd=", "" ) + ".xsd"; else { index = fileName.lastIndexOf( '?' ); if( index != -1 ) fileName = fileName.substring( ++ index ); } // Handle empty values if( fileName.trim().length() == 0 ) fileName = "importedFile__" + new Date().getTime(); // Replace invalid characters index = fileName.lastIndexOf( '.' ); if( index != -1 ) { String ext = fileName.substring( index ); String fwe = fileName.substring( 0, index ); fileName = fwe.replaceAll( "[^-0-9a-zA-Z_]", "-" ) + ext; } return fileName; } /** * Builds an URI from an URI and a suffix. * * <p> * This suffix can be an absolute URL, or a relative path * with respect to the first URI. In this case, the suffix is resolved * with respect to the URI. * </p> * <p> * If the suffix is already an URL, its is returned.<br /> * If the suffix is a relative file path and cannot be resolved, an exception is thrown. * </p> * <p> * The returned URI is normalized. * </p> * * @param referenceUri the reference URI * @param uriSuffix the URI suffix (not null) * @return the new URI * @throws URISyntaxException if the resolution failed */ public static URI buildNewURI( URI referenceUri, String uriSuffix ) throws URISyntaxException { if( uriSuffix == null ) throw new NullPointerException( "The URI suffix cannot be null." ); uriSuffix = uriSuffix.replaceAll( "\\\\", "/" ); URI importUri = null; try { // Absolute URL ? importUri = urlToUri( new URL( uriSuffix )); } catch( Exception e ) { try { // Relative URL ? importUri = referenceUri.resolve( new URI( null, uriSuffix, null )); } catch( Exception e2 ) { String msg = "An URI could not be built from the URI " + referenceUri.toString() + " and the suffix " + uriSuffix + "."; throw new URISyntaxException( msg, e2.getMessage()); } } return importUri.normalize(); } /** * Determines whether a string is an absolute URI. * @param uriAsString the potential URI, as a string * @return true if it is an absolute URI, false otherwise or if it is not a valid URI */ public static boolean isAbsoluteUri( String uriAsString ) { boolean result; try { URI uri = urlToUri( uriAsString ); result = uri.isAbsolute(); } catch( Exception e ) { result = false; } return result; } /** * Returns the relative position of <code>uri</code> with respect to <code>originUri</code>. * * @param originUri the URI which acts as the <i>origin</i>. * @param uri the URI whose relative path must be computed with respect to originUri. * @return the relative path of <code>uri</code> with respect to originUri, if they * are on the same host and have a same scheme, or <code>uri<code> otherwise. */ public static URI getRelativeLocationToUri( URI originUri, URI uri ) { URI result = uri; try { originUri = UriAndUrlHelper.urlToUri( originUri.toURL()); uri = UriAndUrlHelper.urlToUri( uri.toURL()); URI relativeUri = originUri.relativize( uri ).normalize(); if( ! uri.equals( relativeUri )) { result = relativeUri; } else { // Do they have the same scheme? String originScheme = originUri.getScheme(); String scheme = uri.getScheme(); boolean sameScheme = false; if( originScheme != null ) sameScheme = originScheme.equals( scheme ); else sameScheme = scheme == null; // Do they have the same host? String originHost = originUri.getHost(); String host = uri.getHost(); boolean sameHost = false; if( originHost != null ) sameHost = originHost.equals( host ); else sameHost = host == null; // Make a special treatment for "file" scheme. // Are they on the same disk partition? // If no, then there is no relative path to compute. boolean samePartition = true; if( sameScheme && "file".equalsIgnoreCase( originScheme )) { String originDevice = new Path( originUri.getPath()).getDevice(); String device = new Path( uri.getPath()).getDevice(); if( originDevice != null ) samePartition = originDevice.equals( device ); else samePartition = device == null; } // If yes for both, we can define a relative location. // The only reason why URI#relativize( ... ) could have failed previously, // is because this method only works when "uri" is a child of "originUri". // Otherwise, we have to insert ".." when required. if( sameScheme && sameHost && samePartition ) { String originPath = originUri.toString().replaceAll( "\\\\", "/" ); String path = uri.toString().replaceAll( "\\\\", "/" ); // Split the paths String[] originParts = originPath.split( "/" ); String[] fileParts = path.split( "/" ); int matchSegmentsCpt = 0; for( int i=0; i<originParts.length; i++ ) { if( i >= fileParts.length ) break; String otherSegment = fileParts[ i ]; String segment = originParts[ i ]; if( segment.equalsIgnoreCase( otherSegment )) matchSegmentsCpt ++; else break; } // Build the relative location StringBuffer relativePath = new StringBuffer(); if( matchSegmentsCpt > 0 ) { for( int i=matchSegmentsCpt; i<originParts.length - 1; i++ ) relativePath.append( "../" ); for( int i=matchSegmentsCpt; i<fileParts.length - 1; i++ ) relativePath.append( fileParts[ i ] + "/" ); relativePath.append( fileParts[ fileParts.length - 1 ]); // Remove extra ".." and "." result = new URI( null, relativePath.toString(), null ); } } } } catch( URISyntaxException e ) { SoaWsdlCommonPlugin.log( e, IStatus.ERROR ); } catch( MalformedURLException e ) { SoaWsdlCommonPlugin.log( e, IStatus.ERROR ); } return result; } }