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 d2164f75..37bdd637 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
@@ -40,6 +40,7 @@ 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.springframework.xml.sax.SaxUtils;
import org.w3c.dom.Document;
@@ -51,7 +52,24 @@ import org.xml.sax.SAXException;
* Builds a WsdlDefinition with a SOAP 1.1 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. The schema itself is inlined in a types block.
+ * portType based on the operations.
+ *
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.
+ *
+ * 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.
*
@@ -65,8 +83,11 @@ import org.xml.sax.SAXException;
public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jDefinitionBuilder
implements InitializingBean {
- /** The schema namespace URI. */
- private static final String SCHEMA_NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema";
+ /** The schema qualified name. */
+ private static final QName SCHEMA_NAME = new QName("http://www.w3.org/2001/XMLSchema", "schema", "xsd");
+
+ /** The schema import qualified name. */
+ private static final QName IMPORT_NAME = new QName("http://www.w3.org/2001/XMLSchema", "import", "xsd");
/** The default suffix used to detect request elements in the schema. */
public static final String DEFAULT_REQUEST_SUFFIX = "Request";
@@ -88,6 +109,8 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
private Resource schema;
+ private String schemaLocation;
+
private Element schemaElement;
private String targetNamespace;
@@ -104,6 +127,14 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
private String faultSuffix = DEFAULT_FAULT_SUFFIX;
+ private String schemaTargetNamespace;
+
+ private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+ static {
+ documentBuilderFactory.setNamespaceAware(true);
+ }
+
/**
* Sets the suffix used to detect request elements in the schema.
*
@@ -166,6 +197,15 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
this.schema = schema;
}
+ /**
+ * 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;
+ }
+
public final void afterPropertiesSet() throws IOException, ParserConfigurationException, SAXException {
Assert.notNull(schema, "schema is required");
Assert.notNull(portTypeName, "portTypeName is required");
@@ -173,18 +213,16 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
private void parseSchema() throws ParserConfigurationException, SAXException, IOException {
- DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
- documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document schemaDocument = documentBuilder.parse(SaxUtils.createInputSource(schema));
schemaElement = schemaDocument.getDocumentElement();
- Assert.isTrue("schema".equals(schemaElement.getLocalName()),
+ Assert.isTrue(SCHEMA_NAME.getLocalPart().equals(schemaElement.getLocalName()),
"schema document root element has invalid local name : [" + schemaElement.getLocalName() +
"] instead of [schema]");
- Assert.isTrue(SCHEMA_NAMESPACE_URI.equals(schemaElement.getNamespaceURI()),
+ Assert.isTrue(SCHEMA_NAME.getNamespaceURI().equals(schemaElement.getNamespaceURI()),
"schema document root element has invalid namespace uri: [" + schemaElement.getNamespaceURI() +
- "] instead of [" + SCHEMA_NAMESPACE_URI + "]");
- String schemaTargetNamespace = getSchemaTargetNamespace();
+ "] instead of [" + SCHEMA_NAME.getNamespaceURI() + "]");
+ schemaTargetNamespace = getSchemaTargetNamespace();
Assert.hasLength(schemaTargetNamespace, "schema document has no targetNamespace");
if (!StringUtils.hasLength(targetNamespace)) {
targetNamespace = schemaTargetNamespace;
@@ -210,15 +248,39 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
}
/**
- * Creates a Types object that is populated with the types found in the schema.
+ * 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, QNameUtils.getQNameForNode(schemaElement));
- schema.setElement(schemaElement);
+ Schema schema = null;
+ if (!StringUtils.hasLength(schemaLocation)) {
+ schema = (Schema) createExtension(Types.class, QNameUtils.getQNameForNode(schemaElement));
+ schema.setElement(schemaElement);
+ }
+ else {
+ schema = (Schema) createExtension(Types.class, SCHEMA_NAME);
+ Document document = null;
+ try {
+ 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(SCHEMA_NAME.getNamespaceURI(), QNameUtils.toQualifiedName(SCHEMA_NAME));
+ schema.setElement(importingSchemaElement);
+ Element importElement =
+ document.createElementNS(IMPORT_NAME.getNamespaceURI(), QNameUtils.toQualifiedName(IMPORT_NAME));
+ importingSchemaElement.appendChild(importElement);
+ importElement.setAttribute("namespace", schemaTargetNamespace);
+ importElement.setAttribute("schemaLocation", schemaLocation);
+ }
types.addExtensibilityElement(schema);
definition.setTypes(types);
}
@@ -234,7 +296,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
* @see #isFaultMessage(javax.xml.namespace.QName)
*/
protected void buildMessages(Definition definition) throws WSDLException {
- NodeList elements = schemaElement.getElementsByTagNameNS(SCHEMA_NAMESPACE_URI, "element");
+ NodeList elements = schemaElement.getElementsByTagNameNS(SCHEMA_NAME.getNamespaceURI(), "element");
for (int i = 0; i < elements.getLength(); i++) {
Element element = (Element) elements.item(i);
QName elementName = getSchemaElementName(element);
@@ -336,7 +398,6 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilder extends AbstractSoap11Wsdl4jD
portType.setQName(new QName(targetNamespace, portTypeName));
}
- /** @noinspection UnnecessaryLocalVariable */
private void createOperations(Definition definition, PortType portType) throws WSDLException {
for (Iterator messageIterator = definition.getMessages().values().iterator(); messageIterator.hasNext();) {
Message message = (Message) messageIterator.next();
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 49c30b28..4c676727 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
@@ -55,7 +55,7 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilderTest extends XMLTestCase {
}
}
- public void testBuilder() throws Exception {
+ public void testInline() throws Exception {
builder.buildDefinition();
builder.buildDefinition();
builder.buildImports();
@@ -72,7 +72,30 @@ public class XsdBasedSoap11Wsdl4jDefinitionBuilderTest extends XMLTestCase {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
- Document expected = documentBuilder.parse(getClass().getResourceAsStream("expected.wsdl"));
+ Document expected = documentBuilder.parse(getClass().getResourceAsStream("inline.wsdl"));
+ XMLUnit.setIgnoreWhitespace(true);
+ assertXMLEqual("Invalid WSDL built", expected, result);
+ }
+
+ public void testImport() throws Exception {
+ builder.setSchemaLocation("schema.xsd");
+ builder.buildDefinition();
+ builder.buildDefinition();
+ builder.buildImports();
+ builder.buildTypes();
+ builder.buildMessages();
+ builder.buildPortTypes();
+ builder.buildBindings();
+ builder.buildServices();
+ Wsdl11Definition definition = builder.getDefinition();
+ DOMResult domResult = new DOMResult();
+ transformer.transform(definition.getSource(), domResult);
+
+ Document result = (Document) domResult.getNode();
+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ Document expected = documentBuilder.parse(getClass().getResourceAsStream("import.wsdl"));
XMLUnit.setIgnoreWhitespace(true);
assertXMLEqual("Invalid WSDL built", expected, result);
}
diff --git a/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/import.wsdl b/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/import.wsdl
new file mode 100644
index 00000000..0fc12e14
--- /dev/null
+++ b/core/src/test/resources/org/springframework/ws/wsdl/wsdl11/builder/import.wsdl
@@ -0,0 +1,87 @@
+
+TransformerFactory. */
protected TransformerFactory getTransformerFactory() {