Repository: cxf Updated Branches: refs/heads/master ecac53e02 -> 09aacad7d
CXF-7489: Stax2Validation doesn't support schema imports. Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/9cb5b21d Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/9cb5b21d Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/9cb5b21d Branch: refs/heads/master Commit: 9cb5b21db2b3912ae84cb2cf6e0e040a821745d8 Parents: ecac53e Author: facundov <[email protected]> Authored: Tue Aug 29 11:32:53 2017 -0300 Committer: Daniel Kulp <[email protected]> Committed: Wed Aug 30 16:38:48 2017 -0400 ---------------------------------------------------------------------- .../validation/Stax2ValidationUtils.java | 65 +++++-- .../validation/Stax2ValidationUtilsTest.java | 175 +++++++++++++++++++ core/src/test/resources/schemas/echoSchema.xsd | 20 +++ core/src/test/resources/schemas/logSchema.xsd | 15 ++ .../resources/schemas/schemaWithImports.xsd | 4 + 5 files changed, 261 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/9cb5b21d/core/src/main/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtils.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtils.java b/core/src/main/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtils.java index 40d996c..6418b0b 100644 --- a/core/src/main/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtils.java +++ b/core/src/main/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtils.java @@ -25,10 +25,13 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; +import org.w3c.dom.Document; import org.w3c.dom.Element; import org.apache.cxf.common.i18n.Message; @@ -39,6 +42,7 @@ import org.apache.cxf.service.model.SchemaInfo; import org.apache.cxf.service.model.ServiceInfo; import org.apache.cxf.staxutils.DepthXMLStreamReader; import org.apache.ws.commons.schema.XmlSchema; +import org.apache.ws.commons.schema.XmlSchemaExternal; import org.codehaus.stax2.XMLStreamReader2; import org.codehaus.stax2.XMLStreamWriter2; import org.codehaus.stax2.validation.ValidationProblemHandler; @@ -54,6 +58,7 @@ class Stax2ValidationUtils { private static final String KEY = XMLValidationSchema.class.getName(); private static final boolean HAS_WOODSTOX; + static { boolean hasw = false; try { @@ -61,7 +66,7 @@ class Stax2ValidationUtils { new W3CMultiSchemaFactory(); // will throw if wrong woodstox. hasw = true; } catch (Throwable t) { - //ignore + // ignore } HAS_WOODSTOX = hasw; } @@ -78,15 +83,15 @@ class Stax2ValidationUtils { * @throws XMLStreamException */ public boolean setupValidation(XMLStreamReader reader, Endpoint endpoint, ServiceInfo serviceInfo) - throws XMLStreamException { + throws XMLStreamException { // Gosh, this is bad, but I don't know a better solution, unless we're willing // to require the stax2 API no matter what. XMLStreamReader effectiveReader = reader; if (effectiveReader instanceof DepthXMLStreamReader) { - effectiveReader = ((DepthXMLStreamReader)reader).getReader(); + effectiveReader = ((DepthXMLStreamReader) reader).getReader(); } - final XMLStreamReader2 reader2 = (XMLStreamReader2)effectiveReader; + final XMLStreamReader2 reader2 = (XMLStreamReader2) effectiveReader; XMLValidationSchema vs = getValidator(endpoint, serviceInfo); if (vs == null) { return false; @@ -95,7 +100,7 @@ class Stax2ValidationUtils { public void reportProblem(XMLValidationProblem problem) throws XMLValidationException { throw new Fault(new Message("READ_VALIDATION_ERROR", LOG, problem.getMessage()), - Fault.FAULT_CODE_CLIENT); + Fault.FAULT_CODE_CLIENT); } }); reader2.validateAgainst(vs); @@ -103,9 +108,9 @@ class Stax2ValidationUtils { } public boolean setupValidation(XMLStreamWriter writer, Endpoint endpoint, ServiceInfo serviceInfo) - throws XMLStreamException { + throws XMLStreamException { - XMLStreamWriter2 writer2 = (XMLStreamWriter2)writer; + XMLStreamWriter2 writer2 = (XMLStreamWriter2) writer; XMLValidationSchema vs = getValidator(endpoint, serviceInfo); if (vs == null) { return false; @@ -123,18 +128,17 @@ class Stax2ValidationUtils { /** * Create woodstox validator for a schema set. * - * @param schemas - * @return * @throws XMLStreamException */ - private XMLValidationSchema getValidator(Endpoint endpoint, ServiceInfo serviceInfo) throws XMLStreamException { + private XMLValidationSchema getValidator(Endpoint endpoint, ServiceInfo serviceInfo) + throws XMLStreamException { synchronized (endpoint) { - XMLValidationSchema ret = (XMLValidationSchema)endpoint.get(KEY); + XMLValidationSchema ret = (XMLValidationSchema) endpoint.get(KEY); if (ret == null) { if (endpoint.containsKey(KEY)) { return null; } - Map<String, EmbeddedSchema> sources = new TreeMap<String, EmbeddedSchema>(); + Map<String, EmbeddedSchema> sources = new TreeMap<>(); for (SchemaInfo schemaInfo : serviceInfo.getSchemas()) { XmlSchema sch = schemaInfo.getSchema(); @@ -143,14 +147,17 @@ class Stax2ValidationUtils { continue; } - Element serialized = schemaInfo.getElement(); - String schemaSystemId = sch.getSourceURI(); - if (null == schemaSystemId) { - schemaSystemId = sch.getTargetNamespace(); + if (sch.getTargetNamespace() == null && sch.getExternals().size() > 0) { + for (XmlSchemaExternal xmlSchemaExternal : sch.getExternals()) { + addSchema(sources, xmlSchemaExternal.getSchema(), + getElement(xmlSchemaExternal.getSchema().getSourceURI())); + } + continue; + } else if (sch.getTargetNamespace() == null) { + throw new IllegalStateException("An Schema without imports must have a targetNamespace"); } - EmbeddedSchema embeddedSchema = new EmbeddedSchema(schemaSystemId, serialized); - sources.put(sch.getTargetNamespace(), embeddedSchema); + addSchema(sources, sch, schemaInfo.getElement()); } W3CMultiSchemaFactory factory = new W3CMultiSchemaFactory(); @@ -167,4 +174,26 @@ class Stax2ValidationUtils { } } + private void addSchema(Map<String, EmbeddedSchema> sources, XmlSchema schema, Element element) + throws XMLStreamException { + String schemaSystemId = schema.getSourceURI(); + if (null == schemaSystemId) { + schemaSystemId = schema.getTargetNamespace(); + } + EmbeddedSchema embeddedSchema = new EmbeddedSchema(schemaSystemId, element); + sources.put(schema.getTargetNamespace(), embeddedSchema); + } + + private Element getElement(String path) throws XMLStreamException { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(path); + return doc.getDocumentElement(); + } catch (Exception e) { + throw new XMLStreamException("There was an error trying to get external schemas " + e.getMessage()); + } + + } + } http://git-wip-us.apache.org/repos/asf/cxf/blob/9cb5b21d/core/src/test/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtilsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtilsTest.java b/core/src/test/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtilsTest.java new file mode 100644 index 0000000..703592d --- /dev/null +++ b/core/src/test/java/org/apache/cxf/staxutils/validation/Stax2ValidationUtilsTest.java @@ -0,0 +1,175 @@ +/** + * 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.cxf.staxutils.validation; + +import java.io.File; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.stream.StreamSource; + +import org.apache.cxf.endpoint.Endpoint; +import org.apache.cxf.service.model.SchemaInfo; +import org.apache.cxf.service.model.ServiceInfo; +import org.apache.ws.commons.schema.XmlSchemaCollection; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.anyString; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.mock; +import static org.easymock.EasyMock.replay; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +@RunWith(Parameterized.class) +public class Stax2ValidationUtilsTest { + + private static final String VALID_MESSAGE_ECHO = "<echo xmlns=\"http://www.echo.org\">" + + "<echo>Testing echo</echo>" + "</echo>"; + + private static final String INVALID_MESSAGE_ECHO = "<wrongEcho xmlns=\"http://www.echo.org\">" + + "<echo>Testing echo</echo>" + "</wrongEcho>"; + + private static final String VALID_MESSAGE_LOG = "<log xmlns=\"http://www.log.org\">" + + "<message>Testing Log</message>" + "</log>"; + + private static final String INVALID_MESSAGE_LOG = "<wrongLog xmlns=\"http://www.log.org\">" + + "<message>Testing Log</message>" + "</wrongLog>"; + + private static final String ECHO_ERROR_MESSAGE = "tag name \"wrongEcho\" is not allowed."; + + private static final String LOG_ERROR_MESSAGE = "tag name \"wrongLog\" is not allowed."; + + private static final String ECHO_SCHEMA = "schemas/echoSchema.xsd"; + + private static final String LOG_SCHEMA = "schemas/logSchema.xsd"; + + private static final String MULTI_IMPORT_SCHEMA = "schemas/schemaWithImports.xsd"; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private Stax2ValidationUtils utils = new Stax2ValidationUtils(); + private XMLStreamReader xmlReader; + private final Endpoint endpoint = mock(Endpoint.class); + private final ServiceInfo serviceInfo = new ServiceInfo(); + private final SchemaInfo schemaInfo = new SchemaInfo("testUri"); + + private String validMessage; + + private String invalidMessage; + + private String errorMessage; + + private String schemaPath; + + public Stax2ValidationUtilsTest(String validMessage, String invalidMessage, String errorMessage, + String schemaPath) { + this.validMessage = validMessage; + this.invalidMessage = invalidMessage; + this.errorMessage = errorMessage; + this.schemaPath = schemaPath; + } + + @Parameterized.Parameters + public static Collection<String[]> data() { + List<String[]> parameters = new ArrayList(); + parameters.add(new String[]{VALID_MESSAGE_ECHO, INVALID_MESSAGE_ECHO, ECHO_ERROR_MESSAGE, MULTI_IMPORT_SCHEMA}); + parameters.add(new String[]{VALID_MESSAGE_LOG, INVALID_MESSAGE_LOG, LOG_ERROR_MESSAGE, MULTI_IMPORT_SCHEMA}); + parameters.add(new String[]{VALID_MESSAGE_ECHO, INVALID_MESSAGE_ECHO, ECHO_ERROR_MESSAGE, ECHO_SCHEMA}); + parameters.add(new String[]{VALID_MESSAGE_LOG, INVALID_MESSAGE_LOG, LOG_ERROR_MESSAGE, LOG_SCHEMA}); + return parameters; + } + + @Before + public void setUp() throws Exception { + XmlSchemaCollection schemaCol = new XmlSchemaCollection(); + InputStream io = getClass().getClassLoader().getResourceAsStream(schemaPath); + schemaCol.setBaseUri(getTestBaseURI()); + schemaCol.read(new StreamSource(io)); + serviceInfo.addSchema(schemaInfo); + schemaInfo.setSchema(schemaCol.getXmlSchemas()[0]); + expect(endpoint.get(anyObject())).andReturn(null); + expect(endpoint.containsKey(anyObject())).andReturn(false); + expect(endpoint.put(anyString(), anyObject())).andReturn(null); + replay(endpoint); + } + + @Test + public void testValidMessage() throws Exception { + Throwable exception = null; + xmlReader = createReader(validMessage); + utils.setupValidation(xmlReader, endpoint, serviceInfo); + try { + while (xmlReader.hasNext()) { + xmlReader.next(); + } + } catch (Throwable e) { + exception = e; + } + + assertThat(exception, is(nullValue())); + } + + @Test + public void testInvalidMessage() throws Exception { + Throwable exception = null; + xmlReader = createReader(invalidMessage); + utils.setupValidation(xmlReader, endpoint, serviceInfo); + try { + while (xmlReader.hasNext()) { + xmlReader.next(); + } + } catch (Throwable e) { + exception = e; + } + + assertThat(exception, is(notNullValue())); + assertThat(exception.getMessage(), containsString(errorMessage)); + } + + private String getTestBaseURI() { + ClassLoader classLoader = getClass().getClassLoader(); + File file = new File(classLoader.getResource(schemaPath).getFile()); + return file.getAbsolutePath(); + } + + private XMLStreamReader createReader(String message) throws XMLStreamException { + Reader reader = new StringReader(message); + XMLInputFactory factory = XMLInputFactory.newInstance(); + return factory.createXMLStreamReader(reader); + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/9cb5b21d/core/src/test/resources/schemas/echoSchema.xsd ---------------------------------------------------------------------- diff --git a/core/src/test/resources/schemas/echoSchema.xsd b/core/src/test/resources/schemas/echoSchema.xsd new file mode 100644 index 0000000..0c23824 --- /dev/null +++ b/core/src/test/resources/schemas/echoSchema.xsd @@ -0,0 +1,20 @@ +<xsd:schema attributeFormDefault="qualified" + elementFormDefault="qualified" targetNamespace="http://www.echo.org" + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="echo"> + <xsd:complexType> + <xsd:sequence> + <xsd:element maxOccurs="1" minOccurs="1" + name="echo" nillable="true" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="echoResponse"> + <xsd:complexType> + <xsd:sequence> + <xsd:element maxOccurs="1" minOccurs="1" + name="out" nillable="true" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> +</xsd:schema> http://git-wip-us.apache.org/repos/asf/cxf/blob/9cb5b21d/core/src/test/resources/schemas/logSchema.xsd ---------------------------------------------------------------------- diff --git a/core/src/test/resources/schemas/logSchema.xsd b/core/src/test/resources/schemas/logSchema.xsd new file mode 100644 index 0000000..e970a37 --- /dev/null +++ b/core/src/test/resources/schemas/logSchema.xsd @@ -0,0 +1,15 @@ +<xsd:schema attributeFormDefault="qualified" + elementFormDefault="qualified" targetNamespace="http://www.log.org" + xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:element name="log"> + <xsd:complexType> + <xsd:sequence> + <xsd:element maxOccurs="1" minOccurs="1" + name="message" nillable="true" type="xsd:string" /> + </xsd:sequence> + </xsd:complexType> + </xsd:element> + <xsd:element name="logResponse"> + <xsd:complexType /> + </xsd:element> +</xsd:schema> http://git-wip-us.apache.org/repos/asf/cxf/blob/9cb5b21d/core/src/test/resources/schemas/schemaWithImports.xsd ---------------------------------------------------------------------- diff --git a/core/src/test/resources/schemas/schemaWithImports.xsd b/core/src/test/resources/schemas/schemaWithImports.xsd new file mode 100644 index 0000000..33b3488 --- /dev/null +++ b/core/src/test/resources/schemas/schemaWithImports.xsd @@ -0,0 +1,4 @@ +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:import namespace="http://www.log.org" schemaLocation="logSchema.xsd"/> + <xsd:import namespace="http://www.echo.org" schemaLocation="echoSchema.xsd"/> +</xsd:schema> \ No newline at end of file
