Repository: camel Updated Branches: refs/heads/master 5e0c0faf3 -> ba9bd8cb2
CAMEL-8663 - Namespaces defined on the SOAP envelope lost (a modified patch with Stephan's unit test code) Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/ba9bd8cb Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/ba9bd8cb Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/ba9bd8cb Branch: refs/heads/master Commit: ba9bd8cb2a88113ecf152b54a4bf7ff9dca12cfa Parents: 5e0c0fa Author: Akitoshi Yoshida <[email protected]> Authored: Thu May 7 10:31:39 2015 +0200 Committer: Akitoshi Yoshida <[email protected]> Committed: Thu May 7 13:31:21 2015 +0200 ---------------------------------------------------------------------- .../camel/component/cxf/DefaultCxfBinding.java | 23 +- .../cxf/converter/CachedCxfPayload.java | 216 ---------------- .../cxf/converter/CxfPayloadConverter.java | 20 ++ .../converter/DelegatingXMLStreamReader.java | 245 +++++++++++++++++++ ...fPayloadConsumerNamespaceOnEnvelopeTest.java | 102 ++++++++ ...fPayloadProducerNamespaceOnEnvelopeTest.java | 104 ++++++++ .../camel-cxf/src/test/resources/GetToken.wsdl | 71 ++++++ .../camel/component/cxf/GetTokenBeans.xml | 39 +++ 8 files changed, 596 insertions(+), 224 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 7616568..0a5f0bf 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,6 +55,7 @@ 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; @@ -751,14 +752,20 @@ public class DefaultCxfBinding implements CxfBinding, HeaderFilterStrategyAware protected static List<Source> getPayloadBodyElements(Message message, Map<String, String> nsMap) { // take the namespace attribute from soap envelop - Document soapEnv = (Document) message.getContent(Node.class); - if (soapEnv != null) { - NamedNodeMap attrs = soapEnv.getFirstChild().getAttributes(); - for (int i = 0; i < attrs.getLength(); i++) { - Node node = attrs.item(i); - if (!node.getNodeValue().equals(Soap11.SOAP_NAMESPACE) - && !node.getNodeValue().equals(Soap12.SOAP_NAMESPACE)) { - nsMap.put(node.getLocalName(), node.getNodeValue()); + Map<String, String> bodyNC = CastUtils.cast((Map<?, ?>)message.get("soap.body.ns.context")); + if (bodyNC != null) { + // if there is no Node and the addNamespaceContext option is enabled, this map is available + nsMap.putAll(bodyNC); + } else { + Document soapEnv = (Document) message.getContent(Node.class); + if (soapEnv != null) { + NamedNodeMap attrs = soapEnv.getFirstChild().getAttributes(); + for (int i = 0; i < attrs.getLength(); i++) { + Node node = attrs.item(i); + if (!node.getNodeValue().equals(Soap11.SOAP_NAMESPACE) + && !node.getNodeValue().equals(Soap12.SOAP_NAMESPACE)) { + nsMap.put(node.getLocalName(), node.getNodeValue()); + } } } } http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 7cc94a6..1068809 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 @@ -152,220 +152,4 @@ public class CachedCxfPayload<T> extends CxfPayload<T> implements StreamCache { public StreamCache copy(Exchange exchange) throws IOException { return new CachedCxfPayload<T>(this, exchange); } - - private static class DelegatingXMLStreamReader implements XMLStreamReader { - private XMLStreamReader reader; - private final Map<String, String> nsmap; - private final String[] prefixes; - - public DelegatingXMLStreamReader(XMLStreamReader reader, Map<String, String> nsmap) { - this.reader = reader; - this.nsmap = nsmap; - this.prefixes = nsmap.keySet().toArray(new String[0]); - } - - @Override - public Object getProperty(String name) throws IllegalArgumentException { - return reader.getProperty(name); - } - - @Override - public int next() throws XMLStreamException { - return reader.next(); - } - - @Override - public void require(int type, String namespaceURI, String localName) throws XMLStreamException { - reader.require(type, namespaceURI, localName); - } - - @Override - public String getElementText() throws XMLStreamException { - return reader.getElementText(); - } - - @Override - public int nextTag() throws XMLStreamException { - return reader.nextTag(); - } - - @Override - public boolean hasNext() throws XMLStreamException { - return reader.hasNext(); - } - - @Override - public void close() throws XMLStreamException { - reader.close(); - } - - @Override - public String getNamespaceURI(String prefix) { - String nsuri = reader.getNamespaceURI(); - if (nsuri == null) { - nsuri = nsmap.get(prefix); - } - return nsuri; - } - - @Override - public boolean isStartElement() { - return reader.isStartElement(); - } - - @Override - public boolean isEndElement() { - return reader.isEndElement(); - } - - @Override - public boolean isCharacters() { - return reader.isCharacters(); - } - - public boolean isWhiteSpace() { - return reader.isWhiteSpace(); - } - - public String getAttributeValue(String namespaceURI, String localName) { - return reader.getAttributeValue(namespaceURI, localName); - } - - public int getAttributeCount() { - return reader.getAttributeCount(); - } - - public QName getAttributeName(int index) { - return reader.getAttributeName(index); - } - - public String getAttributeNamespace(int index) { - return reader.getAttributeNamespace(index); - } - - public String getAttributeLocalName(int index) { - return reader.getAttributeLocalName(index); - } - - public String getAttributePrefix(int index) { - return reader.getAttributePrefix(index); - } - - public String getAttributeType(int index) { - return reader.getAttributeType(index); - } - - public String getAttributeValue(int index) { - return reader.getAttributeValue(index); - } - - public boolean isAttributeSpecified(int index) { - return reader.isAttributeSpecified(index); - } - - public int getNamespaceCount() { - return prefixes.length + reader.getNamespaceCount(); - } - - public String getNamespacePrefix(int index) { - if (index < prefixes.length) { - return prefixes[index]; - } else { - return reader.getNamespacePrefix(index - prefixes.length); - } - } - - public String getNamespaceURI(int index) { - if (index < prefixes.length) { - return nsmap.get(prefixes[index]); - } else { - return reader.getNamespaceURI(index - prefixes.length); - } - } - - public NamespaceContext getNamespaceContext() { - return reader.getNamespaceContext(); - } - - public int getEventType() { - return reader.getEventType(); - } - - public String getText() { - return reader.getText(); - } - - public char[] getTextCharacters() { - return reader.getTextCharacters(); - } - - public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { - return reader.getTextCharacters(sourceStart, target, targetStart, length); - } - - public int getTextStart() { - return reader.getTextStart(); - } - - public int getTextLength() { - return reader.getTextLength(); - } - - public String getEncoding() { - return reader.getEncoding(); - } - - public boolean hasText() { - return reader.hasText(); - } - - public Location getLocation() { - return reader.getLocation(); - } - - public QName getName() { - return reader.getName(); - } - - public String getLocalName() { - return reader.getLocalName(); - } - - public boolean hasName() { - return reader.hasName(); - } - - public String getNamespaceURI() { - return reader.getNamespaceURI(); - } - - public String getPrefix() { - return reader.getPrefix(); - } - - public String getVersion() { - return reader.getVersion(); - } - - public boolean isStandalone() { - return reader.isStandalone(); - } - - public boolean standaloneSet() { - return reader.standaloneSet(); - } - - public String getCharacterEncodingScheme() { - return reader.getCharacterEncodingScheme(); - } - - public String getPITarget() { - return reader.getPITarget(); - } - - public String getPIData() { - return reader.getPIData(); - } - - } } http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java index 7b8da00..9d24a4e 100644 --- a/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/CxfPayloadConverter.java @@ -21,16 +21,23 @@ import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stax.StAXSource; import javax.xml.transform.stream.StreamSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; + import org.apache.camel.Converter; import org.apache.camel.Exchange; import org.apache.camel.FallbackConverter; @@ -39,6 +46,7 @@ import org.apache.camel.TypeConverter; import org.apache.camel.component.cxf.CxfPayload; import org.apache.camel.converter.jaxp.XmlConverter; import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.cxf.staxutils.StaxSource; import org.apache.cxf.staxutils.StaxUtils; @Converter @@ -194,6 +202,17 @@ public final class CxfPayloadConverter { } TypeConverter tc = registry.lookup(type, Source.class); if (tc != null) { + XMLStreamReader r = null; + if (payload.getNsMap() != null) { + if (s instanceof StaxSource) { + r = ((StaxSource) s).getXMLStreamReader(); + } else if (s instanceof StAXSource) { + r = ((StAXSource) s).getXMLStreamReader(); + } + if (r != null) { + s = new StAXSource(new DelegatingXMLStreamReader(r, payload.getNsMap())); + } + } T t = tc.convertTo(type, s); return t; } @@ -237,4 +256,5 @@ public final class CxfPayloadConverter { } return null; } + } http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 new file mode 100644 index 0000000..354c8c3 --- /dev/null +++ b/components/camel-cxf/src/main/java/org/apache/camel/component/cxf/converter/DelegatingXMLStreamReader.java @@ -0,0 +1,245 @@ +/** + * 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.converter; + +import java.util.Map; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +/** + * + */ +class DelegatingXMLStreamReader implements XMLStreamReader { + private XMLStreamReader reader; + private final Map<String, String> nsmap; + private final String[] prefixes; + + public DelegatingXMLStreamReader(XMLStreamReader reader, Map<String, String> nsmap) { + this.reader = reader; + this.nsmap = nsmap; + this.prefixes = nsmap.keySet().toArray(new String[0]); + } + + @Override + public Object getProperty(String name) throws IllegalArgumentException { + return reader.getProperty(name); + } + + @Override + public int next() throws XMLStreamException { + return reader.next(); + } + + @Override + public void require(int type, String namespaceURI, String localName) throws XMLStreamException { + reader.require(type, namespaceURI, localName); + } + + @Override + public String getElementText() throws XMLStreamException { + return reader.getElementText(); + } + + @Override + public int nextTag() throws XMLStreamException { + return reader.nextTag(); + } + + @Override + public boolean hasNext() throws XMLStreamException { + return reader.hasNext(); + } + + @Override + public void close() throws XMLStreamException { + reader.close(); + } + + @Override + public String getNamespaceURI(String prefix) { + String nsuri = reader.getNamespaceURI(); + if (nsuri == null) { + nsuri = nsmap.get(prefix); + } + return nsuri; + } + + @Override + public boolean isStartElement() { + return reader.isStartElement(); + } + + @Override + public boolean isEndElement() { + return reader.isEndElement(); + } + + @Override + public boolean isCharacters() { + return reader.isCharacters(); + } + + public boolean isWhiteSpace() { + return reader.isWhiteSpace(); + } + + public String getAttributeValue(String namespaceURI, String localName) { + return reader.getAttributeValue(namespaceURI, localName); + } + + public int getAttributeCount() { + return reader.getAttributeCount(); + } + + public QName getAttributeName(int index) { + return reader.getAttributeName(index); + } + + public String getAttributeNamespace(int index) { + return reader.getAttributeNamespace(index); + } + + public String getAttributeLocalName(int index) { + return reader.getAttributeLocalName(index); + } + + public String getAttributePrefix(int index) { + return reader.getAttributePrefix(index); + } + + public String getAttributeType(int index) { + return reader.getAttributeType(index); + } + + public String getAttributeValue(int index) { + return reader.getAttributeValue(index); + } + + public boolean isAttributeSpecified(int index) { + return reader.isAttributeSpecified(index); + } + + public int getNamespaceCount() { + return prefixes.length + reader.getNamespaceCount(); + } + + public String getNamespacePrefix(int index) { + if (index < prefixes.length) { + return prefixes[index]; + } else { + return reader.getNamespacePrefix(index - prefixes.length); + } + } + + public String getNamespaceURI(int index) { + if (index < prefixes.length) { + return nsmap.get(prefixes[index]); + } else { + return reader.getNamespaceURI(index - prefixes.length); + } + } + + public NamespaceContext getNamespaceContext() { + return reader.getNamespaceContext(); + } + + public int getEventType() { + return reader.getEventType(); + } + + public String getText() { + return reader.getText(); + } + + public char[] getTextCharacters() { + return reader.getTextCharacters(); + } + + public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { + return reader.getTextCharacters(sourceStart, target, targetStart, length); + } + + public int getTextStart() { + return reader.getTextStart(); + } + + public int getTextLength() { + return reader.getTextLength(); + } + + public String getEncoding() { + return reader.getEncoding(); + } + + public boolean hasText() { + return reader.hasText(); + } + + public Location getLocation() { + return reader.getLocation(); + } + + public QName getName() { + return reader.getName(); + } + + public String getLocalName() { + return reader.getLocalName(); + } + + public boolean hasName() { + return reader.hasName(); + } + + public String getNamespaceURI() { + return reader.getNamespaceURI(); + } + + public String getPrefix() { + return reader.getPrefix(); + } + + public String getVersion() { + return reader.getVersion(); + } + + public boolean isStandalone() { + return reader.isStandalone(); + } + + public boolean standaloneSet() { + return reader.standaloneSet(); + } + + public String getCharacterEncodingScheme() { + return reader.getCharacterEncodingScheme(); + } + + public String getPITarget() { + return reader.getPITarget(); + } + + public String getPIData() { + return reader.getPIData(); + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 new file mode 100644 index 0000000..e4b6f5d --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadConsumerNamespaceOnEnvelopeTest.java @@ -0,0 +1,102 @@ +/** + * 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.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spring.SpringCamelContext; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.w3c.dom.Document; + +public class CxfPayloadConsumerNamespaceOnEnvelopeTest extends CamelTestSupport { + private AbstractXmlApplicationContext applicationContext; + /* + * The request message is generated directly. The issue here is that the xsi + * and xs namespaces are defined on the SOAP envelope but are used within + * the payload. This can cause issues with some type conversions in PAYLOAD + * mode, as the Camel-CXF endpoint will return some kind of window within + * the StAX parsing (and the namespace definitions are outside). + * + * 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 responsePayload = "<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 requestMessage = "<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>"; + + // Don't remove this, it initializes the CXFTestSupport class + static { + CXFTestSupport.getPort1(); + // Works without streaming... + // System.setProperty("org.apache.camel.component.cxf.streaming", "false"); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + return SpringCamelContext.springCamelContext(applicationContext); + } + + @Before + public void setUp() throws Exception { + applicationContext = new ClassPathXmlApplicationContext("org/apache/camel/component/cxf/GetTokenBeans.xml"); + super.setUp(); + assertNotNull("Should have created a valid spring context", applicationContext); + } + + @After + public void tearDown() throws Exception { + IOHelper.close(applicationContext); + super.tearDown(); + } + + @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") + // Convert the CxfPayload to a String to trigger the issue + .convertBodyTo(String.class) + // Parse to DOM to make sure it's still valid XML + .convertBodyTo(Document.class).setBody().constant(responsePayload); + } + }; + } + +// need cxf-3.0.6 +// @Test + public void testInvokeRouter() { + Object returnValue = template.requestBody("direct:router", requestMessage); + assertNotNull(returnValue); + assertTrue(returnValue instanceof String); + assertTrue(((String) returnValue).contains("Return Value")); + assertTrue(((String) returnValue).contains("http://www.w3.org/2001/XMLSchema-instance")); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 new file mode 100644 index 0000000..872dd98 --- /dev/null +++ b/components/camel-cxf/src/test/java/org/apache/camel/component/cxf/CxfPayloadProducerNamespaceOnEnvelopeTest.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.camel.component.cxf; + +import org.apache.camel.CamelContext; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spring.SpringCamelContext; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.util.IOHelper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.support.AbstractXmlApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.w3c.dom.Document; + +public class CxfPayloadProducerNamespaceOnEnvelopeTest extends CamelTestSupport { + private AbstractXmlApplicationContext applicationContext; + /* + * The response message is generated directly. The issue here is that the + * xsi and xs namespaces are defined on the SOAP envelope but are used + * within the payload. This can cause issues with some type conversions in + * PAYLOAD mode, as the Camel-CXF endpoint will return some kind of window + * within the StAX parsing (and the namespace definitions are outside). + * + * 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 responseMessage = "<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 requestPayload = "<ns2:getToken xmlns:ns2=\"http://camel.apache.org/cxf/namespace\"/>"; + + // Don't remove this, it initializes the CXFTestSupport class + static { + CXFTestSupport.getPort1(); + // Works without streaming... + // System.setProperty("org.apache.camel.component.cxf.streaming", "false"); + } + + @Override + protected CamelContext createCamelContext() throws Exception { + return SpringCamelContext.springCamelContext(applicationContext); + } + + @Before + public void setUp() throws Exception { + applicationContext = new ClassPathXmlApplicationContext("org/apache/camel/component/cxf/GetTokenBeans.xml"); + super.setUp(); + assertNotNull("Should have created a valid spring context", applicationContext); + } + + @After + public void tearDown() throws Exception { + IOHelper.close(applicationContext); + super.tearDown(); + } + + @Override + protected RouteBuilder createRouteBuilder() { + return new RouteBuilder() { + public void configure() { + from("direct:router") // + // call an external Web service in payload mode + .to("cxf:bean:serviceEndpoint?dataFormat=PAYLOAD") + // Convert the CxfPayload to a String to trigger the + // issue + .convertBodyTo(String.class) + // 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(responseMessage); + } + }; + } + +// need cxf-3.0.6 +// @Test + public void testInvokeRouter() { + Object returnValue = template.requestBody("direct:router", requestPayload); + assertNotNull(returnValue); + assertTrue(returnValue instanceof String); + assertTrue(((String) returnValue).contains("Return Value")); + assertTrue(((String) returnValue).contains("http://www.w3.org/2001/XMLSchema-instance")); + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/components/camel-cxf/src/test/resources/GetToken.wsdl ---------------------------------------------------------------------- diff --git a/components/camel-cxf/src/test/resources/GetToken.wsdl b/components/camel-cxf/src/test/resources/GetToken.wsdl new file mode 100644 index 0000000..3adc98f --- /dev/null +++ b/components/camel-cxf/src/test/resources/GetToken.wsdl @@ -0,0 +1,71 @@ +<?xml version='1.0' encoding='UTF-8'?> +<!-- + + 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. + +--> +<wsdl:definitions name="GetTokenImplService" targetNamespace="http://camel.apache.org/cxf/namespace" xmlns:ns1="http://schemas.xmlsoap.org/soap/http" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://camel.apache.org/cxf/namespace" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <wsdl:types> + <xs:schema attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://camel.apache.org/cxf/namespace" xmlns="http://camel.apache.org/cxf/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <xs:complexType name="getToken"> + <xs:sequence> + <xs:element minOccurs="0" name="arg0"/> + </xs:sequence> + </xs:complexType> + <xs:complexType name="getTokenResponse"> + <xs:sequence> + <xs:element minOccurs="0" name="return"/> + </xs:sequence> + </xs:complexType> + <xs:element name="getToken" nillable="true" type="getToken"/> + <xs:element name="getTokenResponse" nillable="true" type="getTokenResponse"/> + </xs:schema> + </wsdl:types> + <wsdl:message name="getToken"> + <wsdl:part element="tns:getToken" name="parameters"> + </wsdl:part> + </wsdl:message> + <wsdl:message name="getTokenResponse"> + <wsdl:part element="tns:getTokenResponse" name="parameters"> + </wsdl:part> + </wsdl:message> + <wsdl:portType name="GetToken"> + <wsdl:operation name="getToken"> + <wsdl:input message="tns:getToken" name="getToken"> + </wsdl:input> + <wsdl:output message="tns:getTokenResponse" name="getTokenResponse"> + </wsdl:output> + </wsdl:operation> + </wsdl:portType> + <wsdl:binding name="GetTokenServiceSoapBinding" type="tns:GetToken"> + <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> + <wsdl:operation name="getToken"> + <soap:operation soapAction="" style="document"/> + <wsdl:input name="getToken"> + <soap:body use="literal"/> + </wsdl:input> + <wsdl:output name="getTokenResponse"> + <soap:body use="literal"/> + </wsdl:output> + </wsdl:operation> + </wsdl:binding> + <wsdl:service name="GetTokenService"> + <wsdl:port binding="tns:GetTokenServiceSoapBinding" name="GetTokenPort"> + <soap:address location="http://localhost:9191/GetToken"/> + <wswa:UsingAddressing xmlns:wswa="http://www.w3.org/2005/02/addressing/wsdl"/> + </wsdl:port> + </wsdl:service> +</wsdl:definitions> http://git-wip-us.apache.org/repos/asf/camel/blob/ba9bd8cb/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 new file mode 100644 index 0000000..acfee79 --- /dev/null +++ b/components/camel-cxf/src/test/resources/org/apache/camel/component/cxf/GetTokenBeans.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:cxf="http://camel.apache.org/schema/cxf" + + xsi:schemaLocation=" + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd + http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd + "> + + <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/> + + <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> +</beans>
