2012-11-05 6 views
6

Ich habe eine einfache Anfrage/Antwort-Setup mit Apache Camel und JMS erstellt. Alles funktioniert gut - Anrufe werden an den serverseitigen Dienst gesendet und die Ergebnisse werden an den Client zurückgegeben. Nur wenn auf der Serverseite eine Ausnahme vorliegt, wird diese Ausnahme nicht an den Aufrufer zurückgegeben. Die Ausnahme erscheint auf dem Server und der Client erhält eine Zeitüberschreitung. Ich möchte die Ausnahme auf der Client-Seite erhalten.Apache Camel JMS - Ausnahmen werden nicht an Anrufer mit Anfrage/Antwort zurückgegeben

Soweit ich die verfügbaren Dokumente verstanden, sollte das, was ich will, das Standardverhalten sein. Ich habe auch mit der onException-Klausel gespielt oder eine andere Route für die Rückübertragung eingerichtet, aber das alles hat nicht geholfen. Also meine Frage ist, was fehlt mir in meinem Setup, um Ausnahmen an den Anrufer zurückgegeben werden?

Hier sind die Details (Code vereinfacht):

  • Die JMS-Warteschlange für die Kommunikation in einem eigenständigen JBoss (7.1.1.FINAL)
  • JNDI wird, um die Fabrik Nachschlag zu schaffen Verbindungen eingesetzt verwendet in die Warteschlange ist
  • der Client derzeit ein Frühling Webapplikation in einer Anlegestelle läuft
  • der Server derzeit eine einfache mit Feder
  • Frühlings-Version konfigurierte eigenständige Java-Anwendung ist 3.1.2.RELEASE
  • Apache Camel 2.10.2

DTOs/Exception Austausch zwischen Client und 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."); 
    } 
} 

Schnittstelle für den Dienst über JMS genannt:

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

Implementierung für den Dienst:

@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-Konfiguration:

<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-Konfiguration:

<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> 

Beobachtet Verhalten, wenn eine Ausnahme auf der Serverseite gibt es:

Im Server protokolliert die folgende Ausgabe angezeigt:

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) 

und der Kunde erhält einen 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 [[email protected]]]] 
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) 

Also noch einmal: Alles andere funktioniert wie erwartet, nur die Ausnahmen nicht an den Aufrufer zurückgegeben. Jede Hilfe wird sehr geschätzt! Danke im Voraus.

Antwort

7

Siehe die Option transferException, die aktiviert werden muss, um die Ausnahme zu serialisieren und als Antwort zurückzugeben. Die Option ist auf der JMS-Dokumentseite dokumentiert unter: http://camel.apache.org/jms

+1

Großartig, diese Option übersehen. Vielen Dank! – lost