Package com.centeractive.ws.legacy

Source Code of com.centeractive.ws.legacy.SchemaUtils

/**
* Copyright (c) 2012 centeractive ag. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301  USA
*/
package com.centeractive.ws.legacy;

import com.centeractive.ws.SoapBuilderException;
import com.centeractive.ws.common.ResourceUtils;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.*;
import org.w3c.dom.*;

import javax.xml.namespace.QName;

import java.io.File;
import java.net.URL;
import java.util.*;

/**
* This class was extracted from the soapUI code base by centeractive ag in October 2011.
* The main reason behind the extraction was to separate the code that is responsible
* for the generation of the SOAP messages from the rest of the soapUI's code that is
* tightly coupled with other modules, such as soapUI's graphical user interface, etc.
* The goal was to create an open-source java project whose main responsibility is to
* handle SOAP message generation and SOAP transmission purely on an XML level.
* <br/>
* centeractive ag would like to express strong appreciation to SmartBear Software and
* to the whole team of soapUI's developers for creating soapUI and for releasing its
* source code under a free and open-source licence. centeractive ag extracted and
* modifies some parts of the soapUI's code in good faith, making every effort not
* to impair any existing functionality and to supplement it according to our
* requirements, applying best practices of software design.
*
* Changes done:
* - changing location in the package structure
* - removal of dependencies and code parts that are out of scope of SOAP message generation
* - minor fixes to make the class compile out of soapUI's code base
* - changing the mechanism using which external resources are loaded
*/

/**
* XML-Schema related tools
*
* @author Ole.Matzura
*/
class SchemaUtils {

  private final static Logger log = Logger.getLogger(SchemaUtils.class);
  private static Map<String, XmlObject> defaultSchemas = new HashMap<String, XmlObject>();

  public static final boolean STRICT_SCHEMA_TYPES = false;

  static {
    initDefaultSchemas();
  }

  public static URL loadResoruce(String resourceName) {
    return ResourceUtils.getResourceWithAbsolutePackagePath(
        SchemaUtils.class, "/xsds/", resourceName);
  }

  public static void initDefaultSchemas() {
    try {
      defaultSchemas.clear();
      loadDefaultSchema(loadResoruce("xop.xsd"));
      loadDefaultSchema(loadResoruce("XMLSchema.xsd"));
      loadDefaultSchema(loadResoruce("xml.xsd"));
      loadDefaultSchema(loadResoruce("swaref.xsd"));
      loadDefaultSchema(loadResoruce("xmime200505.xsd"));
      loadDefaultSchema(loadResoruce("xmime200411.xsd"));
      loadDefaultSchema(loadResoruce("soapEnvelope.xsd"));
      loadDefaultSchema(loadResoruce("soapEncoding.xsd"));
      loadDefaultSchema(loadResoruce("soapEnvelope12.xsd"));
      loadDefaultSchema(loadResoruce("soapEncoding12.xsd"));
    } catch (Exception e) {
      throw new SoapBuilderException(e);
    }
  }


  private static void loadDefaultSchema(URL url) throws Exception {
    XmlObject xmlObject = XmlUtils.createXmlObject(url);
    if (!((Document) xmlObject.getDomNode()).getDocumentElement().getNamespaceURI().equals(Constants.XSD_NS)) {

      return;
    }

    String targetNamespace = getTargetNamespace(xmlObject);

    if (defaultSchemas.containsKey(targetNamespace)) {
      log.warn("Overriding schema for targetNamespace " + targetNamespace);
    }

    defaultSchemas.put(targetNamespace, xmlObject);

    log.debug("Added default schema from " + url.getPath() + " with targetNamespace " + targetNamespace);
  }

  public static SchemaTypeSystem loadSchemaTypes(String wsdlUrl, SchemaLoader loader) {
    try {
      log.debug("Loading schema types from [" + wsdlUrl + "]");
      ArrayList<XmlObject> schemas = new ArrayList<XmlObject>(getSchemas(wsdlUrl, loader).values());
      return buildSchemaTypes(schemas);
    } catch (Exception e) {
      throw new SoapBuilderException(e);
    }
  }

