Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache Camel JMS - Exceptions not returned to caller with request/reply

I created a simple request/reply setup with Apache Camel and JMS. Everything works fine - calls are dispatched to the server side service and results are returned to the client. Only when there is an exception on the server side this exception will not be returned to the caller. The exception appears on the server and the client receives a timeout. I would like to receive the exception on the client side.

As far as I understood the available docs that what I want should be the default behaviour. I also played around with the onException clause or setting up another route for the back transfer but all that did not help. So my question is what am I missing in my setup to get exceptions returned to the caller?

Here are the details (code simplified):

  • The JMS queue for communication is deployed in a standalone JBoss (7.1.1.FINAL)
  • JNDI is used to lookup the Factory to create connections to the queue
  • The client is currently a Spring webapplication running in a Jetty
  • The server is currently a simple standalone Java application configured with Spring
  • Spring version 3.1.2.RELEASE
  • Apache Camel 2.10.2

DTOs/Exception exchanged between client and server:

public class RequestDTO implements Serializable {
    String payload;
    ...
}

public class ResponseDTO implements Serializable {
    String payload;
    ...
}

public class RmtServiceException extends Exception implements Serializable {
    public RmtServiceException() {
        super("Exception in service.");
    }
}

Interface for the service called via JMS:

public interface RmtService {
    ResponseDTO doSomething(RequestDTO request) throws RmtServiceException;
}

Implementation for the Service:

@Component("rmtService")
public class RmtServiceImpl implements RmtService {
    public ResponseDTO doSomething(RequestDTO request) throws RmtServiceException {
        // Return a ResponseDTO if processing is successful,
        // otherwise throw an RmtServiceException
    }
}

Client configuration:

<bean id="remoteJndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
            <prop key="java.naming.provider.url">remote://localhost:4447</prop>
            <prop key="java.naming.security.principal">JNDI_USER</prop>
            <prop key="java.naming.security.credentials">JNDI_PASSWORD</prop>
        </props>
    </property>
</bean>

<bean id="remoteJmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="remoteJndiTemplate"/>
    <property name="jndiName" value="jms/RemoteConnectionFactory"/>
</bean>

<bean id="authenticatedJmsConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="remoteJmsConnectionFactory"/>
    <property name="username" value="JMS_USER"/>
    <property name="password" value="JMS_PASSWORD"/>
</bean>

<bean name="hq" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory" ref="authenticatedJmsConnectionFactory"/>
</bean>

<camel:camelContext id="APIContext" autoStartup="true">
    <camel:endpoint id="queue" uri="hq:queue:test.queue"/>
</camel:camelContext>

<camel:proxy
        id="rmtServiceProxy"
        serviceInterface="RmtService"
        serviceUrl="hq:queue:test.queue"/>

Server configuration:

<bean id="remoteJndiTemplate" class="org.springframework.jndi.JndiTemplate">
    <property name="environment">
        <props>
            <prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
            <prop key="java.naming.provider.url">remote://localhost:4447</prop>
            <prop key="java.naming.security.principal">JNDI_USER</prop>
            <prop key="java.naming.security.credentials">JNDI_PASSWORD</prop>
        </props>
    </property>
</bean>

<bean id="remoteJmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiTemplate" ref="remoteJndiTemplate"/>
    <property name="jndiName" value="jms/RemoteConnectionFactory"/>
</bean>

<bean id="authenticatedJmsConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
    <property name="targetConnectionFactory" ref="remoteJmsConnectionFactory"/>
    <property name="username" value="JMS_USER"/>
    <property name="password" value="JMS_PASSWORD"/>
</bean>

<bean name="hq" class="org.apache.camel.component.jms.JmsComponent">
    <property name="connectionFactory" ref="authenticatedJmsConnectionFactory"/>
</bean>

<camel:camelContext id="APIContext" autoStartup="true">
    <camel:endpoint id="queue" uri="hq:queue:test.queue"/>
    <camel:route>
        <camel:from ref="queue"/>
        <camel:to uri="bean:rmtService"/>
    </camel:route>
</camel:camelContext>

Observed behaviour when there's an exception on the server side:

In the server logs the following Output appears:

