Repository: camel Updated Branches: refs/heads/master c4a16df02 -> 2965c7689
CAMEL-8663 Namespace defined on the SOAP envelope lost; Thanks to Stephan Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/2965c768 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/2965c768 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/2965c768 Branch: refs/heads/master Commit: 2965c76899211e2a4afeebd9d9e153e0f47ce0cf Parents: c4a16df Author: Akitoshi Yoshida <a...@apache.org> Authored: Fri May 8 21:03:54 2015 +0200 Committer: Akitoshi Yoshida <a...@apache.org> Committed: Fri May 8 21:11:51 2015 +0200 ---------------------------------------------------------------------- .../converter/stream/StreamSourceCache.java | 2 +- .../camel/component/cxf/DefaultCxfBinding.java | 1 - .../cxf/converter/CachedCxfPayload.java | 24 +++++------ .../converter/DelegatingXMLStreamReader.java | 41 ++++++++++-------- .../cxf/feature/PayLoadDataFormatFeature.java | 2 + ...sumerNamespaceOnEnvelopeStreamCacheTest.java | 43 +++++++++++++++++++ ...fPayloadConsumerNamespaceOnEnvelopeTest.java | 17 ++++---- ...ducerNamespaceOnEnvelopeStreamCacheTest.java | 44 ++++++++++++++++++++ ...fPayloadProducerNamespaceOnEnvelopeTest.java | 11 +++-- .../camel/component/cxf/GetTokenBeans.xml | 7 +--- 10 files changed, 139 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/camel-core/src/main/java/org/apache/camel/converter/stream/StreamSourceCache.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/converter/stream/StreamSourceCache.java b/camel-core/src/main/java/org/apache/camel/converter/stream/StreamSourceCache.java index a7edfc9..39440c4 100644 --- a/camel-core/src/main/java/org/apache/camel/converter/stream/StreamSourceCache.java +++ b/camel-core/src/main/java/org/apache/camel/converter/stream/StreamSourceCache.java @@ -53,7 +53,7 @@ public final class StreamSourceCache extends StreamSource implements StreamCache } } - private StreamSourceCache(StreamCache streamCache) { + public StreamSourceCache(StreamCache streamCache) { this.streamCache = streamCache; if (streamCache instanceof InputStream) { setInputStream((InputStream) streamCache); http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java index 0a5f0bf..07e879a 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/DefaultCxfBinding.java @@ -55,7 +55,6 @@ import org.apache.cxf.binding.soap.Soap11; import org.apache.cxf.binding.soap.Soap12; import org.apache.cxf.binding.soap.SoapBindingConstants; import org.apache.cxf.binding.soap.SoapHeader; -import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.endpoint.Client; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.headers.Header; http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CachedCxfPayload.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CachedCxfPayload.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CachedCxfPayload.java index 51f54ff..d03ef55 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CachedCxfPayload.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CachedCxfPayload.java @@ -19,7 +19,6 @@ package org.apache.camel.component.cxf.converter; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Collections; import java.util.ListIterator; import java.util.Map; @@ -29,7 +28,6 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; @@ -37,6 +35,7 @@ import org.apache.camel.Exchange; import org.apache.camel.StreamCache; import org.apache.camel.component.cxf.CxfPayload; import org.apache.camel.converter.jaxp.XmlConverter; +import org.apache.camel.converter.stream.CachedOutputStream; import org.apache.camel.converter.stream.StreamSourceCache; import org.apache.cxf.staxutils.StaxSource; import org.slf4j.Logger; @@ -67,17 +66,18 @@ public class CachedCxfPayload<T> extends CxfPayload<T> implements StreamCache { } if (reader != null) { Map<String, String> nsmap = getNsMap(); - if (nsmap == null) { - nsmap = Collections.emptyMap(); + if (nsmap != null && !(reader instanceof DelegatingXMLStreamReader)) { + source = new StAXSource(new DelegatingXMLStreamReader(reader, nsmap)); } - source = new StAXSource(new DelegatingXMLStreamReader(reader, nsmap)); - StreamSource streamSource = exchange.getContext().getTypeConverter().convertTo(StreamSource.class, exchange, source); - if (streamSource != null) { - try { - li.set(new StreamSourceCache(streamSource, exchange)); - } catch (IOException e) { - LOG.error("Cannot Create StreamSourceCache ", e); - } + CachedOutputStream cos = new CachedOutputStream(exchange); + StreamResult sr = new StreamResult(cos); + try { + xml.toResult(source, sr); + li.set(new StreamSourceCache(cos.newStreamCache())); + } catch (TransformerException e) { + LOG.error("Transformation failed ", e); + } catch (IOException e) { + LOG.error("Cannot Create StreamSourceCache ", e); } } else if (!(source instanceof DOMSource)) { Document document = exchange.getContext().getTypeConverter().convertTo(Document.class, exchange, source); http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java index 354c8c3..743a671 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java @@ -17,11 +17,16 @@ package org.apache.camel.component.cxf.converter; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -30,13 +35,12 @@ import javax.xml.stream.XMLStreamReader; */ class DelegatingXMLStreamReader implements XMLStreamReader { private XMLStreamReader reader; - private final Map<String, String> nsmap; - private final String[] prefixes; + private final String[] xprefixes; + private int depth; public DelegatingXMLStreamReader(XMLStreamReader reader, Map<String, String> nsmap) { this.reader = reader; - this.nsmap = nsmap; - this.prefixes = nsmap.keySet().toArray(new String[0]); + this.xprefixes = nsmap.keySet().toArray(new String[0]); } @Override @@ -46,7 +50,14 @@ class DelegatingXMLStreamReader implements XMLStreamReader { @Override public int next() throws XMLStreamException { - return reader.next(); + // only inject namespaces at the root level + final int c = reader.next(); + if (c == XMLStreamConstants.START_ELEMENT) { + depth++; + } else if (c == XMLStreamConstants.END_ELEMENT) { + depth--; + } + return c; } @Override @@ -76,11 +87,7 @@ class DelegatingXMLStreamReader implements XMLStreamReader { @Override public String getNamespaceURI(String prefix) { - String nsuri = reader.getNamespaceURI(); - if (nsuri == null) { - nsuri = nsmap.get(prefix); - } - return nsuri; + return reader.getNamespaceURI(prefix); } @Override @@ -139,22 +146,22 @@ class DelegatingXMLStreamReader implements XMLStreamReader { } public int getNamespaceCount() { - return prefixes.length + reader.getNamespaceCount(); + return (depth == 1 ? xprefixes.length : 0) + reader.getNamespaceCount(); } public String getNamespacePrefix(int index) { - if (index < prefixes.length) { - return prefixes[index]; + if (depth == 1) { + return index < xprefixes.length ? xprefixes[index] : reader.getNamespacePrefix(index - xprefixes.length); } else { - return reader.getNamespacePrefix(index - prefixes.length); + return reader.getNamespacePrefix(index); } } public String getNamespaceURI(int index) { - if (index < prefixes.length) { - return nsmap.get(prefixes[index]); + if (depth == 1) { + return index < xprefixes.length ? getNamespaceURI(xprefixes[index]) : reader.getNamespaceURI(index - xprefixes.length); } else { - return reader.getNamespaceURI(index - prefixes.length); + return reader.getNamespaceURI(index); } } http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/feature/PayLoadDataFormatFeature.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/feature/PayLoadDataFormatFeature.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/feature/PayLoadDataFormatFeature.java index dabde13..09f1acd 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/feature/PayLoadDataFormatFeature.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/feature/PayLoadDataFormatFeature.java @@ -61,6 +61,7 @@ public class PayLoadDataFormatFeature extends AbstractDataFormatFeature { @Override public void initialize(Client client, Bus bus) { + client.getEndpoint().put("org.apache.cxf.binding.soap.addNamespaceContext", "true"); removeFaultInInterceptorFromClient(client); // Need to remove some interceptors that are incompatible @@ -86,6 +87,7 @@ public class PayLoadDataFormatFeature extends AbstractDataFormatFeature { @Override public void initialize(Server server, Bus bus) { + server.getEndpoint().put("org.apache.cxf.binding.soap.addNamespaceContext", "true"); server.getEndpoint().getBinding().getInInterceptors().add(new ConfigureDocLitWrapperInterceptor(true)); if (server.getEndpoint().getBinding() instanceof SoapBinding) { server.getEndpoint().getBinding().getOutInterceptors().add(new SetSoapVersionInterceptor()); http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeStreamCacheTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeStreamCacheTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeStreamCacheTest.java new file mode 100644 index 0000000..5a805b9 --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeStreamCacheTest.java @@ -0,0 +1,43 @@ +/** + * 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.camel.component.cxf; + +import org.w3c.dom.Document; + +import org.apache.camel.builder.RouteBuilder; + +public class CxfPayloadConsumerNamespaceOnEnvelopeStreamCacheTest extends CxfPayloadConsumerNamespaceOnEnvelopeTest { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:router") + // Use message mode to send the raw message + .to("cxf:bean:serviceEndpoint?dataFormat=MESSAGE") + // Convert to String to make testing the result easier + .convertBodyTo(String.class); + // The consumer is running in payload mode + from("cxf:bean:serviceEndpoint?DataFormat=PAYLOAD") + // Use stream caching to trigger the issue + .streamCaching() + // Parse to DOM to make sure it's still valid XML + .convertBodyTo(Document.class).setBody().constant(RESPONSE_PAYLOAD); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java index 063fbeb..9f9ed95 100644 --- a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java @@ -29,8 +29,6 @@ import org.junit.Before; import org.springframework.context.support.AbstractXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; - - public class CxfPayloadConsumerNamespaceOnEnvelopeTest extends CamelTestSupport { /* * The request message is generated directly. The issue here is that the xsi @@ -42,14 +40,13 @@ public class CxfPayloadConsumerNamespaceOnEnvelopeTest extends CamelTestSupport * If some CXF proxy is used to send the message the namespaces will be * defined within the payload (and everything works fine). */ - private static final String RESPONSE_PAYLOAD = "<ns2:getTokenResponse xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"" - + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" - + " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><return xsi:type=\"xs:string\">Return Value</return></ns2:getTokenResponse>"; - private static final String REQUEST_MESSAGE = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " - + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><soap:Body>" - + "<ns2:getToken xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"><arg0 xsi:type=\"xs:string\">Send</arg0></ns2:getToken>" - + "</soap:Body></soap:Envelope>"; - + protected static final String RESPONSE_PAYLOAD = + "<ns2:getTokenResponse xmlns:ns2=\"http://camel.apache.org/cxf/namespace\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + + "<return xsi:type=\"xs:string\">Return Value</return></ns2:getTokenResponse>"; + protected static final String REQUEST_MESSAGE = + "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + + "<soap:Body><ns2:getToken xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"><arg0 xsi:type=\"xs:string\">Send</arg0></ns2:getToken></soap:Body></soap:Envelope>"; + private AbstractXmlApplicationContext applicationContext; // Don't remove this, it initializes the CXFTestSupport class http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeStreamCacheTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeStreamCacheTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeStreamCacheTest.java new file mode 100644 index 0000000..dc06375 --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeStreamCacheTest.java @@ -0,0 +1,44 @@ +/** + * 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.camel.component.cxf; + +import org.w3c.dom.Document; + +import org.apache.camel.builder.RouteBuilder; + +public class CxfPayloadProducerNamespaceOnEnvelopeStreamCacheTest extends CxfPayloadProducerNamespaceOnEnvelopeTest { + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:router") // + .streamCaching() + // call an external Web service in payload mode + .to("cxf:bean:serviceEndpoint?dataFormat=PAYLOAD") + // Check that the issue doesn't occur if stream caching is enabled + // Parse to DOM to make sure it's still valid XML + .convertBodyTo(Document.class) + // Convert back to String to make testing the result + // easier + .convertBodyTo(String.class); + // This route just returns the test message + from("cxf:bean:serviceEndpoint?DataFormat=MESSAGE").setBody().constant(RESPONSE_MESSAGE); + } + }; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.java b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.java index b1a26e2..2d514a1 100644 --- a/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.java +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.java @@ -29,7 +29,6 @@ import org.junit.Before; import org.springframework.context.support.AbstractXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; - public class CxfPayloadProducerNamespaceOnEnvelopeTest extends CamelTestSupport { /* * The response message is generated directly. The issue here is that the @@ -41,11 +40,11 @@ public class CxfPayloadProducerNamespaceOnEnvelopeTest extends CamelTestSupport * If some CXF implementation bean is used as the service the namespaces * will be defined within the payload (and everything works fine). */ - private static final String RESPONSE_MESSAGE = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"" - + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><soap:Body>" - + "<ns2:getTokenResponse xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"><return xsi:type=\"xs:string\">Return Value</return></ns2:getTokenResponse>" - + "</soap:Body></soap:Envelope>"; - private static final String REQUEST_PAYLOAD = "<ns2:getToken xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"/>"; + + protected static final String RESPONSE_MESSAGE = + "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"><soap:Body>" + + "<ns2:getTokenResponse xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"><return xsi:type=\"xs:string\">Return Value</return></ns2:getTokenResponse></soap:Body></soap:Envelope>"; + protected static final String REQUEST_PAYLOAD = "<ns2:getToken xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"/>"; private AbstractXmlApplicationContext applicationContext; http://git-wip-us.apache.org/repos/asf/camel/blob/2965c768/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml b/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml index acfee79..a3c4a28 100644 --- a/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml +++ b/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml @@ -30,10 +30,5 @@ <cxf:cxfEndpoint id="serviceEndpoint" address="http://localhost:${CXFTestSupport.port1}/GetToken/SoapContext/SoapPort" wsdlURL="GetToken.wsdl" serviceName="s:GetTokenService" - xmlns:s="http://camel.apache.org/cxf/namespace"> - <cxf:properties> - <entry key="org.apache.cxf.binding.soap.addNamespaceContext" value="true"/> - </cxf:properties> - - </cxf:cxfEndpoint> + xmlns:s="http://camel.apache.org/cxf/namespace"/> </beans>