  public static SchemaTypeSystem buildSchemaTypes(List<XmlObject> schemas) {
    XmlOptions options = new XmlOptions();
    options.setCompileNoValidation();
    options.setCompileNoPvrRule();
    options.setCompileDownloadUrls();
    options.setCompileNoUpaRule();
    options.setValidateTreatLaxAsSkip();

    for (int c = 0; c < schemas.size(); c++) {
      XmlObject xmlObject = schemas.get(c);
      if (xmlObject == null
          || !((Document) xmlObject.getDomNode()).getDocumentElement().getNamespaceURI()
          .equals(Constants.XSD_NS)) {
        schemas.remove(c);
        c--;
      }
    }



    // TODO
    boolean strictSchemaTypes = STRICT_SCHEMA_TYPES;//SoapUI.getSettings().getBoolean( WsdlSettings.STRICT_SCHEMA_TYPES );
    if (!strictSchemaTypes) {
      Set<String> mdefNamespaces = new HashSet<String>();

      for (XmlObject xObj : schemas) {
        mdefNamespaces.add(getTargetNamespace(xObj));
      }

      options.setCompileMdefNamespaces(mdefNamespaces);
    }

    ArrayList<?> errorList = new ArrayList<Object>();
    options.setErrorListener(errorList);

    XmlCursor cursor = null;

    try {
      // remove imports
      for (int c = 0; c < schemas.size(); c++) {
        XmlObject s = schemas.get(c);

        Map<?, ?> map = new HashMap<String, String>();
        cursor = s.newCursor();
        cursor.toStartDoc();
        if (toNextContainer(cursor)) {
          cursor.getAllNamespaces(map);
        } else {
          log.warn("Can not get namespaces for " + s);
        }

        String tns = getTargetNamespace(s);

        // log.info( "schema for [" + tns + "] contained [" + map.toString()
        // + "] namespaces" );

        if (strictSchemaTypes && defaultSchemas.containsKey(tns)) {
          schemas.remove(c);
          c--;
        } else {
          removeImports(s);
        }

        cursor.dispose();
        cursor = null;
      }

      // schemas.add( soapVersion.getSoapEncodingSchema());
      // schemas.add( soapVersion.getSoapEnvelopeSchema());
      schemas.addAll(defaultSchemas.values());

      SchemaTypeSystem sts = XmlBeans.compileXsd(schemas.toArray(new XmlObject[schemas.size()]),
                                                 XmlBeans.getBuiltinTypeSystem(), options);

      return sts;
      // return XmlBeans.typeLoaderUnion(new SchemaTypeLoader[] { sts,
      // XmlBeans.getBuiltinTypeSystem() });
    } catch (Exception e) {
      throw new SoapBuilderException(e);
    } finally {
      for (int c = 0; c < errorList.size(); c++) {
        log.warn("Error: " + errorList.get(c));
      }

      if (cursor != null) {
        cursor.dispose();
      }
    }
  }

  public static boolean toNextContainer(XmlCursor cursor) {
    while (!cursor.isContainer() && !cursor.isEnddoc()) {
      cursor.toNextToken();
    }

    return cursor.isContainer();
  }

  public static String getTargetNamespace(XmlObject s) {
    return ((Document) s.getDomNode()).getDocumentElement().getAttribute("targetNamespace");
  }

  public static Map<String, XmlObject> getSchemas(String wsdlUrl, SchemaLoader loader) {
    Map<String, XmlObject> result = new HashMap<String, XmlObject>();
    getSchemas(wsdlUrl, result, loader, null /* , false */);
    return result;
  }

