Freeman, I believe this commit would introduce CXF-7185 for the source data binding…. Can you adjust accordingly? You can see what was done for JAXB.
Thanks! Dan > On Mar 7, 2017, at 3:44 AM, [email protected] wrote: > > Repository: cxf > Updated Branches: > refs/heads/master 09fb22b25 -> 08c9194ce > > > [CXF-7269]schemavalidate failed when use mtom and Provider > > > Project: http://git-wip-us.apache.org/repos/asf/cxf/repo > Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/08c9194c > Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/08c9194c > Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/08c9194c > > Branch: refs/heads/master > Commit: 08c9194ce2c567ebfe59f59ee628b1197d90fd43 > Parents: 09fb22b > Author: Freeman Fang <[email protected]> > Authored: Tue Mar 7 16:44:03 2017 +0800 > Committer: Freeman Fang <[email protected]> > Committed: Tue Mar 7 16:44:03 2017 +0800 > > ---------------------------------------------------------------------- > .../databinding/source/XMLStreamDataWriter.java | 111 ++++++++++++++++- > .../cxf/systest/mtom/ClientMtomXopTest.java | 119 ++++++++++++++++++- > testutils/pom.xml | 4 + > .../cxf/mtom_xop/TestMtomProviderImpl.java | 104 ++++++++++++++++ > testutils/src/main/resources/wsdl/mtom_xop.wsdl | 3 + > 5 files changed, 335 insertions(+), 6 deletions(-) > ---------------------------------------------------------------------- > > > http://git-wip-us.apache.org/repos/asf/cxf/blob/08c9194c/core/src/main/java/org/apache/cxf/databinding/source/XMLStreamDataWriter.java > ---------------------------------------------------------------------- > diff --git > a/core/src/main/java/org/apache/cxf/databinding/source/XMLStreamDataWriter.java > > b/core/src/main/java/org/apache/cxf/databinding/source/XMLStreamDataWriter.java > index 8bd9b71..afbcca0 100644 > --- > a/core/src/main/java/org/apache/cxf/databinding/source/XMLStreamDataWriter.java > +++ > b/core/src/main/java/org/apache/cxf/databinding/source/XMLStreamDataWriter.java > @@ -29,12 +29,17 @@ import javax.xml.stream.XMLStreamWriter; > import javax.xml.transform.Source; > import javax.xml.transform.dom.DOMSource; > import javax.xml.validation.Schema; > +import javax.xml.validation.Validator; > > import org.w3c.dom.Document; > import org.w3c.dom.DocumentFragment; > import org.w3c.dom.Node; > +import org.w3c.dom.NodeList; > > +import org.xml.sax.ErrorHandler; > import org.xml.sax.SAXException; > +import org.xml.sax.SAXParseException; > + > > import org.apache.cxf.common.i18n.Message; > import org.apache.cxf.common.logging.LogUtils; > @@ -46,10 +51,16 @@ import org.apache.cxf.staxutils.StaxUtils; > import org.apache.cxf.staxutils.W3CDOMStreamWriter; > > public class XMLStreamDataWriter implements DataWriter<XMLStreamWriter> { > + > private static final Logger LOG = > LogUtils.getL7dLogger(XMLStreamDataWriter.class); > > + > private Schema schema; > > + public XMLStreamDataWriter() { > + > + } > + > public void write(Object obj, MessagePartInfo part, XMLStreamWriter > output) { > write(obj, output); > } > @@ -61,7 +72,10 @@ public class XMLStreamDataWriter implements > DataWriter<XMLStreamWriter> { > DataSource ds = (DataSource)obj; > if (schema != null) { > DOMSource domSource = new > DOMSource(StaxUtils.read(ds.getInputStream())); > - schema.newValidator().validate(domSource); > + Validator schemaValidator = schema.newValidator(); > + schemaValidator.setErrorHandler( > + new > MtomValidationErrorHandler(schemaValidator.getErrorHandler(), > domSource.getNode())); > + schemaValidator.validate(domSource); > StaxUtils.copy(domSource, writer); > } else { > reader = > StaxUtils.createXMLStreamReader(ds.getInputStream()); > @@ -71,7 +85,10 @@ public class XMLStreamDataWriter implements > DataWriter<XMLStreamWriter> { > > } else if (obj instanceof Node) { > if (schema != null) { > - schema.newValidator().validate(new DOMSource((Node)obj)); > + Validator schemaValidator = schema.newValidator(); > + schemaValidator.setErrorHandler( > + new > MtomValidationErrorHandler(schemaValidator.getErrorHandler(), (Node)obj)); > + schemaValidator.validate(new DOMSource((Node)obj)); > } > Node nd = (Node)obj; > writeNode(nd, writer); > @@ -82,7 +99,10 @@ public class XMLStreamDataWriter implements > DataWriter<XMLStreamWriter> { > //make the source re-readable. > s = new DOMSource(StaxUtils.read(s)); > } > - schema.newValidator().validate(s); > + Validator schemaValidator = schema.newValidator(); > + schemaValidator.setErrorHandler( > + new > MtomValidationErrorHandler(schemaValidator.getErrorHandler(), > ((DOMSource)s).getNode())); > + schemaValidator.validate(s); > } > if (s instanceof DOMSource > && ((DOMSource) s).getNode() == null) { > @@ -152,5 +172,90 @@ public class XMLStreamDataWriter implements > DataWriter<XMLStreamWriter> { > > public void setProperty(String key, Object value) { > } > + > + private static class MtomValidationErrorHandler implements ErrorHandler { > + private ErrorHandler origErrorHandler; > + private Node node; > + > + MtomValidationErrorHandler(ErrorHandler origErrorHandler, Node node) > { > + this.origErrorHandler = origErrorHandler; > + this.node = node; > + } > + > + > + @Override > + public void warning(SAXParseException exception) throws SAXException > { > + > + if (this.origErrorHandler != null) { > + this.origErrorHandler.warning(exception); > + } else { > + // do nothing > + } > + } > + > + @Override > + public void error(SAXParseException exception) throws SAXException { > + if (this.isCVC312Exception(exception)) { > + String elementName = > this.getAttachmentElementName(exception); > + if (node != null && this.findIncludeNode(node, elementName)) > { > + return; > + } > + } > + > + if (this.origErrorHandler != null) { > + this.origErrorHandler.error(exception); > + } else { > + throw exception; > + } > + > + } > + > + @Override > + public void fatalError(SAXParseException exception) throws > SAXException { > + if (this.origErrorHandler != null) { > + this.origErrorHandler.fatalError(exception); > + } else { > + throw exception; > + } > + > + } > + > + private boolean isCVC312Exception(SAXParseException exception) { > + String msg = exception.getMessage(); > + return msg.startsWith("cvc-type.3.1.2: ") > + && msg.endsWith("is a simple type, so it must have no > element information item [children]."); > + > + > + } > + > + private String getAttachmentElementName(SAXParseException exception) > { > + String msg = exception.getMessage(); > + String str[] = msg.split("'"); > + return str[1]; > + } > + > + private boolean findIncludeNode(Node checkNode, String mtomElement) { > + boolean ret = false; > + NodeList nList = checkNode.getChildNodes(); > + for (int i = 0; i < nList.getLength(); i++) { > + Node nNode = nList.item(i); > + if (nNode.getLocalName() != null > + && nNode.getLocalName().equals(mtomElement)) { > + NodeList subNodeList = nNode.getChildNodes(); > + for (int j = 0; j < subNodeList.getLength(); j++) { > + Node subNode = subNodeList.item(j); > + if > (subNode.getNamespaceURI().equals("http://www.w3.org/2004/08/xop/include") > + && subNode.getLocalName().equals("Include")) { > + // This is the Mtom element which break the > SchemaValidation so ignore this > + return true; > + } > + } > + } else { > + ret = findIncludeNode(nNode, mtomElement); > + } > + } > + return ret; > + } > + } > > } > > http://git-wip-us.apache.org/repos/asf/cxf/blob/08c9194c/systests/uncategorized/src/test/java/org/apache/cxf/systest/mtom/ClientMtomXopTest.java > ---------------------------------------------------------------------- > diff --git > a/systests/uncategorized/src/test/java/org/apache/cxf/systest/mtom/ClientMtomXopTest.java > > b/systests/uncategorized/src/test/java/org/apache/cxf/systest/mtom/ClientMtomXopTest.java > index 184bd64..1616b48 100644 > --- > a/systests/uncategorized/src/test/java/org/apache/cxf/systest/mtom/ClientMtomXopTest.java > +++ > b/systests/uncategorized/src/test/java/org/apache/cxf/systest/mtom/ClientMtomXopTest.java > @@ -38,10 +38,10 @@ import > org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor; > import org.apache.cxf.endpoint.Client; > import org.apache.cxf.endpoint.ClientImpl; > import org.apache.cxf.endpoint.Endpoint; > -import org.apache.cxf.ext.logging.LoggingInInterceptor; > -import org.apache.cxf.ext.logging.LoggingOutInterceptor; > import org.apache.cxf.frontend.ClientProxy; > import org.apache.cxf.helpers.IOUtils; > +import org.apache.cxf.interceptor.LoggingInInterceptor; > +import org.apache.cxf.interceptor.LoggingOutInterceptor; > import org.apache.cxf.jaxws.EndpointImpl; > import org.apache.cxf.jaxws.JaxWsClientProxy; > import org.apache.cxf.jaxws.binding.soap.SOAPBindingImpl; > @@ -51,6 +51,7 @@ import org.apache.cxf.message.Message; > import org.apache.cxf.mime.TestMtom; > import org.apache.cxf.mime.types.XopStringType; > import org.apache.cxf.mtom_xop.TestMtomImpl; > +import org.apache.cxf.mtom_xop.TestMtomProviderImpl; > import org.apache.cxf.service.Service; > import org.apache.cxf.service.model.EndpointInfo; > import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; > @@ -63,7 +64,9 @@ import org.junit.Test; > public class ClientMtomXopTest extends AbstractBusClientServerTestBase { > public static final String PORT = allocatePort(ClientMtomXopTest.class); > public static final QName MTOM_PORT = new > QName("http://cxf.apache.org/mime", "TestMtomPort"); > + public static final QName MTOM_PORT_PROVIDER = new > QName("http://cxf.apache.org/mime", "TestMtomProviderPort"); > public static final QName MTOM_SERVICE = new > QName("http://cxf.apache.org/mime", "TestMtomService"); > + > > > public static class Server extends AbstractBusTestServerBase { > @@ -71,14 +74,21 @@ public class ClientMtomXopTest extends > AbstractBusClientServerTestBase { > protected void run() { > Object implementor = new TestMtomImpl(); > String address = "http://localhost:" + PORT + "/mime-test"; > + String addressProvider = "http://localhost:" + PORT + > "/mime-test-provider"; > try { > jaxep = (EndpointImpl) javax.xml.ws.Endpoint.publish(address, > implementor); > Endpoint ep = jaxep.getServer().getEndpoint(); > ep.getInInterceptors().add(new > TestMultipartMessageInterceptor()); > ep.getOutInterceptors().add(new > TestAttachmentOutInterceptor()); > - > + jaxep.getInInterceptors().add(new LoggingInInterceptor()); > + jaxep.getOutInterceptors().add(new LoggingOutInterceptor()); > SOAPBinding jaxWsSoapBinding = (SOAPBinding) > jaxep.getBinding(); > jaxWsSoapBinding.setMTOMEnabled(true); > + EndpointImpl endpoint = > + > (EndpointImpl)javax.xml.ws.Endpoint.publish(addressProvider, new > TestMtomProviderImpl()); > + endpoint.getProperties().put("schema-validation-enabled", > "true"); > + endpoint.getInInterceptors().add(new LoggingInInterceptor()); > + endpoint.getOutInterceptors().add(new > LoggingOutInterceptor()); > > } catch (Exception e) { > Thread.currentThread().interrupt(); > @@ -197,6 +207,109 @@ public class ClientMtomXopTest extends > AbstractBusClientServerTestBase { > throw ex; > } > } > + > + > + @Test > + public void testMtomXopProvider() throws Exception { > + TestMtom mtomPort = createPort(MTOM_SERVICE, MTOM_PORT_PROVIDER, > TestMtom.class, true, true); > + try { > + Holder<DataHandler> param = new Holder<DataHandler>(); > + Holder<String> name; > + byte bytes[]; > + InputStream in; > + > + InputStream pre = > this.getClass().getResourceAsStream("/wsdl/mtom_xop.wsdl"); > + int fileSize = 0; > + for (int i = pre.read(); i != -1; i = pre.read()) { > + fileSize++; > + } > + > + int count = 50; > + byte[] data = new byte[fileSize * count]; > + for (int x = 0; x < count; x++) { > + > this.getClass().getResourceAsStream("/wsdl/mtom_xop.wsdl").read(data, > + > fileSize * x, > + > fileSize); > + } > + > + Object[] validationTypes = new Object[]{Boolean.TRUE, > SchemaValidationType.IN, SchemaValidationType.BOTH}; > + > + for (Object validationType : validationTypes) { > + > ((BindingProvider)mtomPort).getRequestContext().put(Message.SCHEMA_VALIDATION_ENABLED, > + > validationType); > + > + param.value = new DataHandler(new ByteArrayDataSource(data, > "application/octet-stream")); > + name = new Holder<String>("call detail"); > + mtomPort.testXop(name, param); > + assertEquals("name unchanged", "return detail + call > detail", name.value); > + assertNotNull(param.value); > + > + in = param.value.getInputStream(); > + bytes = IOUtils.readBytesFromStream(in); > + assertEquals(data.length, bytes.length); > + in.close(); > + > + param.value = new DataHandler(new ByteArrayDataSource(data, > "application/octet-stream")); > + name = new Holder<String>("call detail"); > + mtomPort.testXop(name, param); > + assertEquals("name unchanged", "return detail + call > detail", name.value); > + assertNotNull(param.value); > + > + in = param.value.getInputStream(); > + bytes = IOUtils.readBytesFromStream(in); > + assertEquals(data.length, bytes.length); > + in.close(); > + } > + > + validationTypes = new Object[]{Boolean.FALSE, > SchemaValidationType.OUT, SchemaValidationType.NONE}; > + for (Object validationType : validationTypes) { > + > ((BindingProvider)mtomPort).getRequestContext().put(Message.SCHEMA_VALIDATION_ENABLED, > + > validationType); > + SAAJOutInterceptor saajOut = new SAAJOutInterceptor(); > + SAAJInInterceptor saajIn = new SAAJInInterceptor(); > + > + param.value = new DataHandler(new ByteArrayDataSource(data, > "application/octet-stream")); > + name = new Holder<String>("call detail"); > + mtomPort.testXop(name, param); > + assertEquals("name unchanged", "return detail + call > detail", name.value); > + assertNotNull(param.value); > + > + in = param.value.getInputStream(); > + bytes = IOUtils.readBytesFromStream(in); > + assertEquals(data.length, bytes.length); > + in.close(); > + > + > ClientProxy.getClient(mtomPort).getInInterceptors().add(saajIn); > + > ClientProxy.getClient(mtomPort).getInInterceptors().add(saajOut); > + param.value = new DataHandler(new ByteArrayDataSource(data, > "application/octet-stream")); > + name = new Holder<String>("call detail"); > + mtomPort.testXop(name, param); > + assertEquals("name unchanged", "return detail + call > detail", name.value); > + assertNotNull(param.value); > + > + in = param.value.getInputStream(); > + bytes = IOUtils.readBytesFromStream(in); > + assertEquals(data.length, bytes.length); > + in.close(); > + > + > ClientProxy.getClient(mtomPort).getInInterceptors().remove(saajIn); > + > ClientProxy.getClient(mtomPort).getInInterceptors().remove(saajOut); > + } > + } catch (UndeclaredThrowableException ex) { > + throw (Exception)ex.getCause(); > + } catch (Exception ex) { > + if (ex.getMessage().contains("Connection reset") > + && System.getProperty("java.specification.version", > "1.5").contains("1.6")) { > + //There seems to be a bug/interaction with Java 1.6 and > Jetty where > + //Jetty will occasionally send back a RST prior to all the > data being > + //sent back to the client when using localhost (which is > what we do) > + //we'll ignore for now > + return; > + } > + System.out.println(System.getProperties()); > + throw ex; > + } > + } > > @Test > public void testMtomWithFileName() throws Exception { > > http://git-wip-us.apache.org/repos/asf/cxf/blob/08c9194c/testutils/pom.xml > ---------------------------------------------------------------------- > diff --git a/testutils/pom.xml b/testutils/pom.xml > index bd481ad..fb611ab 100644 > --- a/testutils/pom.xml > +++ b/testutils/pom.xml > @@ -53,6 +53,10 @@ > <optional>true</optional> > </dependency> > <dependency> > + <groupId>org.apache.geronimo.specs</groupId> > + <artifactId>geronimo-javamail_1.4_spec</artifactId> > + </dependency> > + <dependency> > <groupId>org.springframework</groupId> > <artifactId>spring-core</artifactId> > <scope>provided</scope> > > http://git-wip-us.apache.org/repos/asf/cxf/blob/08c9194c/testutils/src/main/java/org/apache/cxf/mtom_xop/TestMtomProviderImpl.java > ---------------------------------------------------------------------- > diff --git > a/testutils/src/main/java/org/apache/cxf/mtom_xop/TestMtomProviderImpl.java > b/testutils/src/main/java/org/apache/cxf/mtom_xop/TestMtomProviderImpl.java > new file mode 100644 > index 0000000..de1f442 > --- /dev/null > +++ > b/testutils/src/main/java/org/apache/cxf/mtom_xop/TestMtomProviderImpl.java > @@ -0,0 +1,104 @@ > +/** > + * 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.mtom_xop; > + > +import java.io.InputStream; > + > +import javax.activation.DataHandler; > +import javax.mail.util.ByteArrayDataSource; > +import javax.xml.soap.AttachmentPart; > +import javax.xml.soap.MessageFactory; > +import javax.xml.soap.SOAPBody; > +import javax.xml.soap.SOAPBodyElement; > +import javax.xml.soap.SOAPElement; > +import javax.xml.soap.SOAPEnvelope; > +import javax.xml.soap.SOAPMessage; > +import javax.xml.soap.SOAPPart; > +import javax.xml.ws.Provider; > +import javax.xml.ws.Service.Mode; > +import javax.xml.ws.ServiceMode; > +import javax.xml.ws.WebServiceProvider; > +import javax.xml.ws.soap.MTOM; > + > + > +@WebServiceProvider(portName = "TestMtomProviderPort", > +serviceName = "TestMtomService", > +targetNamespace = "http://cxf.apache.org/mime", > +wsdlLocation = "testutils/mtom_xop.wsdl") > +@ServiceMode(value = Mode.MESSAGE) > +@MTOM > + > +public class TestMtomProviderImpl implements Provider<SOAPMessage> { > + > + public SOAPMessage invoke(final SOAPMessage request) { > + try { > + System.out.println("=== Received client request ==="); > + > + // create the SOAPMessage > + SOAPMessage message = > MessageFactory.newInstance().createMessage(); > + SOAPPart part = message.getSOAPPart(); > + SOAPEnvelope envelope = part.getEnvelope(); > + SOAPBody body = envelope.getBody(); > + > + > + SOAPBodyElement testResponse = body > + .addBodyElement(envelope.createName("testXopResponse", null, > "http://cxf.apache.org/mime/types")); > + SOAPElement name = testResponse.addChildElement("name", null, > "http://cxf.apache.org/mime/types"); > + name.setTextContent("return detail + call detail"); > + SOAPElement attachinfo = testResponse.addChildElement( > + "attachinfo", null, > "http://cxf.apache.org/mime/types"); > + SOAPElement include = attachinfo.addChildElement("Include", > "xop", > + > "http://www.w3.org/2004/08/xop/include"); > + > + InputStream pre = > this.getClass().getResourceAsStream("/wsdl/mtom_xop.wsdl"); > + int fileSize = 0; > + for (int i = pre.read(); i != -1; i = pre.read()) { > + fileSize++; > + } > + > + int count = 50; > + byte[] data = new byte[fileSize * count]; > + for (int x = 0; x < count; x++) { > + > this.getClass().getResourceAsStream("/wsdl/mtom_xop.wsdl").read(data, > + > fileSize * x, > + > fileSize); > + } > + > + > + DataHandler dh = new DataHandler(new ByteArrayDataSource(data, > "application/octet-stream")); > + > + // create the image attachment > + AttachmentPart attachment = message.createAttachmentPart(dh); > + attachment.setContentId("mtom_xop.wsdl"); > + message.addAttachmentPart(attachment); > + System.out > + .println("Adding attachment: " + attachment.getContentId() + > ":" + attachment.getSize()); > + > + // add the reference to the image attachment > + include.addAttribute(envelope.createName("href"), "cid:" + > attachment.getContentId()); > + > + return message; > + > + } catch (Exception e) { > + e.printStackTrace(); > + } > + return null; > + } > + > +} > > http://git-wip-us.apache.org/repos/asf/cxf/blob/08c9194c/testutils/src/main/resources/wsdl/mtom_xop.wsdl > ---------------------------------------------------------------------- > diff --git a/testutils/src/main/resources/wsdl/mtom_xop.wsdl > b/testutils/src/main/resources/wsdl/mtom_xop.wsdl > index 02b15fd..b84ded2 100644 > --- a/testutils/src/main/resources/wsdl/mtom_xop.wsdl > +++ b/testutils/src/main/resources/wsdl/mtom_xop.wsdl > @@ -96,6 +96,9 @@ > <wsdl:port name="TestMtomPort" binding="tns:TestMtomBinding"> > <soap:address location="http://localhost:9036/mime-test"/> > </wsdl:port> > + <wsdl:port name="TestMtomProviderPort" binding="tns:TestMtomBinding"> > + <soap:address > location="http://localhost:9036/mime-test-provider"/> > + </wsdl:port> > </wsdl:service> > <wsdl:service name="TestMtomJMSService"> > <wsdl:port name="TestMtomJMSPort" binding="tns:TestMtomBinding"> > -- Daniel Kulp [email protected] - http://dankulp.com/blog Talend Community Coder - http://coders.talend.com
