/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.jaxws.util; import org.apache.axis2.jaxws.ExceptionFactory; import org.apache.axis2.jaxws.i18n.Messages; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.InputSource; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URL; import java.util.StringTokenizer; /** * This class is the base for an implementation of a WSDL4J interface that * will be supplied to a WSDLReader instance. Its primary goal is to assist * with locating imported WSDL documents. */ public abstract class BaseWSDLLocator { private static Log log = LogFactory.getLog(BaseWSDLLocator.class); protected String baseURI, lastestImportURI; protected InputStream baseInputStream; /** * Returns an InputStream pointed at an imported wsdl pathname relative * to the parent resource or loadStrategy. * * @param importPath identifies the WSDL file within the context * @return an stream of the WSDL file */ abstract protected InputStream getInputStream(String importPath) throws IOException; /** * Allows for a level of indirection, such as a catalog, when importing URIs. * * @param importURI a URI specifying the document to import * @param parent a URI specifying the location of the parent document doing * the importing * @return the resolved import location, or null if no indirection is performed */ abstract protected String getRedirectedURI(String importURI, String parent); /** * Returns an InputSource "pointed at" the base document. */ public InputSource getBaseInputSource() { return new InputSource(baseInputStream); } /** * Returns an InputSource pointed at an imported wsdl document whose * parent document was located at parentLocation and whose * relative location to the parent document is specified by * relativeLocation. * * @param parentLocation a URI specifying the location of the * document doing the importing. * @param relativeLocation a URI specifying the location of the * document to import, relative to the parent document's location. */ public InputSource getImportInputSource(String parentLocation, String relativeLocation) { if (log.isDebugEnabled()) { log.debug("getImportInputSource, parentLocation= " + parentLocation + " relativeLocation= " + relativeLocation); } InputStream is = null; URL absoluteURL = null; String redirectedURI = getRedirectedURI(relativeLocation, parentLocation); if (redirectedURI != null) relativeLocation = redirectedURI; try { if (isAbsoluteImport(relativeLocation)) { try{ absoluteURL = new URL(relativeLocation); is = absoluteURL.openStream(); lastestImportURI = absoluteURL.toExternalForm(); } catch(Throwable t){ if (relativeLocation.startsWith("file://")) { try { relativeLocation = "file:/" + relativeLocation.substring("file://".length()); absoluteURL = new URL(relativeLocation); is = absoluteURL.openStream(); lastestImportURI = absoluteURL.toExternalForm(); } catch (Throwable t2) { } } } if(is == null){ try{ URI fileURI = new URI(relativeLocation); absoluteURL = fileURI.toURL(); is = absoluteURL.openStream(); lastestImportURI = absoluteURL.toExternalForm(); } catch(Throwable t){ //No FFDC code needed } } if(is == null){ try{ File file = new File(relativeLocation); absoluteURL = file.toURL(); is = absoluteURL.openStream(); lastestImportURI = absoluteURL.toExternalForm(); } catch(Throwable t){ //No FFDC code needed } } } else { String importPath = normalizePath(parentLocation, relativeLocation); is = getInputStream(importPath); lastestImportURI = importPath; } } catch (IOException ex) { throw ExceptionFactory.makeWebServiceException( Messages.getMessage("WSDLRelativeErr1", relativeLocation, parentLocation, ex.toString())); } if(is == null){ throw ExceptionFactory.makeWebServiceException( Messages.getMessage("WSDLRelativeErr2", relativeLocation, parentLocation)); } if(log.isDebugEnabled()){ log.debug("Loaded file: " + relativeLocation); } return new InputSource(is); } /** * Returns a URI representing the location of the base document. */ public String getBaseURI() { return baseURI; } /** * Returns a URI representing the location of the last import document * to be resolved. This is useful when resolving nested imports. */ public String getLatestImportURI() { return lastestImportURI; } /* * @param rawURI the uri for base wsdl file, which could be the form of * META-INF/base.wsdl or just base.wsdl, but it can be /base.wsdl (no leading slash according to spec) * @return the uri which is one level up the raw uri with the trailing slash (if not empty) * */ protected String convertURI(String rawURI) { int idx = rawURI.lastIndexOf('/'); if(idx > 0) { rawURI = rawURI.substring(0, idx + 1); return rawURI; } // this may be an absolute file reference else { idx = rawURI.lastIndexOf('\\'); if(idx > 0) { rawURI = rawURI.substring(0, idx + 1); return rawURI; } return ""; } } protected boolean isAbsoluteImport(String uri) { boolean absolute = false; if(uri != null){ if(uri.indexOf(":/") != -1){ absolute = true; } else if(uri.indexOf(":\\") != -1){ absolute = true; } } return absolute; } /** * The ZipFile can not handle relative imports of that have directory components * of the form "..". Given a 'relativeLocation' relative to 'parentLocation', replace * any ".." with actual path component names. * @param parentLocation Path relative to the module root of the file that is doing the * importing. * @param relativeLocation Path relative to the parentLocation of the file that is being imported. * @return String contatining the path to the file being imported (i.e. relativeLocation) that is * relative to the module root and has all ".." and "." path components removed and replaced * with the corresponding actual directory name. */ private static final char WSDL_PATH_SEPERATOR_CHAR = '/'; private static final String WSDL_PATH_SEPERATOR = (Character.valueOf(WSDL_PATH_SEPERATOR_CHAR)).toString(); protected String normalizePath(String parentLocation, String relativeLocation) { if (log.isDebugEnabled()) { log.debug("normalizePath, parentLocation= " + parentLocation + " relativeLocation= " + relativeLocation); } // Get the path from the module root to the directory containing the importing WSDL file. // Note this path will end in a "/" and will not contain any ".." path components. String pathFromRoot = convertURI(parentLocation); // Construct the path to the location relative to the module root based on the parent location, // removing any ".." or "." path components. StringBuffer pathToRelativeLocation = new StringBuffer(pathFromRoot); StringTokenizer tokenizedRelativeLocation = new StringTokenizer(relativeLocation, WSDL_PATH_SEPERATOR); if (log.isDebugEnabled()) { log.debug("pathFromRoot = " + pathFromRoot); log.debug("relativeLocation = " + relativeLocation); } while (tokenizedRelativeLocation.hasMoreTokens()) { String nextToken = tokenizedRelativeLocation.nextToken(); if (nextToken.equals("..")) { // Relative parent directory, so chop off the last path component in the path to back // up to the parent directory. First delete the trailing "/" from the path if there // is one, then delete characters from the end of the path until we find the next "/". int charToDelete = pathToRelativeLocation.length() - 1; if (pathToRelativeLocation.charAt(charToDelete) == WSDL_PATH_SEPERATOR_CHAR || pathToRelativeLocation.charAt(charToDelete) == '\\') { pathToRelativeLocation.deleteCharAt(charToDelete--); } while (pathToRelativeLocation.charAt(charToDelete) != WSDL_PATH_SEPERATOR_CHAR && pathToRelativeLocation.charAt(charToDelete) != '\\') { pathToRelativeLocation.deleteCharAt(charToDelete--); } } else if (nextToken.equals(".")) { // Relative current directory, do not add or delete any path components } else { // Make sure the current path ends in a "/" or "\\" then append this path component // This handles locations within the module and URIs if ((pathToRelativeLocation.indexOf(String.valueOf(WSDL_PATH_SEPERATOR_CHAR)) != -1) && (pathToRelativeLocation.charAt(pathToRelativeLocation.length() - 1)!= WSDL_PATH_SEPERATOR_CHAR)) { pathToRelativeLocation.append(WSDL_PATH_SEPERATOR_CHAR); } // This handles file based locations else if((pathToRelativeLocation.indexOf("\\") != -1) && (pathToRelativeLocation. charAt(pathToRelativeLocation.length() -1) != '\\')) { pathToRelativeLocation.append('\\'); } pathToRelativeLocation.append(nextToken); } } if (log.isDebugEnabled()) { log.debug("Built path = " + pathToRelativeLocation.toString()); } return pathToRelativeLocation.toString(); } }