ERROR: org.apache.camel.processor.DefaultErrorHandler - Failed delivery for (MessageId: ID-XXX-49296-1352104153517-0-8 on ExchangeId: ID-XXX-49296-1352104153517-0-7). Exhausted after delivery attempt: 1 caught: org.apache.camel.RuntimeCamelException: RmtServiceException: Exception in service.
org.apache.camel.RuntimeCamelException: RmtServiceException: Exception in service.
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1270)
at org.apache.camel.component.bean.BeanInvocation.invoke(BeanInvocation.java:87)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:130)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:99)
at org.apache.camel.component.bean.BeanProcessor.process(BeanProcessor.java:73)
at org.apache.camel.impl.ProcessorEndpoint.onExchange(ProcessorEndpoint.java:101)
at org.apache.camel.impl.ProcessorEndpoint$1.process(ProcessorEndpoint.java:71)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
at org.apache.camel.processor.SendProcessor$2.doInAsyncProducer(SendProcessor.java:122)
at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:298)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:117)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:73)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:91)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
at org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:334)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:220)
at org.apache.camel.processor.RouteContextProcessor.processNext(RouteContextProcessor.java:45)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.processor.interceptor.DefaultChannel.process(DefaultChannel.java:303)
at org.apache.camel.processor.RouteContextProcessor.processNext(RouteContextProcessor.java:45)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.processor.UnitOfWorkProcessor.processAsync(UnitOfWorkProcessor.java:150)
at org.apache.camel.processor.UnitOfWorkProcessor.process(UnitOfWorkProcessor.java:117)
at org.apache.camel.processor.RouteInflightRepositoryProcessor.processNext(RouteInflightRepositoryProcessor.java:48)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:73)
at org.apache.camel.processor.DelegateAsyncProcessor.processNext(DelegateAsyncProcessor.java:99)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:90)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:73)
at org.apache.camel.util.AsyncProcessorHelper.process(AsyncProcessorHelper.java:99)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:86)
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:104)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:562)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:500)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:468)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:326)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:264)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1071)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1063)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:960)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)
Caused by: RmtServiceException: Exception in service.
at RmtServiceImpl.doSomething(...)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.camel.component.bean.BeanInvocation.invoke(BeanInvocation.java:83)
... 48 more
WARN : org.apache.camel.component.jms.EndpointMessageListener - Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - RmtServiceException: Exception in service.]
... (Same stacktrace again)

And the client receives a timeout:

WARN : org.apache.camel.component.jms.reply.TemporaryQueueReplyManager - Timeout occurred after 20000 millis waiting for reply message with correlationID [ID-XXX-49307-1352104250851-0-13]. Setting ExchangeTimedOutException on (MessageId: ID-XXX-49307-1352104250851-0-15 on ExchangeId: ID-XXX-49307-1352104250851-0-14) and continue routing.
2012-11-05 10:03:11.964:WARN:oejs.ServletHandler:/app/some/action
java.lang.reflect.UndeclaredThrowableException
at $Proxy45.doSomething(Unknown Source)
at ...
Caused by: 
org.apache.camel.ExchangeTimedOutException: The OUT message was not received within: 20000 millis due reply message with correlationID: ID-XXX-49307-1352104250851-0-13 not received. Exchange[Message: BeanInvocation public abstract ResponseDTO RmtService.doSomething(RequestDTO) throws RmtServiceException with [RequestDTO@...]]]
at org.apache.camel.component.jms.reply.ReplyManagerSupport.processReply(ReplyManagerSupport.java:133)
at org.apache.camel.component.jms.reply.TemporaryQueueReplyHandler.onTimeout(TemporaryQueueReplyHandler.java:61)
at org.apache.camel.component.jms.reply.CorrelationTimeoutMap.onEviction(CorrelationTimeoutMap.java:53)
at org.apache.camel.component.jms.reply.CorrelationTimeoutMap.onEviction(CorrelationTimeoutMap.java:30)
at org.apache.camel.support.DefaultTimeoutMap.purge(DefaultTimeoutMap.java:203)
at org.apache.camel.support.DefaultTimeoutMap.run(DefaultTimeoutMap.java:159)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:204)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:680)

So once again: Everything else works as expected, only the exceptions are not returned to the caller. Any help on this is greatly appreciated! Thanks in advance.

like image 613
lost Avatar asked Nov 05 '12 09:11

lost


1 Answers

See the option transferException which you would need to enable to serialize the exception and return as response. The option is documented on the JMS doc page at: http://camel.apache.org/jms

like image 89
Claus Ibsen Avatar answered Sep 22 '22 16:09

Claus Ibsen