Camel JMS CXF endpoints doesn't create new temp reply queue - soap

I have two CXF endpoints which use JMS as the transport; one is used as a consumer and the second as a producer. Here is a very trimmed down setup.
<camelcxf:cxfEndpoint xmlns:i="http://inbound.com/inbound"
id="myInboundEndpoint"
endpointName="i:InboundService"
serviceName="i:InboundService"
address="camel://direct:my-inbound-route"
serviceClass="com.InboundService"
bus="cxf"
wsdlURL="classpath:META-INF/wsdl/inbound.wsdl">
<camelcxf:properties>
<entry key="dataFormat" value="POJO"/>
</camelcxf:properties>
</camelcxf:cxfEndpoint>
<camelcxf:cxfEndpoint xmlns:o="http://outbound.com/outbound"
id="myOutboundEndpoint"
endpointName="o:OutboundService"
serviceName="o:OutboundService"
address=""jms://""
serviceClass="com.OutboundService"
bus="cxf"
wsdlURL="classpath:META-INF/wsdl/outbound.wsdl">
<camelcxf:properties>
<entry key="dataFormat" value="POJO"/>
</camelcxf:properties>
<camelcxf:features>
<bean class="org.apache.cxf.transport.jms.JMSConfigFeature">
<property name="jmsConfig" ref="jmsConfig" />
</bean>
</camelcxf:features>
</camelcxf:cxfEndpoint>
<bean id="jmsConfig" class="org.apache.cxf.transport.jms.JMSConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory" />
<property name="targetDestination" value="some-queue" />
</bean>
<camelContext>
<route id="inQueue">
<from uri="activemq:inbound-queue" />
<to uri="direct:my-inbound-route" />
</route>
<route id="inVm">
<from uri="direct:in-vm" />
<to uri="direct:my-inbound-route" />
</route>
<route id="serviceProxy">
<from uri="cxf:bean:myInboundEndpoint?synchronous=true" />
<setHeader headerName="operationName"><constant>myOtherOperation</constant></setHeader>
<to uri="cxf:bean:outboundEndpoint?synchronous=true" />
</route>
</camelContext>
But what happens when the second route is called is that CXF component or camel tries to re-use all the JMS config from the original inbound message including the reply queue rather than creating another temp reply queue just for this exchange. This seems to be taken of the headers from the in message.
If you just use pure JMS and take CXF out of the equation then camel correctly creates a new queue for the inner part of the route although I need to continue to use CXF as there are some legacy interceptors I'm bound to use.
I have tried both using the jms:// + JMSConfig style as well as the camel:// style.
I am currently using the jaxws:client approach and just referencing using bean:myBean?method=myMethod which works but doesn't allow me to propagate SOAP headers from the original inbound method hence switching to use cxf:endpoint instead.
I have tried to find an example of someone using SOAP over JMS using CXF and there seems to be no concrete examples.
So the question is.... is there any additional configuration I need to do for my producer or is there some otherway I can do SOAP over JMS using CXF and propagate/set some headers from the original message/camel exchange?

I think you may need to filter the header of replyTo from the inMessage.
If you want to use SOAP over JMS, you can specify all the JMS related setting on the address without hacking the JMSConfiguration. Here is the document that you can take as an example.

Related

Camel REST - Path based routing

