Package org.apache.tuscany.idl.wsdl

Source Code of org.apache.tuscany.idl.wsdl.WSDLOperation

/*
* 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.tuscany.idl.wsdl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import javax.wsdl.Fault;
import javax.wsdl.Input;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Output;
import javax.wsdl.Part;
import javax.xml.namespace.QName;

import org.apache.tuscany.spi.idl.ElementInfo;
import org.apache.tuscany.spi.idl.InvalidServiceContractException;
import org.apache.tuscany.spi.idl.TypeInfo;
import org.apache.tuscany.spi.idl.WrapperInfo;
import org.apache.tuscany.spi.model.DataType;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaObject;
import org.apache.ws.commons.schema.XmlSchemaObjectCollection;
import org.apache.ws.commons.schema.XmlSchemaParticle;
import org.apache.ws.commons.schema.XmlSchemaSequence;
import org.apache.ws.commons.schema.XmlSchemaSimpleType;
import org.apache.ws.commons.schema.XmlSchemaType;

/**
* Metadata for a WSDL operation
*/
public class WSDLOperation {
    private static final String OPERATION_KEY = org.apache.tuscany.spi.model.Operation.class.getName();

    protected XMLSchemaRegistry schemaRegistry;

    protected Operation operation;

    private String dataBinding;

    protected org.apache.tuscany.spi.model.Operation<QName> operationModel;

    protected DataType<List<DataType<QName>>> inputType;

    protected DataType<QName> outputType;

    protected List<DataType<QName>> faultTypes;

    /**
     * @param operation The WSDL4J operation
     * @param dataBinding The default databinding
     * @param schemaRegistry The XML Schema registry
     */
    public WSDLOperation(Operation operation, String dataBinding, XMLSchemaRegistry schemaRegistry) {
        super();
        this.operation = operation;
        this.dataBinding = dataBinding;
        this.schemaRegistry = schemaRegistry;
        this.wrapper = new Wrapper();
    }

    private Wrapper wrapper;

    private Boolean wrapperStyle;

    /**
     * Test if the operation qualifies wrapper style as defined by the JAX-WS 2.0 spec
     *
     * @return true if the operation qualifies wrapper style, otherwise false
     */
    public boolean isWrapperStyle() {
        if (wrapperStyle == null) {
            wrapperStyle =
                    Boolean.valueOf(wrapper.getInputChildElements() != null
                            && (operation.getOutput() == null || wrapper.getOutputChildElements() != null));
        }
        return wrapperStyle.booleanValue();
    }

    public Wrapper getWrapper() {
        if (!isWrapperStyle()) {
            throw new IllegalStateException("The operation is not wrapper style.");
        } else {
            return wrapper;
        }
    }

    /**
     * @return
     * @throws InvalidServiceContractException
     */
    public DataType<List<DataType<QName>>> getInputType() throws InvalidServiceContractException {
        if (inputType == null) {
            Input input = operation.getInput();
            Message message = (input == null) ? null : input.getMessage();
            inputType = getMessageType(message);
            inputType.setDataBinding("idl:input");
        }
        return inputType;
    }

    /**
     * @return
     * @throws NotSupportedWSDLException
     */
    public DataType<QName> getOutputType() throws InvalidServiceContractException {
        if (outputType == null) {
            Output output = operation.getOutput();
            Message outputMsg = (output == null) ? null : output.getMessage();

            List outputParts = (outputMsg == null) ? null : outputMsg.getOrderedParts(null);
            if (outputParts != null && outputParts.size() > 0) {
                if (outputParts.size() > 1) {
                    // We don't support output with multiple parts
                    throw new NotSupportedWSDLException("Multi-part output is not supported");
                }
                Part part = (Part) outputParts.get(0);
                outputType = new WSDLPart(part).getDataType();
                // outputType.setMetadata(WSDLOperation.class.getName(), this);
            }
        }
        return outputType;
    }