  /**
   * Returns a map mapping urls to corresponding XmlSchema XmlObjects for the specified wsdlUrl
   */
  public static void getSchemas(String wsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader, String tns) {
    if (existing.containsKey(wsdlUrl)) {
      return;
    }

    log.debug("Getting schema " + wsdlUrl);

    ArrayList<?> errorList = new ArrayList<Object>();

    Map<String, XmlObject> result = new HashMap<String, XmlObject>();

    boolean common = false;

    try {
      XmlOptions options = new XmlOptions();
      options.setCompileNoValidation();
      options.setSaveUseOpenFrag();
      options.setErrorListener(errorList);
      options.setSaveSyntheticDocumentElement(new QName(Constants.XSD_NS, "schema"));

      XmlObject xmlObject = loader.loadXmlObject(wsdlUrl, options);
      if (xmlObject == null) {
        throw new Exception("Failed to load schema from [" + wsdlUrl + "]");
      }

      Document dom = (Document) xmlObject.getDomNode();
      Node domNode = dom.getDocumentElement();


      // is this an xml schema?
      if (domNode.getLocalName().equals("schema") && Constants.XSD_NS.equals(domNode.getNamespaceURI())) {
        // set targetNamespace (this happens if we are following an include
        // statement)
        if (tns != null) {
          Element elm = ((Element) domNode);
          if (!elm.hasAttribute("targetNamespace")) {
            common = true;
            elm.setAttribute("targetNamespace", tns);
          }

          // check for namespace prefix for targetNamespace
          NamedNodeMap attributes = elm.getAttributes();
          int c = 0;
          for (; c < attributes.getLength(); c++) {
            Node item = attributes.item(c);
            if (item.getNodeName().equals("xmlns")) {
              break;
            }

            if (item.getNodeValue().equals(tns) && item.getNodeName().startsWith("xmlns")) {
              break;
            }
          }

          if (c == attributes.getLength()) {
            elm.setAttribute("xmlns", tns);
          }
        }

        if (common && !existing.containsKey(wsdlUrl + "@" + tns)) {
          result.put(wsdlUrl + "@" + tns, xmlObject);
        } else {
          result.put(wsdlUrl, xmlObject);
        }
      } else {
        existing.put(wsdlUrl, null);

        XmlObject[] schemas = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:schema");

        for (int i = 0; i < schemas.length; i++) {

          XmlCursor xmlCursor = schemas[i].newCursor();
          String xmlText = xmlCursor.getObject().xmlText(options);
          // schemas[i] = XmlObject.Factory.parse( xmlText, options );
          schemas[i] = XmlUtils.createXmlObject(xmlText, options);
          schemas[i].documentProperties().setSourceName(wsdlUrl);

          result.put(wsdlUrl + "@" + (i + 1), schemas[i]);
        }

        XmlObject[] wsdlImports = xmlObject.selectPath("declare namespace s='" + Constants.WSDL11_NS
                                                       + "' .//s:import/@location");
        for (int i = 0; i < wsdlImports.length; i++) {

          String location = ((SimpleValue) wsdlImports[i]).getStringValue();

          if (location != null) {
            if (!location.startsWith("file:") && location.indexOf("://") == -1) {
              location = joinRelativeUrl(wsdlUrl, location);
            }

            getSchemas(location, existing, loader, null);
          }
        }

        XmlObject[] wadl10Imports = xmlObject.selectPath("declare namespace s='" + Constants.WADL10_NS
                                                         + "' .//s:grammars/s:include/@href");
        for (int i = 0; i < wadl10Imports.length; i++) {
          String location = ((SimpleValue) wadl10Imports[i]).getStringValue();
          if (location != null) {
            if (!location.startsWith("file:") && location.indexOf("://") == -1) {
              location = joinRelativeUrl(wsdlUrl, location);
            }

            getSchemas(location, existing, loader, null);
          }
        }

        XmlObject[] wadlImports = xmlObject.selectPath("declare namespace s='" + Constants.WADL11_NS
                                                       + "' .//s:grammars/s:include/@href");
        for (int i = 0; i < wadlImports.length; i++) {
          String location = ((SimpleValue) wadlImports[i]).getStringValue();
          if (location != null) {
            if (!location.startsWith("file:") && location.indexOf("://") == -1) {
              location = joinRelativeUrl(wsdlUrl, location);
            }

            getSchemas(location, existing, loader, null);
          }
        }

      }

      existing.putAll(result);

      XmlObject[] schemas = result.values().toArray(new XmlObject[result.size()]);

      for (int c = 0; c < schemas.length; c++) {
        xmlObject = schemas[c];

        XmlObject[] schemaImports = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS
                                                         + "' .//s:import/@schemaLocation");
        for (int i = 0; i < schemaImports.length; i++) {
          String location = ((SimpleValue) schemaImports[i]).getStringValue();
          Element elm = ((Attr) schemaImports[i].getDomNode()).getOwnerElement();

          if (location != null && !defaultSchemas.containsKey(elm.getAttribute("namespace"))) {
            if (!location.startsWith("file:") && location.indexOf("://") == -1) {
              location = joinRelativeUrl(wsdlUrl, location);
            }

            getSchemas(location, existing, loader, null);
          }
        }

        XmlObject[] schemaIncludes = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS
                                                          + "' .//s:include/@schemaLocation");
        for (int i = 0; i < schemaIncludes.length; i++) {
          String location = ((SimpleValue) schemaIncludes[i]).getStringValue();
          if (location != null) {
            String targetNS = getTargetNamespace(xmlObject);

            if (!location.startsWith("file:") && location.indexOf("://") == -1) {
              location = joinRelativeUrl(wsdlUrl, location);
            }

            getSchemas(location, existing, loader, targetNS);
          }
        }
      }
    } catch (Exception e) {
      throw new SoapBuilderException(e);
    }
  }

  public static void getDefinitionParts(String origWsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader)
      throws Exception {
    String wsdlUrl = origWsdlUrl;
    if (existing.containsKey(wsdlUrl)) {
      return;
    }

    XmlObject xmlObject = loader.loadXmlObject(wsdlUrl, null);
    existing.put(wsdlUrl, xmlObject);
    // wsdlUrl = loader.getBaseURI();

    selectDefinitionParts(wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WSDL11_NS
                                                                + "' .//s:import/@location");
    selectDefinitionParts(wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WADL10_NS
                                                                + "' .//s:grammars/s:include/@href");
    selectDefinitionParts(wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.WADL11_NS
                                                                + "' .//s:grammars/s:include/@href");
    selectDefinitionParts(wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.XSD_NS
                                                                + "' .//s:import/@schemaLocation");
    selectDefinitionParts(wsdlUrl, existing, loader, xmlObject, "declare namespace s='" + Constants.XSD_NS
                                                                + "' .//s:include/@schemaLocation");
  }

  public static String joinRelativeUrl(String baseUrl, String url) {
    if (baseUrl.indexOf('?') > 0) {
      baseUrl = baseUrl.substring(0, baseUrl.indexOf('?'));
    }

    boolean isWindowsUrl = baseUrl.indexOf('\\') >= 0;
    boolean isUsedInUnix = File.separatorChar == '/';

    if (isUsedInUnix && isWindowsUrl) {
      baseUrl = baseUrl.replace('\\', '/');
      url = url.replace('\\', '/');
    }

    boolean isFile = baseUrl.startsWith("file:");

    int ix = baseUrl.lastIndexOf('\\');
    if (ix == -1) {
      ix = baseUrl.lastIndexOf('/');
    }

    // absolute?
    if (url.startsWith("/") && !isFile) {
      ix = baseUrl.indexOf("/", baseUrl.indexOf("//") + 2);
      return baseUrl.substring(0, ix) + url;
    }

    // remove leading "./"
    while (url.startsWith(".\\") || url.startsWith("./")) {
      url = url.substring(2);
    }

    // remove leading "../"
    while (url.startsWith("../") || url.startsWith("..\\")) {
      int ix2 = baseUrl.lastIndexOf('\\', ix - 1);
      if (ix2 == -1) {
        ix2 = baseUrl.lastIndexOf('/', ix - 1);
      }
      if (ix2 == -1) {
        break;
      }

      baseUrl = baseUrl.substring(0, ix2 + 1);
      ix = ix2;

      url = url.substring(3);
    }

    // remove "/./"
    while (url.indexOf("/./") != -1 || url.indexOf("\\.\\") != -1) {
      int ix2 = url.indexOf("/./");
      if (ix2 == -1) {
        ix2 = url.indexOf("\\.\\");
      }

      url = url.substring(0, ix2) + url.substring(ix2 + 2);
    }

    // remove "/../"
    while (url.indexOf("/../") != -1 || url.indexOf("\\..\\") != -1) {
      int ix2 = -1;

      int ix3 = url.indexOf("/../");
      if (ix3 == -1) {
        ix3 = url.indexOf("\\..\\");
        ix2 = url.lastIndexOf('\\', ix3 - 1);
      } else {
        ix2 = url.lastIndexOf('/', ix3 - 1);
      }

      if (ix2 == -1) {
        break;
      }

      url = url.substring(0, ix2) + url.substring(ix3 + 3);
    }

    String result = baseUrl.substring(0, ix + 1) + url;
    if (isFile) {
      result = result.replace('/', File.separatorChar);
    }

    return result;
  }

  private static void selectDefinitionParts(String wsdlUrl, Map<String, XmlObject> existing, SchemaLoader loader,
                                            XmlObject xmlObject, String path) throws Exception {
    XmlObject[] wsdlImports = xmlObject.selectPath(path);
    for (int i = 0; i < wsdlImports.length; i++) {
      String location = ((SimpleValue) wsdlImports[i]).getStringValue();
      if (location != null) {
        if (StringUtils.isNotBlank(location)) {
          if (!location.startsWith("file:") && location.indexOf("://") == -1) {
            location = joinRelativeUrl(wsdlUrl, location);
          }

          getDefinitionParts(location, existing, loader);
        } else {
          Node domNode = ((Attr) wsdlImports[i].getDomNode()).getOwnerElement();
          domNode.getParentNode().removeChild(domNode);
        }
      }
    }
  }

  /**
   * Extracts namespaces - used in tool integrations for mapping..
   */
  public static Collection<String> extractNamespaces(SchemaTypeSystem schemaTypes, boolean removeDefault) {
    Set<String> namespaces = new HashSet<String>();
    SchemaType[] globalTypes = schemaTypes.globalTypes();
    for (int c = 0; c < globalTypes.length; c++) {
      namespaces.add(globalTypes[c].getName().getNamespaceURI());
    }

    if (removeDefault) {
      namespaces.removeAll(defaultSchemas.keySet());
      namespaces.remove(Constants.SOAP11_ENVELOPE_NS);
      namespaces.remove(Constants.SOAP_ENCODING_NS);
    }

    return namespaces;
  }

  /**
   * Used when creating a TypeSystem from a complete collection of SchemaDocuments so that referenced types are not downloaded (again)
   */
  public static void removeImports(XmlObject xmlObject) throws XmlException {
    XmlObject[] imports = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:import");

    for (int c = 0; c < imports.length; c++) {
      XmlCursor cursor = imports[c].newCursor();
      cursor.removeXml();
      cursor.dispose();
    }

    XmlObject[] includes = xmlObject.selectPath("declare namespace s='" + Constants.XSD_NS + "' .//s:include");

    for (int c = 0; c < includes.length; c++) {
      XmlCursor cursor = includes[c].newCursor();
      cursor.removeXml();
      cursor.dispose();
    }
  }

}
TOP

Related Classes of com.centeractive.ws.legacy.SchemaUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.