blob: 69f98d9a0b6d1ac40f8d4ff3990e115fdbe27453 [file] [log] [blame]
/*
* 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();
}
}