    /**
     * @return
     * @throws NotSupportedWSDLException
     */
    public List<DataType<QName>> getFaultTypes() throws InvalidServiceContractException {
        if (faultTypes == null) {
            Collection faults = operation.getFaults().values();
            faultTypes = new ArrayList<DataType<QName>>();
            for (Object f : faults) {
                Fault fault = (Fault) f;
                Message faultMsg = fault.getMessage();
                List faultParts = faultMsg.getOrderedParts(null);
                if (faultParts.size() != 1) {
                    throw new NotSupportedWSDLException("The fault message MUST have a single part");
                }
                Part part = (Part) faultParts.get(0);
                WSDLPart wsdlPart = new WSDLPart(part);
                faultTypes.add(wsdlPart.getDataType());
            }
        }
        return faultTypes;
    }

    private DataType<List<DataType<QName>>> getMessageType(Message message) throws InvalidServiceContractException {
        List<DataType<QName>> partTypes = new ArrayList<DataType<QName>>();
        if (message != null) {
            Collection parts = message.getOrderedParts(null);
            for (Object p : parts) {
                WSDLPart part = new WSDLPart((Part) p);
                DataType<QName> partType = part.getDataType();
                partTypes.add(partType);
            }
        }
        return new DataType<List<DataType<QName>>>(dataBinding, Object[].class, partTypes);
    }

    /**
     * @return
     * @throws NotSupportedWSDLException
     */
    public org.apache.tuscany.spi.model.Operation<QName> getOperation() throws InvalidServiceContractException {
        if (operationModel == null) {
            boolean oneway = (operation.getOutput() == null);
            operationModel =
                    new org.apache.tuscany.spi.model.Operation<QName>(operation.getName(), getInputType(),
                            getOutputType(), getFaultTypes(), oneway, dataBinding);
            operationModel.setWrapperStyle(isWrapperStyle());
            // operationModel.setMetaData(WSDLOperation.class.getName(), this);
            if (isWrapperStyle()) {
                operationModel.setWrapper(getWrapper().getWrapperInfo());
                // Register the operation with the types
                for (DataType<?> d : wrapper.getUnwrappedInputType().getLogical()) {
                    d.setMetadata(OPERATION_KEY, operationModel);
                }
                if (wrapper.getUnwrappedOutputType() != null) {
                    wrapper.getUnwrappedOutputType().setMetadata(OPERATION_KEY, operationModel);
                }
            }
        }
        inputType.setMetadata(OPERATION_KEY, operationModel);
        if (outputType != null) {
            outputType.setMetadata(OPERATION_KEY, operationModel);
        }
        return operationModel;
    }

    /**
     * Metadata for a WSDL part
     */
    public class WSDLPart {
        private Part part;

        private XmlSchemaElement element;

        private DataType<QName> dataType;

        public WSDLPart(Part part) throws InvalidWSDLException {
            this.part = part;
            QName elementName = part.getElementName();
            if (elementName != null) {
                element = schemaRegistry.getElement(elementName);
                if (element == null) {
                    throw new InvalidWSDLException("Element cannot be resolved: " + elementName);
                }
            } else {
                // Create an faked XSD element to host the metadata
                element = new XmlSchemaElement();
                element.setName(part.getName());
                element.setQName(new QName(null, part.getName()));
                QName typeName = part.getTypeName();
                if (typeName != null) {
                    XmlSchemaType type = schemaRegistry.getType(typeName);
                    if (type == null) {
                        throw new InvalidWSDLException("Type cannot be resolved: " + typeName);
                    }
                    element.setSchemaType(type);
                    element.setSchemaTypeName(type.getQName());
                }
            }
            dataType = new DataType<QName>(dataBinding, Object.class, element.getQName());
            // dataType.setMetadata(WSDLPart.class.getName(), this);
            dataType.setMetadata(ElementInfo.class.getName(), getElementInfo(element));
        }

        /**
         * @return the element
         */
        public XmlSchemaElement getElement() {
            return element;
        }

        /**
         * @return the part
         */
        public Part getPart() {
            return part;
        }

        /**
         * @return the dataType
         */
        public DataType<QName> getDataType() {
            return dataType;
        }
    }

