Sure, done. Cheers ------------- Freeman(Yue) Fang
Red Hat, Inc. FuseSource is now part of Red Hat > On Mar 7, 2017, at 9:09 PM, Daniel Kulp <[email protected]> wrote: > > > 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 >
