Package com.sun.enterprise.jbi.serviceengine.util.soap

Source Code of com.sun.enterprise.jbi.serviceengine.util.soap.WSDLConverter

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.enterprise.jbi.serviceengine.util.soap;

import com.ibm.wsdl.extensions.soap.SOAPAddressImpl;
import com.ibm.wsdl.extensions.soap.SOAPBindingImpl;
import com.ibm.wsdl.extensions.soap.SOAPBodyImpl;
import com.ibm.wsdl.extensions.soap.SOAPFaultImpl;
import com.ibm.wsdl.extensions.soap.SOAPHeaderImpl;
import com.ibm.wsdl.extensions.soap.SOAPOperationImpl;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Part;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.extensions.ElementExtensible;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.ExtensionRegistry;
import javax.wsdl.extensions.soap.SOAPAddress;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.wsdl.extensions.soap.SOAPFault;
import javax.wsdl.extensions.soap.SOAPHeader;
import javax.wsdl.extensions.soap.SOAPOperation;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.wsdl.xml.WSDLWriter;
import javax.xml.namespace.QName;
import org.w3c.dom.Element;

/**
*
* Converts any non-SOAP WSDL to a SOAP WSDL.
*
* If the original WSDL is a SOAP WSDL then it is not modified.
*
* @author bhavanishankar@dev.java.net
*/
public class WSDLConverter {
   
    ExtensionRegistry extnReg;
    WSDLReader wsdlReader;
    WSDLWriter wsdlWriter;
   
    public static final String SOAP_NS = "http://schemas.xmlsoap.org/wsdl/soap/";
    public static final String SOAP_PREFIX = "soap";
    public static final String SOAP_BINDING_SUFFIX = "binding";
    public static final String SOAP_OPERATION_SUFFIX = "operation";
    public static final String SOAP_ADDRESS_SUFFIX = "address";
    public static final String SOAP_BODY_SUFFIX = "body";
    public static final String SOAP_HEADER_SUFFIX = "header";
    public static final String SOAP_FAULT_SUFFIX = "fault";
   
    public static final String SOAP_HTTP_TRANSPORT_URI = "http://schemas.xmlsoap.org/soap/http";
    public static final String SOAP_ADDRESS_LOCATION = "REPLACE_WITH_ACTUAL_URL";
   
    public static final String RPC_STYLE = "rpc";
    public static final String DOCUMENT_STYLE = "document";
    public static final String USE_LITERAL = "literal";
   
    public WSDLConverter() throws Exception {
       
        WSDLFactory factory = WSDLFactory.newInstance();
        wsdlReader = factory.newWSDLReader();
        wsdlWriter = factory.newWSDLWriter();
       
        extnReg = new ExtensionRegistry();
       
        extnReg.mapExtensionTypes(Binding.class,
                new QName(SOAP_NS,SOAP_BINDING_SUFFIX),
                SOAPBindingImpl.class);
       
        extnReg.mapExtensionTypes(ExtensibilityElement.class,
                new QName(SOAP_NS,SOAP_OPERATION_SUFFIX),
                SOAPOperationImpl.class);
       
        extnReg.mapExtensionTypes(ExtensibilityElement.class,
                new QName(SOAP_NS,SOAP_ADDRESS_SUFFIX),
                SOAPAddressImpl.class);
       
        extnReg.mapExtensionTypes(SOAPBody.class,
                new QName(SOAP_NS,SOAP_BODY_SUFFIX),
                SOAPBodyImpl.class);
       
        extnReg.mapExtensionTypes(SOAPHeader.class,
                new QName(SOAP_NS,SOAP_HEADER_SUFFIX),
                SOAPHeaderImpl.class);
       
        extnReg.mapExtensionTypes(SOAPFault.class,
                new QName(SOAP_NS,SOAP_FAULT_SUFFIX),
                SOAPFaultImpl.class);
       
    }
   
