diff --git a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl11DefinitionBuilder.java b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl11DefinitionBuilder.java index 41c9c749..2fe1c57f 100644 --- a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl11DefinitionBuilder.java +++ b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/Wsdl11DefinitionBuilder.java @@ -21,8 +21,7 @@ import org.springframework.ws.wsdl.WsdlDefinitionException; /** * Defines the contract for classes that can create a {@link Wsdl11Definition} at runtime. *
- * Used by {@link org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition} to generate the WSDL based on a schema, a - * class, etc. + * Used by {@link DynamicWsdl11Definition} to generate the WSDL based on a schema, a class, etc. * * @author Arjen Poutsma * @since 1.0.0 diff --git a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/AbstractSoap12Wsdl4jDefinitionBuilder.java b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/AbstractSoap12Wsdl4jDefinitionBuilder.java new file mode 100755 index 00000000..208e3884 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/AbstractSoap12Wsdl4jDefinitionBuilder.java @@ -0,0 +1,247 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed 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.springframework.ws.wsdl.wsdl11.builder; + +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.WSDLException; +import javax.wsdl.extensions.ExtensibilityElement; +import javax.wsdl.extensions.ExtensionRegistry; +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.xml.namespace.QName; + +/** + * Abstract base class forWsdl11DefinitionBuilder implementations that use WSDL4J and contain a SOAP 1.2
+ * binding. Requires the locationUri property to be set before use.
+ *
+ * @author Arjen Poutsma
+ * @author Alex Marshall
+ * @see #setLocationUri(String)
+ * @since 1.1.0
+ */
+public abstract class AbstractSoap12Wsdl4jDefinitionBuilder extends AbstractBindingWsdl4jDefinitionBuilder {
+
+ private static final String WSDL_SOAP_NAMESPACE_URI = "http://schemas.xmlsoap.org/wsdl/soap12/";
+
+ private static final String WSDL_SOAP_PREFIX = "soap12";
+
+ /** The default soap12:binding transport attribute value. */
+ public static final String DEFAULT_TRANSPORT_URI = "http://schemas.xmlsoap.org/soap/http";
+
+ private String transportUri = DEFAULT_TRANSPORT_URI;
+
+ private String locationUri;
+
+ /**
+ * Sets the value used for the soap12:binding transport attribute value.
+ *
+ * @see SOAP12Binding#setTransportURI(String)
+ * @see #DEFAULT_TRANSPORT_URI
+ */
+ public void setTransportUri(String transportUri) {
+ this.transportUri = transportUri;
+ }
+
+ /** Sets the value used for the soap12:address location attribute value. */
+ public void setLocationUri(String locationUri) {
+ this.locationUri = locationUri;
+ }
+
+ /** Adds the WSDL SOAP namespace to the definition. */
+ protected void populateDefinition(Definition definition) throws WSDLException {
+ definition.addNamespace(WSDL_SOAP_PREFIX, WSDL_SOAP_NAMESPACE_URI);
+ }
+
+ /**
+ * Calls {@link AbstractBindingWsdl4jDefinitionBuilder#populateBinding(Binding, PortType)}, creates {@link
+ * SOAP12Binding}, and calls {@link #populateSoapBinding(SOAP12Binding)}.
+ *
+ * @param binding the WSDL4J Binding
+ * @param portType the corresponding PortType
+ * @throws WSDLException in case of errors
+ */
+ protected void populateBinding(Binding binding, PortType portType) throws WSDLException {
+ super.populateBinding(binding, portType);
+ SOAP12Binding soapBinding = (SOAP12Binding) createSoapExtension(Binding.class, "binding");
+ populateSoapBinding(soapBinding);
+ binding.addExtensibilityElement(soapBinding);
+ }
+
+ /**
+ * Called after the {@link SOAP12Binding} has been created. Default implementation sets the binding style to
+ * "document", and set the transport URI to the value set on this builder. Subclasses can override this
+ * behavior.
+ *
+ * @param soapBinding the WSDL4J SOAP12Binding
+ * @throws WSDLException in case of errors
+ * @see SOAP12Binding#setStyle(String)
+ * @see SOAP12Binding#setTransportURI(String)
+ * @see #setTransportUri(String)
+ * @see #DEFAULT_TRANSPORT_URI
+ */
+ protected void populateSoapBinding(SOAP12Binding soapBinding) throws WSDLException {
+ soapBinding.setStyle("document");
+ soapBinding.setTransportURI(transportUri);
+ }
+
+ /**
+ * Calls {@link AbstractBindingWsdl4jDefinitionBuilder#populateBindingOperation(BindingOperation, Operation)},
+ * creates a {@link SOAP12Operation}, and calls {@link #populateSoapOperation(SOAP12Operation)}.
+ *
+ * @param bindingOperation the WSDL4J BindingOperation
+ * @throws WSDLException in case of errors
+ */
+ protected void populateBindingOperation(BindingOperation bindingOperation, Operation operation)
+ throws WSDLException {
+ super.populateBindingOperation(bindingOperation, operation);
+ SOAP12Operation soapOperation = (SOAP12Operation) createSoapExtension(BindingOperation.class, "operation");
+ populateSoapOperation(soapOperation);
+ bindingOperation.addExtensibilityElement(soapOperation);
+ }
+
+ /**
+ * Called after the {@link SOAP12Operation} has been created.
+ *
+ * Default implementation set the SOAPAction uri to an empty string.
+ *
+ * @param soapOperation the WSDL4J SOAP12Operation
+ * @throws WSDLException in case of errors
+ * @see SOAP12Operation#setSoapActionURI(String)
+ */
+ protected void populateSoapOperation(SOAP12Operation soapOperation) throws WSDLException {
+ soapOperation.setSoapActionURI("");
+ }
+
+ /**
+ * Creates a {@link SOAP12Body}, and calls {@link #populateSoapBody(SOAP12Body)}.
+ *
+ * @param bindingInput the WSDL4J BindingInput
+ * @throws WSDLException in case of errors
+ */
+ protected void populateBindingInput(BindingInput bindingInput, Input input) throws WSDLException {
+ super.populateBindingInput(bindingInput, input);
+ SOAP12Body soapBody = (SOAP12Body) createSoapExtension(BindingInput.class, "body");
+ populateSoapBody(soapBody);
+ bindingInput.addExtensibilityElement(soapBody);
+ }
+
+ /**
+ * Creates a {@link SOAP12Body}, and calls {@link #populateSoapBody(SOAP12Body)}.
+ *
+ * @param bindingOutput the WSDL4J BindingOutput
+ * @throws WSDLException in case of errors
+ */
+ protected void populateBindingOutput(BindingOutput bindingOutput, Output output) throws WSDLException {
+ super.populateBindingOutput(bindingOutput, output);
+ SOAP12Body soapBody = (SOAP12Body) createSoapExtension(BindingOutput.class, "body");
+ populateSoapBody(soapBody);
+ bindingOutput.addExtensibilityElement(soapBody);
+ }
+
+ /**
+ * Creates a {@link SOAP12Body}, and calls {@link #populateSoapBody(SOAP12Body)}.
+ *
+ * @param bindingFault the WSDL4J BindingFault
+ * @throws WSDLException in case of errors
+ */
+ protected void populateBindingFault(BindingFault bindingFault, Fault fault) throws WSDLException {
+ super.populateBindingFault(bindingFault, fault);
+ SOAP12Fault soapFault = (SOAP12Fault) createSoapExtension(BindingFault.class, "fault");
+ populateSoapFault(bindingFault, soapFault);
+ bindingFault.addExtensibilityElement(soapFault);
+ }
+
+ /**
+ * Called after the {@link SOAP12Body} has been created. Default implementation sets the use style to
+ * "literal". Subclasses can override this behavior.
+ *
+ * @param soapBody the WSDL4J SOAP12Body
+ * @throws WSDLException in case of errors
+ * @see SOAP12Body#setUse(String)
+ */
+ protected void populateSoapBody(SOAP12Body soapBody) throws WSDLException {
+ soapBody.setUse("literal");
+ }
+
+ /**
+ * Called after the {@link SOAP12Fault} has been created. Default implementation sets the use style to
+ * "literal", and sets the name equal to the binding fault. Subclasses can override this behavior.
+ *
+ * @param bindingFault the WSDL4J BindingFault
+ * @param soapFault the WSDL4J SOAPFault
+ * @throws WSDLException in case of errors
+ * @see SOAP12Fault#setUse(String)
+ */
+ protected void populateSoapFault(BindingFault bindingFault, SOAP12Fault soapFault) throws WSDLException {
+ soapFault.setName(bindingFault.getName());
+ soapFault.setUse("literal");
+ }
+
+ /**
+ * Creates a {@link SOAP12Address}, and calls {@link #populateSoapAddress(SOAP12Address)}.
+ *
+ * @param port the WSDL4J Port
+ * @throws WSDLException in case of errors
+ */
+ protected void populatePort(Port port, Binding binding) throws WSDLException {
+ super.populatePort(port, binding);
+ SOAP12Address soapAddress = (SOAP12Address) createSoapExtension(Port.class, "address");
+ populateSoapAddress(soapAddress);
+ port.addExtensibilityElement(soapAddress);
+ }
+
+ /**
+ * Called after the {@link SOAP12Address} has been created. Default implementation sets the location URI to the
+ * value set on this builder. Subclasses can override this behavior.
+ *
+ * @param soapAddress the WSDL4J SOAPAddress
+ * @throws WSDLException in case of errors
+ * @see SOAP12Address#setLocationURI(String)
+ * @see #setLocationUri(String)
+ */
+ protected void populateSoapAddress(SOAP12Address soapAddress) throws WSDLException {
+ soapAddress.setLocationURI(locationUri);
+ }
+
+ /**
+ * Creates a SOAP 1.2 extensibility element.
+ *
+ * @param parentType a class object indicating where in the WSDL definition this extension will exist
+ * @param localName the local name of the extensibility element
+ * @return the extensibility element
+ * @throws WSDLException in case of errors
+ * @see ExtensionRegistry#createExtension(Class,javax.xml.namespace.QName)
+ */
+ protected ExtensibilityElement createSoapExtension(Class parentType, String localName) throws WSDLException {
+ return createExtension(parentType, new QName(WSDL_SOAP_NAMESPACE_URI, localName));
+ }
+
+}
diff --git a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilder.java b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilder.java
index 3ed2fe1d..5929dcf5 100644
--- a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilder.java
+++ b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilder.java
@@ -266,14 +266,11 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Creates messages for each element found in the schema for which isRequestMessage(),
- * isResponseMessage(), or isFaultMessage() is true.
+ * Creates messages for each element found in the schema for which {@link #isRequestMessage(QName)}, {@link
+ * #isResponseMessage(QName)}, or {@link #isFaultMessage(QName)} is true.
*
* @param definition the WSDL4J Definition
* @throws WSDLException in case of errors
- * @see #isRequestMessage(javax.xml.namespace.QName)
- * @see #isResponseMessage(javax.xml.namespace.QName)
- * @see #isFaultMessage(javax.xml.namespace.QName)
*/
protected void buildMessages(Definition definition) throws WSDLException {
List elementDeclarations = schemaHelper.getElementDeclarations(followIncludeImport);
@@ -303,8 +300,8 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Indicates whether the given name name should be included as request Message in the definition.
- * Default implementation checks whether the local part ends with the request suffix.
+ * Indicates whether the given name name should be included as request {@link Message} in the definition. Default
+ * implementation checks whether the local part ends with the request suffix.
*
* @param name the name of the element elligable for being a message
* @return true if to be included as message; false otherwise
@@ -315,8 +312,8 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Indicates whether the given name should be included as Message in the definition. Default
- * implementation checks whether the local part ends with the response suffix.
+ * Indicates whether the given name should be included as {@link Message} in the definition. Default implementation
+ * checks whether the local part ends with the response suffix.
*
* @param name the name of the element elligable for being a message
* @return true if to be included as message; false otherwise
@@ -327,8 +324,8 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Indicates whether the given name should be included as Message in the definition. Default
- * implementation checks whether the local part ends with the fault suffix.
+ * Indicates whether the given name should be included as {@link Message} in the definition. Default implementation
+ * checks whether the local part ends with the fault suffix.
*
* @param name the name of the element elligable for being a message
* @return true if to be included as message; false otherwise
@@ -339,7 +336,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Called after the Message has been created.
+ * Called after the {@link Message} has been created.
*
* Default implementation sets the name of the message to the element name.
*
@@ -352,7 +349,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Called after the Part has been created.
+ * Called after the {@link Part} has been created.
*
* Default implementation sets the element name of the part.
*
@@ -375,7 +372,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Called after the PortType has been created.
+ * Called after the {@link PortType} has been created.
*
* Default implementation sets the name of the port type to the defined value.
*
@@ -471,7 +468,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Called after the Operation has been created.
+ * Called after the {@link Operation} has been created.
*
* Default implementation sets the name of the operation to name of the messages, without suffix.
*
diff --git a/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilder.java b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilder.java
new file mode 100755
index 00000000..50e63e73
--- /dev/null
+++ b/core/src/main/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilder.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2006 the original author or authors.
+ *
+ * Licensed 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.springframework.ws.wsdl.wsdl11.builder;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import javax.wsdl.Definition;
+import javax.wsdl.Fault;
+import javax.wsdl.Input;
+import javax.wsdl.Message;
+import javax.wsdl.Operation;
+import javax.wsdl.OperationType;
+import javax.wsdl.Output;
+import javax.wsdl.Part;
+import javax.wsdl.PortType;
+import javax.wsdl.Service;
+import javax.wsdl.Types;
+import javax.wsdl.WSDLException;
+import javax.wsdl.extensions.schema.Schema;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.io.Resource;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition;
+import org.springframework.xml.namespace.QNameUtils;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+/**
+ * Builds a WsdlDefinition with a SOAP 1.2 binding based on an XSD schema. This builder iterates over all
+ * elements found in the schema, and creates a message for those elements that end with the
+ * request or response suffix. It combines these messages into operations, and builds a
+ * portType based on the operations.
+ *
+ * By default, the schema file is inlined in a types block. However, if the schemaLocation
+ * property is set, an XSD import is used instead. As such, the imported schema file can contain further
+ * imports, which will be resolved correctly in accordance with the schema location.
+ *
+ * To create messages from imported and included schemas, set the followIncludeImport property to
+ * true.
+ *
+ * Typically used within a {@link DynamicWsdl11Definition}, like so:
+ * + * <bean id="airline" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition"> + * <property name="builder"> + * <bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder"> + * <property name="schema" value="/WEB-INF/airline.xsd"/> + * <property name="portTypeName" value="Airline"/> + * <property name="locationUri" value="http://localhost:8080/airline/services"/> + * </bean> + * </property> + * </bean> + *+ * + * Requires the
schema and portTypeName properties to be set.
+ *
+ * @author Arjen Poutsma
+ * @author Alex Marshall
+ * @see #setSchema(org.springframework.core.io.Resource)
+ * @see #setPortTypeName(String)
+ * @see #setRequestSuffix(String)
+ * @see #setResponseSuffix(String)
+ * @since 1.1.0
+ */
+public class XsdBasedSoap12Wsdl4jDefinitionBuilder extends AbstractSoap12Wsdl4jDefinitionBuilder
+ implements InitializingBean {
+
+ /** The default suffix used to detect request elements in the schema. */
+ public static final String DEFAULT_REQUEST_SUFFIX = "Request";
+
+ /** The default suffix used to detect response elements in the schema. */
+ public static final String DEFAULT_RESPONSE_SUFFIX = "Response";
+
+ /** The default suffix used to detect fault elements in the schema. */
+ public static final String DEFAULT_FAULT_SUFFIX = "Fault";
+
+ /** The default prefix used to register the schema namespace in the WSDL. */
+ public static final String DEFAULT_SCHEMA_PREFIX = "schema";
+
+ /** The default prefix used to register the target namespace in the WSDL. */
+ public static final String DEFAULT_PREFIX = "tns";
+
+ /** The suffix used to create a service name from a port type name. */
+ public static final String SERVICE_SUFFIX = "Service";
+
+ private Resource schemaResource;
+
+ private XsdSchemaHelper schemaHelper;
+
+ private String schemaLocation;
+
+ private String targetNamespace;
+
+ private String portTypeName;
+
+ private String schemaPrefix = DEFAULT_SCHEMA_PREFIX;
+
+ private String prefix = DEFAULT_PREFIX;
+
+ private String requestSuffix = DEFAULT_REQUEST_SUFFIX;
+
+ private String responseSuffix = DEFAULT_RESPONSE_SUFFIX;
+
+ private String faultSuffix = DEFAULT_FAULT_SUFFIX;
+
+ private boolean followIncludeImport = false;
+
+ /**
+ * Sets the suffix used to detect request elements in the schema.
+ *
+ * @see #DEFAULT_REQUEST_SUFFIX
+ */
+ public void setRequestSuffix(String requestSuffix) {
+ this.requestSuffix = requestSuffix;
+ }
+
+ /**
+ * Sets the suffix used to detect response elements in the schema.
+ *
+ * @see #DEFAULT_RESPONSE_SUFFIX
+ */
+ public void setResponseSuffix(String responseSuffix) {
+ this.responseSuffix = responseSuffix;
+ }
+
+ /**
+ * Sets the suffix used to detect fault elements in the schema.
+ *
+ * @see #DEFAULT_FAULT_SUFFIX
+ */
+ public void setFaultSuffix(String faultSuffix) {
+ this.faultSuffix = faultSuffix;
+ }
+
+ /** Sets the port type name used for this definition. Required. */
+ public void setPortTypeName(String portTypeName) {
+ this.portTypeName = portTypeName;
+ }
+
+ /** Sets the target namespace used for this definition. */
+ public void setTargetNamespace(String targetNamespace) {
+ this.targetNamespace = targetNamespace;
+ }
+
+ /**
+ * Sets the prefix used to declare the schema target namespace.
+ *
+ * @see #DEFAULT_SCHEMA_PREFIX
+ */
+ public void setSchemaPrefix(String schemaPrefix) {
+ this.schemaPrefix = schemaPrefix;
+ }
+
+ /**
+ * Sets the prefix used to declare the target namespace.
+ *
+ * @see #DEFAULT_PREFIX
+ */
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ /** Sets the XSD schema to use for generating the WSDL. */
+ public void setSchema(Resource schemaResource) {
+ Assert.notNull(schemaResource, "'schema' must not be null");
+ Assert.isTrue(schemaResource.exists(), "schema \"" + schemaResource + "\" does not exit");
+ this.schemaResource = schemaResource;
+ }
+
+ /**
+ * Sets the location of the schema to import. If this property is set, the schema element in the
+ * generated WSDL will only contain an import, referring to the value of this property.
+ */
+ public void setSchemaLocation(String schemaLocation) {
+ Assert.hasLength(schemaLocation, "'schemaLocation' must not be empty");
+ this.schemaLocation = schemaLocation;
+ }
+
+ /**
+ * Indicates whether schema <xsd:include/> and <xsd:import/> should be
+ * followed. Default is false.
+ */
+ public void setFollowIncludeImport(boolean followIncludeImport) {
+ this.followIncludeImport = followIncludeImport;
+ }
+
+ public final void afterPropertiesSet() throws IOException, ParserConfigurationException, SAXException {
+ Assert.notNull(schemaResource, "'schema' is required");
+ Assert.notNull(portTypeName, "'portTypeName' is required");
+ schemaHelper = new XsdSchemaHelper(schemaResource);
+ if (!StringUtils.hasLength(targetNamespace)) {
+ targetNamespace = schemaHelper.getTargetNamespace();
+ }
+ }
+
+ /** Adds the target namespace and schema namespace to the definition. */
+ protected void populateDefinition(Definition definition) throws WSDLException {
+ super.populateDefinition(definition);
+ definition.setTargetNamespace(targetNamespace);
+ definition.addNamespace(schemaPrefix, schemaHelper.getTargetNamespace());
+ if (!targetNamespace.equals(schemaHelper.getTargetNamespace())) {
+ definition.addNamespace(prefix, targetNamespace);
+ }
+ }
+
+ /** Does nothing. */
+ protected void buildImports(Definition definition) throws WSDLException {
+ }
+
+ /**
+ * Creates a {@link Types} object containing a {@link Schema}. By default, the schema set by the schema
+ * property will be inlined into this type. If the schemaLocation is set, object
+ * that is populated with the types found in the schema.
+ *
+ * @param definition the WSDL4J Definition
+ * @throws WSDLException in case of errors
+ */
+ protected void buildTypes(Definition definition) throws WSDLException {
+ Types types = definition.createTypes();
+ Schema schema = (Schema) createExtension(Types.class, XsdSchemaHelper.SCHEMA_NAME);
+ if (!StringUtils.hasLength(schemaLocation)) {
+ schema.setElement(schemaHelper.getSchemaElement());
+ }
+ else {
+ Document document;
+ try {
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ document = documentBuilder.newDocument();
+ }
+ catch (ParserConfigurationException ex) {
+ throw new WSDLException(WSDLException.PARSER_ERROR, "Could not create DocumentBuilder", ex);
+ }
+ Element importingSchemaElement = document.createElementNS(XsdSchemaHelper.SCHEMA_NAME.getNamespaceURI(),
+ QNameUtils.toQualifiedName(XsdSchemaHelper.SCHEMA_NAME));
+ schema.setElement(importingSchemaElement);
+ Element importElement = document.createElementNS(XsdSchemaHelper.IMPORT_NAME.getNamespaceURI(),
+ QNameUtils.toQualifiedName(XsdSchemaHelper.IMPORT_NAME));
+ importingSchemaElement.appendChild(importElement);
+ importElement.setAttribute("namespace", schemaHelper.getTargetNamespace());
+ importElement.setAttribute("schemaLocation", schemaLocation);
+ }
+ types.addExtensibilityElement(schema);
+ definition.setTypes(types);
+ }
+
+ /**
+ * Creates messages for each element found in the schema for which {@link #isRequestMessage(QName)}, {@link
+ * #isResponseMessage(QName)}, or {@link #isFaultMessage(QName)} is true.
+ *
+ * @param definition the WSDL4J Definition
+ * @throws WSDLException in case of errors
+ */
+ protected void buildMessages(Definition definition) throws WSDLException {
+ List elementDeclarations = schemaHelper.getElementDeclarations(followIncludeImport);
+ for (Iterator iterator = elementDeclarations.iterator(); iterator.hasNext();) {
+ QName elementName = (QName) iterator.next();
+ if (elementName != null &&
+ (isRequestMessage(elementName) || isResponseMessage(elementName) || isFaultMessage(elementName))) {
+ if (!StringUtils.hasLength(definition.getPrefix(elementName.getNamespaceURI()))) {
+ int i = 0;
+ while (true) {
+ String prefix = schemaPrefix + Integer.toString(i);
+ if (!StringUtils.hasLength(definition.getNamespace(prefix))) {
+ definition.addNamespace(prefix, elementName.getNamespaceURI());
+ break;
+ }
+ }
+ }
+ Message message = definition.createMessage();
+ populateMessage(message, elementName);
+ Part part = definition.createPart();
+ populatePart(part, elementName);
+ message.addPart(part);
+ message.setUndefined(false);
+ definition.addMessage(message);
+ }
+ }
+ }
+
+ /**
+ * Indicates whether the given name name should be included as request {@link Message} in the definition. Default
+ * implementation checks whether the local part ends with the request suffix.
+ *
+ * @param name the name of the element elligable for being a message
+ * @return true if to be included as message; false otherwise
+ * @see #setRequestSuffix(String)
+ */
+ protected boolean isRequestMessage(QName name) {
+ return name.getLocalPart().endsWith(requestSuffix);
+ }
+
+ /**
+ * Indicates whether the given name should be included as {@link Message} in the definition. Default implementation
+ * checks whether the local part ends with the response suffix.
+ *
+ * @param name the name of the element elligable for being a message
+ * @return true if to be included as message; false otherwise
+ * @see #setResponseSuffix(String)
+ */
+ protected boolean isResponseMessage(QName name) {
+ return name.getLocalPart().endsWith(responseSuffix);
+ }
+
+ /**
+ * Indicates whether the given name should be included as {@link Message} in the definition. Default implementation
+ * checks whether the local part ends with the fault suffix.
+ *
+ * @param name the name of the element elligable for being a message
+ * @return true if to be included as message; false otherwise
+ * @see #setFaultSuffix(String)
+ */
+ protected boolean isFaultMessage(QName name) {
+ return name.getLocalPart().endsWith(faultSuffix);
+ }
+
+ /**
+ * Called after the {@link Message} has been created.
+ *
+ * Default implementation sets the name of the message to the element name.
+ *
+ * @param message the WSDL4J Message
+ * @param elementName the element name
+ * @throws WSDLException in case of errors
+ */
+ protected void populateMessage(Message message, QName elementName) throws WSDLException {
+ message.setQName(new QName(targetNamespace, elementName.getLocalPart()));
+ }
+
+ /**
+ * Called after the {@link Part} has been created.
+ *
+ * Default implementation sets the element name of the part.
+ *
+ * @param part the WSDL4J Part
+ * @param elementName the elementName
+ * @throws WSDLException in case of errors
+ * @see Part#setElementName(javax.xml.namespace.QName)
+ */
+ protected void populatePart(Part part, QName elementName) throws WSDLException {
+ part.setElementName(elementName);
+ part.setName(elementName.getLocalPart());
+ }
+
+ protected void buildPortTypes(Definition definition) throws WSDLException {
+ PortType portType = definition.createPortType();
+ populatePortType(portType);
+ createOperations(definition, portType);
+ portType.setUndefined(false);
+ definition.addPortType(portType);
+ }
+
+ /**
+ * Called after the {@link PortType} has been created.
+ *
+ * Default implementation sets the name of the port type to the defined value.
+ *
+ * @param portType the WSDL4J PortType
+ * @throws WSDLException in case of errors
+ * @see #setPortTypeName(String)
+ */
+ protected void populatePortType(PortType portType) throws WSDLException {
+ portType.setQName(new QName(targetNamespace, portTypeName));
+ }
+
+ private void createOperations(Definition definition, PortType portType) throws WSDLException {
+ for (Iterator messageIterator = definition.getMessages().values().iterator(); messageIterator.hasNext();) {
+ Message message = (Message) messageIterator.next();
+ for (Iterator partIterator = message.getParts().values().iterator(); partIterator.hasNext();) {
+ Part part = (Part) partIterator.next();
+ if (isRequestMessage(part.getElementName())) {
+ Message requestMessage = message;
+ Message responseMessage = definition.getMessage(getResponseMessageName(requestMessage.getQName()));
+ Message faultMessage = definition.getMessage(getFaultMessageName(requestMessage.getQName()));
+ Operation operation = definition.createOperation();
+ populateOperation(operation, requestMessage, responseMessage);
+ if (requestMessage != null) {
+ Input input = definition.createInput();
+ input.setMessage(requestMessage);
+ input.setName(requestMessage.getQName().getLocalPart());
+ operation.setInput(input);
+ }
+ if (responseMessage != null) {
+ Output output = definition.createOutput();
+ output.setMessage(responseMessage);
+ output.setName(responseMessage.getQName().getLocalPart());
+ operation.setOutput(output);
+ }
+ if (faultMessage != null) {
+ Fault fault = definition.createFault();
+ fault.setMessage(faultMessage);
+ fault.setName(faultMessage.getQName().getLocalPart());
+ operation.addFault(fault);
+ }
+ if (requestMessage != null && responseMessage != null) {
+ operation.setStyle(OperationType.REQUEST_RESPONSE);
+ }
+ else if (requestMessage != null && responseMessage == null) {
+ operation.setStyle(OperationType.ONE_WAY);
+ }
+ else if (requestMessage == null && responseMessage != null) {
+ operation.setStyle(OperationType.NOTIFICATION);
+ }
+ operation.setUndefined(false);
+ portType.addOperation(operation);
+ }
+ }
+ }
+ }
+
+ /**
+ * Given an request message name, return the corresponding response message name.
+ *
+ * Default implementation removes the request suffix, and appends the response suffix.
+ *
+ * @param requestMessageName the name of the request message
+ * @return the name of the corresponding response message, or null
+ */
+ protected QName getResponseMessageName(QName requestMessageName) {
+ String localPart = requestMessageName.getLocalPart();
+ if (localPart.endsWith(requestSuffix)) {
+ String prefix = localPart.substring(0, localPart.length() - requestSuffix.length());
+ return new QName(requestMessageName.getNamespaceURI(), prefix + responseSuffix);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Given an request message name, return the corresponding fault message name.
+ *
+ * Default implementation removes the request suffix, and appends the fault suffix.
+ *
+ * @param requestMessageName the name of the request message
+ * @return the name of the corresponding response message, or null
+ */
+ protected QName getFaultMessageName(QName requestMessageName) {
+ String localPart = requestMessageName.getLocalPart();
+ if (localPart.endsWith(requestSuffix)) {
+ String prefix = localPart.substring(0, localPart.length() - requestSuffix.length());
+ return new QName(requestMessageName.getNamespaceURI(), prefix + faultSuffix);
+ }
+ else {
+ return null;
+ }
+ }
+
+ /**
+ * Called after the {@link Operation} has been created.
+ *
+ * Default implementation sets the name of the operation to name of the messages, without suffix.
+ *
+ * @param operation the WSDL4J Operation
+ * @param requestMessage the WSDL4J request Message
+ * @param responseMessage the WSDL4J response Message
+ * @throws WSDLException in case of errors
+ * @see #setPortTypeName(String)
+ */
+ protected void populateOperation(Operation operation, Message requestMessage, Message responseMessage)
+ throws WSDLException {
+ String localPart = requestMessage.getQName().getLocalPart();
+ String operationName = null;
+ if (localPart.endsWith(requestSuffix)) {
+ operationName = localPart.substring(0, localPart.length() - requestSuffix.length());
+ }
+ else {
+ localPart = responseMessage.getQName().getLocalPart();
+ if (localPart.endsWith(responseSuffix)) {
+ operationName = localPart.substring(0, localPart.length() - responseSuffix.length());
+ }
+ }
+ operation.setName(operationName);
+ }
+
+ /** Sets the name of the service to the name of the port type, with "Service" appended to it. */
+ protected void populateService(Service service) throws WSDLException {
+ service.setQName(new QName(targetNamespace, portTypeName + SERVICE_SUFFIX));
+ }
+
+}
diff --git a/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilderTest.java b/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilderTest.java
index 42841614..2d32cddc 100644
--- a/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilderTest.java
+++ b/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap11Wsdl4jDefinitionBuilderTest.java
@@ -139,7 +139,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilderTest extends XMLTestCase {
transformer.transform(definition.getSource(), domResult);
Document result = (Document) domResult.getNode();
- Document expected = documentBuilder.parse(getClass().getResourceAsStream("airline.wsdl"));
+ Document expected = documentBuilder.parse(getClass().getResourceAsStream("airline-soap11.wsdl"));
XMLUnit.setIgnoreWhitespace(true);
assertXMLEqual("Invalid WSDL built", expected, result);
}
diff --git a/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilderTest.java b/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilderTest.java
new file mode 100644
index 00000000..0253b05a
--- /dev/null
+++ b/core/src/test/java/org/springframework/ws/wsdl/wsdl11/builder/XsdBasedSoap12Wsdl4jDefinitionBuilderTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2006 the original author or authors.
+ *
+ * Licensed 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.springframework.ws.wsdl.wsdl11.builder;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMResult;
+
+import org.custommonkey.xmlunit.XMLTestCase;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.ws.wsdl.wsdl11.Wsdl11Definition;
+import org.w3c.dom.Document;
+
+public class XsdBasedSoap12Wsdl4jDefinitionBuilderTest extends XMLTestCase {
+
+ private XsdBasedSoap12Wsdl4jDefinitionBuilder builder;
+
+ private Transformer transformer;
+
+ private DocumentBuilder documentBuilder;
+
+ protected void setUp() throws Exception {
+ builder = new XsdBasedSoap12Wsdl4jDefinitionBuilder();
+ builder.setLocationUri("http://localhost:8080/");
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ transformer = transformerFactory.newTransformer();
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ XMLUnit.setIgnoreWhitespace(true);
+ }
+
+ public void testNonExistingSchema() throws Exception {
+ try {
+ builder.setSchema(new ClassPathResource("bla"));
+ fail("IllegalArgumentException expected");
+ }
+ catch (IllegalArgumentException ex) {
+ // expected
+ }
+ }
+
+ public void testAirline() throws Exception {
+ builder.setSchema(new ClassPathResource("airline.xsd", getClass()));
+ builder.setPortTypeName("Airline");
+ builder.setTargetNamespace("http://www.springframework.org/spring-ws/samples/airline/definitions");
+ builder.afterPropertiesSet();
+ buildAll();
+ Wsdl11Definition definition = builder.getDefinition();
+ DOMResult domResult = new DOMResult();
+ transformer.transform(definition.getSource(), domResult);
+
+ Document result = (Document) domResult.getNode();
+ Document expected = documentBuilder.parse(getClass().getResourceAsStream("airline-soap12.wsdl"));
+ XMLUnit.setIgnoreWhitespace(true);
+ assertXMLEqual("Invalid WSDL built", expected, result);
+ }
+
+ private void buildAll() {
+ builder.buildDefinition();
+ builder.buildImports();
+ builder.buildTypes();
+ builder.buildMessages();
+ builder.buildPortTypes();
+ builder.buildBindings();
+ builder.buildServices();
+ }
+
+
+}
\ No newline at end of file
diff --git a/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline.wsdl b/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline-soap11.wsdl
similarity index 100%
rename from core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline.wsdl
rename to core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline-soap11.wsdl
diff --git a/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline-soap12.wsdl b/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline-soap12.wsdl
new file mode 100644
index 00000000..a138b073
--- /dev/null
+++ b/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/airline-soap12.wsdl
@@ -0,0 +1,207 @@
+
+