org.ebayopensource.turmeric.eclipse.utils.wsdl.WSDLUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.ebayopensource.turmeric.eclipse.utils.wsdl.WSDLUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
 * Licensed 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
 *******************************************************************************/
package org.ebayopensource.turmeric.eclipse.utils.wsdl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;

import javax.wsdl.Definition;
import javax.wsdl.Import;
import javax.wsdl.Types;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.schema.Schema;
import javax.wsdl.extensions.schema.SchemaReference;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.wsdl.xml.WSDLWriter;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.ebayopensource.turmeric.eclipse.utils.lang.StringUtil;
import org.ebayopensource.turmeric.eclipse.utils.plugin.WorkspaceUtil;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;
import org.xml.sax.InputSource;

/**
 * The Class WSDLUtil.
 *
 * @author yayu
 */
public final class WSDLUtil {

    /** The Constant URL_PREFIX_JAR_FILE. */
    public static final String URL_PREFIX_JAR_FILE = "jar:file:";

    /** The Constant JAR_FILE_SEPARATOR. */
    public static final String JAR_FILE_SEPARATOR = "!" + WorkspaceUtil.PATH_SEPERATOR;

    /** The Constant ATTR_ID_TARGETNAMESPACE. */
    public static final String ATTR_ID_TARGETNAMESPACE = "targetNamespace";

    /** The Constant NAMESPACE_PREFIX_W3ORG. */
    public static final String NAMESPACE_PREFIX_W3ORG = "http://www.w3.org/";

    /** The Constant NAMESPACE_PREFIX_XMLSOAP. */
    public static final String NAMESPACE_PREFIX_XMLSOAP = "http://schemas.xmlsoap.org";

    private WSDLUtil() {
        super();
    }