I have to develop a Camel REST route with path-based routing.
The scenario is as follows: we have a business partner which provided a REST web service for displaying documents. The REST web service is deployed on 3 different servers, depending on the geographic location.
So we basically have 3 server like these:
http://north.acme.com/flowdocv2/rest/repository/attachment/{id}/findById
http://center.acme.com/flowdocv2/rest/repository/attachment/{id}/findById
http://south.acme.com/flowdocv2/rest/repository/attachment/{id}/findById
My aim is to develop a single Camel route to map these server, accepting the name of the server in the path. Something like this:
http://my.camel.com/center/repository/attachment/{id}/findById
http://my.camel.com/north/repository/attachment/{id}/findById
http://my.camel.com/south/repository/attachment/{id}/findById
My (simplified and not working) blueprint.xml:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0"
xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0
https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<cm:property-placeholder persistent-id="my.config.file"/>
<reference id="sharedNettyHttpServer" interface="org.apache.camel.component.netty4.http.NettySharedHttpServer"/>
<camelContext id="my_context" xmlns="http://camel.apache.org/schema/blueprint">
<restConfiguration component="netty4-http">
<endpointProperty key="nettySharedHttpServer" value="#sharedNettyHttpServer"/>
</restConfiguration>
<rest path="/center/repository">
<get uri="/attachment/{attachmentId}/findById">
<route streamCache="true" trace="true">
<to uri="http://center.acme.com/flowdocv2/rest?bridgeEndpoint=true"/>
</route>
</get>
</rest>
<rest path="/north/repository">
<get uri="/attachment/{attachmentId}/findById">
<route streamCache="true" trace="true">
<to uri="http://north.acme.com/flowdocv2/rest?bridgeEndpoint=true"/>
</route>
</get>
</rest>
</camelContext>
</blueprint>
The problem is that I don't know how to remove /center, /north or /south from the path, so the header is forwared to the destination service, which doesn't know how to deal with it.
Invoking:
http://my.camel.com/center/repository/attachment/{id}/findById
results in the following URL being invoked on the destination server:
http://center.acme.com/flowdocv2/rest/center/repository/attachment/{id}/findById
How to get rid of center? I don't want to deploy 3 camel routes on different ports.
Thank you
I think it is actually a bit easier. As long as you do not hang onto netty and you are using Camel 2.11+ you can use camel-urlrewrite
Basically, you define a single rewrite rule in a configuration and add this to your route bundle.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
<rule>
<name>Generic Proxy</name>
<note>
This rule completely rewrites the url to call.
Basically, in Camel's "to", you could write whatever you want
</note>
<from>^/(.*?)/(.*)</from>
<to>http://$1.acme.com/flowdocv2/rest/$2</to>
</rule>
</urlrewrite>
Now, you can utilize a rather simple route:
<?xml version="1.0" encoding="UTF-8"?>
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.0.0" xmlns:cxf="http://camel.apache.org/schema/blueprint/cxf" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0
https://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-blueprint.xsd">
<bean id="myRewrite" class="org.apache.camel.component.urlrewrite.HttpUrlRewrite">
<property name="configFile" value="class/path/to/proxyrewrite.xml" />
</bean>
<camelContext id="my_context" xmlns="http://camel.apache.org/schema/blueprint">
<route id="proxyRoute">
<from uri="jetty:http://localhost:9090/proxy" />
<to uri="jetty:http://somewhere/myapp2?bridgeEndpoint=true&throwExceptionOnFailure=false&urlRewrite=#myRewrite" />
</route>
</camelContext>
</blueprint>
However, netty is not supported, so I chose the next best thing.
When you call http://localhost:9090/proxy/north/foo, the rewrite will actually change the url to call to http://north.acme.com/flowdoc2/rest/foo.
There are a few caveats with this. First, you have to use one of the supported components for UrlRewrite. Second, it seems that you have to have the rewrite config file in you classpath - so no blueprint-only route. Third: I did not test it, but I think you get the gist. I make this a community wiki answer, so that others, more capable than me, can expand on this answer.

Expose a Pass-Through proxy with Jboss Fuse

I am an newbie with JBoss Fuse and I would like to expose a Pass-Through proxy with Jboss Fuse.
I am using JBoss EAP 6.4 in which I have installed the JBoss Fuse 6.3.
Also I have downloaded Red Hat JBoss Developer Studio 10.4.0.GA and I have started some new Fuse Integration Projects in Spring DSL.
The main idea is to create a Fuse which will work as a front layer of a SOAP Web Service in order to use the throttling and some others features of Fuse.
Could you please advise me, if this is feasible?
Thanks you in advance!
EDIT:
I was looking something like the following:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<camelContext id="_camelContext1" xmlns="http://camel.apache.org/schema/spring">
<route id="_route1">
<from id="_from1" uri="cxf:beanId:address"/>
<to id="_to1" uri="cxf:beanId:address"/>
</route>
</camelContext>
</beans>
But I need to implement the SOAP (CXF) Web Service which will be stand before the Camel route. Am I wrong?
You can try experimenting with Apache Camel.
Listen from some port and route incoming requests to the SOAP web service, here's an example:
<camelContext xmlns="http://camel.apache.org/schema/blueprint" id="PassThroughProxy" >
<route id="ProxyRoute">
<from uri="jetty:http://0.0.0.0:8080?matchOnUriPrefix=true"/>
<log message="Incoming message - headers: ${headers}" />
<log message="Incoming message - payload: ${body}" />
<to uri="bean:someProcessorHere" />
<to uri="http://soap.somewhere.net:80?bridgeEndpoint=true&throwExceptionOnFailure=false"/>
</route>
</camelContext>
Use Jetty component as input, process HTTP headers and/or body using Camel (processor, routes, ...), then use HTTP component as a client to the real web service.
You can configure SSL support, custom headers handling and so on.
If I were you, I'd use some dedicated piece of software to do this job, like Nginx.

Spring Integration - Apache ActiveMQ to Kafka