    private SOAPBinding createSoapBinding() throws Exception {
        SOAPBinding soapBinding = (SOAPBinding)extnReg.createExtension(Binding.class,
                new QName(SOAP_NS,SOAP_BINDING_SUFFIX));
        soapBinding.setTransportURI(SOAP_HTTP_TRANSPORT_URI);
        return soapBinding;
    }
   
    private SOAPAddress createSoapAddress() throws Exception {
        SOAPAddress soapAddress = (SOAPAddress)extnReg.createExtension(ExtensibilityElement.class,
                new QName(SOAP_NS,SOAP_ADDRESS_SUFFIX));
        soapAddress.setLocationURI(SOAP_ADDRESS_LOCATION);
        return soapAddress;
    }
   
    private SOAPOperation createSoapOperation() throws Exception {
        SOAPOperation soapOperation = (SOAPOperation)extnReg.createExtension(
                ExtensibilityElement.class,
                new QName(SOAP_NS, SOAP_OPERATION_SUFFIX));
        return soapOperation;
    }
   
    private SOAPBody createSoapBody() throws Exception {
        SOAPBody soapBody = (SOAPBody)extnReg.createExtension(
                SOAPBody.class,
                new QName(SOAP_NS, SOAP_BODY_SUFFIX));
        soapBody.setUse(USE_LITERAL);
        return soapBody;
    }
   
    private SOAPHeader createSoapHeader() throws Exception {
        SOAPHeader soapHeader = (SOAPHeader)extnReg.createExtension(
                SOAPHeader.class,
                new QName(SOAP_NS, SOAP_HEADER_SUFFIX));
        soapHeader.setUse(USE_LITERAL);
        return soapHeader;
    }
   
    private SOAPFault createSoapFault() throws Exception {
        SOAPFault soapFault = (SOAPFault)extnReg.createExtension(
                SOAPFault.class,
                new QName(SOAP_NS, SOAP_FAULT_SUFFIX));
        soapFault.setUse(USE_LITERAL);
        return soapFault;
    }
   
