From e5b7380c874745c989d1816b8f552504f038e1bc Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 26 Sep 2013 20:33:20 +0000 Subject: 2.0 branch for possible maintenance release git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1526672 13f79535-47bb-0310-9956-ffa450edef68 --- .../binding/ws/wsdlgen/BindingWSDLGenerator.java | 372 ++++++ .../ws/wsdlgen/Interface2WSDLGenerator.java | 1185 ++++++++++++++++++++ .../binding/ws/wsdlgen/WSDLContractBuilder.java | 96 ++ .../ws/wsdlgen/WSDLDefinitionGenerator.java | 340 ++++++ .../ws/wsdlgen/WSDLGenerationException.java | 54 + .../binding/ws/wsdlgen/WSDLServiceGenerator.java | 546 +++++++++ .../ws/wsdlgen/WebServiceBindingBuilder.java | 109 ++ 7 files changed, 2702 insertions(+) create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/BindingWSDLGenerator.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/Interface2WSDLGenerator.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLContractBuilder.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLDefinitionGenerator.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLGenerationException.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLServiceGenerator.java create mode 100644 sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WebServiceBindingBuilder.java (limited to 'sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org') diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/BindingWSDLGenerator.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/BindingWSDLGenerator.java new file mode 100644 index 0000000000..b66ac4e370 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/BindingWSDLGenerator.java @@ -0,0 +1,372 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.wsdl.Definition; +import javax.wsdl.PortType; +import javax.wsdl.WSDLException; +import javax.wsdl.xml.WSDLWriter; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ResolverExtension; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.InvalidInterfaceException; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicySubject; +import org.apache.tuscany.sca.xsd.XSDFactory; + +/** + * @version $Rev$ $Date$ + */ +public class BindingWSDLGenerator { + private static final Logger logger = Logger.getLogger(BindingWSDLGenerator.class.getName()); + private static final QName SOAP12_INTENT = new QName("http://docs.oasis-open.org/ns/opencsa/sca/200912", "SOAP.v1_2"); + + public static boolean printWSDL; // external code sets this to print generated WSDL + + private BindingWSDLGenerator() { + // this class has static methods only and cannot be instantiated + } + + /** + * Log a warning message. + * @param problem + */ + private static void logWarning(Problem problem) { + Logger problemLogger = Logger.getLogger(problem.getSourceClassName(), problem.getResourceBundleName()); + if (problemLogger != null){ + problemLogger.logp(Level.WARNING, problem.getSourceClassName(), null, problem.getMessageId(), problem.getMessageParams()); + } else { + logger.severe("Can't get logger " + problem.getSourceClassName()+ " with bundle " + problem.getResourceBundleName()); + } + } + + /** + * Report a warning. + * @param message + * @param binding + * @param parameters + */ + private static void warning(Monitor monitor, String message, WebServiceBinding wsBinding, String... messageParameters) { + Problem problem = monitor.createProblem(BindingWSDLGenerator.class.getName(), "wsdlgen-validation-messages", Severity.WARNING, wsBinding, message, (Object[])messageParameters); + if (monitor != null) { + monitor.problem(problem); + } else { + logWarning(problem); + } + } + + /** + * Report an error. + * @param message + * @param binding + * @param parameters + */ + private static void error(Monitor monitor, String message, WebServiceBinding wsBinding, String... messageParameters) { + Problem problem = monitor.createProblem(BindingWSDLGenerator.class.getName(), "wsdlgen-validation-messages", Severity.ERROR, wsBinding, message, (Object[])messageParameters); + if (monitor != null) { + monitor.problem(problem); + } else { + throw new WSDLGenerationException(problem.toString(), null, problem); + } + } + + /** + * Report an exception error. + * @param message + * @param binding + * @param exception + */ + private static void error(Monitor monitor, String message, WebServiceBinding wsBinding, Exception ex) { + Problem problem = monitor.createProblem(BindingWSDLGenerator.class.getName(), "wsdlgen-validation-messages", Severity.ERROR, wsBinding, message, ex); + if (monitor != null) { + monitor.problem(problem); + } else { + throw new WSDLGenerationException(problem.toString(), ex, problem); + } + } + + /** + * Report a fatal error. + * @param message + * @param binding + * @param exception + */ + private static void fatal(Monitor monitor, String message, WebServiceBinding wsBinding, String... messageParameters) { + Problem problem = monitor.createProblem(BindingWSDLGenerator.class.getName(), "wsdlgen-validation-messages", Severity.ERROR,wsBinding, message, (Object[])messageParameters); + throw new WSDLGenerationException(problem.toString(), null, problem); + } + + /** + * Report a fatal exception error. + * @param message + * @param binding + * @param exception + */ + private static void fatal(Monitor monitor, String message, WebServiceBinding wsBinding, Exception ex) { + Problem problem = monitor.createProblem(BindingWSDLGenerator.class.getName(), "wsdlgen-validation-messages", Severity.ERROR, wsBinding, message, ex); + throw new WSDLGenerationException(problem.toString(), ex, problem); + } + + /** + * This method can be called from the binding builder or from the runtime. + * Report problems and exceptions in the most appropriate way for both + * of these cases. + */ + public static void generateWSDL(Component component, + Contract contract, + WebServiceBinding wsBinding, + ExtensionPointRegistry extensionPoints, + Monitor monitor) { + if (monitor == null) { + monitor = new BuilderContext(extensionPoints).getMonitor(); + } + try { + createWSDLDocument(component, contract, wsBinding, extensionPoints, monitor); + } catch (WSDLGenerationException ex) { + if (ex.getProblem() != null) { + warning(monitor, "WsdlGenProblem", wsBinding, component.getName(), contract.getName()); + if (monitor != null) { + monitor.problem(ex.getProblem()); + } else { + throw ex; + } + } else if (ex.getCause() instanceof Exception) { + warning(monitor, "WsdlGenException", wsBinding, component.getName(), contract.getName()); + error(monitor, "WsdlGenException2", wsBinding, (Exception)ex.getCause()); + } else { // should never happen + throw new IllegalStateException(ex); + } + } catch (RuntimeException ex) { + warning(monitor, "WsdlGenException", wsBinding, component.getName(), contract.getName()); + error(monitor, "WsdlGenException2", wsBinding, component.getName(), contract.getName(), ex.getMessage()); + } + } + + private static void createWSDLDocument(Component component, + Contract contract, + WebServiceBinding wsBinding, + ExtensionPointRegistry extensionPoints, + Monitor monitor) { + FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + DataBindingExtensionPoint dataBindings = extensionPoints.getExtensionPoint(DataBindingExtensionPoint.class); + WSDLFactory wsdlFactory = modelFactories.getFactory(WSDLFactory.class); + XSDFactory xsdFactory = modelFactories.getFactory(XSDFactory.class); + DocumentBuilderFactory documentBuilderFactory = modelFactories.getFactory(DocumentBuilderFactory.class); + + if (((Contract)contract).getInterfaceContract(wsBinding) == null) { + // can happen if incorrect component service name + fatal(monitor, "MissingInterfaceContract", wsBinding, component.getName(), contract.getName()); + } + + InterfaceContract icontract = wsBinding.getBindingInterfaceContract(); + if (icontract == null) { + icontract = ((Contract)contract).getInterfaceContract(wsBinding).makeUnidirectional(false); + if (icontract instanceof JavaInterfaceContract) { + ModelResolver resolver = component instanceof ResolverExtension ? + ((ResolverExtension)component).getModelResolver() : null; + icontract = createWSDLInterfaceContract( + (JavaInterfaceContract)icontract, + requiresSOAP12(wsBinding), + resolver, + dataBindings, + wsdlFactory, + xsdFactory, + documentBuilderFactory, + monitor); + } else { + try { + //TUSCANY-2316 Cloning the Interface Contract to avoid overriding data binding information + icontract = (InterfaceContract)icontract.clone(); + } catch (Exception e) { + //ignore + } + } + wsBinding.setBindingInterfaceContract(icontract); + } + + /* + // Look at all the Web Service bindings of the SCA service to see if any + // of them have an existing generated WSDL definitions document. If found, + // use it for this binding as well. If not found, generate a new document. + Definition definition = null; + for (Binding binding : contract.getBindings()) { + if (binding instanceof WebServiceBinding) { + definition = ((WebServiceBinding)binding).getWSDLDocument(); + if (definition != null) { + wsBinding.setWSDLDocument(definition); + break; + } + } + } + */ + // The above code is currently not used. Instead, we only look + // for a WSDL definitions document in this binding and don't + // attempt to share the same document across multiple bindings. + + // generate a WSDL definitions document if needed + Definition definition = wsBinding.getGeneratedWSDLDocument(); + if (definition == null) { + definition = WSDLServiceGenerator.configureWSDLDefinition(wsBinding, component, contract, monitor); + wsBinding.setGeneratedWSDLDocument(definition); + } + } + + protected static boolean requiresSOAP12(WebServiceBinding wsBinding) { + if (wsBinding instanceof PolicySubject) { + List intents = ((PolicySubject)wsBinding).getRequiredIntents(); + for (Intent intent : intents) { + if (SOAP12_INTENT.equals(intent.getName())) { + return true; + } + } + } + return false; + } + + /** + * Create a WSDLInterfaceContract from a JavaInterfaceContract + */ + public static WSDLInterfaceContract createWSDLInterfaceContract(JavaInterfaceContract contract, + boolean requiresSOAP12, + ModelResolver resolver, + DataBindingExtensionPoint dataBindings, + WSDLFactory wsdlFactory, + XSDFactory xsdFactory, + DocumentBuilderFactory documentBuilderFactory, + Monitor monitor) { + + WSDLInterfaceContract wsdlContract = wsdlFactory.createWSDLInterfaceContract(); + + if (contract.getInterface() != null){ + WSDLInterface wsdlInterface = createWSDLInterface((JavaInterface)contract.getInterface(), + requiresSOAP12, + resolver, + dataBindings, + wsdlFactory, + xsdFactory, + documentBuilderFactory, + monitor); + wsdlContract.setInterface(wsdlInterface); + } + + if (contract.getCallbackInterface() != null){ + WSDLInterface wsdlInterface = createWSDLInterface((JavaInterface)contract.getCallbackInterface(), + requiresSOAP12, + resolver, + dataBindings, + wsdlFactory, + xsdFactory, + documentBuilderFactory, + monitor); + wsdlContract.setCallbackInterface(wsdlInterface); + } + + return wsdlContract; + } + + /** + * Create a WSDLInterface from a JavaInterface + */ + public static WSDLInterface createWSDLInterface(JavaInterface javaInterface, + boolean requiresSOAP12, + ModelResolver resolver, + DataBindingExtensionPoint dataBindings, + WSDLFactory wsdlFactory, + XSDFactory xsdFactory, + DocumentBuilderFactory documentBuilderFactory, + Monitor monitor) { + + WSDLInterface wsdlInterface = wsdlFactory.createWSDLInterface(); + WSDLDefinition wsdlDefinition = wsdlFactory.createWSDLDefinition(); + + Definition def = null; + try { + Interface2WSDLGenerator wsdlGenerator = + new Interface2WSDLGenerator(requiresSOAP12, resolver, dataBindings, xsdFactory, documentBuilderFactory, monitor); + def = wsdlGenerator.generate(javaInterface, wsdlDefinition); + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + + // for debugging + if (printWSDL) { + try { + System.out.println("Generated WSDL for Java interface " + javaInterface.getName() + " class " + javaInterface.getJavaClass().getName()); + WSDLWriter writer = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLWriter(); + writer.writeWSDL(def, System.out); + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + wsdlDefinition.setDefinition(def); + wsdlInterface.setWsdlDefinition(wsdlDefinition); + wsdlInterface.setRemotable(true); + wsdlInterface.setUnresolved(false); + wsdlInterface.setRemotable(true); + PortType portType = (PortType)def.getAllPortTypes().values().iterator().next(); + wsdlInterface.setPortType(portType); + + try { + wsdlFactory.createWSDLInterface(wsdlInterface, portType, wsdlDefinition, resolver, monitor); + } catch (InvalidInterfaceException e) { + throw new WSDLGenerationException(e); + } + + // copy operation intents and policy sets from Java to WSDL interface + // in case we need to refer to them in later processing + for(Operation javaOperation : javaInterface.getOperations()){ + for(Operation wsdlOperation : wsdlInterface.getOperations()){ + if (wsdlOperation.getName().equals(javaOperation.getName())){ + wsdlOperation.getRequiredIntents().addAll(javaOperation.getRequiredIntents()); + wsdlOperation.getPolicySets().addAll(javaOperation.getPolicySets()); + break; + } + } + } + + return wsdlInterface; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/Interface2WSDLGenerator.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/Interface2WSDLGenerator.java new file mode 100644 index 0000000000..c20ffd7c43 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/Interface2WSDLGenerator.java @@ -0,0 +1,1185 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import java.lang.reflect.Method; +import java.net.URI; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.wsdl.Binding; +import javax.wsdl.BindingOperation; +import javax.wsdl.Definition; +import javax.wsdl.Fault; +import javax.wsdl.Input; +import javax.wsdl.Message; +import javax.wsdl.OperationType; +import javax.wsdl.Output; +import javax.wsdl.Part; +import javax.wsdl.PortType; +import javax.wsdl.Types; +import javax.wsdl.WSDLException; +import javax.wsdl.extensions.schema.Schema; +import javax.wsdl.factory.WSDLFactory; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.databinding.DataBinding; +import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint; +import org.apache.tuscany.sca.databinding.XMLTypeHelper; +import org.apache.tuscany.sca.databinding.jaxb.JAXBDataBinding; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.ParameterMode; +import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.java.JavaInterface; +import org.apache.tuscany.sca.interfacedef.java.JavaOperation; +import org.apache.tuscany.sca.interfacedef.util.ElementInfo; +import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper; +import org.apache.tuscany.sca.interfacedef.util.TypeInfo; +import org.apache.tuscany.sca.interfacedef.util.WrapperInfo; +import org.apache.tuscany.sca.interfacedef.util.XMLType; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.apache.tuscany.sca.xsd.XSDFactory; +import org.apache.tuscany.sca.xsd.XSDefinition; +import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaCollection; +import org.apache.ws.commons.schema.XmlSchemaComplexContent; +import org.apache.ws.commons.schema.XmlSchemaComplexContentExtension; +import org.apache.ws.commons.schema.XmlSchemaComplexType; +import org.apache.ws.commons.schema.XmlSchemaElement; +import org.apache.ws.commons.schema.XmlSchemaException; +import org.apache.ws.commons.schema.XmlSchemaGroupBase; +import org.apache.ws.commons.schema.XmlSchemaImport; +import org.apache.ws.commons.schema.XmlSchemaObject; +import org.apache.ws.commons.schema.XmlSchemaObjectCollection; +import org.apache.ws.commons.schema.XmlSchemaSerializer.XmlSchemaSerializerException; +import org.apache.ws.commons.schema.utils.NamespaceMap; +import org.oasisopen.sca.ServiceRuntimeException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * @version $Rev$ $Date$ + */ +public class Interface2WSDLGenerator { + private static final Logger logger = Logger.getLogger(Interface2WSDLGenerator.class.getName()); + private static final String SCHEMA_NS = "http://www.w3.org/2001/XMLSchema"; + private static final String SCHEMA_NAME = "schema"; + private static final QName SCHEMA_QNAME = new QName(SCHEMA_NS, SCHEMA_NAME); + private static final String XMLNS_NS = "http://www.w3.org/2000/xmlns/"; + + private static final String ANYTYPE_NAME = "anyType"; + private static final QName ANYTYPE_QNAME = new QName(SCHEMA_NS, ANYTYPE_NAME); + + + private WSDLFactory factory; + private DataBindingExtensionPoint dataBindings; + private WSDLDefinitionGenerator definitionGenerator; + private DocumentBuilderFactory documentBuilderFactory; + private boolean requiresSOAP12; + private ModelResolver resolver; + private XSDFactory xsdFactory; + private Monitor monitor; + + public Interface2WSDLGenerator(boolean requiresSOAP12, + ModelResolver resolver, + DataBindingExtensionPoint dataBindings, + XSDFactory xsdFactory, + DocumentBuilderFactory documentBuilderFactory, + Monitor monitor) throws WSDLException { + super(); + this.requiresSOAP12 = requiresSOAP12; + this.resolver = resolver; + this.documentBuilderFactory = documentBuilderFactory; + definitionGenerator = new WSDLDefinitionGenerator(requiresSOAP12); + this.dataBindings = dataBindings; + this.xsdFactory = xsdFactory; + this.monitor = monitor; + try{ + this.factory = AccessController.doPrivileged(new PrivilegedExceptionAction() { + public WSDLFactory run() throws WSDLException{ + WSDLFactory factory = WSDLFactory.newInstance(); + return factory; + } + }); + } catch (PrivilegedActionException e){ + throw (WSDLException) e.getException(); + } + + } + + /** + * Log a warning message. + * @param problem + */ + private static void logWarning(Problem problem) { + Logger problemLogger = Logger.getLogger(problem.getSourceClassName(), problem.getResourceBundleName()); + if (problemLogger != null){ + problemLogger.logp(Level.WARNING, problem.getSourceClassName(), null, problem.getMessageId(), problem.getMessageParams()); + } else { + logger.severe("Can't get logger " + problem.getSourceClassName()+ " with bundle " + problem.getResourceBundleName()); + } + } + + /** + * Report a warning. + * @param message + * @param binding + * @param parameters + */ + private void warning(String message, Interface interfaze, String... messageParameters) { + Problem problem = monitor.createProblem(this.getClass().getName(), "wsdlgen-validation-messages", Severity.WARNING, interfaze, message, (Object[])messageParameters); + if (monitor != null) { + monitor.problem(problem); + } else { + logWarning(problem); + } + } + + /** + * Report a fatal error. + * @param message + * @param binding + * @param parameters + */ + private void fatal(String message, Interface interfaze, String... messageParameters) { + Problem problem = monitor.createProblem(this.getClass().getName(), "wsdlgen-validation-messages", Severity.ERROR, interfaze, message, (Object[])messageParameters); + throw new WSDLGenerationException(problem.toString(), null, problem); + } + + private XMLTypeHelper getTypeHelper(DataType type, Map helpers) { + if (type == null) { + return null; + } + String db = type.getDataBinding(); + if (db == null) { + return null; + } + // TUSCANY-3800 + while ("java:array".equals(db)) { + type = (DataType)type.getLogical(); + db = type.getDataBinding(); + } + return helpers.get(db); + } + + private boolean inputTypesCompatible(DataType wrapperType, DataType> inputType, Map helpers) { + XMLTypeHelper wrapperHelper = getTypeHelper(wrapperType, helpers); + for (DataType dt : inputType.getLogical()) { + if (getTypeHelper(dt, helpers) != wrapperHelper) { + return false; + } + } + return true; + } + + private boolean outputTypeCompatible(DataType wrapperType, DataType outputType, Map helpers) { + // TUSCANY-3283 - use same algorithm as input types as we now support + // multiple output values so the real output types will + // be wrapped in an "idl:output" data type + /* + if (getTypeHelper(outputType, helpers) != getTypeHelper(wrapperType, helpers)) { + return false; + } else { + return true; + } + */ + return inputTypesCompatible(wrapperType, outputType, helpers); + } + + private void addDataType(Map> map, DataType type, Map helpers) { + if (type == null) { + return; + } + String db = type.getDataBinding(); + if (db == null) { + return; + } + if ("java:array".equals(db)) { + DataType dt = (DataType)type.getLogical(); + db = dt.getDataBinding(); + } + XMLTypeHelper helper = helpers.get(db); + List types = map.get(helper); + if (types == null) { + types = new ArrayList(); + map.put(helper, types); + } + types.add(type); + } + + private Map> getDataTypes(Interface intf, boolean useWrapper, Map helpers) { + Map> dataTypes = new HashMap>(); + for (Operation op : intf.getOperations()) { + WrapperInfo inputWrapper = op.getInputWrapper(); + DataType dt1 = null; + boolean useInputWrapper = useWrapper & inputWrapper != null; + if (useInputWrapper) { + dt1 = inputWrapper.getWrapperType(); + useInputWrapper &= inputTypesCompatible(dt1, op.getInputType(), helpers); + } + if (useInputWrapper) { + addDataType(dataTypes, dt1, helpers); + } else { + for (DataType dt : op.getInputType().getLogical()) { + addDataType(dataTypes, dt, helpers); + } + } + + WrapperInfo outputWrapper = op.getOutputWrapper(); + DataType dt2 = null; + boolean useOutputWrapper = useWrapper & outputWrapper != null; + if (useOutputWrapper) { + dt2 = outputWrapper.getWrapperType(); + useOutputWrapper &= outputTypeCompatible(dt2, op.getOutputType(), helpers); + } + if (useOutputWrapper) { + addDataType(dataTypes, dt2, helpers); + } else { + if (op.getOutputType().getLogical().size() != 0) { + dt2 = op.getOutputType().getLogical().get(0); + } + addDataType(dataTypes, dt2, helpers); + } + + for (DataType dt3 : op.getFaultTypes()) { + DataType dt4 = dt3.getLogical(); + addDataType(dataTypes, dt4, helpers); + } + } + // Adding classes referenced by @XmlSeeAlso in the java interface + if (intf instanceof JavaInterface) { + JavaInterface javaInterface = (JavaInterface)intf; + Class[] seeAlso = getSeeAlso(javaInterface.getJavaClass()); + if (seeAlso != null) { + for (Class cls : seeAlso) { + DataType dt = new DataTypeImpl(JAXBDataBinding.NAME, cls, XMLType.UNKNOWN); + addDataType(dataTypes, dt, helpers); + } + } + seeAlso = getSeeAlso(javaInterface.getCallbackClass()); + if (seeAlso != null) { + for (Class cls : seeAlso) { + DataType dt = new DataTypeImpl(JAXBDataBinding.NAME, cls, XMLType.UNKNOWN); + addDataType(dataTypes, dt, helpers); + } + } + } + return dataTypes; + } + + private static Class[] getSeeAlso(Class interfaze) { + if (interfaze == null) { + return null; + } + XmlSeeAlso seeAlso = interfaze.getAnnotation(XmlSeeAlso.class); + if (seeAlso == null) { + return null; + } else { + return seeAlso.value(); + } + } + + + public Definition generate(Interface interfaze, WSDLDefinition wsdlDefinition) throws WSDLException { + if (interfaze == null) { + return null; + } + if (interfaze instanceof WSDLInterface) { + return ((WSDLInterface)interfaze).getWsdlDefinition().getDefinition(); + } + JavaInterface iface = (JavaInterface)interfaze; + if (!interfaze.isRemotable()) { + fatal("InterfaceNotRemotable", interfaze, iface.getName()); + } + QName name = getQName(iface); + Definition definition = factory.newDefinition(); + if (requiresSOAP12) { + definition.addNamespace("SOAP12", "http://schemas.xmlsoap.org/wsdl/soap12/"); + } else { + definition.addNamespace("SOAP", "http://schemas.xmlsoap.org/wsdl/soap/"); + } + definition.addNamespace("wsdl", "http://schemas.xmlsoap.org/wsdl/"); + definition.addNamespace("xs", SCHEMA_NS); + + String namespaceURI = name.getNamespaceURI(); + definition.setTargetNamespace(namespaceURI); + definition.setQName(new QName(namespaceURI, name.getLocalPart() + "Service", name.getPrefix())); + definition.addNamespace(name.getPrefix(), namespaceURI); + + PortType portType = definition.createPortType(); + portType.setQName(name); + Binding binding = definitionGenerator.createBinding(definition, portType); + Map helpers = new HashMap(); + Map> wrappers = new HashMap>(); + for (Operation op : interfaze.getOperations()) { + javax.wsdl.Operation operation = generateOperation(definition, op, helpers, wrappers); + portType.addOperation(operation); + String action = ((JavaOperation)op).getAction(); + // Removed improper defaulting of SOAP action when using doc/lit BARE. + // The correct default is "" (empty string). + if (action == null) { + action = ""; + } + BindingOperation bindingOp = definitionGenerator.createBindingOperation(definition, operation, action); + binding.addBindingOperation(bindingOp); + } + portType.setUndefined(false); + definition.addPortType(portType); + binding.setUndefined(false); + definition.addBinding(binding); + wsdlDefinition.setBinding(binding); + + // call each helper in turn to populate the wsdl.types element + XmlSchemaCollection schemaCollection = new XmlSchemaCollection(); + + // TUSCANY-3283 - "true" here means also generate the wrapper types using JAXB + Map> dataTypes = getDataTypes(interfaze, true, helpers); + for (Map.Entry> en: dataTypes.entrySet()) { + XMLTypeHelper helper = en.getKey(); + if (helper == null) { + continue; + } + List xsDefinitions = helper.getSchemaDefinitions(xsdFactory, resolver, en.getValue()); + + // TUSCANY-3283 - move the nonamespace types into the namespace of the interface + // as per JAXWS + mergeNoNamespaceSchema(namespaceURI, xsDefinitions); + + for (XSDefinition xsDef: xsDefinitions) { + //addSchemaExtension(xsDef, schemaCollection, wsdlDefinition, definition); + loadXSD(schemaCollection, xsDef); + wsdlDefinition.getXmlSchemas().add(xsDef); + } + } + + // remove global wrapper elements with schema definitions from generation list + for (QName wrapperName: new HashSet(wrappers.keySet())) { + if (wsdlDefinition.getXmlSchemaElement(wrapperName) != null) { + wrappers.remove(wrapperName); + } + } + + // below we might generate wrapper schema into a DOM. If the schema are in a namespace + // that is already been loaded then we need to throw away the schema collection and reload + // it because you can't load a DOM into a schema collection if the schema for the namespace + // has already been loaded + boolean reloadSchema = false; + + // generate schema elements for wrappers that aren't defined in the schemas + // TUSCANY-3283 - as we're generating wrappers with JAXB it won't + // go through here for all wrappers. It will just have to do the ones + // where there is no JAXB mapping for the child types, e.g. SDO DataObject + if (wrappers.size() > 0) { + int i = 0; + int index = 0; + Map wrapperXSDs = new HashMap(); + Map> prefixMaps = new HashMap>(); + for (Map.Entry> entry: wrappers.entrySet()) { + String targetNS = entry.getKey().getNamespaceURI(); + Document schemaDoc = null; + Element schema = null; + XSDefinition xsDef = wrapperXSDs.get(targetNS); + if (xsDef != null) { + schemaDoc = xsDef.getDocument(); + schema = schemaDoc.getDocumentElement(); + } else { + // TUSCANY-3283 - if we have to generate a new schema check to see if the + // WSDL doc already has a schema in this namespace + xsDef = wsdlDefinition.getSchema(targetNS); + if (xsDef != null) { + schemaDoc = xsDef.getDocument(); + schema = schemaDoc.getDocumentElement(); + //wrapperXSDs.put(targetNS, xsDef); + Map prefixMap = prefixMaps.get(schema); + if (prefixMap == null){ + prefixMap = new HashMap(); + prefixMaps.put(schema, prefixMap); + String [] prefixes = xsDef.getSchema().getNamespaceContext().getDeclaredPrefixes(); + for (int j = 0; j < prefixes.length; j++){ + prefixMap.put(xsDef.getSchema().getNamespaceContext().getNamespaceURI(prefixes[j]), + prefixes[j]); + } + } + reloadSchema = true; + } else { + schemaDoc = createDocument(); + schema = schemaDoc.createElementNS(SCHEMA_NS, "xs:schema"); + // The elementFormDefault should be set to unqualified, see TUSCANY-2388 + schema.setAttribute("elementFormDefault", "unqualified"); + schema.setAttribute("attributeFormDefault", "qualified"); + schema.setAttribute("targetNamespace", targetNS); + schema.setAttributeNS(XMLNS_NS, "xmlns:xs", SCHEMA_NS); + schemaDoc.appendChild(schema); + // TUSCANY-3283 - the extension is created at the bottom + //Schema schemaExt = createSchemaExt(definition); + //schemaExt.setElement(schema); + prefixMaps.put(schema, new HashMap()); + xsDef = xsdFactory.createXSDefinition(); + xsDef.setUnresolved(true); + xsDef.setNamespace(targetNS); + xsDef.setDocument(schemaDoc); + // TUSCANY-2465: Set the system id to avoid schema conflict + xsDef.setLocation(URI.create("xsd_" + index + ".xsd")); + index++; + wrapperXSDs.put(targetNS, xsDef); + wsdlDefinition.getXmlSchemas().add(xsDef); + } + } + Element wrapper = schemaDoc.createElementNS(SCHEMA_NS, "xs:element"); + schema.appendChild(wrapper); + wrapper.setAttribute("name", entry.getKey().getLocalPart()); + if (entry.getValue().size() == 1 && entry.getValue().get(0).getQName() == null) { + // special case for global fault element + QName typeName = entry.getValue().get(0).getType().getQName(); + String nsURI = typeName.getNamespaceURI(); + if ("".equals(nsURI)) { + wrapper.setAttribute("type", typeName.getLocalPart()); + addSchemaImport(schema, "", schemaDoc); + } else if (targetNS.equals(nsURI)) { + wrapper.setAttribute("type", typeName.getLocalPart()); + } else if (SCHEMA_NS.equals(nsURI)) { + wrapper.setAttribute("type", "xs:" + typeName.getLocalPart()); + } else { + Map prefixMap = prefixMaps.get(schema); + String prefix = prefixMap.get(nsURI); + if (prefix == null) { + prefix = "ns" + i++; + prefixMap.put(nsURI, prefix); + schema.setAttributeNS(XMLNS_NS, "xmlns:" + prefix, nsURI); + addSchemaImport(schema, nsURI, schemaDoc); + } + wrapper.setAttribute("type", prefix + ":" + typeName.getLocalPart()); + } + } else { + // normal wrapper containing type definition inline + Element complexType = schemaDoc.createElementNS(SCHEMA_NS, "xs:complexType"); + wrapper.appendChild(complexType); + if (entry.getValue().size() > 0) { + Element sequence = schemaDoc.createElementNS(SCHEMA_NS, "xs:sequence"); + complexType.appendChild(sequence); + for (ElementInfo element: entry.getValue()) { + Element xsElement = schemaDoc.createElementNS(SCHEMA_NS, "xs:element"); + if (element.isMany()) { + xsElement.setAttribute("maxOccurs", "unbounded"); + } + xsElement.setAttribute("minOccurs", "0"); + xsElement.setAttribute("name", element.getQName().getLocalPart()); + if (element.isNillable()) { + xsElement.setAttribute("nillable", "true"); + } + QName typeName = element.getType().getQName(); + String nsURI = typeName.getNamespaceURI(); + if ("".equals(nsURI)) { + xsElement.setAttribute("type", typeName.getLocalPart()); + addSchemaImport(schema, "", schemaDoc); + } else if (SCHEMA_NS.equals(nsURI)) { + xsElement.setAttribute("type", "xs:" + typeName.getLocalPart()); + } else { + Map prefixMap = prefixMaps.get(schema); + String prefix = prefixMap.get(nsURI); + if (prefix == null) { + if (targetNS.equals(nsURI)) { + prefix = "tns"; + } else { + prefix = "ns" + i++; + addSchemaImport(schema, nsURI, schemaDoc); + } + prefixMap.put(nsURI, prefix); + schema.setAttributeNS(XMLNS_NS, "xmlns:" + prefix, nsURI); + } + xsElement.setAttribute("type", prefix + ":" + typeName.getLocalPart()); + } + sequence.appendChild(xsElement); + } + } + } + } + } + + if (reloadSchema){ + schemaCollection = new XmlSchemaCollection(); + for (XSDefinition xsDef: wsdlDefinition.getXmlSchemas()){ + xsDef.setSchema(null); + xsDef.setSchemaCollection(null); + } + } + + for (XSDefinition xsDef: wsdlDefinition.getXmlSchemas()){ + addSchemaExtension(xsDef, schemaCollection, wsdlDefinition, definition); + } + + return definition; + } + + // TUSCANY-3283 - merge the nonamespace schema into the default namespace schema + private void mergeNoNamespaceSchema(String toNamespace, List xsDefinitions){ + String fromNamespace = ""; + Document fromDoc = null; + XSDefinition fromXsDef = null; + Document toDoc = null; + List relatedDocs = new ArrayList(); + + for (XSDefinition xsDef: xsDefinitions) { + if(xsDef.getNamespace().equals("")){ + fromXsDef = xsDef; + fromDoc = xsDef.getDocument(); + } else if(xsDef.getNamespace().equals(toNamespace)){ + toDoc = xsDef.getDocument(); + } else { + relatedDocs.add(xsDef.getDocument()); + } + } + + if (fromDoc != null && toDoc != null){ + try { + List resultingDocs = mergeSchema(fromNamespace, fromDoc, toNamespace, toDoc, relatedDocs); + + for (XmlSchema schema : resultingDocs){ + for (XSDefinition xsDef: xsDefinitions) { + if (xsDef.getNamespace().equals(schema.getTargetNamespace())){ + Document doc = schema.getSchemaDocument(); + // just for debugging + //printDOM(doc); + xsDef.setDocument(doc); + //xsDef.setSchema(schema); + } + } + } + + xsDefinitions.remove(fromXsDef); + } catch (XmlSchemaSerializerException ex){ + throw new WSDLGenerationException(ex); + } + } + } + + // TUSCANY-3283 - merge the nonamespace schema into the default namespace schema + private List mergeSchema(String fromNamespace, + Document fromDoc, + String toNamespace, + Document toDoc, + List relatedDocs) throws XmlSchemaSerializerException{ + // Read all the input DOMs into a schema collection so we can manipulate them + XmlSchemaCollection schemaCollection = new XmlSchemaCollection(); + schemaCollection.read(fromDoc.getDocumentElement()); + schemaCollection.read(toDoc.getDocumentElement()); + + for(Document doc : relatedDocs){ + schemaCollection.read(doc.getDocumentElement()); + } + + XmlSchema fromSchema = null; + XmlSchema toSchema = null; + List resultSchema = new ArrayList(); + XmlSchema schemas[] = schemaCollection.getXmlSchemas(); + for (int i=0; i < schemas.length; i++){ + XmlSchema schema = schemas[i]; + + if (schema.getTargetNamespace() == null){ + fromSchema = schema; + } else if (schema.getTargetNamespace().equals(toNamespace)){ + toSchema = schema; + resultSchema.add(schema); + } else if (schema.getTargetNamespace().equals("http://www.w3.org/2001/XMLSchema")){ + // do nothing as we're not going to print out the + // schema schema + } else { + resultSchema.add(schema); + } + } + + if (fromSchema == null || toSchema == null){ + return resultSchema; + } + + // copy all the FROM items to the TO schema + XmlSchemaObjectCollection fromItems = fromSchema.getItems(); + XmlSchemaObjectCollection toItems = toSchema.getItems(); + List movedItems = new ArrayList(); + + Iterator iter = fromItems.getIterator(); + while(iter.hasNext()){ + // don't copy import for TO namespace + XmlSchemaObject obj = iter.next(); + if (obj instanceof XmlSchemaImport && + ((XmlSchemaImport)obj).getNamespace().equals(toNamespace)){ + // do nothing + } else { + toItems.add(obj); + movedItems.add(obj); + } + } + + // check that all types in the TO namespace are now referred to correctly across the schema + for(XmlSchemaObject obj : movedItems){ + fixUpMovedTypeReferences(fromNamespace, toNamespace, obj, resultSchema); + } + + return resultSchema; + } + + // TUSCANY-3283 - fix up any references to types moved to the default namespace schema + public void fixUpMovedTypeReferences(String fromNamespace, String toNamespace, XmlSchemaObject fixUpObj, List relatedSchema){ + + if (!(fixUpObj instanceof XmlSchemaComplexType)){ + return; + } + + for (XmlSchema schema : relatedSchema){ + int importRemoveIndex = -1; + for (int i = 0; i < schema.getItems().getCount(); i++){ + XmlSchemaObject obj = schema.getItems().getItem(i); + + processXMLSchemaObject(toNamespace, obj, fixUpObj); + + // remove FROM imports + if (obj instanceof XmlSchemaImport && + ((XmlSchemaImport)obj).getNamespace().equals(fromNamespace)){ + importRemoveIndex = i; + } + } + + if (importRemoveIndex >= 0){ + schema.getItems().removeAt(importRemoveIndex); + } + } + } + + // TUSCANY-3283 - iterate down the schema tree looking for references to the item being moved + public void processXMLSchemaObject(String toNamespace, XmlSchemaObject obj, XmlSchemaObject fixUpObj){ + if (obj instanceof XmlSchemaComplexType){ + processXMLSchemaObject(toNamespace, ((XmlSchemaComplexType)obj).getParticle(), fixUpObj); + processXMLSchemaObject(toNamespace, ((XmlSchemaComplexType)obj).getContentModel(), fixUpObj); + } else if (obj instanceof XmlSchemaComplexContent){ + processXMLSchemaObject(toNamespace, ((XmlSchemaComplexContent)obj).getContent(), fixUpObj); + } else if (obj instanceof XmlSchemaElement){ + XmlSchemaElement element = (XmlSchemaElement)obj; + if(element.getSchemaType() == fixUpObj){ + QName name = element.getSchemaTypeName(); + QName newName = new QName(toNamespace, name.getLocalPart()); + element.setSchemaTypeName(newName); + } + ((XmlSchemaElement)obj).getSchemaType(); + } else if (obj instanceof XmlSchemaGroupBase){ + XmlSchemaObjectCollection items = ((XmlSchemaGroupBase)obj).getItems(); + Iterator iter = items.getIterator(); + while(iter.hasNext()){ + processXMLSchemaObject(toNamespace, iter.next(), fixUpObj); + } + } else if (obj instanceof XmlSchemaComplexContentExtension){ + XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension)obj; + QName name = extension.getBaseTypeName(); + QName newName = new QName(toNamespace, name.getLocalPart()); + extension.setBaseTypeName(newName); + } + // TODO - what other structure items will be generated by JAXB? + } + + /* + * TUSCANY-3283 - Just used when debugging DOM problems + */ + private void printDOM(Document document){ + try { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + Source source = new DOMSource(document); + Result result = new StreamResult(System.out); + transformer.transform(source, result); + System.out.println("\n"); + System.out.flush(); + } catch (Exception ex){ + ex.toString(); + } + } + + + private static void addSchemaImport(Element schema, String nsURI, Document schemaDoc) { + Element imp = schemaDoc.createElementNS(SCHEMA_NS, "xs:import"); + if (!"".equals(nsURI)) { + imp.setAttribute("namespace", nsURI); + } + // Scan all xs:import elements to match namespace + NodeList childNodes = schema.getElementsByTagNameNS(SCHEMA_NS, "import"); + for (int i = 0; i < childNodes.getLength(); i++) { + Node childNode = childNodes.item(i); + if (childNode instanceof Element) { + String ns = ((Element)childNode).getAttributeNS(SCHEMA_NS, "namespace"); + if (nsURI.equals(ns)) { + // The xs:import with the same namespace has been declared + return; + } + } + } + // Try to find the first node after the import elements + Node firstNodeAfterImport = null; + if (childNodes.getLength() > 0) { + firstNodeAfterImport = childNodes.item(childNodes.getLength() - 1).getNextSibling(); + } else { + firstNodeAfterImport = schema.getFirstChild(); + } + + if (firstNodeAfterImport == null) { + schema.appendChild(imp); + } else { + schema.insertBefore(imp, firstNodeAfterImport); + } + } + + private void addSchemaExtension(XSDefinition xsDef, + XmlSchemaCollection schemaCollection, + WSDLDefinition wsdlDefinition, + Definition definition) throws WSDLException { + if (xsDef.getAggregatedDefinitions() != null) { + for (XSDefinition xsd: xsDef.getAggregatedDefinitions()) { + addSchemaExtension(xsd, schemaCollection, wsdlDefinition, definition); + } + } else { + String nsURI = xsDef.getNamespace(); + Document document = xsDef.getDocument(); + if (document == null) { + try { + NamespaceMap prefixMap = new NamespaceMap(); + prefixMap.add("xs", SCHEMA_NS); + prefixMap.add("tns", nsURI); + XmlSchema schemaDef = xsDef.getSchema(); + schemaDef.setNamespaceContext(prefixMap); + Document[] docs = schemaDef.getAllSchemas(); + document = docs[docs.length-1]; + document.setDocumentURI(xsDef.getLocation().toString()); + xsDef.setDocument(document); + } catch (XmlSchemaException e) { + throw new RuntimeException(e); + } + } + loadXSD(schemaCollection, xsDef); + //wsdlDefinition.getXmlSchemas().add(xsDef); + Element schema = document.getDocumentElement(); + Schema schemaExt = createSchemaExt(definition); + schemaExt.setDocumentBaseURI(document.getDocumentURI()); + schemaExt.setElement(schema); + } + } + + private static void loadXSD(XmlSchemaCollection schemaCollection, XSDefinition definition) { + if (definition.getSchema() != null) { + return; + } + if (definition.getDocument() != null) { + String uri = null; + if (definition.getLocation() != null) { + uri = definition.getLocation().toString(); + } + XmlSchema schema = schemaCollection.read(definition.getDocument(), uri, null); + if (definition.getSchemaCollection() == null) { + definition.setSchemaCollection(schemaCollection); + } + if (definition.getSchema() == null) { + definition.setSchema(schema); + } + } + } + + public Schema createSchemaExt(Definition definition) throws WSDLException { + Types types = definition.getTypes(); + if (types == null) { + types = definition.createTypes(); + definition.setTypes(types); + } + + Schema schemaExt = createSchema(definition); + types.addExtensibilityElement(schemaExt); + + return schemaExt; + } + + public Schema createSchema(Definition definition) throws WSDLException { + return (Schema)definition.getExtensionRegistry().createExtension(Types.class, SCHEMA_QNAME); + } + + public Document createDocument() { + Document document; + try { + if (documentBuilderFactory == null) { + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + } + document = documentBuilderFactory.newDocumentBuilder().newDocument(); + } catch (ParserConfigurationException ex) { + throw new WSDLGenerationException(ex); + } + // document.setDocumentURI("http://"); + return document; + } + + protected QName getQName(Interface interfaze) { + JavaInterface iface = (JavaInterface)interfaze; + QName qname = iface.getQName(); + if (qname != null) { + return qname; + } else { + Class javaClass = iface.getJavaClass(); + return new QName(JavaXMLMapper.getNamespace(javaClass), javaClass.getSimpleName(), "tns"); + } + } + + public javax.wsdl.Operation generateOperation(Definition definition, + Operation op, + Map helpers, + Map> wrappers) + throws WSDLException { + javax.wsdl.Operation operation = definition.createOperation(); + operation.setName(op.getName()); + operation.setUndefined(false); + + Input input = definition.createInput(); + Message inputMsg = definition.createMessage(); + String namespaceURI = definition.getQName().getNamespaceURI(); + QName inputMsgName = new QName(namespaceURI, op.getName()); + inputMsg.setQName(inputMsgName); + inputMsg.setUndefined(false); + definition.addMessage(inputMsg); + + List elements = null; + // FIXME: By default, java interface is mapped to doc-lit-wrapper style WSDL + if (op.getInputWrapper() != null) { + // Generate doc-lit-wrapper style + inputMsg.addPart(generateWrapperPart(definition, op, helpers, wrappers, true)); + } else { + // Bare style + int i = 0; + for (DataType d : op.getInputType().getLogical()) { + inputMsg.addPart(generatePart(definition, d, "arg" + i)); + elements = new ArrayList(); + ElementInfo element = getElementInfo(d.getPhysical(), d, null, helpers); + elements.add(element); + QName elementName = ((XMLType)d.getLogical()).getElementName(); + wrappers.put(elementName, elements); + i++; + } + } + input.setMessage(inputMsg); + operation.setInput(input); + + if (!op.isNonBlocking()) { + Output output = definition.createOutput(); + Message outputMsg = definition.createMessage(); + QName outputMsgName = new QName(namespaceURI, op.getName() + "Response"); + outputMsg.setQName(outputMsgName); + outputMsg.setUndefined(false); + definition.addMessage(outputMsg); + + if (op.getOutputWrapper() != null) { + outputMsg.addPart(generateWrapperPart(definition, op, helpers, wrappers, false)); + } else { + + if ((op.getOutputType() != null) && ( op.getOutputType().getLogical().size() != 0)) { + DataType outputType = op.getOutputType().getLogical().get(0); + outputMsg.addPart(generatePart(definition, outputType, "return")); + elements = new ArrayList(); + ElementInfo element = getElementInfo(outputType.getPhysical(), outputType, null, helpers); + elements.add(element); + QName elementName = ((XMLType)outputType.getLogical()).getElementName(); + wrappers.put(elementName, elements); + } + } + output.setMessage(outputMsg); + + operation.setOutput(output); + operation.setStyle(OperationType.REQUEST_RESPONSE); + } else { + operation.setStyle(OperationType.ONE_WAY); + } + + for (DataType faultType: op.getFaultTypes()) { + Fault fault = definition.createFault(); + // TUSCANY-3778 - use the definition namespace not the element namespace to create the fault message + QName faultName = ((XMLType)faultType.getLogical().getLogical()).getElementName(); + QName faultMsgName = new QName(namespaceURI, faultName.getLocalPart()); + fault.setName(faultName.getLocalPart()); + Message faultMsg = definition.getMessage(faultMsgName); + if (faultMsg == null) { + faultMsg = definition.createMessage(); + faultMsg.setQName(faultMsgName); + faultMsg.setUndefined(false); + definition.addMessage(faultMsg); + faultMsg.addPart(generatePart(definition, faultType.getLogical(), faultName.getLocalPart())); + } + fault.setMessage(faultMsg); + operation.addFault(fault); + if (faultType.getLogical().getPhysical() != faultType.getPhysical()) { + // create special wrapper for type indirection to real fault bean + DataType logical = faultType.getLogical(); + elements = new ArrayList(); + elements.add(getElementInfo(logical.getPhysical(), logical, null, helpers)); + } else { + // convert synthesized fault bean to a wrapper type + for (DataType propDT: op.getFaultBeans().get(faultName)) { + XMLType logical = propDT.getLogical(); + elements = new ArrayList(); + elements.add(getElementInfo(propDT.getPhysical(), propDT, logical.getElementName(), helpers)); + } + } + wrappers.put(faultName, elements); + } + + operation.setUndefined(false); + return operation; + } + + public Part generatePart(Definition definition, DataType arg, String partName) { + Part part = definition.createPart(); + part.setName(partName); + if (arg != null && arg.getLogical() instanceof XMLType) { + XMLType xmlType = (XMLType)arg.getLogical(); + QName elementName = xmlType.getElementName(); + part.setElementName(elementName); + addNamespace(definition, elementName); + if (xmlType.getElementName() == null) { + QName typeName = xmlType.getTypeName(); + part.setTypeName(typeName); + addNamespace(definition, typeName); + } + } + return part; + } + + public Part generateWrapperPart(Definition definition, + Operation operation, + Map helpers, + Map> wrappers, + boolean input) throws WSDLException { + Part part = definition.createPart(); + String partName = input ? operation.getName() : (operation.getName() + "Response"); + part.setName(partName); + + WrapperInfo inputWrapper = operation.getInputWrapper(); + WrapperInfo outputWrapper = operation.getOutputWrapper(); + + if ((inputWrapper != null) && (outputWrapper != null)) { + ElementInfo elementInfo = + input ? inputWrapper.getWrapperElement() : outputWrapper.getWrapperElement(); + List elements = + input ? inputWrapper.getChildElements() : outputWrapper.getChildElements(); + QName wrapperName = elementInfo.getQName(); + part.setElementName(wrapperName); + addNamespace(definition, wrapperName); + wrappers.put(wrapperName, elements); + + // FIXME: [rfeng] Ideally, we should try to register the wrappers only. But we are + // expriencing the problem that we cannot handle XSD imports + /* + Class wrapperClass = input ? opWrapper.getInputWrapperClass() : opWrapper.getOutputWrapperClass(); + DataType wrapperDT = input ? opWrapper.getInputWrapperType() : opWrapper.getOutputWrapperType(); + if (wrapperClass != null) { + getElementInfo(wrapperClass, wrapperDT, wrapperName, helpers); + return part; + } + */ + + Method method = ((JavaOperation)operation).getJavaMethod(); + + /* + * Making this change, though not understanding + * whether we can assume JAXWSJavaInterfaceProcessor was already used to process + */ + if (input) { + List inputDTs = operation.getInputType().getLogical(); + for (int i = 0; i < inputDTs.size(); i++) { + DataType nextInput = inputDTs.get(i); + elements.set(i, getElementInfo(nextInput.getPhysical(), nextInput, elements.get(i).getQName(), helpers)); + } + + } else { + List outputDTs = operation.getOutputType().getLogical(); + for (int i = 0; i < outputDTs.size(); i++) { + DataType nextOutput = outputDTs.get(i); + elements.set(i, getElementInfo(nextOutput.getPhysical(), nextOutput, elements.get(i).getQName(), helpers)); + } + } + } + return part; + } + + private ElementInfo getElementInfo(Class javaType, + DataType dataType, + QName name, + Map helpers) { + String db = dataType.getDataBinding(); + while ("java:array".equals(db)) { + dataType = (DataType)dataType.getLogical(); + db = dataType.getDataBinding(); + } + XMLTypeHelper helper = helpers.get(db); + if (helper == null) { + DataBinding dataBinding = dataBindings.getDataBinding(db); + if (dataBinding == null) { + QName element = name; + if (element == null || dataType.getLogical() instanceof XMLType) { + XMLType xmlType = (XMLType)dataType.getLogical(); + if (xmlType.getElementName() != null) { + element = xmlType.getElementName(); + } + } + return new ElementInfo(element, new TypeInfo(ANYTYPE_QNAME, false, null)); + // throw new ServiceRuntimeException("No data binding for " + db); + } + + helper = dataBinding.getXMLTypeHelper(); + if (helper == null) { + // Default to JAXB + helper = helpers.get(JAXBDataBinding.NAME); + if (helper == null) { + helper = dataBindings.getDataBinding(JAXBDataBinding.NAME).getXMLTypeHelper(); + helpers.put(JAXBDataBinding.NAME, helper); + } + } + helpers.put(db, helper); + } + // TUSCANY-3616 - don't revert a byte[] to a byte type but retain the mapping to base64Binary + // which is carried in the dataType and the original javaType + TypeInfo typeInfo = null; + ElementInfo element = null; + if (byte[].class == javaType){ + typeInfo = helper.getTypeInfo(javaType, dataType.getLogical()); + element = new ElementInfo(name, typeInfo); + element.setMany(false); + } else { + typeInfo = helper.getTypeInfo(javaType.isArray() ? javaType.getComponentType() : javaType, dataType.getLogical()); + element = new ElementInfo(name, typeInfo); + element.setMany(javaType.isArray()); + } + + // TUSCANY-3298: Check the "many" flag set by databinding introspection + Object logical = dataType.getLogical(); + if (logical instanceof XMLType && ((XMLType)logical).isMany()) { + element.setMany(true); + } + + element.setNillable(!javaType.isPrimitive()); + return element; + } + + private static void addNamespace(Definition definition, QName name) { + String namespace = name.getNamespaceURI(); + if (definition.getPrefix(namespace) == null) { + definition.addNamespace("ns" + definition.getNamespaces().size(), namespace); + } + } + + /* + // currently not using the next three methods + public XmlSchemaType getXmlSchemaType(DataType type) { + return null; + } + + // FIXME: WE need to add databinding-specific Java2XSD generation + public Element generateXSD(DataType dataType) { + DataBinding dataBinding = dataBindings.getDataBinding(dataType.getDataBinding()); + if (dataBinding != null) { + // return dataBinding.generateSchema(dataType); + } + return null; + } + + public void generateWrapperElements(Operation op) { + XmlSchemaCollection collection = new XmlSchemaCollection(); + String ns = getQName(op.getInterface()).getNamespaceURI(); + XmlSchema schema = new XmlSchema(ns, collection); + schema.setAttributeFormDefault(new XmlSchemaForm(XmlSchemaForm.QUALIFIED)); + schema.setElementFormDefault(new XmlSchemaForm(XmlSchemaForm.QUALIFIED)); + + XmlSchemaElement inputElement = new XmlSchemaElement(); + inputElement.setQName(new QName(ns, op.getName())); + XmlSchemaComplexType inputType = new XmlSchemaComplexType(schema); + inputType.setName(""); + XmlSchemaSequence inputSeq = new XmlSchemaSequence(); + inputType.setParticle(inputSeq); + List argTypes = op.getInputType().getLogical(); + for (DataType argType : argTypes) { + XmlSchemaElement child = new XmlSchemaElement(); + Object logical = argType.getLogical(); + if (logical instanceof XMLType) { + child.setName(((XMLType)logical).getElementName().getLocalPart()); + XmlSchemaType type = getXmlSchemaType(argType); + child.setType(type); + } + inputSeq.getItems().add(child); + } + inputElement.setType(inputType); + + XmlSchemaElement outputElement = new XmlSchemaElement(); + outputElement.setQName(new QName(ns, op.getName() + "Response")); + XmlSchemaComplexType outputType = new XmlSchemaComplexType(schema); + outputType.setName(""); + XmlSchemaSequence outputSeq = new XmlSchemaSequence(); + outputType.setParticle(outputSeq); + DataType returnType = op.getOutputType(); + XmlSchemaElement child = new XmlSchemaElement(); + Object logical = returnType.getLogical(); + if (logical instanceof XMLType) { + child.setName(((XMLType)logical).getElementName().getLocalPart()); + XmlSchemaType type = getXmlSchemaType(returnType); + child.setType(type); + } + outputSeq.getItems().add(child); + outputElement.setType(outputType); + + schema.getElements().add(inputElement.getQName(), inputElement); + schema.getElements().add(outputElement.getQName(), outputElement); + + } + */ + + public WSDLFactory getFactory() { + return factory; + } + + public void setFactory(WSDLFactory factory) { + this.factory = factory; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLContractBuilder.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLContractBuilder.java new file mode 100644 index 0000000000..8a8dfb03f8 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLContractBuilder.java @@ -0,0 +1,96 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.Endpoint; +import org.apache.tuscany.sca.assembly.EndpointReference; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.assembly.builder.ContractBuilder; +import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.apache.tuscany.sca.contribution.resolver.ModelResolver; +import org.apache.tuscany.sca.contribution.resolver.ResolverExtension; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint; +import org.apache.tuscany.sca.interfacedef.InterfaceContract; +import org.apache.tuscany.sca.interfacedef.java.JavaInterfaceContract; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLFactory; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterfaceContract; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.runtime.RuntimeEndpoint; +import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; +import org.apache.tuscany.sca.xsd.XSDFactory; + +/** + * Created WSDL contracts for Endpoints or EndpointReferences for use during + * interface contract mapping. The assmebly spec defines WSDL as the lowest + * common denominator for contract mapping. + */ +public class WSDLContractBuilder implements ContractBuilder { + + private ExtensionPointRegistry extensionPoints; + private FactoryExtensionPoint modelFactories; + private DataBindingExtensionPoint dataBindings; + private WSDLFactory wsdlFactory; + private XSDFactory xsdFactory; + private DocumentBuilderFactory documentBuilderFactory; + + public WSDLContractBuilder(ExtensionPointRegistry extensionPoints) { + this.extensionPoints = extensionPoints; + + modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + dataBindings = extensionPoints.getExtensionPoint(DataBindingExtensionPoint.class); + wsdlFactory = modelFactories.getFactory(WSDLFactory.class); + xsdFactory = modelFactories.getFactory(XSDFactory.class); + documentBuilderFactory = modelFactories.getFactory(DocumentBuilderFactory.class); + + } + + public boolean build(InterfaceContract interfaceContract, BuilderContext context){ + Monitor monitor = null; + + if (context != null){ + monitor = context.getMonitor(); + } +// Uncomment the printWSDL = lines to see the WSDL that is generated +// for interface matching purposes +// BindingWSDLGenerator.printWSDL = true; + JavaInterfaceContract javaContract = (JavaInterfaceContract)interfaceContract; + WSDLInterfaceContract wsdlContract = + BindingWSDLGenerator.createWSDLInterfaceContract(javaContract, + false, + null, + dataBindings, + wsdlFactory, + xsdFactory, + documentBuilderFactory, + monitor); + javaContract.setNormalizedWSDLContract(wsdlContract); +// BindingWSDLGenerator.printWSDL = false; + return true; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLDefinitionGenerator.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLDefinitionGenerator.java new file mode 100644 index 0000000000..6edd4dc86a --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLDefinitionGenerator.java @@ -0,0 +1,340 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import java.util.Iterator; + +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.Input; +import javax.wsdl.Operation; +import javax.wsdl.Output; +import javax.wsdl.Port; +import javax.wsdl.PortType; +import javax.wsdl.Service; +import javax.wsdl.Types; +import javax.wsdl.WSDLException; +import javax.wsdl.extensions.ExtensibilityElement; +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.SOAPOperation; +import javax.wsdl.extensions.soap12.SOAP12Address; +import javax.wsdl.extensions.soap12.SOAP12Binding; +import javax.wsdl.extensions.soap12.SOAP12Body; +import javax.wsdl.extensions.soap12.SOAP12Fault; +import javax.wsdl.extensions.soap12.SOAP12Operation; +import javax.wsdl.factory.WSDLFactory; +import javax.wsdl.xml.WSDLReader; +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.w3c.dom.Element; + +/** + * + * @version $Rev$ $Date$ + */ +public class WSDLDefinitionGenerator { + private static final String SOAP_NS = "http://schemas.xmlsoap.org/wsdl/soap/"; + public static final QName SOAP_ADDRESS = new QName(SOAP_NS, "address"); + private static final QName SOAP_BINDING = new QName(SOAP_NS, "binding"); + private static final QName SOAP_BODY = new QName(SOAP_NS, "body"); + private static final QName SOAP_FAULT = new QName(SOAP_NS, "fault"); + private static final QName SOAP_OPERATION = new QName(SOAP_NS, "operation"); + private static final String SOAP12_NS = "http://schemas.xmlsoap.org/wsdl/soap12/"; + public static final QName SOAP12_ADDRESS = new QName(SOAP12_NS, "address"); + private static final QName SOAP12_BINDING = new QName(SOAP12_NS, "binding"); + private static final QName SOAP12_BODY = new QName(SOAP12_NS, "body"); + private static final QName SOAP12_FAULT = new QName(SOAP12_NS, "fault"); + private static final QName SOAP12_OPERATION = new QName(SOAP12_NS, "operation"); + + private static final String BINDING_SUFFIX = "Binding"; + private static final String SERVICE_SUFFIX = "Service"; + private static final String PORT_SUFFIX = "Port"; + + private boolean requiresSOAP12; + private QName soapAddress; + private QName soapBinding; + private QName soapBody; + private QName soapFault; + private QName soapOperation; + private String wsBindingName; + + public WSDLDefinitionGenerator(WebServiceBinding wsBinding) { + this(BindingWSDLGenerator.requiresSOAP12(wsBinding)); + wsBindingName = wsBinding.getName(); + } + + public WSDLDefinitionGenerator(boolean isSOAP12) { + super(); + this.requiresSOAP12 = isSOAP12; + soapAddress = requiresSOAP12 ? SOAP12_ADDRESS : SOAP_ADDRESS; + soapBinding = requiresSOAP12 ? SOAP12_BINDING : SOAP_BINDING; + soapBody = requiresSOAP12 ? SOAP12_BODY : SOAP_BODY; + soapFault = requiresSOAP12 ? SOAP12_FAULT : SOAP_FAULT; + soapOperation = requiresSOAP12 ? SOAP12_OPERATION : SOAP_OPERATION; + } + + public Definition cloneDefinition(WSDLFactory factory, Definition definition) throws WSDLException { + Element root = definition.getDocumentationElement(); + root = (Element)root.cloneNode(true); + WSDLReader reader = factory.newWSDLReader(); + return reader.readWSDL(definition.getDocumentBaseURI(), root); + } + + public Types createTypes(Definition definition) { + Types types = definition.createTypes(); + definition.setTypes(types); + return types; + } + + public Binding createBinding(Definition definition, PortType portType) { + try { + Binding binding = definition.createBinding(); + binding.setPortType(portType); + configureBinding(definition, binding, portType); + ExtensibilityElement bindingExtension = + definition.getExtensionRegistry().createExtension(Binding.class, soapBinding); + if (requiresSOAP12) { + ((SOAP12Binding)bindingExtension).setStyle("document"); + ((SOAP12Binding)bindingExtension).setTransportURI("http://schemas.xmlsoap.org/soap/http"); + } else { + ((SOAPBinding)bindingExtension).setStyle("document"); + ((SOAPBinding)bindingExtension).setTransportURI("http://schemas.xmlsoap.org/soap/http"); + } + binding.addExtensibilityElement(bindingExtension); + return binding; + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + protected void configureBinding(Definition definition, Binding binding, PortType portType) throws WSDLException { + if ( wsBindingName != null ) { + QName name = new QName(definition.getTargetNamespace(), wsBindingName + getSOAPVersionString() + BINDING_SUFFIX); + if ( definition.getBinding(name) == null ) { + binding.setQName(name); + return; + } + } + + QName portTypeName = portType.getQName(); + if (portTypeName != null) { + // Choose Binding if available. If this name is in use, insert + // separating underscores until there is no clash. + for (String suffix = BINDING_SUFFIX; ; suffix = "_" + suffix) { + QName name = new QName(definition.getTargetNamespace(), portTypeName.getLocalPart() + suffix); + if (definition.getBinding(name) == null) { + binding.setQName(name); + break; + } + } + } + } + + @SuppressWarnings("unchecked") + public void createBindingOperations(Definition definition, Binding binding, PortType portType) { + try { + for (Iterator oi = portType.getOperations().iterator(); oi.hasNext();) { + Operation operation = (Operation)oi.next(); + // Removed improper defaulting of SOAP action. createBindingOperations() is called + // when binding.ws does not supply a WSDL binding and the reference is using interface.wsdl. + // In this case there is no source for a user-supplied action. + // The correct default is "" (empty string). + BindingOperation bindingOperation = + createBindingOperation(definition, operation, ""); + binding.addBindingOperation(bindingOperation); + } + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + @SuppressWarnings("unchecked") + public BindingOperation createBindingOperation(Definition definition, Operation operation, String action) + throws WSDLException { + BindingOperation bindingOperation = definition.createBindingOperation(); + bindingOperation.setOperation(operation); + configureBindingOperation(bindingOperation, operation); + ExtensibilityElement operationExtension = + definition.getExtensionRegistry().createExtension(BindingOperation.class, soapOperation); + if (requiresSOAP12) { + ((SOAP12Operation)operationExtension).setSoapActionURI(action); + } else { + ((SOAPOperation)operationExtension).setSoapActionURI(action); + } + bindingOperation.addExtensibilityElement(operationExtension); + if (operation.getInput() != null) { + BindingInput bindingInput = definition.createBindingInput(); + configureBindingInput(bindingInput, operation.getInput()); + ExtensibilityElement inputExtension = + definition.getExtensionRegistry().createExtension(BindingInput.class, soapBody); + if (requiresSOAP12) { + ((SOAP12Body)inputExtension).setUse("literal"); + } else { + ((SOAPBody)inputExtension).setUse("literal"); + } + bindingInput.addExtensibilityElement(inputExtension); + bindingOperation.setBindingInput(bindingInput); + } + if (operation.getOutput() != null) { + BindingOutput bindingOutput = definition.createBindingOutput(); + configureBindingOutput(bindingOutput, operation.getOutput()); + ExtensibilityElement outputExtension = + definition.getExtensionRegistry().createExtension(BindingOutput.class, soapBody); + if (requiresSOAP12) { + ((SOAP12Body)outputExtension).setUse("literal"); + } else { + ((SOAPBody)outputExtension).setUse("literal"); + } + bindingOutput.addExtensibilityElement(outputExtension); + bindingOperation.setBindingOutput(bindingOutput); + } + for (Iterator fi = operation.getFaults().values().iterator(); fi.hasNext();) { + Fault fault = (Fault)fi.next(); + BindingFault bindingFault = definition.createBindingFault(); + ExtensibilityElement faultExtension = + definition.getExtensionRegistry().createExtension(BindingFault.class, soapFault); + configureBindingFault(bindingFault, faultExtension, fault); + bindingFault.addExtensibilityElement(faultExtension); + bindingOperation.addBindingFault(bindingFault); + } + return bindingOperation; + } + + protected void configureBindingOperation(BindingOperation bindingOperation, Operation operation) + throws WSDLException { + bindingOperation.setName(operation.getName()); + } + + protected void configureBindingInput(BindingInput bindingInput, Input input) throws WSDLException { + bindingInput.setName(input.getName()); + } + + protected void configureBindingOutput(BindingOutput bindingOutput, Output output) throws WSDLException { + bindingOutput.setName(output.getName()); + } + + protected void configureBindingFault(BindingFault bindingFault, + ExtensibilityElement faultExtension, + Fault fault) + throws WSDLException { + String faultName = fault.getName(); + bindingFault.setName(faultName); + if (requiresSOAP12) { + ((SOAP12Fault)faultExtension).setName(faultName); + ((SOAP12Fault)faultExtension).setUse("literal"); + } else { + ((SOAPFault)faultExtension).setName(faultName); + ((SOAPFault)faultExtension).setUse("literal"); + } + } + + public Service createService(Definition definition, PortType portType, String serviceName) { + try { + Service service = definition.createService(); + configureService(definition, service, portType, serviceName); + definition.addService(service); + return service; + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + public Service createService(Definition definition, Binding binding, String serviceName) { + try { + Service service = definition.createService(); + configureService(definition, service, binding.getPortType(), serviceName); + definition.addService(service); + return service; + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + protected void configureService(Definition definition, Service service, PortType portType, String serviceName) throws WSDLException { + if ( serviceName != null ) { + QName name = new QName(definition.getTargetNamespace(), serviceName); + if ( definition.getService(name) == null ) { + service.setQName(name); + return; + } + } + + QName portTypeName = portType.getQName(); + if (portTypeName != null) { + // Choose Service if available. If this name is in use, insert + // separating underscores until there is no clash. + for (String suffix = SERVICE_SUFFIX; ; suffix = "_" + suffix) { + QName name = new QName(definition.getTargetNamespace(), portTypeName.getLocalPart() + suffix); + if (definition.getService(name) == null) { + service.setQName(name); + break; + } + } + } + } + + public Port createPort(Definition definition, Binding binding, Service service, String uri) { + try { + Port port = definition.createPort(); + port.setBinding(binding); + configurePort(port, binding); + if (uri != null) { + ExtensibilityElement portExtension = + definition.getExtensionRegistry().createExtension(Port.class, soapAddress); + if (requiresSOAP12) { + ((SOAP12Address)portExtension).setLocationURI(uri); + } else { + ((SOAPAddress)portExtension).setLocationURI(uri); + } + port.addExtensibilityElement(portExtension); + } + service.addPort(port); + return port; + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + protected void configurePort(Port port, Binding binding) throws WSDLException { + if ( wsBindingName != null ) { + port.setName(wsBindingName + getSOAPVersionString() + PORT_SUFFIX); + } else if (binding.getPortType() != null && binding.getPortType().getQName() != null) { + port.setName(binding.getPortType().getQName().getLocalPart() + PORT_SUFFIX); + } + } + + private String getSOAPVersionString() { + if ( requiresSOAP12 ) { + return "SOAP12"; + } else { + return "SOAP11"; + } + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLGenerationException.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLGenerationException.java new file mode 100644 index 0000000000..1a9b26d618 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLGenerationException.java @@ -0,0 +1,54 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import org.apache.tuscany.sca.monitor.Problem; +import org.oasisopen.sca.ServiceRuntimeException; + +public class WSDLGenerationException extends ServiceRuntimeException { + private static final long serialVersionUID = 1L; + private Problem problem; + + public WSDLGenerationException() { + super(); + } + + public WSDLGenerationException(String message, Throwable cause) { + super(message, cause); + } + + public WSDLGenerationException(String message) { + super(message); + } + + public WSDLGenerationException(Throwable cause) { + super(cause); + } + + public WSDLGenerationException(String message, Throwable cause, Problem problem) { + super(message, cause); + this.problem = problem; + } + + public Problem getProblem() { + return problem; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLServiceGenerator.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLServiceGenerator.java new file mode 100644 index 0000000000..8839bb9679 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WSDLServiceGenerator.java @@ -0,0 +1,546 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +//FIXME: trim the import list down to what's really needed + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.wsdl.Binding; +import javax.wsdl.Definition; +import javax.wsdl.Import; +import javax.wsdl.Message; +import javax.wsdl.Part; +import javax.wsdl.Port; +import javax.wsdl.PortType; +import javax.wsdl.Service; +import javax.wsdl.WSDLException; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.soap.SOAPAddress; +import javax.wsdl.extensions.soap.SOAPBinding; +import javax.wsdl.extensions.soap12.SOAP12Address; +import javax.wsdl.extensions.soap12.SOAP12Binding; +import javax.wsdl.factory.WSDLFactory; +import javax.wsdl.xml.WSDLWriter; +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.AbstractContract; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.CompositeService; +import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.apache.tuscany.sca.interfacedef.Interface; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; +import org.apache.tuscany.sca.interfacedef.wsdl.WSDLInterface; +import org.apache.tuscany.sca.monitor.Monitor; +import org.apache.tuscany.sca.monitor.Problem; +import org.apache.tuscany.sca.monitor.Problem.Severity; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * WSDLServiceGenerator generates a binding WSDL service document. + * + * @version $Rev$ $Date$ + */ +public class WSDLServiceGenerator { + // the following switch is temporary for debugging + public static boolean printWSDL; // external code sets this to print generated WSDL + + private static final Logger logger = Logger.getLogger(WSDLServiceGenerator.class.getName()); + private static final QName TRANSPORT_JMS_QUALIFIED_INTENT = + new QName("http://docs.oasis-open.org/ns/opencsa/sca/200912", "transport.jms"); + private static final String DEFAULT_QUEUE_CONNECTION_FACTORY = "TuscanyQueueConnectionFactory"; + private static final String ADDRESS = "Address"; + + private WSDLServiceGenerator() { + // this class has static methods only and cannot be instantiated + } + + /** + * Log a warning message. + * @param problem + */ + private static void logWarning(Problem problem) { + Logger problemLogger = Logger.getLogger(problem.getSourceClassName(), problem.getResourceBundleName()); + if (problemLogger != null){ + problemLogger.logp(Level.WARNING, problem.getSourceClassName(), null, problem.getMessageId(), problem.getMessageParams()); + } else { + logger.severe("Can't get logger " + problem.getSourceClassName()+ " with bundle " + problem.getResourceBundleName()); + } + } + + /** + * Report a warning. + * @param message + * @param binding + * @param parameters + */ + private static void warning(Monitor monitor, String message, WebServiceBinding wsBinding, String... messageParameters) { + Problem problem = monitor.createProblem(WSDLServiceGenerator.class.getName(), "wsdlgen-validation-messages", Severity.WARNING, wsBinding, message, (Object[])messageParameters); + if (monitor != null) { + monitor.problem(problem); + } else { + logWarning(problem); + } + } + + /** + * Report an error. + * @param message + * @param binding + * @param parameters + */ + private static void error(Monitor monitor, String message, WebServiceBinding wsBinding, String... messageParameters) { + Problem problem = monitor.createProblem(WSDLServiceGenerator.class.getName(), "wsdlgen-validation-messages", Severity.ERROR, wsBinding, message, (Object[])messageParameters); + if (monitor != null) { + monitor.problem(problem); + } else { + throw new WSDLGenerationException(problem.toString(), null, problem); + } + } + + /** + * Generate a suitably configured WSDL definition + */ + protected static Definition configureWSDLDefinition(WebServiceBinding wsBinding, + Component component, + AbstractContract contract, + Monitor monitor) { + + //[nash] changes to the builder sequence avoid calling this for a CompositeService + assert !(contract instanceof CompositeService); + + boolean generatedWsdl = false; + String contractName = contract.getName(); + + List ports = new ArrayList(); + WSDLDefinition wsdlDefinition = wsBinding.getUserSpecifiedWSDLDefinition(); + if (wsdlDefinition == null) { + error(monitor, "NoWsdlInterface", wsBinding, component.getName(), contract.getName()); + return null; + } + Definition def = wsdlDefinition.getDefinition(); + if (wsdlDefinition.getBinding() == null) { + // The WSDL document was provided by the user. Generate a new + // WSDL document with imports from the user-provided document. + WSDLFactory factory = null; + try { + factory = WSDLFactory.newInstance(); + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + Definition newDef = factory.newDefinition(); + + // Construct a target namespace from the base URI of the user's + // WSDL document (is this what we should be using?) and a path + // computed according to the SCA Web Service binding spec. + String nsName = component.getName() + "/" + contractName; + String namespaceURI = null; + try { + URI userTNS = new URI(def.getTargetNamespace()); + namespaceURI = userTNS.resolve("/" + nsName).toString(); + } catch (URISyntaxException e1) { + throw new WSDLGenerationException(e1); + } catch (IllegalArgumentException e2) { + throw new WSDLGenerationException(e2); + } + + // set name and targetNamespace attributes on the definition + String defsName = component.getName() + "." + contractName; + newDef.setQName(new QName(namespaceURI, defsName)); + newDef.setTargetNamespace(namespaceURI); + newDef.addNamespace("tns", namespaceURI); + + // set wsdl namespace prefix on the definition + newDef.addNamespace("wsdl", "http://schemas.xmlsoap.org/wsdl/"); + + // import the service or reference interface portType + List imports = new ArrayList(); + Interface interfaze = wsBinding.getBindingInterfaceContract().getInterface(); + if (interfaze instanceof WSDLInterface) { + PortType portType = ((WSDLInterface)interfaze).getPortType(); + boolean ok = importPortType(portType, wsdlDefinition, newDef, imports); + if (!ok) { + error(monitor, "PortTypeNotFound", wsBinding, portType.getQName().toString(), + component.getName(), contract.getName()); + } + } + + // import an existing binding if specified + Binding binding = wsBinding.getBinding(); + if (binding != null) { + boolean ok = importBinding(binding, wsdlDefinition, newDef, imports); + if (ok) { + boolean ok2 = importPortType(binding.getPortType(), wsdlDefinition, newDef, imports); + if (!ok2) { + error(monitor, "PortTypeNotFound", wsBinding, binding.getPortType().getQName().toString(), + component.getName(), contract.getName()); + } + } else { + error(monitor, "BindingNotFound", wsBinding, binding.getQName().toString(), + component.getName(), contract.getName()); + } + } + + // import bindings and portTypes needed by services and ports + QName serviceQName = wsBinding.getServiceName(); + String portName = wsBinding.getPortName(); + if (serviceQName != null) { + Service service = def.getService(serviceQName); + if (portName != null) { + Port port = service.getPort(portName); + Port newPort = copyPort(newDef, port, wsBinding); + if (newPort != null) { + importBinding(port.getBinding(), wsdlDefinition, newDef, imports); + ports.add(newPort); + } else { + error(monitor, "InvalidPort", wsBinding, serviceQName.toString(), portName, + component.getName(), contract.getName()); + } + } else { + for (Object port : service.getPorts().values()) { + Port newPort = copyPort(newDef, (Port)port, wsBinding); + if (newPort != null) { + importBinding(((Port)port).getBinding(), wsdlDefinition, newDef, imports); + ports.add(newPort); + } else { + // not an error, just ignore the port + warning(monitor, "IgnoringPort", wsBinding, serviceQName.toString(), ((Port)port).getName(), + component.getName(), contract.getName()); + } + } + if (ports.size() == 0) { + error(monitor, "NoValidPorts", wsBinding, serviceQName.toString(), + component.getName(), contract.getName()); + } + } + } + + // replace original WSDL definition by the generated definition + def = newDef; + + } else { + generatedWsdl = true; + // The WSDL definition was generated by Interface2WSDLGenerator. + // Reuse it instead of creating a new definition here. + } + + // add a service and ports to the generated definition + WSDLDefinitionGenerator helper = + new WSDLDefinitionGenerator(wsBinding); + WSDLInterface wi = (WSDLInterface)wsBinding.getBindingInterfaceContract().getInterface(); + PortType portType = wi.getPortType(); + // If using the WSDL definition that was generated by Interface2WSDLGenerator, + // add the component name to the WSDL service name. This is done so that the + // WSDL service name doesn't clash with other components that use the same contract. + // The runtime may have a need to keep the WSDL services separate, e.g. to support + // different policy attachments on each service. It isn't necessary to add the + // component name when using user-supplied WSDL because in that case the above code + // created a new WSDL document in a namespace that is qualified by the component name. + String wsdlServiceName = contract.getName(); + if (generatedWsdl) { + wsdlServiceName = component.getURI().replace('/','_') + '_' + wsdlServiceName; + } + Service service = helper.createService(def, portType, wsdlServiceName); + if (wsBinding.getBinding() == null && ports.size() == 0) { + Binding binding = helper.createBinding(def, portType); + if (BindingWSDLGenerator.requiresSOAP12(wsBinding)) { + def.addNamespace("SOAP12", "http://schemas.xmlsoap.org/wsdl/soap12/"); + } else { + def.addNamespace("SOAP11", "http://schemas.xmlsoap.org/wsdl/soap/"); + } + helper.createBindingOperations(def, binding, portType); + binding.setUndefined(false); + + // set binding style based on the interface specified by the + // user if one is available + // TODO - set encoding style also currently default to literal + if (wsdlDefinition != null && wsdlDefinition.getDefinition() != null){ + Message firstMessage = (Message)wsdlDefinition.getDefinition().getMessages().values().iterator().next(); + Part firstPart = (Part)firstMessage.getParts().values().iterator().next(); + if (firstPart.getTypeName() != null){ + for (Object ext : binding.getExtensibilityElements()){ + if (ext instanceof SOAPBinding){ + ((SOAPBinding)ext).setStyle("rpc"); + break; + } + } + } + } + + def.addBinding(binding); + + String endpointURI = computeActualURI(wsBinding, null); + Port port = helper.createPort(def, binding, service, endpointURI); + wsBinding.setService(service); + wsBinding.setPort(port); + } else { + if (ports.size() > 0) { + // there are one or more user-specified valid ports + for (Port port : ports) { + service.addPort(port); + } + if (ports.size() == 1) { + // only one port, so use it + wsBinding.setPort(ports.get(0)); + } else { + // multiple ports, make them all available + wsBinding.setPort(null); + } + } else { + // no valid user-specified ports, so create a suitably configured port + String endpointURI = computeActualURI(wsBinding, null); + Port port = helper.createPort(def, wsBinding.getBinding(), service, endpointURI); + if (BindingWSDLGenerator.requiresSOAP12(wsBinding)) { + def.addNamespace("SOAP12", "http://schemas.xmlsoap.org/wsdl/soap12/"); + } else { + def.addNamespace("SOAP11", "http://schemas.xmlsoap.org/wsdl/soap/"); + } + wsBinding.setPort(port); + } + wsBinding.setService(service); + } + + // for debugging + if (printWSDL) { + try { + System.out.println("Generated WSDL for " + component.getName() + "/" + contractName); + WSDLWriter writer = javax.wsdl.factory.WSDLFactory.newInstance().newWSDLWriter(); + writer.writeWSDL(def, System.out); + } catch (WSDLException e) { + throw new WSDLGenerationException(e); + } + } + + return def; + } + + private static boolean importPortType(PortType portType, + WSDLDefinition wsdlDef, + Definition newDef, + List imports) { + return addImport(portType.getQName(), PortType.class, wsdlDef, newDef, imports); + } + + private static boolean importBinding(Binding binding, + WSDLDefinition wsdlDef, + Definition newDef, + List imports) { + boolean ok = addImport(binding.getQName(), Binding.class, wsdlDef, newDef, imports); + if (ok) { + List bindingExtensions = binding.getExtensibilityElements(); + for (final Object extension : bindingExtensions) { + if (extension instanceof SOAPBinding) { + newDef.addNamespace("SOAP11", "http://schemas.xmlsoap.org/wsdl/soap/"); + } + if (extension instanceof SOAP12Binding) { + newDef.addNamespace("SOAP12", "http://schemas.xmlsoap.org/wsdl/soap12/"); + } + } + } + return ok; + } + + private static boolean addImport(QName name, + Class type, + WSDLDefinition wsdlDef, + Definition newDef, + List imports) { + String namespace = name.getNamespaceURI(); + if (newDef.getImports(namespace) == null) { + WSDLDefinition impDef = findDefinition(wsdlDef, name, type); + if (impDef != null) { + Import imp = newDef.createImport(); + imp.setNamespaceURI(namespace); + imp.setLocationURI(impDef.getURI().toString()); + imp.setDefinition(impDef.getDefinition()); + newDef.addNamespace("ns" + imports.size(), namespace); + newDef.addImport(imp); + imports.add(impDef); + return true; + } else { + // import was not added because element not found + return false; + } + } + return true; + } + + private static WSDLDefinition findDefinition(WSDLDefinition wsdlDef, QName name, Class type) { + if (wsdlDef == null || name == null) { + return wsdlDef; + } + if (wsdlDef.getURI() != null) { // not a facade + Definition def = wsdlDef.getDefinition(); + Map types = type == PortType.class ? def.getPortTypes() : def.getBindings(); + if (types.get(name) != null) { + return wsdlDef; + } + } + for (WSDLDefinition impDef : wsdlDef.getImportedDefinitions()) { + WSDLDefinition d = findDefinition(impDef, name, type); + if (d != null) { + return d; + } + } + return null; + } + + private static Port copyPort(Definition def, Port port, WebServiceBinding wsBinding) { + Port newPort = def.createPort(); + newPort.setName(port.getName()); + newPort.setBinding(port.getBinding()); + List portExtensions = port.getExtensibilityElements(); + for (final Object extension : portExtensions) { + ExtensibilityElement newExt = null; + if (extension instanceof SOAPAddress) { + def.addNamespace("SOAP11", "http://schemas.xmlsoap.org/wsdl/soap/"); + try { + newExt = def.getExtensionRegistry().createExtension( + Port.class, WSDLDefinitionGenerator.SOAP_ADDRESS); + } catch (WSDLException e) { + } + // By this stage the URI should have been copied from the WSDL port and + // should have run through the binding URI builder. + //String uri = computeActualURI(wsBinding, port); + String uri = wsBinding.getURI(); + ((SOAPAddress)newExt).setLocationURI(uri); + newPort.addExtensibilityElement(newExt); + } else if (extension instanceof SOAP12Address) { + def.addNamespace("SOAP12", "http://schemas.xmlsoap.org/wsdl/soap12/"); + try { + newExt = def.getExtensionRegistry().createExtension( + Port.class, WSDLDefinitionGenerator.SOAP12_ADDRESS); + } catch (WSDLException e) { + } + // By this stage the URI should have been copied from the WSDL port and + // should have run through the binding URI builder. + //String uri = computeActualURI(wsBinding, port); + String uri = wsBinding.getURI(); + ((SOAP12Address)newExt).setLocationURI(uri); + newPort.addExtensibilityElement(newExt); + } else { + // we don't support ports with other extensibility elements such as HTTPAddress + return null; + } + } + return newPort; + } + + /** + * Compute the endpoint URI based on section 2.1.1 of the WS binding Specification + * 1. The URIs in the endpoint(s) of the referenced WSDL, which may be relative + * 2. The URI specified by the wsa:Address element of the + * wsa:EndpointReference, which may be relative + * 3. The explicitly stated URI in the "uri" attribute of the binding.ws element, + * which may be relative, + * 4. The implicit URI as defined by in section 1.7 in the SCA Assembly Specification + * If the has no wsdlElement but does have a uri attribute then + * the uri takes precedence over any implicitly used WSDL. + * + */ + private static String computeActualURI(WebServiceBinding wsBinding, Port port) { + + URI eprURI = null; + if (wsBinding.getEndPointReference() != null) { + eprURI = getEPR(wsBinding); + } + + URI wsdlURI = null; + if (wsBinding.getServiceName() != null && wsBinding.getBindingName() == null) { + // explicitly points at a WSDL port, may be a relative URI + wsdlURI = getEndpoint(port); + } + + // if the WSDL port/endpoint has an absolute URI use that + if (wsdlURI != null && wsdlURI.isAbsolute()) { + return wsdlURI.toString(); + } + + // if the wsa:EndpointReference has an address element with an absolute URI use that + if (eprURI != null && eprURI.isAbsolute()) { + return eprURI.toString(); + } + + // either there is no WSDL port endpoint URI or that URI is relative + String actualURI = wsBinding.getURI(); + if (eprURI != null && eprURI.toString().length() != 0) { + // there is a relative URI in the binding EPR + actualURI = actualURI + "/" + eprURI; + } + + if (wsdlURI != null && wsdlURI.toString().length() != 0) { + // there is a relative URI in the WSDL port + actualURI = actualURI + "/" + wsdlURI; + } + + if (actualURI != null) { + actualURI = URI.create(actualURI).normalize().toString(); + } + + return actualURI; + } + + private static URI getEPR(WebServiceBinding wsBinding) { + NodeList nodeList = wsBinding.getEndPointReference().getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node childNode = nodeList.item(i); + if (childNode instanceof Element && ADDRESS.equals(childNode.getLocalName())) { + NodeList addrNodes = childNode.getChildNodes(); + for (int j = 0; j < addrNodes.getLength(); j++) { + Node addrNode = addrNodes.item(j); + if (addrNode instanceof Text) { + return URI.create(((Text)addrNode).getWholeText()); + } + } + } + } + return null; + } + + /** + * Returns the endpoint of a given port. + */ + private static URI getEndpoint(Port wsdlPort) { + if (wsdlPort != null) { + List wsdlPortExtensions = wsdlPort.getExtensibilityElements(); + for (Object extension : wsdlPortExtensions) { + if (extension instanceof SOAPAddress) { + String uri = ((SOAPAddress)extension).getLocationURI(); + return (uri == null || "".equals(uri)) ? null : URI.create(uri); + } + if (extension instanceof SOAP12Address) { + SOAP12Address address = (SOAP12Address)extension; + String uri = address.getLocationURI(); + return (uri == null || "".equals(uri)) ? null : URI.create(uri); + } + } + } + return null; + } + +} diff --git a/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WebServiceBindingBuilder.java b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WebServiceBindingBuilder.java new file mode 100644 index 0000000000..5e83622b79 --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/binding-ws-wsdlgen/src/main/java/org/apache/tuscany/sca/binding/ws/wsdlgen/WebServiceBindingBuilder.java @@ -0,0 +1,109 @@ +/* + * 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.sca.binding.ws.wsdlgen; + +import java.util.List; + +import javax.xml.namespace.QName; + +import org.apache.tuscany.sca.assembly.Base; +import org.apache.tuscany.sca.assembly.Component; +import org.apache.tuscany.sca.assembly.Contract; +import org.apache.tuscany.sca.assembly.builder.BindingBuilder; +import org.apache.tuscany.sca.assembly.builder.BuilderContext; +import org.apache.tuscany.sca.binding.ws.WebServiceBinding; +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.core.FactoryExtensionPoint; +import org.apache.tuscany.sca.definitions.Definitions; +import org.apache.tuscany.sca.policy.BindingType; +import org.apache.tuscany.sca.policy.DefaultingPolicySubject; +import org.apache.tuscany.sca.policy.DefaultIntent; +import org.apache.tuscany.sca.policy.Intent; +import org.apache.tuscany.sca.policy.PolicyFactory; +import org.apache.tuscany.sca.policy.PolicySubject; + +/** + * A factory for the calculated WSDL document needed by Web Service bindings. + * + * @version $Rev$ $Date$ + */ +public class WebServiceBindingBuilder implements BindingBuilder { + + private ExtensionPointRegistry extensionPoints; + private PolicyFactory policyFactory; + + public WebServiceBindingBuilder(ExtensionPointRegistry extensionPoints) { + this.extensionPoints = extensionPoints; + + FactoryExtensionPoint modelFactories = extensionPoints.getExtensionPoint(FactoryExtensionPoint.class); + this.policyFactory = modelFactories.getFactory(PolicyFactory.class); + } + + /** + * Create a calculated WSDL document and save it in the Web Service binding. + */ + public void build(Component component, Contract contract, WebServiceBinding binding, BuilderContext context, boolean rebuild) { + // in some cases (callback service endpoint processing) we need to re-set the binding interface contract + // and re-generate the WSDL doc from it. This is because the callback binding may be cloned from the + // forward binding + if (rebuild == true){ + binding.setBindingInterfaceContract(null); + binding.setGeneratedWSDLDocument(null); + } + + BindingWSDLGenerator.generateWSDL(component, contract, binding, extensionPoints, context.getMonitor()); + + /* + * Set the default mayProvides intent provided by the binding. For example, + * It mayProvides SOAP.v1_1 and SOAP.v1_2. If you don't specify any intents + * it implements SOAP.v1_1 by default and hence the default intent + * is SOAP.v1_1. Binding.ws doesn't allwaysProvide SOAP.v1_1 though as if the + * user specifies the SOAP.v1_2 the binding does SOAP.v1_2 instead of SOAP.v1_1 + * + * This logic is here rather than in the binding model so that the behaviour + * of the implementation is not dictated by the hard coded configuration of the + * model. This build runs before the policy builders where this information is used + * TODO - can we get this code into the actual impl modules itself. Move this builder? + */ + List defaultIntents = ((DefaultingPolicySubject)binding).getDefaultIntents(); + DefaultIntent defaultIntent = policyFactory.createDefaultIntent(); + + Definitions systemDefinitions = context.getDefinitions(); + if (systemDefinitions != null){ + BindingType bindingType = systemDefinitions.getBindingType(binding.getType()); + for (Intent mayProvideIntent : bindingType.getMayProvidedIntents()){ + if (mayProvideIntent.getName().getLocalPart().equals("SOAP.v1_1")){ + defaultIntent.setIntent(mayProvideIntent); + } + if (mayProvideIntent.getName().getLocalPart().equals("SOAP.v1_2")){ + defaultIntent.getMutuallyExclusiveIntents().add(mayProvideIntent); + } + } + + defaultIntents.add(defaultIntent); + } + + } + + public QName getBindingType() { + return WebServiceBinding.TYPE; + } + +} -- cgit v1.2.3