Send plain soap over http using camel - java

I am trying to set up a very simple route to send SOAP content over http and then show the response:
<route>
<from uri="direct:start"/>
<setBody>
<constant><![CDATA[<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"><SOAP:Header></SOAP:Header><SOAP:Body></SOAP:Body></SOAP:Envelope>]]>
</constant>
</setBody>
<to uri="https://localhost:8443/api"/>
<log message="${out.body}"/>
</route>
I am not getting any error but is not really showing the response.
What am I missing here?
I am simply runnig my app like this:
public class App {
public static void main( String[] args ) {
ApplicationContext
ctx = new ClassPathXmlApplicationContext("META-INF/spring/camel-config.xml");
}
}

You have not set some headers.
Try to modify your route like below:
<route>
<from uri="timer://foo?fixedRate=true&period=60000"/>
<setHeader headerName="CamelHttpMethod">
<constant>POST</constant>
</setHeader>
<setHeader headerName="Content-type">
<constant>text/xml;charset=UTF-8</constant>
</setHeader>
<setHeader headerName="Accept-Encoding">
<constant>gzip,deflate</constant>
</setHeader>
<setBody>
<constant><![CDATA[<SOAP:Envelope xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/"><SOAP:Header></SOAP:Header><SOAP:Body></SOAP:Body></SOAP:Envelope>]]>
</constant>
</setBody>
<to uri="https://localhost:8443/api"/>
<log message="${out.body}"/>
</route>
I have changed the beginning of the route, because I don't know how you're sending messages to direct:start.

Related

No camel consumer available for routes of type direct-vm when testing

I'm working with unit tests using Camel and, When I execute this test from Camel In Action repository it works perfectly but when I change the route type from SEDA to direct-vm it fails with the following message:
Caused by: org.apache.camel.component.directvm.DirectVmConsumerNotAvailableException: No consumers available on endpoint: direct-vm://camel. Exchange[ID....
The difference of these 2 types, SEDA and direct-vm, is that the first is asynchronous and the second is synchronous. Is that the reason why the test fails? How can I make the test work for direct-vm type of routes?
I'm using JDK 1.8 and Camel 2.25.2
UPDATE: I have found an issue with the mockEndpoints() method inside the adviceWith, the routes are not being mocked. This is what is printed in the logs when I launch the test:
2021-07-20 16:27:36.501 INFO 31220 --- [ main] org.apache.camel.model.RouteDefinition : Adviced route before/after as XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
<from uri="direct-vm:quotes"/>
<choice id="choice2">
<when id="when2">
<simple>${body} contains 'Camel'</simple>
<log id="log4" loggingLevel="INFO" message="camel route"/>
<to id="to11" uri="direct-vm:camel"/>
</when>
<otherwise id="otherwise2">
<log id="log5" loggingLevel="INFO" message="other route"/>
<to id="to12" uri="direct-vm:other"/>
</otherwise>
</choice>
</route>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
<from uri="direct-vm:hitme"/>
<choice id="choice2">
<when id="when2">
<simple>${body} contains 'Camel'</simple>
<log id="log4" loggingLevel="INFO" message="camel route"/>
<to id="to11" uri="direct-vm:camel"/>
</when>
<otherwise id="otherwise2">
<log id="log5" loggingLevel="INFO" message="other route"/>
<to id="to12" uri="direct-vm:other"/>
</otherwise>
</choice>
</route>
But if I use instead weaveByToUri to mock the routes:
weaveByToUri("direct-vm:camel").replace().to("mock:direct-vm:camel");
weaveByToUri("direct-vm:other").replace().to("mock:direct-vm:other");
The routes are mocked and the test works:
2021-07-20 16:30:42.409 INFO 9920 --- [ main] org.apache.camel.model.RouteDefinition : Adviced route before/after as XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
<from uri="direct-vm:quotes"/>
<choice id="choice2">
<when id="when2">
<simple>${body} contains 'Camel'</simple>
<log id="log4" loggingLevel="INFO" message="camel route"/>
<to id="to11" uri="direct-vm:camel"/>
</when>
<otherwise id="otherwise2">
<log id="log5" loggingLevel="INFO" message="other route"/>
<to id="to12" uri="direct-vm:other"/>
</otherwise>
</choice>
</route>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<route xmlns="http://camel.apache.org/schema/spring" customId="true" id="basicRoute">
<from uri="direct-vm:hitme"/>
<choice id="choice2">
<when id="when2">
<simple>${body} contains 'Camel'</simple>
<log id="log4" loggingLevel="INFO" message="camel route"/>
<pipeline>
<to uri="mock:direct-vm:camel"/>
</pipeline>
</when>
<otherwise id="otherwise2">
<log id="log5" loggingLevel="INFO" message="other route"/>
<pipeline>
<to uri="mock:direct-vm:other"/>
</pipeline>
</otherwise>
</choice>
</route>
Should It be a bug in the mockEndpoints method?
If you want to use direct-vm in a test you'll have to run another CamelContext that contains consumer for the direct-vm endpoint you want to test. You can do this with Main class.
public class Example extends CamelTestSupport {
#Override
protected CamelContext createCamelContext() throws Exception {
return new DefaultCamelContext();
}
#Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct-vm:helloReceiver")
.routeId("helloReceiver")
.log("Message received: ${body}")
.to("mock:result");
}
};
}
#Test
public void testDirectVM() throws Exception{
RouteBuilder builder = new RouteBuilder(){
#Override
public void configure() throws Exception {
from("direct:helloSender")
.routeId("helloSender")
.to("direct-vm:helloReceiver");
}
};
MockEndpoint mockEndpoint = getMockEndpoint("mock:result");
mockEndpoint.expectedMessageCount(1);
mockEndpoint.message(0).body().isEqualTo("hello");
Main camelMain = new Main();
camelMain.addRouteBuilder(builder);
camelMain.start();
camelMain.getCamelTemplate()
.sendBody("direct:helloSender", "hello");
mockEndpoint.assertIsSatisfied();
}
}
However it would be better to just to use string variable with setter for the direct-vm endpoint that you can easily change to mock endpoint during testing. Give it id and you can use weaveById to make it return whatever you need for the tests.
The error message No consumers available on endpoint: ... typically means you have a producer that sends messages to a synchronous endpoint but no consumer that listens to this endpoint.
Is it possible that you just changed the producer to direct-vm?
By the way: direct-vm is typically used to connect Camel routes inside the same JVM but from different Camel contexts. One example for this is between OSGi bundles. If you only have 1 Camel context, just use direct.

How to set HTTP Method dynamically from blueprint(Camel-http)

I use camel-apache companent camel-http. I'm trying to set the http method from my custom header. I use blueprint
override process:
exchange.getOut().setHeader("custom_http_method", "GET");
blueprint route:
<route>
<from uri="activemq://for_redmine" />
<setHeader headerName="Content-Type">
<constant>application/json; charset=utf-8</constant>
</setHeader>
<setHeader headerName="X-Redmine-API-Key">
<constant>beb50ea768f5d16c96030a9dbbf3cb5c4a5ccdcd</constant>
</setHeader>
<setHeader headerName="CamelHttpMethod">
<constant>${header.custom_http_method}</constant>
</setHeader>
<toD uri="${header.url}"/>
</route>
error:
org.apache.camel.TypeConversionException: Error during type conversion from type: java.lang.String to the required type: org.apache.camel.http.common.HttpMethods with value ${header.custom_http_method} due java.lang.IllegalArgumentException: No enum constant org.apache.camel.http.common.HttpMethods.${header.custom_http_method}
as far as I understood, $ {header.custom_http_method} did not return value.
toD uri="${header.url}" - works correctly
Try to use simple instead of constant when setting the header CamelHttpMethod
<route>
<from uri="activemq://for_redmine" />
....
<setHeader headerName="CamelHttpMethod">
<simple>${header.custom_http_method}</simple>
</setHeader>
<toD uri="${header.url}"/>
</route>

Camel get response from Route

I am able to called Web Service, now what ever response came from web service, i need to fetch same response in java code so that i am able to further processing.
<camelContext xmlns="http://camel.apache.org/schema/spring" trace="false">
<route id="my_Sample_Camel_Route_with_CXF">
<from uri="file:src/data?noop=true"/>
<log loggingLevel="INFO" message=">>> ${body}"/>
<to uri="cxf://http://www.webservicex.net/stockquote.asmx?wsdlURL=src/main/resources/META-INF/stockquote.wsdl&serviceName={http://www.webserviceX.NET/}StockQuote&portName={http://www.webserviceX.NET/}StockQuoteSoap&dataFormat=MESSAGE"/>
<log loggingLevel="INFO" message=">>> ${body}"/>
</route>
Instead of logging using

Send response to file request?

One of my client put the file request under directory placeorder with below configuration in CAMEL
<route id="FileToJMS">
<from uri="file:target/placeorder" />
<to uri="jms:incomingOrders" />
</route>
Once processing is done from incomingOrders, i want to send the some response to customer who initiated file request. How can i achieve it with CAMEL (probably using request reply or return address pattern). Any ideas?
Like so:
<route id="FileToJMS">
<from uri="file:target/placeorder" />
<to uri="jms:incomingOrders" />
<to uri="mock:response"/>
</route>
replace "mock:response" with whatever component you want to send the response with

Camel AggregationStrategy behaving unexpectedly

I have a situation where I want to pass data into an Aggregator, but I don't want the aggregator to do anything until it has received messages from 3 distinct routes:
<route id="route-1">
<from uri="direct:fizz" />
<to uri="bean:bean1?method=process" />
<setHeader headerName="id">
<constant>1</constant>
</setHeader>
<to uri="direct:aggregator" />
</route>
<route id="route-2">
<from uri="direct:buzz" />
<to uri="bean:bean2?method=process" />
<setHeader headerName="id">
<constant>2</constant>
</setHeader>
<to uri="direct:aggregator" />
</route>
<route id="route-3">
<from uri="direct:foo" />
<to uri="bean:bean3?method=process" />
<setHeader headerName="id">
<constant>3</constant>
</setHeader>
<to uri="direct:aggregator" />
</route>
<route id="aggregator-route">
<from uri="direct:aggregator" />
<aggregate strategyRef="myAggregationStrategy" completionSize="1">
<correlationExpression>
<simple>header.id</simple>
</correlationExpression>
<to uri="bean:lastBean?method=process" />
</aggregate>
</route>
The way this is configured, when the aggregator's completionSize is set to 1 or 2, the aggregated Exchange is routed on to my lastBean. However, if I set completionSize to 3, for some reason, lastBean#process never gets invoked.
I'm sure that I'm using header.id and the aggregator incorrectly here. In the correlationExpression, I just need to make sure that we have 1 Message from each of the 3 routes.
So my question: what do I need to do to make my aggregator "wait" until it has received 1 message from route-1, 1 message from route-2 and 1 message from route-3?
If you are correlating messages from three routes, there needs to be a way for them all to have a matching header.id value by the time they reach the aggregating route.
In your example, each route sets a different id value so there would be no match. If you set the id value to "1" in each route, I think it would start to work as expected.

Categories

Resources