    /**
     * The "Wrapper Style" WSDL operation is defined by The Java API for XML-Based Web Services (JAX-WS) 2.0
     * specification, section 2.3.1.2 Wrapper Style.
     * <p>
     * A WSDL operation qualifies for wrapper style mapping only if the following criteria are met:
     * <ul>
     * <li>(i) The operation�s input and output messages (if present) each contain only a single part
     * <li>(ii) The input message part refers to a global element declaration whose localname is equal to the operation
     * name
     * <li>(iii) The output message part refers to a global element declaration
     * <li>(iv) The elements referred to by the input and output message parts (henceforth referred to as wrapper
     * elements) are both complex types defined using the xsd:sequence compositor
     * <li>(v) The wrapper elements only contain child elements, they must not contain other structures such as
     * wildcards (element or attribute), xsd:choice, substitution groups (element references are not permitted) or
     * attributes; furthermore, they must not be nillable.
     * </ul>
     */
    public class Wrapper {
        private XmlSchemaElement inputWrapperElement;

        private XmlSchemaElement outputWrapperElement;

        private List<XmlSchemaElement> inputElements;

        private List<XmlSchemaElement> outputElements;

        private DataType<List<DataType<QName>>> unwrappedInputType;

        private DataType<QName> unwrappedOutputType;
       
        private transient WrapperInfo wrapperInfo;

        private List<XmlSchemaElement> getChildElements(XmlSchemaElement element) {
            if (element == null) {
                return null;
            }
            XmlSchemaType type = element.getSchemaType();
            if (!(type instanceof XmlSchemaComplexType)) {
                // Has to be a complexType
                return null;
            }
            XmlSchemaComplexType complexType = (XmlSchemaComplexType) type;
            if (complexType.getAttributes().getCount() != 0 || complexType.getAnyAttribute() != null) {
                // No attributes
                return null;
            }
            XmlSchemaParticle particle = complexType.getParticle();
            if (particle == null) {
                // No particle
                return Collections.emptyList();
            }
            if (!(particle instanceof XmlSchemaSequence)) {
                return null;
            }
            XmlSchemaSequence sequence = (XmlSchemaSequence) complexType.getParticle();
            XmlSchemaObjectCollection items = sequence.getItems();
            List<XmlSchemaElement> childElements = new ArrayList<XmlSchemaElement>();
            for (int i = 0; i < items.getCount(); i++) {
                XmlSchemaObject schemaObject = items.getItem(i);
                if (!(schemaObject instanceof XmlSchemaElement)) {
                    return null;
                }
                XmlSchemaElement childElement = (XmlSchemaElement) schemaObject;
                if (childElement.getName() == null || childElement.getRefName() != null || childElement.isNillable()) {
                    return null;
                }
                // TODO: Do we support maxOccurs >1 ?
                if (childElement.getMaxOccurs() > 1) {
                    return null;
                }
                childElements.add(childElement);
            }
            return childElements;
        }

        /**
         * Return a list of child XSD elements under the wrapped request element
         *
         * @return a list of child XSD elements or null if if the request element is not wrapped
         */
        public List<XmlSchemaElement> getInputChildElements() {
            if (inputElements != null) {
                return inputElements;
            }
            Input input = operation.getInput();
            if (input != null) {
                Message inputMsg = input.getMessage();
                Collection parts = inputMsg.getParts().values();
                if (parts.size() != 1) {
                    return null;
                }
                Part part = (Part) parts.iterator().next();
                QName elementName = part.getElementName();
                if (elementName == null) {
                    return null;
                }
                if (!operation.getName().equals(elementName.getLocalPart())) {
                    return null;
                }
                inputWrapperElement = schemaRegistry.getElement(elementName);
                if (inputWrapperElement == null) {
                    return null;
                }
                inputElements = getChildElements(inputWrapperElement);
                return inputElements;
            } else {
                return null;
            }
        }