I am using the below configuration for integrating activemq with kafka. I receive message from activemq and forwards it to kafka. However, i am noticing that messages are getting dequeued from JMS Queue but messages are not going to kafka.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jms="http://www.springframework.org/schema/integration/jms"
xmlns:integration="http://www.springframework.org/schema/integration"
xmlns:int-kafka="http://www.springframework.org/schema/integration/kafka"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/kafka
http://www.springframework.org/schema/integration/kafka/spring-integration-kafka.xsd">
<jms:message-driven-channel-adapter
id="helloJMSAdapater" destination="helloJMSQueue" connection-factory="jmsConnectionfactory"
channel="helloChannel" extract-payload="true" />
<integration:channel id="helloChannel" />
<integration:service-activator id="sayHelloServiceActivator"
input-channel="helloChannel" ref="sayHelloService" method="sayHello" />
<int-kafka:outbound-channel-adapter
id="kafkaOutboundChannelAdapter" kafka-template="template"
auto-startup="false" sync="true" channel="helloChannel" topic="test1234"
>
</int-kafka:outbound-channel-adapter>
<bean id="template" class="org.springframework.kafka.core.KafkaTemplate">
<constructor-arg>
<bean class="org.springframework.kafka.core.DefaultKafkaProducerFactory">
<constructor-arg>
<map>
<entry key="bootstrap.servers" value="localhost:9092" />
<!--entry key="retries" value="5" /> <entry key="batch.size" value="16384"
/> <entry key="linger.ms" value="1" /> <entry key="buffer.memory" value="33554432"
/> < entry key="key.serializer" value="org.apache.kafka.common.serialization.StringSerializer"
/> <entry key="value.serializer" value="org.apache.kafka.common.serialization.StringSerializer"
/ -->
</map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</beans>
Also, in case there is any issue from Kafka, it is not even reporting any exception stack trace.
Did i miss anything ?
Your messages are consumed by sayHelloServiceActivator.
So change your helloChannel channel type to
<publish-subscribe-channel id="helloChannel"/>
Default is DirectChannel
The DirectChannel has point-to-point semantics but otherwise is more
similar to the PublishSubscribeChannel than any of the queue-based
channel implementations described above. It implements the
SubscribableChannel interface instead of the PollableChannel
interface, so it dispatches Messages directly to a subscriber. As a
point-to-point channel, however, it differs from the
PublishSubscribeChannel in that it will only send each Message to a
single subscribed MessageHandler.
As #Hassen Bennour says, if you want to send a message to two consumers, you need a publish/subscribe channel.
That said, you have auto-startup="false" on the kafka adapter, so it won't even be subscribed to the channel.
If it was started, with your current configuration messages would be sent round-robin alternately to the service activator and adapter.

Spring Integration: Mail error and HTTP gateway response

