/** * * 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.airavata.workflow.model.gpel.script; import java.util.List; import javax.xml.namespace.QName; import org.apache.airavata.common.exception.AiravataException; import org.apache.airavata.common.utils.WSConstants; import org.apache.airavata.common.utils.XMLUtil; import org.apache.airavata.workflow.model.component.ws.WSComponentPort; import org.apache.airavata.workflow.model.graph.GraphException; import org.apache.airavata.workflow.model.graph.Node; import org.apache.airavata.workflow.model.graph.system.InputNode; import org.apache.airavata.workflow.model.graph.system.ParameterNode; import org.apache.airavata.workflow.model.graph.system.SystemDataPort; import org.apache.airavata.workflow.model.graph.ws.WSGraph; import org.apache.airavata.workflow.model.utils.WorkflowConstants; import org.apache.airavata.workflow.model.wf.Workflow; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xmlpull.infoset.XmlElement; import org.xmlpull.infoset.XmlNamespace; //import xsul5.XmlConstants; //import xsul5.wsdl.WsdlDefinitions; //import xsul5.wsdl.WsdlDocumentation; //import xsul5.wsdl.WsdlMessage; //import xsul5.wsdl.WsdlPortType; //import xsul5.wsdl.WsdlPortTypeOperation; //import xsul5.wsdl.plnk.PartnerLinkRole; //import xsul5.wsdl.plnk.PartnerLinkType; public class WorkflowWSDL { /** * Run */ private String workflowOperationName; private static final String INPUT_MESSAGE_ELEMENT_SUFFIX = ""; private static final String OUTPUT_MESSAGE_ELEMENT_SUFFIX = "Response"; /** * Run */ private String workflowInputMessageElelmentName; /** * RunOutput */ private String workflowOutputMessageElementName; private static final String INPUT_MESSAGE_SUFFIX = "InputMessage"; private static final String OUTPUT_MESSAGE_SUFFIX = "OutputMessage"; /** * RunInputMessage */ private String workflowInputMessageName; /** * RunOutputMessage */ private String workflowOutputMessageName; /** * input */ public static final String INPUT_PART_NAME = "input"; /** * output */ public static final String OUTPUT_PART_NAME = "output"; private static final String TARGET_NS_NAME_PREFIX = WorkflowConstants.NS_URI_XBAYA; private static final String TYPE_SUFFIX = "Type"; private Workflow workflow; private WSGraph graph; // private WsdlDefinitions definitions; private XmlNamespace targetNamespace; private XmlNamespace typesNamespace; private QName portTypeQName; // private Map<QName, PartnerLinkRole> partnerLinkRoleMap; private static final Logger log = LoggerFactory.getLogger(WorkflowWSDL.class); /** * Constructs a WorkflowWsdl. * * @param workflow * @param operationName */ public WorkflowWSDL(Workflow workflow, String operationName) { this.workflow = workflow; this.graph = workflow.getGraph(); // this.partnerLinkRoleMap = new HashMap<QName, PartnerLinkRole>(); workflowOperationName = operationName; workflowInputMessageElelmentName = workflowOperationName + INPUT_MESSAGE_ELEMENT_SUFFIX; workflowOutputMessageElementName = workflowOperationName + OUTPUT_MESSAGE_ELEMENT_SUFFIX; workflowInputMessageName = workflowOperationName + INPUT_MESSAGE_SUFFIX; workflowOutputMessageName = workflowOperationName + OUTPUT_MESSAGE_SUFFIX; } // /** // * @return the WSLD definitions // */ // public WsdlDefinitions getWsdlDefinitions() { // return this.definitions; // } /** * @return The target namespace. */ public XmlNamespace getTargetNamespace() { return this.targetNamespace; } /** * @return The types namespace. typens:"http://..../xsd/" */ public XmlNamespace getTypesNamespace() { return this.typesNamespace; } /** * @return The portType QName. */ public QName getPortTypeQName() { return this.portTypeQName; } /** * Creates WSDL. * * @throws GraphException */ public void create() throws GraphException { try { // String targetNSName = TARGET_NS_NAME_PREFIX + this.graph.getID() + "/"; // this.targetNamespace = XmlConstants.BUILDER.newNamespace(WSConstants.TARGET_NS_PREFIX, targetNSName); // String typesNSName = targetNSName + "xsd/"; // this.typesNamespace = XmlConstants.BUILDER.newNamespace(WSConstants.TYPE_NS_PREFIX, typesNSName); // // this.definitions = new WsdlDefinitions(targetNSName); // this.definitions.xml().setAttributeValue(WSConstants.NAME_ATTRIBUTE, this.graph.getID()); // // this.definitions.xml().declareNamespace(this.targetNamespace); // this.definitions.xml().declareNamespace(this.typesNamespace); // this.definitions.xml().declareNamespace(WSConstants.XSD_NS); // this.definitions.xml().declareNamespace(PartnerLinkType.NS); // addDocumentation(); // addTypes(); // WsdlMessage inputMessage = createInputMessage(); // WsdlMessage outputMessage = createOutputMessage(); // createPortType(inputMessage, outputMessage); addComment(); } catch (RuntimeException e) { throw new GraphException(e); } } /** * @param servicePortTypeQName * @return PartnerLinkRole */ // public PartnerLinkRole getPartnerRoll(QName servicePortTypeQName) { // return this.partnerLinkRoleMap.get(servicePortTypeQName); // } /** * Adds a partnerLinkType. * * This method is called by BPELScript. * * @param partnerLinkTypeName * @param partnerRollName * @param servicePortTypeQName * @return PartnerLinkRole */ // public PartnerLinkRole addPartnerLinkTypeAndRoll(String partnerLinkTypeName, String partnerRollName, // QName servicePortTypeQName) { // PartnerLinkType partnerLinkType = new PartnerLinkType(partnerLinkTypeName); // PartnerLinkRole partnerRoll = new PartnerLinkRole(partnerRollName, servicePortTypeQName); // partnerLinkType.addRole(partnerRoll); // // declareNamespaceIfNecessary("p", servicePortTypeQName.getNamespaceURI(), true); // this.definitions.xml().addElement(partnerLinkType.xml()); // // this.partnerLinkRoleMap.put(servicePortTypeQName, partnerRoll); // return partnerRoll; // } /** * @param operationName * @param receiveNode * @return The portType added. */ // public WsdlPortType addReceivePortType(String operationName, ReceiveNode receiveNode) { // // // // <types> // // // // // <types> and <schema> have been defined. // XmlElement types = this.definitions.getTypes(); // XmlElement schema = types.element(WSConstants.SCHEMA_TAG); // // XmlElement sequence = setupParameterType(operationName, null, schema); // for (DataPort outputPort : receiveNode.getOutputPorts()) { // addParameter(receiveNode, (SystemDataPort) outputPort, sequence, schema); // } // // // // // <message> // // // String messageName = operationName + INPUT_MESSAGE_SUFFIX; // String partName = INPUT_PART_NAME; // String messageElementName = operationName + INPUT_MESSAGE_ELEMENT_SUFFIX; // WsdlMessage inputMessage = createMessage(messageName, partName, messageElementName); // // String portTypeName = operationName; // WsdlPortType portType = createPortType(portTypeName, operationName, inputMessage, null); // return portType; // } private void addComment() { // XmlComment comment = this.definitions.xml().newComment( // "\nThis document is automatically generated by " + WorkflowConstants.APPLICATION_NAME_ + " " // + ApplicationVersion.VERSION + ".\n"); // this.definitions.xml().insertChild(0, "\n"); // this.definitions.xml().insertChild(0, comment); // this.definitions.xml().insertChild(0, "\n"); } /** * Sets the documentation element. */ private void addDocumentation() { String description = this.workflow.getDescription(); // if (description != null) { // WsdlDocumentation documentation = new WsdlDocumentation(description); // this.definitions.setDocumentation(documentation); // } } /** * Adds the types element. * * @return The types element */ // private XmlElement addTypes() { // XmlElement types = this.definitions.getOrCreateTypes(); // // XmlElement schema = types.addElement(WSConstants.SCHEMA_TAG); // schema.setAttributeValue(WSConstants.TARGET_NAMESPACE_ATTRIBUTE, this.typesNamespace.getName()); // schema.setAttributeValue(WSConstants.XMLNS, WSConstants.XSD_NS_URI); // schema.setAttributeValue(WSConstants.ELEMENT_FORM_DEFAULT_ATTRIBUTE, WSConstants.UNQUALIFIED_VALUE); // List<InputNode> inputNodes = GraphUtil.getInputNodes(this.graph); //// XmlElement inputMetadata = this.graph.getInputMetadata(); //// addParameters(workflowInputMessageElelmentName, inputMetadata, inputNodes, schema); // //// List<OutputNode> outputNodes = GraphUtil.getOutputNodes(this.graph); //// XmlElement outputMetadata = this.graph.getOutputMetadata(); //// addParameters(workflowOutputMessageElementName, outputMetadata, outputNodes, schema); // // return types; // } private void addParameters(String name, XmlElement appinfo, List<? extends ParameterNode> nodes, XmlElement schema) { XmlElement sequence = setupParameterType(name, appinfo, schema); for (ParameterNode node : nodes) { addParameter(node, sequence, schema); } } /** * @param name * @param appinfo * @param schema * @return The sequence element. */ private XmlElement setupParameterType(String name, XmlElement appinfo, XmlElement schema) { XmlElement element = schema.addElement(WSConstants.ELEMENT_TAG); element.setAttributeValue(WSConstants.NAME_ATTRIBUTE, name); String type = name + TYPE_SUFFIX; element.setAttributeValue(WSConstants.TYPE_ATTRIBUTE, WSConstants.TYPE_NS_PREFIX + ":" + type); // add metadata if (appinfo != null) { XmlElement annotation = element.addElement(WSConstants.ANNOTATION_TAG); try { annotation.addElement(XMLUtil.deepClone(appinfo)); } catch (AiravataException e) { log.error(e.getMessage(), e); } } XmlElement complex = schema.addElement(WSConstants.COMPLEX_TYPE_TAG); complex.setAttributeValue(WSConstants.NAME_ATTRIBUTE, type); XmlElement sequence = complex.addElement(WSConstants.SEQUENCE_TAG); return sequence; } /** * Adds the parameter element. * * @param node * @param sequence * @param schema * @return The parameter element */ private XmlElement addParameter(ParameterNode node, XmlElement sequence, XmlElement schema) { XmlElement element; SystemDataPort port = node.getPort(); element = addParameter(node, port, sequence, schema); // // Annotation // String description = node.getDescription(); XmlElement appinfo = node.getMetadata(); // description if (description != null && description.trim().length() != 0) { XmlElement annotation = element.element(null, WSConstants.ANNOTATION_TAG, true); XmlElement documentation = annotation.addElement(WSConstants.DOCUMENTATION_TAG); documentation.setText(node.getDescription()); } // appinfo if (appinfo != null) { XmlElement annotation = element.element(null, WSConstants.ANNOTATION_TAG, true); try { annotation.addElement(XMLUtil.deepClone(appinfo)); } catch (AiravataException e) { log.error(e.getMessage(), e); } } // // Add default value if it's input. // if (node instanceof InputNode) { InputNode inputNode = (InputNode) node; Object value = inputNode.getDefaultValue(); if (value instanceof String) { element.setAttributeValue(WSConstants.DEFAULT_ATTRIBUTE, (String) value); } else if (value instanceof XmlElement) { // Add the default value in <annotation><default> because there // is no standard way. XmlElement valueElement = null; try { valueElement = XMLUtil.deepClone((XmlElement) value); } catch (AiravataException e) { log.error(e.getMessage(), e); } XmlElement annotation = element.element(null, WSConstants.ANNOTATION_TAG, true); XmlElement defaultElement = annotation.addElement(WSComponentPort.DEFAULT); defaultElement.addElement(valueElement); } } return element; } private XmlElement addParameter(Node node, SystemDataPort port, XmlElement sequence, XmlElement schema) { XmlElement element = sequence.addElement(WSConstants.ELEMENT_TAG); /*element.setAttributeValue(WSConstants.NAME_ATTRIBUTE, node.getID()); // // type // QName type = port.getType(); WSComponentPort componentPort = port.getWSComponentPort(); WsdlDefinitions wsdl = null; if (componentPort != null) { //FIXME // wsdl = componentPort.getComponent().getWSDL(); // type = declareTypeIfNecessary(wsdl, type); } int arrayDimension = port.getArrayDimension(); if (arrayDimension == 1) { String typeName = declareArrayType(schema, type, wsdl); type = new QName(this.typesNamespace.getName(), typeName); } else if (arrayDimension > 1) { // TODO throw new WorkflowRuntimeException("multi-dimentional arrays are not supported yet."); } if (WSConstants.XSD_ANY_TYPE.equals(type) && componentPort != null) { XmlElement elementElement = componentPort.getElement(); if (elementElement == null) { // Types are not defined anywhare. Leave it as xsd:any. setTypeAttribute(element, type); } else { // Copy the embedded type defition. XmlElement clonedElementElement = null; try { clonedElementElement = XMLUtil.deepClone(elementElement); } catch (UtilsException e) { e.printStackTrace(); } String typeString = clonedElementElement.attributeValue(WSConstants.TYPE_ATTRIBUTE); if (typeString == null) { for (Object child : clonedElementElement.children()) { if (child instanceof XmlElement) { ((XmlElement) child).setParent(null); } element.addChild(child); } } else { // The case when type is really xsd:any setTypeAttribute(element, type); } } } else { // The normal case. setTypeAttribute(element, type); }*/ return element; } private void setTypeAttribute(XmlElement element, QName type) { String namespaceURI = type.getNamespaceURI(); XmlNamespace namespace = element.lookupNamespaceByName(namespaceURI); element.setAttributeValue(WSConstants.TYPE_ATTRIBUTE, namespace.getPrefix() + ":" + type.getLocalPart()); } /** * @param serviceWSDL * @param paramType * @return The QName of the type. This QName always has prefix. */ // private QName declareTypeIfNecessary(WsdlDefinitions serviceWSDL, QName paramType) { // if (WSConstants.XSD_NS_URI.equals(paramType.getNamespaceURI())) { // // No need to define // return new QName(WSConstants.XSD_NS_URI, paramType.getLocalPart(), WSConstants.XSD_NS_PREFIX); // } // // // check if this type already exists in the workflow WSDL. // XmlElement typeDefinition = null; // try { // typeDefinition = WSDLUtil.getTypeDefinition(this.definitions, paramType); // // if (typeDefinition == null) { // // // now lets check whether there is an import in the service wsdl schema // // that would import this type, // // if so we would be done by just importing that schema // // typeDefinition = WSDLUtil.findTypeDefinitionInImports(serviceWSDL, paramType); // if (typeDefinition != null) { // XmlElement importEle = WSDLUtil.getImportContainingTypeDefinition(serviceWSDL, paramType); // addImportIfNecessary(importEle); // String prefix = declareNamespaceIfNecessary(paramType.getPrefix(), paramType.getNamespaceURI(), // false); // return new QName(paramType.getNamespaceURI(), paramType.getLocalPart(), prefix); // } // // // copy the type defition and use it. // // // Need to copy the whole schema because it might have different // // targetNamespace. // XmlElement newSchema = WSDLUtil.getSchema(serviceWSDL, paramType); // if (newSchema == null) { // // This should have been caught in WSComponent // throw new WorkflowRuntimeException("could not find definition for type " + paramType + " in " // + WSDLUtil.getWSDLQName(serviceWSDL)); // } // this.definitions.getTypes().addChild(XMLUtil.deepClone(newSchema)); // // String prefix = declareNamespaceIfNecessary(paramType.getPrefix(), paramType.getNamespaceURI(), false); // return new QName(paramType.getNamespaceURI(), paramType.getLocalPart(), prefix); // } else { // XmlNamespace namespace = this.definitions.xml().lookupNamespaceByName(paramType.getNamespaceURI()); // return new QName(paramType.getNamespaceURI(), paramType.getLocalPart(), namespace.getPrefix()); // } // } catch (UtilsException e) { // log.error(e.getMessage(), e); // } // return null; // } // private void addImportIfNecessary(XmlElement importEle) { // XmlElement schema = this.definitions.getTypes().element(WSConstants.SCHEMA_TAG); // Iterable<XmlElement> imports = schema.elements(null, WSConstants.IMPORT_TAG); // for (XmlElement importElement : imports) { // if (importElement.attributeValue("namespace").equals(importEle.attributeValue("namespace")) // && importElement.attributeValue("schemaLocation") // .equals(importEle.attributeValue("schemaLocation"))) { // return; // } // } // schema.addChild(0, importEle); // } // private String declareArrayType(XmlElement schema, QName valueType, WsdlDefinitions serviceWSDL) { // XmlElement complexType = schema.addElement(WSConstants.COMPLEX_TYPE_TAG); // String typeName = valueType.getLocalPart() + "ArrayType"; // // TODO check if this typeName is already used. // complexType.setAttributeValue(WSConstants.NAME_ATTRIBUTE, typeName); // XmlElement sequence = complexType.addElement(WSConstants.SEQUENCE_TAG); // XmlElement element = sequence.addElement(WSConstants.ELEMENT_TAG); // element.setAttributeValue(WSConstants.MIN_OCCURS_ATTRIBUTE, "0"); // element.setAttributeValue(WSConstants.MAX_OCCURS_ATTRIBUTE, WSConstants.UNBOUNDED_VALUE); // element.setAttributeValue(WSConstants.NAME_ATTRIBUTE, "value"); // valueType = declareTypeIfNecessary(serviceWSDL, valueType); // element.setAttributeValue(WSConstants.TYPE_ATTRIBUTE, valueType.getPrefix() + ":" + valueType.getLocalPart()); // return typeName; // } // /** // * Creates the input message. // * // * @return The input message // */ // private WsdlMessage createInputMessage() { // return createMessage(workflowInputMessageName, INPUT_PART_NAME, workflowInputMessageElelmentName); // } // // /** // * Creates the output message. // * // * @return The output message // */ // private WsdlMessage createOutputMessage() { // return createMessage(workflowOutputMessageName, OUTPUT_PART_NAME, workflowOutputMessageElementName); // } // // private WsdlMessage createMessage(String messageName, String partName, String messageElementName) { // WsdlMessage outMessage = this.definitions.addMessage(messageName); // outMessage.addPartWithElement(partName, new QName(this.typesNamespace.getName(), messageElementName, // this.typesNamespace.getPrefix())); // return outMessage; // } // // /** // * Creates the portType. // * // * @param inputMessage // * @param outputMessage // * @return The portType // */ // private WsdlPortType createPortType(WsdlMessage inputMessage, WsdlMessage outputMessage) { // String portTypeName = this.graph.getID(); // this.portTypeQName = new QName(this.targetNamespace.getName(), portTypeName); // return createPortType(this.graph.getID(), workflowOperationName, inputMessage, outputMessage); // } // // private WsdlPortType createPortType(String portTypeName, String operationName, WsdlMessage inputMessage, // WsdlMessage outputMessage) { // WsdlPortType portType = this.definitions.addPortType(portTypeName); // WsdlPortTypeOperation operation = portType.addOperation(operationName); // if (inputMessage != null) { // operation.setInput(inputMessage); // } // if (outputMessage != null) { // operation.setOutput(outputMessage); // } // return portType; // } // // private String declareNamespaceIfNecessary(String prefixCandidate, String uri, boolean alwaysUseSuffix) { // XmlNamespace namespace = this.definitions.xml().lookupNamespaceByName(uri); // if (namespace == null) { // return declareNamespace(prefixCandidate, uri, alwaysUseSuffix); // } else { // return namespace.getPrefix(); // } // } // // /** // * @param prefixCandidate // * @param uri // * @param alwaysUseSuffix // * @return The prefix actually used. // */ // private String declareNamespace(String prefixCandidate, String uri, boolean alwaysUseSuffix) { // if (prefixCandidate == null || prefixCandidate.length() == 0) { // prefixCandidate = "a"; // } // String prefix = prefixCandidate; // if (alwaysUseSuffix) { // prefix += "0"; // } // if (this.definitions.xml().lookupNamespaceByPrefix(prefix) != null) { // int i = 1; // prefix = prefixCandidate + i; // while (this.definitions.xml().lookupNamespaceByPrefix(prefix) != null) { // i++; // } // } // this.definitions.xml().declareNamespace(prefix, uri); // return prefix; // } /** * Returns the workflowOperationName. * * @return The workflowOperationName */ public String getWorkflowOperationName() { return this.workflowOperationName; } /** * Sets workflowOperationName. * * @param workflowOperationName * The workflowOperationName to set. */ public void setWorkflowOperationName(String workflowOperationName) { this.workflowOperationName = workflowOperationName; } /** * Returns the workflowInputMessageName. * * @return The workflowInputMessageName */ public String getWorkflowInputMessageName() { return this.workflowInputMessageName; } /** * Sets workflowInputMessageName. * * @param workflowInputMessageName * The workflowInputMessageName to set. */ public void setWorkflowInputMessageName(String workflowInputMessageName) { this.workflowInputMessageName = workflowInputMessageName; } /** * Returns the workflowOutputMessageName. * * @return The workflowOutputMessageName */ public String getWorkflowOutputMessageName() { return this.workflowOutputMessageName; } /** * Sets workflowOutputMessageName. * * @param workflowOutputMessageName * The workflowOutputMessageName to set. */ public void setWorkflowOutputMessageName(String workflowOutputMessageName) { this.workflowOutputMessageName = workflowOutputMessageName; } /** * Returns the workflowInputMessageElelmentName. * * @return The workflowInputMessageElelmentName */ public String getWorkflowInputMessageElelmentName() { return this.workflowInputMessageElelmentName; } /** * Sets workflowInputMessageElelmentName. * * @param workflowInputMessageElelmentName * The workflowInputMessageElelmentName to set. */ public void setWorkflowInputMessageElelmentName(String workflowInputMessageElelmentName) { this.workflowInputMessageElelmentName = workflowInputMessageElelmentName; } /** * Returns the workflowOutputMessageElementName. * * @return The workflowOutputMessageElementName */ public String getWorkflowOutputMessageElementName() { return this.workflowOutputMessageElementName; } /** * Sets workflowOutputMessageElementName. * * @param workflowOutputMessageElementName * The workflowOutputMessageElementName to set. */ public void setWorkflowOutputMessageElementName(String workflowOutputMessageElementName) { this.workflowOutputMessageElementName = workflowOutputMessageElementName; } }