        /**
         * Return a list of child XSD elements under the wrapped response element
         *
         * @return a list of child XSD elements or null if if the response element is not wrapped
         */
        public List<XmlSchemaElement> getOutputChildElements() {
            if (outputElements != null) {
                return outputElements;
            }
            Output output = operation.getOutput();
            if (output != null) {
                Message outputMsg = output.getMessage();
                Collection parts = outputMsg.getParts().values();
                if (parts.size() != 1) {
                    return null;
                }
                Part part = (Part) parts.iterator().next();
                QName elementName = part.getElementName();
                if (elementName == null) {
                    return null;
                }
                outputWrapperElement = schemaRegistry.getElement(elementName);
                if (outputWrapperElement == null) {
                    return null;
                }
                outputElements = getChildElements(outputWrapperElement);
                // FIXME: Do we support multiple child elements for the response?
                return outputElements;
            } else {
                return null;
            }
        }

        /**
         * @return the inputWrapperElement
         */
        public XmlSchemaElement getInputWrapperElement() {
            return inputWrapperElement;
        }

        /**
         * @return the outputWrapperElement
         */
        public XmlSchemaElement getOutputWrapperElement() {
            return outputWrapperElement;
        }

        public DataType<List<DataType<QName>>> getUnwrappedInputType() {
            if (unwrappedInputType == null) {
                List<DataType<QName>> childTypes = new ArrayList<DataType<QName>>();
                for (XmlSchemaElement element : getInputChildElements()) {
                    DataType<QName> type = new DataType<QName>(dataBinding, Object.class, element.getQName());
                    type.setMetadata(ElementInfo.class.getName(), getElementInfo(element));
                    childTypes.add(type);
                }
                unwrappedInputType =
                        new DataType<List<DataType<QName>>>("idl:unwrapped.input", Object[].class, childTypes);
            }
            return unwrappedInputType;
        }

        public DataType<QName> getUnwrappedOutputType() throws InvalidServiceContractException {
            if (unwrappedOutputType == null) {
                List<XmlSchemaElement> elements = getOutputChildElements();
                if (elements != null && elements.size() > 0) {
                    if (elements.size() > 1) {
                        // We don't support output with multiple parts
                        throw new NotSupportedWSDLException("Multi-part output is not supported");
                    }
                    XmlSchemaElement element = elements.get(0);
                    unwrappedOutputType = new DataType<QName>(dataBinding, Object.class, element.getQName());
                    unwrappedOutputType.setMetadata(ElementInfo.class.getName(), getElementInfo(element));
                }
            }
            return unwrappedOutputType;
        }

        public WrapperInfo getWrapperInfo() throws InvalidServiceContractException {
            if (wrapperInfo == null) {
                ElementInfo in = getElementInfo(getInputWrapperElement());
                ElementInfo out = getElementInfo(getOutputWrapperElement());
                List<ElementInfo> inChildren = new ArrayList<ElementInfo>();
                for (XmlSchemaElement e : getInputChildElements()) {
                    inChildren.add(getElementInfo(e));
                }
                List<ElementInfo> outChildren = new ArrayList<ElementInfo>();
                if (out != null) {
                    for (XmlSchemaElement e : getOutputChildElements()) {
                        outChildren.add(getElementInfo(e));
                    }
                }
                wrapperInfo =
                        new WrapperInfo(in, out, inChildren, outChildren, getUnwrappedInputType(), getUnwrappedOutputType());
            }
            return wrapperInfo;
        }
    }

    private static ElementInfo getElementInfo(XmlSchemaElement element) {
        if (element == null) {
            return null;
        }
        return new ElementInfo(element.getQName(), getTypeInfo(element.getSchemaType()));
    }

    private static TypeInfo getTypeInfo(XmlSchemaType type) {
        if (type == null) {
            return null;
        }
        XmlSchemaType baseType = (XmlSchemaType) type.getBaseSchemaType();
        QName name = type.getQName();
        boolean simple = (type instanceof XmlSchemaSimpleType);
        if (baseType == null) {
            return new TypeInfo(name, simple, null);
        } else {
            return new TypeInfo(name, simple, getTypeInfo(baseType));
        }
    }

}
TOP

Related Classes of org.apache.tuscany.idl.wsdl.WSDLOperation

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.