My use case is simple. I want to handle an exception caused by a system being unreachable, perform a retry based upon a configured retry policy, send an email when the retry threshold has been met, and return a custom response back the caller.
The challenges I am facing is that I cannot both send an email and return a response back to the caller. Since I was using a int-mail:outbound-channel-adapter initially, I would expect this behavior since this is a one-way component:
<int:chain input-channel="defaultErrorChannel">
<int:service-activator id="mailMessageActivator" expression="#mailHandler.process(payload)" />
<int-mail:outbound-channel-adapter mail-sender="mailSender" />
</int:chain>
However, if I introduce a int-amqp:outbound-gateway in front of the int-mail:outbound-channel-adapter (see the Error Handling config below), I would expect to be able to invoke a int:service-activator to construct and return a response to the caller.
Am I thinking about this the wrong way? I see that someone else had a similar question which is still unanswered. Both of the configurations I mentioned send emails, but always block from the caller without receiving a response upon timeout.
Here are the relevant parts of my configuration:
Gateway
<int:gateway id="customerGateway" service-interface="com.uscs.crm.integration.CustomerGateway"
default-request-channel="syncCustomers" default-reply-channel="replySyncCustomers" default-reply-timeout="30000">
</int:gateway>
<int:object-to-json-transformer input-channel="syncCustomers" output-channel="outboundRequestChannel" />
<int-http:outbound-gateway request-channel="outboundRequestChannel" reply-channel="replySyncCustomers"
url="http://voorhees148.uscold.com:9595/web/customerSync/createCustomer"
http-method="POST"
rest-template="restTemplate"
expected-response-type="com.uscs.crm.model.CustSyncResponseVO"
mapped-request-headers="Authorization, HTTP_REQUEST_HEADERS">
<int-http:request-handler-advice-chain>
<ref bean="retryWithBackoffAdviceSession" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
Error Handling
<int:channel id="defaultErrorChannel"/>
<int:channel id="errorResponses"/>
<!--
ExponentialBackOffPolicy.multipler is applied to wait time over each retry attempt
with a ExponentialBackOffPolicy.maximum configured.
-->
<bean id="retryWithBackoffAdviceSession" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="2000" />
<property name="multiplier" value="2" />
<property name="maxInterval" value="30000"/>
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="3"/>
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="defaultErrorChannel"/>
</bean>
</property>
</bean>
<bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler"></bean>
<int:chain input-channel="defaultErrorChannel" output-channel="replySyncCustomers">
<int:service-activator id="mailMessageActivator" expression="#mailHandler.process(payload)" />
<int:header-enricher>
<int:header name="ERROR_ID" expression="T(java.lang.System).currentTimeMillis()"/>
</int:header-enricher>
<int-amqp:outbound-gateway
exchange-name="error-responses-exchange"
routing-key-expression="'error.response.'+headers.ERROR_ID"
amqp-template="amqpTemplate" />
<!-- Will this service-activator return a response to the caller (int:gateway) using channel `replySyncCustomers`? -->
<int:service-activator id="custSyncResponseActivator" expression="#custSyncResponseHandler.process(payload)" />
</int:chain>
<int-amqp:inbound-gateway queue-names="error-responses" request-channel="errorResponses"
connection-factory="rabbitConnectionFactory" acknowledge-mode="AUTO" />
<int-mail:outbound-channel-adapter channel="errorResponses" mail-sender="mailSender" />
<!-- (Outbound Channel Adapter/Gateway) rabbit exchanges, queues, and bindings used by this app -->
<rabbit:topic-exchange name="error-responses-exchange" auto-delete="false" durable="true">
<rabbit:bindings>
<rabbit:binding queue="error-responses" pattern="error.response.*"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:queue name="error-responses" auto-delete="false" durable="true"/>
SOLUTION: I was able to get this working with help from #Artem. Below are the changes I made.
Service Activator Implementation (handling ErrorMessage)
The key is the line which returns the reconstructed Message with all of the header information from the ErrorMessage.
#Override
public Message<CustSyncResponseVO> process(Message<MessagingException> errorMessage) {
MessagingException errorException = errorMessage.getPayload();
CustSyncResponseVO custSyncResponse = new CustSyncResponseVO();
custSyncResponse.setResponseMessage(ExceptionUtils
.convertToString(errorMessage.getPayload()));
return MessageBuilder.withPayload(custSyncResponse)
.copyHeaders(errorMessage.getHeaders())
.copyHeadersIfAbsent(errorException.getFailedMessage().getHeaders()).build();
}
Service Activator Config
Used SpEL to reference the #root context to retrieve the ErrorMessage instead of the default which would be MessagingException (payload) and passed it to my process method on the POJO.
<bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler" />
<int:chain id="errorGatewayResponseChain" input-channel="defaultErrorChannel" output-channel="replySyncCustomers">
<int:service-activator id="custSyncResponseActivator" expression="#custSyncResponseHandler.process(#root)" />
</int:chain>
I don't see reason to introduce the AMQP middleware complexity there just for sending email in the end.
What only you need is <publish-subscribe-channel id="defaultErrorChannel"> with to endpoints as subscribers to it.
The first one is one-way email sending <chain> and the second one is custSyncResponseActivator to reply something to your <int-http:outbound-gateway>.
You can find more info on the matter in the Spring Integration Reference Manual.

apache restlet connector overload

I use restlet in camel route in from("restlet:http/myLink") clause. When user's requests more then ten per second, I begin recieve errors processing request like a "org.restlet.engine.connector.Controller run
INFO: Connector overload detected. Stop accepting new work"
I think, that error is caused by number of threads,request query's size or number,or something like that. I try set to maxThreads param different values in spring config
<bean id="restlet" class="org.apache.camel.component.restlet.RestletComponent">
<property name="maxThreads" value="15"/>
</bean>
but I am not succeed. In documentation http://camel.apache.org/restlet.html I ddin't find ant param for setting size\number of request queue. I need help :(
P.S. camel-restlet version is 2.12.2
Update
I try to set big numbers to maxThreads,maxConnectionsPerHost,maxTotalConnections, but it's useless. If inject org.restlet.Component to camel's config like that:
<bean id="restletComponent" class="org.restlet.Component" />
<bean id="restlet" class="org.apache.camel.component.restlet.RestletComponent">
<constructor-arg index="0">
<ref bean="restletComponent" />
</constructor-arg>
<property name="maxThreads" value="255"/>
<property name="maxConnectionsPerHost" value="1000"/>
<property name="maxTotalConnections" value="1000" />
</bean>
How I can override properties, that use BaseHelper params?
After go through the options of lowThread as well.
But I found current released camel doesn't support it.