    /**
     * To url.
     *
     * @param file the file
     * @return the uRL
     */
    public static URL toURL(final File file) {
        if (file == null)
            return null;
        try {
            return file.toURI().toURL();
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Checks if is valid url.
     *
     * @param url the url
     * @return true, if is valid url
     */
    public static boolean isValidURL(final String url) {
        //return Pattern.matches(VALID_URL_PATTERN, url);
        if (StringUtils.isBlank(url))
            return false;
        try {
            new URL(url);
        } catch (MalformedURLException e) {
            return false;
        }
        return true;
    }

    /**
     * Validate url.
     *
     * @param url the url
     * @return the string
     */
    public static String validateURL(final String url) {
        if (StringUtils.isBlank(url))
            return "url is blank.";
        try {
            new URL(StringEscapeUtils.escapeHtml(url));
        } catch (final MalformedURLException e) {
            return e.getLocalizedMessage();
        }
        return "";
    }

    /**
     * Read wsdl.
     *
     * @param wsdlLocation The fully qualified location of the WSDL file.
     * @return The WSDL definition instance.
     * @throws WSDLException If the any errors encountered during the deserialization.
     */
    public static Definition readWSDL(final String wsdlLocation) throws WSDLException {
        final WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
        return reader.readWSDL(wsdlLocation);
    }

    /**
     * This is intended to be used for wsdl file inside jar file.
     *
     * @param wsdlStream the wsdl stream
     * @return the definition
     * @throws WSDLException the wSDL exception
     */
    public static Definition readWSDL(final InputStream wsdlStream) throws WSDLException {
        return readWSDL(null, wsdlStream);
    }

    /**
     * Reading wsdl from the provided jar file.
     * The format for documetn base URI would be "jar:file:[JAR_FILE_LOCATION]!/[WSDL_JAR_ENTRY_PATH]"
     *
     * @param file the file
     * @param jarEntryLocation the jar entry location
     * @return The instance of WSDL definition, or null is could not read it.
     * @throws WSDLException the wSDL exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static Definition readWSDLFromJarFile(final File file, final String jarEntryLocation)
            throws WSDLException, IOException {
        InputStream wsdlStream = null;
        if (file.exists() && file.canRead()) {
            final JarFile jarFile = new JarFile(file);
            final JarEntry jarEntry = jarFile.getJarEntry(jarEntryLocation);
            if (jarEntry != null) {
                // found the wsdl file
                wsdlStream = jarFile.getInputStream(jarEntry);
                return WSDLUtil.readWSDL(StringUtil.toString(URL_PREFIX_JAR_FILE, file.getAbsolutePath(),
                        JAR_FILE_SEPARATOR, jarEntryLocation), wsdlStream);
            }
        }
        return null;
    }

    /**
     * Read wsdl.
     *
     * @param documentBaseURI The parent folder of the wsdl file
     * @param wsdlStream The input stream
     * @return The WSDL definition instance.
     * @throws WSDLException If the any errors encountered during the deserialization.
     */
    public static Definition readWSDL(final String documentBaseURI, final InputStream wsdlStream)
            throws WSDLException {
        try {
            final WSDLReader reader = WSDLFactory.newInstance().newWSDLReader();
            InputSource inputSource = new InputSource(wsdlStream);
            return reader.readWSDL(documentBaseURI, inputSource);
        } finally {
            IOUtils.closeQuietly(wsdlStream);
        }
    }

    private static String[] getParentFolder(String fullFileName) {
        String[] result = new String[2];
        final String slash = "/";
        if (StringUtils.isNotBlank(fullFileName)) {
            fullFileName = StringUtils.replaceChars(fullFileName, File.separator, slash);
            result[0] = fullFileName.indexOf(slash) >= 0 ? StringUtils.substringBeforeLast(fullFileName, slash)
                    : "";
            result[1] = StringUtils.substringAfterLast(fullFileName, "/");
        }
        return result;
    }

    /**
     * The use of this method is discouraged, because it will try to read the
     * WSDL first, which might cause some performance issues.
     *
     * @param wsdl the wsdl
     * @param fileName the file name
     * @throws WSDLException the wSDL exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static void writeWSDL(final String wsdl, final String fileName) throws WSDLException, IOException {
        writeWSDL(readWSDL(wsdl), fileName);
    }

    /**
     * Write wsdl.
     *
     * @param wsdl the wsdl
     * @param fileName the file name
     * @throws WSDLException the wSDL exception
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static void writeWSDL(final Definition wsdl, final String fileName) throws WSDLException, IOException {
        writeWSDL(wsdl, fileName, new HashSet<String>());
    }

    private static InputStream readUrl(String locUri) throws MalformedURLException, IOException {
        URL url = URI.create(locUri).toURL();
        return url.openStream();

    }

    private static void handleImports(final Collection<List<Import>> imports, final String parentFolder,
            final Set<String> processedSchemas, final Map<InputStream, String> streamsToCopy) throws IOException {
        for (List<Import> list : imports) {
            for (Import _import : list) {
                if (isRelativeURI(_import.getLocationURI())) {// it is using a relative path
                    final String locUri = _import.getDefinition().getDocumentBaseURI();

                    if (processedSchemas.contains(locUri) == false) {
                        final String schemaParentFolder = getParentFolder(_import.getLocationURI())[0];
                        if (schemaParentFolder != null && parentFolder != null) {
                            String targetFileLocation = parentFolder + File.separator + schemaParentFolder
                                    + File.separator + FilenameUtils.getName(locUri);// a output
                            // file
                            // name;
                            InputStream stream = readUrl(locUri);
                            if (stream != null) {
                                streamsToCopy.put(stream, targetFileLocation);
                            }
                        }
                        processedSchemas.add(locUri);
                    }
                }

                // as of now, we only support two levels of import
                if (_import.getDefinition().getTypes() != null) {
                    final String schemaParentFolder = getParentFolder(_import.getLocationURI())[0];
                    if (schemaParentFolder != null && parentFolder != null) {
                        String targetLocation = parentFolder + File.separator + schemaParentFolder;
                        handleSchemas(_import.getDefinition().getTypes(), targetLocation, processedSchemas,
                                streamsToCopy);
                    }
                }
            }
        }
    }

    /**
     * <p>
     * Serialize the provided WSDL definition instance to the designated
     * location.
     * </p>
     * 
     * @param wsdl
     *            The WSDL definition instance
     * @param fileName
     *            The fully qualified WSDL file name
     * @param processedSchemas
     *            A list of schema file location which has already been
     *            processed. This prevents the issue that two schemas import
     *            each other.
     * @throws WSDLException
     *             If failed to handle the WSDL serialization
     * @throws IOException 
     */
    private static void writeWSDL(final Definition wsdl, final String fileName, final Set<String> processedSchemas)
            throws WSDLException, IOException {
        final WSDLWriter writer = WSDLFactory.newInstance().newWSDLWriter();
        final String parentFolder = getParentFolder(fileName)[0];
        final Map<InputStream, String> streamsToCopy = new ConcurrentHashMap<InputStream, String>();

        // if there are any schema imports, we should be able to handle it
        if (wsdl.getImports() != null && wsdl.getImports().isEmpty() == false) {
            handleImports(wsdl.getImports().values(), parentFolder, processedSchemas, streamsToCopy);
        }
        if (wsdl.getTypes() != null) {
            handleSchemas(wsdl.getTypes(), parentFolder, processedSchemas, streamsToCopy);
        }

        File parentDir = new File(parentFolder);
        if (parentDir.exists() == false)
            FileUtils.forceMkdir(parentDir);

        for (InputStream srcStream : streamsToCopy.keySet()) {
            File targetFile = new File(streamsToCopy.get(srcStream));
            FileUtils.forceMkdir(targetFile.getParentFile());

            try {
                FileOutputStream output = new FileOutputStream(targetFile);
                try {
                    IOUtils.copy(srcStream, output);
                } finally {
                    IOUtils.closeQuietly(output);
                }
            } finally {
                IOUtils.closeQuietly(srcStream);
            }
        }

        //output wsdl
        OutputStream out = null;
        try {
            out = new FileOutputStream(fileName);
            writer.writeWSDL(wsdl, out);
        } finally {
            IOUtils.closeQuietly(out);
        }
    }

    private static void handleSchemaReference(List<SchemaReference> schemaRefs, String parentFolder,
            final Set<String> processedSchemas, final Map<InputStream, String> streamsToCopy) throws IOException {
        for (SchemaReference schemaReference : schemaRefs) {
            if (!isRelativeURI(schemaReference.getSchemaLocationURI())) {
                continue;
            }

            final Schema refSchema = schemaReference.getReferencedSchema();
            final String locUri = refSchema != null ? refSchema.getDocumentBaseURI()
                    : schemaReference.getSchemaLocationURI();

            if (processedSchemas.contains(locUri) == false && refSchema != null) {
                String schemaParentFolder = getParentFolder(schemaReference.getSchemaLocationURI())[0];

                if (schemaParentFolder != null && parentFolder != null) {
                    String targetFileLocation = parentFolder + File.separator + schemaParentFolder + File.separator
                            + FilenameUtils.getName(locUri);

                    InputStream stream = readUrl(locUri);
                    if (stream != null) {
                        streamsToCopy.put(stream, targetFileLocation);
                    }
                }

                processedSchemas.add(locUri);

                // next round
                if (refSchema.getImports().isEmpty() == false) {
                    for (Object o : refSchema.getImports().values()) {
                        handleSchemaReference((List<SchemaReference>) o, parentFolder, processedSchemas,
                                streamsToCopy);
                    }
                }

                if (CollectionUtils.isNotEmpty(refSchema.getIncludes())) {
                    handleSchemaReference(refSchema.getIncludes(), parentFolder, processedSchemas, streamsToCopy);

                }
            }
        }
    }

    private static void handleSchemas(Types types, String parentFolder, final Set<String> processedSchemas,
            final Map<InputStream, String> streamsToCopy) throws IllegalArgumentException, IOException {
        for (Object obj : types.getExtensibilityElements()) {
            if (obj instanceof Schema) {
                Schema schema = (Schema) obj;
                for (Object key : schema.getImports().keySet()) {
                    Object value = schema.getImports().get(key);
                    if (value instanceof List) {
                        handleSchemaReference((List<SchemaReference>) value, parentFolder, processedSchemas,
                                streamsToCopy);
                    }
                }

                if (CollectionUtils.isNotEmpty(schema.getIncludes())) {
                    handleSchemaReference(schema.getIncludes(), parentFolder, processedSchemas, streamsToCopy);
                }

            } else if (obj instanceof UnknownExtensibilityElement) {
                throw new IllegalArgumentException(
                        "The WSDL4J in the current environment is rather old and does not support the \"Schema\" datatype. Please make sure your environment use a newer version.");
            }
        }
    }

    /**
     * Gets the service name from wsdl.
     *
     * @param wsdl the wsdl
     * @return the service name from wsdl
     */
    public static String getServiceNameFromWSDL(final Definition wsdl) {
        if (wsdl != null && wsdl.getServices().isEmpty() == false) {
            return ((javax.wsdl.Service) wsdl.getServices().values().toArray()[0]).getQName().getLocalPart();
        }
        return null;
    }

    /**
     * Gets the service location from wsdl.
     *
     * @param wsdl the wsdl
     * @return the service location from wsdl
     */
    public static String getServiceLocationFromWSDL(final Definition wsdl) {
        String serviceLocation = null;
        if (wsdl != null && wsdl.getServices().isEmpty() == false) {
            for (Object obj : ((javax.wsdl.Service) (wsdl.getServices().values().toArray()[0])).getPorts()
                    .values()) {
                javax.wsdl.Port port = (javax.wsdl.Port) obj;
                if (port.getExtensibilityElements().size() > 0) {
                    Object elem = port.getExtensibilityElements().get(0);
                    if (elem instanceof javax.wsdl.extensions.http.HTTPAddress) {
                        serviceLocation = ((javax.wsdl.extensions.http.HTTPAddress) elem).getLocationURI();
                        break;
                    } else if (elem instanceof javax.wsdl.extensions.soap.SOAPAddress) {
                        serviceLocation = ((javax.wsdl.extensions.soap.SOAPAddress) elem).getLocationURI();
                        break;
                    } else {
                        try {
                            final Method method = elem.getClass().getMethod("getLocationURI");
                            final Object result = method.invoke(elem);
                            if (result != null) {
                                serviceLocation = result.toString();
                                //although we have found the service location, 
                                //but we would still prefer the http and soap addresses,
                                //thus we will not break from the loop.
                            }
                        } catch (Exception e) {
                            StackTraceElement[] elements = new Throwable().getStackTrace();
                            Logger.getLogger(WSDLUtil.class.getName()).throwing(elements[0].getClassName(),
                                    elements[0].getMethodName(), e);
                        }
                    }
                }
            }
        }
        return serviceLocation;
    }

    /**
     * Gets the target namespace.
     *
     * @param location The location of the WSDL file
     * @return the target namespace
     * @throws WSDLException the wSDL exception
     */
    public static String getTargetNamespace(final String location) throws WSDLException {
        return readWSDL(location).getTargetNamespace();
    }

    /**
     * Gets the target namespace.
     *
     * @param wsdl the wsdl
     * @return the target namespace
     * @throws WSDLException the wSDL exception
     */
    public static String getTargetNamespace(final Definition wsdl) throws WSDLException {
        return wsdl.getTargetNamespace();
    }

    /**
     * Gets the target namespace.
     *
     * @param documentBaseURI the document base uri
     * @param inpuStream the inpu stream
     * @return the target namespace
     * @throws WSDLException the wSDL exception
     */
    public static String getTargetNamespace(final String documentBaseURI, final InputStream inpuStream)
            throws WSDLException {
        return readWSDL(documentBaseURI, inpuStream).getTargetNamespace();
    }

    //Moving util methods from WSDLUtilTest class to here
    /**
     * Gets the plugin os path.
     *
     * @param pluginId the plugin id
     * @param subDirPath the sub dir path
     * @return the plugin os path
     */
    public static String getPluginOSPath(String pluginId, String subDirPath) {
        URL platformContextURL = getPluginOSURL(pluginId, subDirPath);
        String fullPath = (new File(platformContextURL.getPath())).getAbsolutePath();
        IPath osPath = new Path(fullPath);
        return osPath.toString();
    }

    /**
     * Gets the plugin osurl.
     *
     * @param pluginId the plugin id
     * @param subDirPath the sub dir path
     * @return the plugin osurl
     */
    public static URL getPluginOSURL(String pluginId, String subDirPath) {
        Bundle bundle = Platform.getBundle(pluginId);
        if (bundle == null) {
            return null;
        }

        URL installLocation = bundle.getEntry("/");
        URL local = null;
        URL platformContextURL = null;
        try {
            local = FileLocator.toFileURL(installLocation);

            platformContextURL = subDirPath == null ? local : new URL(local, subDirPath.toString());
        } catch (Exception _ex) {
            return null;
        }
        return platformContextURL;
    }

    private static boolean isRelativeURI(String url) {
        if (StringUtils.isEmpty(url))
            return false;

        URI uri = null;
        try {
            uri = URI.create(url);
        } catch (RuntimeException e) {
            // ignore it
        }

        return uri != null && !uri.isAbsolute();
    }

    /**
     * Known W3 and XMLSOAP namespaces will not be included.
     *
     * @param wsdl the wsdl
     * @return a list of TargetNamespaces from the schemas including the imported
     */
    public static Collection<String> getAllTargetNamespaces(final Definition wsdl) {
        final Collection<String> result = new LinkedHashSet<String>();
        if (wsdl == null)
            return result;
        /*if (StringUtils.isNotBlank(wsdl.getTargetNamespace()))
           result.add(wsdl.getTargetNamespace());*/

        if (wsdl.getImports() != null && wsdl.getImports().isEmpty() == false) {
            for (List<Import> list : (Collection<List<Import>>) wsdl.getImports().values()) {
                for (Import _import : list) {
                    result.addAll(getAllTargetNamespaces(_import.getDefinition()));
                }
            }
        }

        if (wsdl.getTypes() != null) {
            for (Object obj : wsdl.getTypes().getExtensibilityElements()) {
                if (obj instanceof Schema) {
                    getAllTargetNamespaces((Schema) obj, result, new HashSet<String>());
                } else if (obj instanceof UnknownExtensibilityElement) {
                    throw new IllegalArgumentException(
                            "The WSDL4J in the current environment is rather old and does not support the \"Schema\" datatype. Please make sure your environment use a newer version.");
                }
            }
        }
        return result;
    }

    private static void getAllTargetNamespaces(final Schema schema, final Collection<String> namespaces,
            final Set<String> processedSchemas) {
        if (schema != null) {
            final String locUri = schema.getDocumentBaseURI();
            //we need to check whether this schema has been processed or not
            if (processedSchemas.contains(locUri))
                return;
            processedSchemas.add(locUri);
            final String targetNamespace = schema.getElement().getAttribute(ATTR_ID_TARGETNAMESPACE);
            if (StringUtils.isNotBlank(targetNamespace)
                    && targetNamespace.startsWith(NAMESPACE_PREFIX_W3ORG) == false
                    && targetNamespace.startsWith(NAMESPACE_PREFIX_XMLSOAP) == false)
                namespaces.add(targetNamespace.trim());
            for (Object key : schema.getImports().keySet()) {
                Object value = schema.getImports().get(key);
                if (value instanceof List) {
                    for (final SchemaReference ref : (List<SchemaReference>) value) {
                        getAllTargetNamespaces(ref.getReferencedSchema(), namespaces, processedSchemas);
                    }
                }
            }

            if (CollectionUtils.isNotEmpty(schema.getIncludes())) {
                for (final SchemaReference ref : (List<SchemaReference>) schema.getIncludes()) {
                    getAllTargetNamespaces(ref.getReferencedSchema(), namespaces, processedSchemas);
                }
            }
        }
    }
}