    /**
     * Style can be calculated by looking into how the input/output parts are defined.
     * Style can not be calculated by looking into fault.
     *
     * WS-I Basic Profile 1.0 :
     *
     * R2203   An rpc-literal binding in a DESCRIPTION MUST refer,
     * in its soapbind:body element(s), only to wsdl:part element(s)
     * that have been defined using the type attribute.
     *
     * R2204   A document-literal binding in a DESCRIPTION MUST refer,
     * in each of its soapbind:body element(s), only to wsdl:part element(s)
     * that have been defined using the element attribute.
     *
     */
    private String getStyle(Operation portTypeOperation) {
        try {
            if(portTypeOperation.getInput() != null) {
                List<Part> parts = portTypeOperation.getInput().getMessage().getOrderedParts(null);
                for(Part p : parts) {
                    if(p.getTypeName() != null) {
                        return RPC_STYLE;
                    }
                }
            }
            if(portTypeOperation.getOutput() != null) {
                List<Part> parts = portTypeOperation.getOutput().getMessage().getOrderedParts(null);
                for(Part p : parts) {
                    if(p.getTypeName() != null) {
                        return RPC_STYLE;
                    }
                }
            }
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        return DOCUMENT_STYLE;
    }
   
    private void processElement(
            ElementExtensible elementExtensible,
            Message message,
            String style) throws Exception {
        if(RPC_STYLE.equals(style)) {
            SOAPBody soapBody = createSoapBody();
            /**
             * namespace needs to be set in <soap:body> only for 'rpc' style.
             *
             * WS-I Basic Profile 1.0 :
             *
             * R2716   A document-literal binding in a DESCRIPTION MUST NOT have
             * the namespace  attribute specified on contained soapbind:body,
             * soapbind:header, soapbind:headerfault and  soapbind:fault elements.
             *
             * R2717 : An rpc-literal binding in a DESCRIPTION MUST have
             * the namespace attribute specified, the value of which MUST
             * be an absolute URI, on contained  soapbind:body elements.
             *
             * R2726   An rpc-literal binding in a DESCRIPTION MUST NOT have
             * the namespace attribute specified on contained soapbind:header,
             * soapbind:headerfault and soapbind:fault elements.
             *
             */
            soapBody.setNamespaceURI(
                    message.getQName().getNamespaceURI());
            elementExtensible.addExtensibilityElement(soapBody);
        } else {
            List<Part> orderedParts = message.getOrderedParts(null);
            boolean partBoundToBody = false; // only one part can be bound to <soap:body>.
            for(int i=orderedParts.size()-1; i>=0; i--) {
                Part p = orderedParts.get(i);
                if( (p.getElementName().getLocalPart().equals
                        (message.getQName().getLocalPart())) // wrapped doc/literal
                        || (i==0 && !partBoundToBody) // bare doc/literal
                        ) {
                    partBoundToBody = true;
                    SOAPBody soapBody = createSoapBody();
                    List<String> parts = new ArrayList<String>();
                    parts.add(p.getName());
                    soapBody.setParts(parts);
                    elementExtensible.addExtensibilityElement(soapBody);
                } else {
                    SOAPHeader soapHeader = createSoapHeader();
                    soapHeader.setPart(p.getName());
                    soapHeader.setMessage(message.getQName());
                    elementExtensible.addExtensibilityElement(soapHeader);
                }
            }
        }
        //return elementExtensible;
    }
   
    /**
     * Converts all <wsdl:service> sections.
     */
    private boolean convertServices(Definition defn) throws Exception  {
       
        boolean wsdlModified = false;
       
        Map<QName,Service> services = defn.getServices();
       
        if(services == null || services.isEmpty()) {
            return wsdlModified;
        }
       
        Service[] originalServices = services.values().toArray(new Service[0]);
       
        for(Service originalService : originalServices) {
           
            Map<String,Port> originalPorts = originalService.getPorts();
           
            boolean isSOAP = false;
            Service newService = defn.createService();
           
            for(String key : originalPorts.keySet()) {
               
                Port originalPort = originalPorts.get(key);
               
                /**
                 * Step1. Skip if it is already SOAP
                 */
                List<ExtensibilityElement> extList = originalPort.getExtensibilityElements();
                for(ExtensibilityElement extElem : extList) {
                    if(extElem instanceof SOAPAddress) {
                        isSOAP = true;
                        break;
                    }
                }
                if(isSOAP) {
                    continue;
                }
               
                wsdlModified = true;
               
                /**
                 * Step2. Collect the required information from
                 * the existing <wsdl:port>
                 */
                String originalPortName = originalPort.getName();
                Element originalPortDocElem = originalPort.getDocumentationElement();
                Binding originalBinding = originalPort.getBinding();
               
                /**
                 * Step3. Create a new port and add it to <wsdl:service>
                 *
                 *  <wsdl:port name="#name" binding="#tns:binding">
                 *      <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
                 </wsdl:port>
                 *
                 */
                Port newPort = defn.createPort();
                // Add -> name="#name"
                newPort.setName(originalPortName);
               
                // Add -> binding="#tns:binding"
                // Since 'originalBinding' might have been deleted already, so get the binding from defn
                newPort.setBinding(defn.getBinding(originalBinding.getQName()));
                newPort.setDocumentationElement(originalPortDocElem);
               
                // Add -> <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
                SOAPAddress soapAddress = createSoapAddress();
               
                //sa.setRequired(true);
                newPort.addExtensibilityElement(soapAddress);
               
                /**
                 * Step4. Add the newly created <wsdl:port> to <wsdl:service>.
                 */
                newService.setQName(originalService.getQName());
                newService.addPort(newPort);
            }
           
            if(!isSOAP) {
                defn.removeService(originalService.getQName());
                defn.addService(newService);
            }
        }
        return wsdlModified;
    }
   
    /**
     * Converts all <wsdl:binding> sections.
     */
    private boolean convertBindings(Definition defn) throws Exception {
       
        boolean wsdlModified = false;
       
        Map<QName,Binding> bindings = defn.getBindings();
       
        if(bindings == null || bindings.isEmpty()) {
            return wsdlModified;
        }
       
        Binding[] originalBindings = bindings.values().toArray(new Binding[0]);
       
        for(Binding originalBinding : originalBindings) {
           
            /**
             * Step 1. Skip if it is already SOAP
             */
            boolean isSOAP = false;
           
            List<ExtensibilityElement> extList = originalBinding.getExtensibilityElements();
            for(ExtensibilityElement extElem : extList) {
                if(extElem instanceof SOAPBinding) {
                    isSOAP = true;
                    break;
                }
            }
           
            if(isSOAP) {
                continue;
            }
           
            wsdlModified = true;
           
            /**
             * Step 2. Collect the required information from
             * the existing <wsdl:port>
             */
           
            PortType p = originalBinding.getPortType();
            QName originalBindingQname = originalBinding.getQName();
            List<BindingOperation> originalBindingOps = originalBinding.getBindingOperations();
           
           
            /**
             * Step 3. Create a new binding
             *
             *  <wsdl:binding name="#name" type="#type">
             *      <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
             *      <wsdl:operation name="#operation1">
             *          <soap:operation/>
             *          <wsdl:input>
             *              <soap:body use="literal" namespace="#namespace"/>
             *          </wsdl:input>
             *          <wsdl:output>
             *              <soap:body use="literal" namespace="#namespace"/>
             *          </wsdl:output>
             *          <wsdl:fault name="#faultname">
             *              <soap:fault name="#faultname" use="literal"/>
             *          </wsdl:fault>
             *          ...more faults...
             *      </wsdl:operation>
             *      ...more operations...
             *  </wsdl:binding>
             *
             */
            Binding newBinding = defn.createBinding();
            // Add -> name="#name"
            newBinding.setQName(originalBindingQname);
            // Add -> type="#type"
            newBinding.setPortType(p);
            newBinding.setUndefined(false);
           
            // Add -> <soap:binding tranport="http://schemas.xmlsoap.org/soap/http"
            SOAPBinding soapBinding = createSoapBinding();
            newBinding.addExtensibilityElement(soapBinding);
           
            /**
             * Add ->
             *
             *  <wsdl:operation name="#operation1">
             *      ....
             *  </wsdl:operation>
             *  ... more operations...
             *
             */
            String style = null;
           
            for(BindingOperation originalBindingOp : originalBindingOps) {
                BindingOperation newBindingOp = defn.createBindingOperation();
               
                newBindingOp.setOperation(originalBindingOp.getOperation());
                Operation portTypeOperation = newBindingOp.getOperation();
               
                /**
                 *
                 * Style should be set in <soap:binding/>, not in <soap:operation/>
                 *
                 * WS-I Basic Profile 1.0 :
                 *
                 * 5.6.3 Consistency of style Attribute :
                 *
                 * The style, "document" or "rpc", of an interaction is specified
                 * at the wsdl:operation level, permitting wsdl:bindings whose wsdl:operations
                 * have different styles. This has led to interoperability problems.
                 *
                 * R2705 A wsdl:binding in a DESCRIPTION MUST use either be a rpc-literal binding
                 * or a document-literal binding.
                 *
                 */
                if(style == null) {
                    style = getStyle(portTypeOperation);
                    if(RPC_STYLE.equals(style)) { // default style is 'document', no need to set.
                        soapBinding.setStyle(style);
                    }
                }
               
                // Add > name="#operation".
                newBindingOp.setName(originalBindingOp.getName());
                newBindingOp.setDocumentationElement(originalBindingOp.getDocumentationElement());
               
                // Add -> <soap:operation/>
                SOAPOperation soapOperation = createSoapOperation();
                newBindingOp.addExtensibilityElement(soapOperation);
               
                // Add -> <wsdl:input><soap:body use="literal" namespace="#namespace"/></wsdl:input>
                if(portTypeOperation.getInput() != null) {
                    BindingInput newBindingInput = defn.createBindingInput();
                    processElement(
                            newBindingInput,
                            portTypeOperation.getInput().getMessage(),
                            style);
                    newBindingOp.setBindingInput(newBindingInput);
                }
               
                // Add -> <wsdl:output><soap:body use="literal" namespace="#namespace"/></wsdl:output>
                if(portTypeOperation.getOutput() != null) {
                    BindingOutput newBindingOutput = defn.createBindingOutput();
                    processElement(
                            newBindingOutput,
                            portTypeOperation.getOutput().getMessage(),
                            style);
                    newBindingOp.setBindingOutput(newBindingOutput);
                }
               
                // Add -> <wsdl:fault name="faultname"><soap:fault use="literal" name="#faultname"/></wsdl:fault>....more faults...
                if(portTypeOperation.getFaults() != null) {
                    Map<String,Fault> faults = portTypeOperation.getFaults();
                    for(String faultName : faults.keySet()) {
                        BindingFault newBindingFault = defn.createBindingFault();
                        newBindingFault.setName(faultName);
                       
                        SOAPFault soapFault = createSoapFault();
                        soapFault.setName(faultName);
                       
                        newBindingFault.addExtensibilityElement(soapFault);
                        newBindingOp.addBindingFault(newBindingFault);
                    }
                }
               
                newBinding.addBindingOperation(newBindingOp);
            }
           
            /**
             * Step4. Replace the existing <wsdl:binding> with new one.
             */
            defn.removeBinding(originalBindingQname);
            defn.addBinding(newBinding);
        }
       
        return wsdlModified;
    }
   
    private void writeWSDL(Definition defn, String wsdl) throws Exception {
       
        defn.addNamespace(SOAP_PREFIX, SOAP_NS);
        /**
         * Take care of i18n while creating a FileWriter.
         */
        FileWriter fw = new FileWriter(wsdl);
        wsdlWriter.writeWSDL(defn, fw);
        fw.close();
    }
   
    public boolean convert(String wsdl) throws Exception {
       
        String wsdlLocationUri = new File(wsdl).toURI().toString();
       
        Definition defn = wsdlReader.readWSDL(wsdlLocationUri);
       
        boolean wsdlModified = false;
        /**
         * Modify the <wsdl:binding> sections.
         */
        wsdlModified = convertBindings(defn);
       
        /**
         * Modify the <wsdl:service> sections.
         */
        wsdlModified = convertServices(defn);
       
        if(wsdlModified) {
            System.out.println("Modified WSDL : " + wsdl);
            writeWSDL(defn, wsdl);
        }
       
        return wsdlModified;
    }
   
    List<String> listWSDLs(File baseDir) {
        List<String> files = new ArrayList();
        for(File f : baseDir.listFiles()) {
            if(f.isDirectory()) {
                files.addAll(listWSDLs(f));
            } else if(f.getAbsolutePath().endsWith("wsdl")) {
                files.add(f.getAbsolutePath());
            }
        }
        return files;
    }
   
    public List<String> convertAllWSDLs(String baseDir) {
        List<String> convertedWSDLs = new ArrayList<String>();
        List<String> wsdls = listWSDLs(new File(baseDir));
        for(String wsdl : wsdls) {
            try {
                if(convert(wsdl)) {
                    convertedWSDLs.add(wsdl.substring(baseDir.length() + 1));
                }
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        }
        System.out.println("BaseDir = " + baseDir + ", Converted WSDLs = " + convertedWSDLs);
        return convertedWSDLs;
    }
   
    public static List<String> convertWSDLs(String baseDir) {
        try {
            WSDLConverter converter = new WSDLConverter();
            return converter.convertAllWSDLs(baseDir);
        } catch(Exception ex) {
            ex.printStackTrace();
        }
        return new ArrayList<String>();
    }
   
    void print(String s) {
        System.out.println(s);
    }
   
   
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
       
        convertWSDLs("/tmp/wsdl");//System.getProperty("java.io.tmpdir"));
       
    }
   
   
}
TOP

Related Classes of com.sun.enterprise.jbi.serviceengine.util.soap.WSDLConverter

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.