| /** |
| * 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.Element; |
| import org.w3c.dom.Text; |
| |
| import org.apache.camel.Exchange; |
| import org.apache.camel.ExchangePattern; |
| import org.apache.camel.Processor; |
| import org.apache.camel.builder.RouteBuilder; |
| import org.apache.camel.builder.xml.XPathBuilder; |
| import org.apache.camel.impl.DefaultExchange; |
| import org.apache.camel.test.AvailablePortFinder; |
| import org.apache.camel.test.junit4.CamelTestSupport; |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.cxf.binding.soap.SoapHeader; |
| import org.junit.Test; |
| |
| public class CxfConsumerPayloadXPathTest extends CamelTestSupport { |
| |
| public static final String HEADER_SIZE = "tstsize"; |
| |
| @Test |
| public void size1XPathStringResultTest() throws Exception { |
| simpleTest(1, new TestRouteWithXPathStringResultBuilder()); |
| } |
| |
| @Test |
| public void size100XPathStringResultTest() throws Exception { |
| simpleTest(100, new TestRouteWithXPathStringResultBuilder()); |
| } |
| |
| @Test |
| public void size1000XPathStringResultTest() throws Exception { |
| simpleTest(1000, new TestRouteWithXPathStringResultBuilder()); |
| } |
| |
| @Test |
| public void size10000XPathStringResultTest() throws Exception { |
| simpleTest(10000, new TestRouteWithXPathStringResultBuilder()); |
| } |
| |
| @Test |
| public void size1XPathTest() throws Exception { |
| simpleTest(1, new TestRouteWithXPathBuilder()); |
| } |
| |
| @Test |
| public void size100XPathTest() throws Exception { |
| simpleTest(100, new TestRouteWithXPathBuilder()); |
| } |
| |
| @Test |
| public void size1000XPathTest() throws Exception { |
| simpleTest(1000, new TestRouteWithXPathBuilder()); |
| } |
| |
| @Test |
| public void size10000XPathTest() throws Exception { |
| simpleTest(10000, new TestRouteWithXPathBuilder()); |
| } |
| |
| //the textnode appears to have siblings! |
| @Test |
| public void size10000DomTest() throws Exception { |
| simpleTest(10000, new TestRouteWithDomBuilder()); |
| } |
| |
| @Test |
| public void size1000DomFirstTest() throws Exception { |
| simpleTest(1000, new TestRouteWithDomFirstOneOnlyBuilder()); |
| } |
| |
| private class TestRouteWithXPathBuilder extends BaseRouteBuilder { |
| @Override |
| public void configure() { |
| from("cxf://" + testAddress + "?dataFormat=PAYLOAD") |
| .streamCaching() |
| .process(new XPathProcessor()) |
| .process(new ResponseProcessor()); |
| } |
| } |
| |
| private class TestRouteWithXPathStringResultBuilder extends BaseRouteBuilder { |
| @Override |
| public void configure() { |
| from("cxf://" + testAddress + "?dataFormat=PAYLOAD") |
| .streamCaching() |
| .process(new XPathStringResultProcessor()) |
| .process(new ResponseProcessor()); |
| } |
| } |
| |
| private class TestRouteWithDomFirstOneOnlyBuilder extends BaseRouteBuilder { |
| @Override |
| public void configure() { |
| from("cxf://" + testAddress + "?dataFormat=PAYLOAD") |
| .streamCaching() |
| .process(new DomFirstOneOnlyProcessor()) |
| .process(new ResponseProcessor()); |
| } |
| } |
| |
| private class TestRouteWithDomBuilder extends BaseRouteBuilder { |
| @Override |
| public void configure() { |
| from("cxf://" + testAddress + "?dataFormat=PAYLOAD") |
| .streamCaching() |
| .process(new DomProcessor()) |
| .process(new ResponseProcessor()); |
| } |
| } |
| |
| //implementation simular to xpath() in route: no data loss |
| private class XPathStringResultProcessor implements Processor { |
| @Override |
| public void process(Exchange exchange) throws Exception { |
| Object obj = exchange.getIn().getBody(); |
| //xpath expression directly results in a: String |
| String content = (String) XPathBuilder.xpath("//xml/text()").stringResult().evaluate(context, obj, Object.class); |
| exchange.getOut().setBody(content); |
| exchange.getOut().setHeaders(exchange.getIn().getHeaders()); |
| } |
| } |
| |
| //this version leads to data loss |
| private class XPathProcessor implements Processor { |
| @Override |
| public void process(Exchange exchange) throws Exception { |
| Object obj = exchange.getIn().getBody(); |
| //xpath expression results in a: net.sf.saxon.dom.DOMNodeList |
| //after which it is converted to a String |
| String content = XPathBuilder.xpath("//xml/text()").evaluate(context, obj, String.class); |
| exchange.getOut().setBody(content); |
| exchange.getOut().setHeaders(exchange.getIn().getHeaders()); |
| } |
| } |
| |
| //this version leads to data loss |
| private class DomFirstOneOnlyProcessor implements Processor { |
| @Override |
| public void process(Exchange exchange) throws Exception { |
| Object obj = exchange.getIn().getBody(); |
| @SuppressWarnings("unchecked") |
| CxfPayload<SoapHeader> payload = (CxfPayload<SoapHeader>) obj; |
| Element el = payload.getBody().get(0); |
| Text textnode = (Text) el.getFirstChild(); |
| exchange.getOut().setBody(textnode.getNodeValue()); |
| exchange.getOut().setHeaders(exchange.getIn().getHeaders()); |
| } |
| } |
| |
| private class DomProcessor implements Processor { |
| @Override |
| public void process(Exchange exchange) throws Exception { |
| Object obj = exchange.getIn().getBody(); |
| @SuppressWarnings("unchecked") |
| CxfPayload<SoapHeader> payload = (CxfPayload<SoapHeader>) obj; |
| Element el = payload.getBody().get(0); |
| Text textnode = (Text) el.getFirstChild(); |
| |
| StringBuilder b = new StringBuilder(); |
| b.append(textnode.getNodeValue()); |
| textnode = (Text) textnode.getNextSibling(); |
| while (textnode != null) { |
| //the textnode appears to have siblings! |
| b.append(textnode.getNodeValue()); |
| textnode = (Text) textnode.getNextSibling(); |
| } |
| |
| exchange.getOut().setBody(b.toString()); |
| exchange.getOut().setHeaders(exchange.getIn().getHeaders()); |
| } |
| } |
| |
| private class ResponseProcessor implements Processor { |
| @Override |
| public void process(Exchange exchange) throws Exception { |
| Object obj = exchange.getIn().getBody(); |
| String content = (String) obj; |
| String msgOut = constructSoapMessage(content); |
| exchange.getOut().setBody(msgOut); |
| exchange.getOut().setHeaders(exchange.getIn().getHeaders()); |
| exchange.getOut().setHeader(HEADER_SIZE, "" + content.length()); |
| } |
| } |
| |
| private void simpleTest(int repeat, BaseRouteBuilder builder) throws Exception { |
| setUseRouteBuilder(false); |
| context.addRoutes(builder); |
| startCamelContext(); |
| |
| String content = StringUtils.repeat("x", repeat); |
| String msgIn = constructSoapMessage(content); |
| |
| Exchange exchgIn = new DefaultExchange(context); |
| exchgIn.setPattern(ExchangePattern.InOut); |
| exchgIn.getIn().setBody(msgIn); |
| |
| //Execute |
| Exchange exchgOut = template.send(builder.getTestAddress(), exchgIn); |
| |
| //Verify |
| String result = exchgOut.getOut().getBody(String.class); |
| assertNotNull("response on http call", result); |
| |
| //check for data loss in received input (after xpath) |
| String headerSize = exchgOut.getOut().getHeader(HEADER_SIZE, String.class); |
| assertEquals("" + repeat, headerSize); |
| |
| assertTrue("dataloss in output occurred", result.length() > repeat); |
| |
| stopCamelContext(); |
| } |
| |
| |
| private abstract class BaseRouteBuilder extends RouteBuilder { |
| protected final String testAddress = getAvailableUrl("test"); |
| |
| public String getTestAddress() { |
| return testAddress; |
| } |
| } |
| |
| private String getAvailableUrl(String pathEnd) { |
| int availablePort = AvailablePortFinder.getNextAvailable(); |
| String url = "http://localhost:" + availablePort |
| + "/" + getClass().getSimpleName(); |
| return url + "/" + pathEnd; |
| } |
| |
| private String constructSoapMessage(String content) { |
| return |
| "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" |
| + "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">" |
| + "<soapenv:Body><xml>" + content + "</xml></soapenv:Body>" |
| + "</soapenv:Envelope>"; |
| } |
| } |