How to detect loss of JMS Topic connection - jms

We have swing GUI clients that are connecting to a server process.
The clients 'call' services on the server using jms:queue 'from' endpoints defined in Camel routes, and using ActiveMQ as the underlying JMS broker.
However, the client also offers a Camel jms:topic endpoint for the server to broadcast messages back to the client.
Unfortunately, it looks like the topic connection is getting lost somehow, and although the client can still 'call' the services on the server, the server cannot send any messages to the client's topic endpoint.
The client-side spring definition of the Camel endpoint is as follows:
<camel:route>
<camel:from uri="jms:topic:inUseQueue"/>
<camel:to uri="bean:inUseInterfaceImpl"/>
</camel:route>
And the server-side producer is defined as follows:
<bean id="inUseManagerImpl" class="org.apache.camel.spring.remoting.CamelProxyFactoryBean">
<property name="serviceUrl" value="jms:topic:inUseQueue"/>
<property name="serviceInterface" value="uniworks.core.inuse.InUseInterface"/>
</bean>
Does anyone know of a way that we can somehow detect the loss of this topic connection on the client side?

An easy workaround shall be to override isSingleton() method of CamelProxyFactoryBean. Return false and let spring create the producer bean on every invocation instead of caching it. Or you can also define the scope of CamelProxyFactoryBean to be prototype.
Also you can try with the ActiveMQ camel component that supports connection pooling.

I realize this is a 8 month old question, but hey what the hell.
would it make sense to make the server broadcast "isalive" message once a minute, this way if the client doesn't get any of the "isalive" messages it can presume it has been disconnected.

Related

Spring integration service-interface gateway reply channel as shared Pub/Sub

This is similar to Intermittent BridgeHandler & PublishSubscribeChannel call when gateways' reply channel is pub/sub but the scenario is different in that the reply-channel is not getting "lost". The question is what is the best resolution for my scenario.
I am using Spring integration to launch Spring batch jobs. I have a number of input routes e.g. file polling and http requests. These all route to a batch-int Job Launching Gateway. The referenced Job Launcher has a task executor so job launches are asynchronous. This gateway replies on a specified channel.
<int:gateway service-interface="c.c.c.etl.gateway.JobSubmissionService" id="jobSubmissionService" default-request-channel="jobLauchInputChannel" default-reply-channel="jobLaunchReplyChannel">
</int:gateway>
<int:bridge id="filePollerBridge" input-channel="filePollerOutputChannel" output-channel="jobLauchInputChannel" />
<batch-int:job-launching-gateway request-channel="jobLauchInputChannel" reply-channel="jobLaunchReplyChannel" job-launcher="jobLauncher">
</batch-int:job-launching-gateway>
<int:publish-subscribe-channel id="jobLaunchReplyChannel" />
<int:bridge id="jobLaunchReplyChannelBridge" input-channel="jobLaunchReplyChannel" output-channel="loggingChannel">
</int:bridge>
This specified channel 'jobLaunchReplyChannel' is pub/sub and has a logger listening to it. This channel is also used as the reply channel for a service-interface gateway.
The issue I am having is that when jobs are requested via sources that are not the gateway (e.g. the poller) the Bridge that is added by gateway throws an exception because no reply channel is set on replies.
I have resolved this by adding a header to messages sent via the gateway and filtering out messages only with this header to a new 'gatewayReplyChannel'.
<int:gateway service-interface="c.c.c.etl.gateway.JobSubmissionService" id="jobSubmissionService" default-request-channel="httpJobRequestInputChannel" default-reply-channel="jobSubmissionServiceReplyChannel">
<int:default-header name="isJobSubmissionServiceMessage" value="true" />
</int:gateway>
<int:channel id="jobSubmissionServiceReplyChannel"></int:channel>
<int:filter id="jobSubmissionServiceReplyChannelFilter" input-channel="jobLaunchReplyChannel" expression="headers.get('isJobSubmissionServiceMessage') == null ? false : headers.get('isJobSubmissionServiceMessage')" output-channel="jobSubmissionServiceReplyChannel"
throw-exception-on-rejection="false" />
Is there a better way to do this?
Eh.. That's an interesting issue. The main cause is because MessagingGatewaySupport creates replyMessageCorrelator endpoint for an internal BridgeHandler.
And we really have that strange behaviour when we send message to the reply-channel directly. That BridgeHandler tries to send message to the replyChannel from headers.
And we really can't do anything to prevent that logic. And can't protect that explicit reply-channel from direct messages.
I think your solution is correct. Another way to overcome that: add replyChannel header from the start of another flow (file polling in your case) just using something like this:
<header-enricher>
<reply-channel ref="nullChannel"/>
</header-enricher>
Feel free to raise a JIRA issue on the matter and we'll take a look what we can do. At least we can document these specifics.

Why does my camel route try to reply to the JMS consumer?

I have an Apache Camel route configured in Spring which takes a message from a JMS (ActiveMQ) queue, transforms the message and uses the CXF component to send the results to a web service. This all works fine but I always get an exception thrown at the end of the route that the CXF response object isn't synchronizable, referring to the fact that it's trying to convert the exchange/message body back into a JMS message. But why?
Here's my camel context extract:-
<route>
<from uri="jms:queue:transactions" />
<process ref="convertToFormatForCXF" />
<to uri="cxf:bean:myService?defaultOperationName=process" />
<stop />
</route>
and here's a snippet from the logs:-
EndpointMessageListener WARN Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse]
org.apache.camel.RuntimeCamelException: java.lang.RuntimeException: net.sophis.soa.dataexchange.LogoutResponse
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1363)
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:124)
Even the doesn't prevent the stack trace. Now I've found out that if I add the disableReplyTo=true to the JMS consumer then the stacktrace doesn't show which is excellent.
I suppose I'm just trying to work out what was happening? Was the CXF response object going to be added to the 'transactions' JMS queue? My intention was for the flow to stop once the CXF producer had completed.
Can anyone help my understanding please? The Camel documentation wasn't much help on this.
Was the CXF response object going to be added to the 'transactions' JMS queue?
No. It would have been added to a temporary queue.
From http://camel.apache.org/jms.html#JMS-Request-replyoverJMS
The JmsProducer detects the InOut and provides a JMSReplyTo header with the reply destination to be used. By default Camel uses a temporary queue, but you can use the replyTo option on the endpoint to specify a fixed reply queue (see more below about fixed reply queue).
Camel will automatic setup a consumer which listen on the reply queue, so you should not do anything.

Spring Integration/RabbitMQ/AMQP: How do I create outbound-channel-adapters for dynamic input channels?

I'm working on abstracting out any sort of messaging framework for some code I'm working on. Basically, I'm using a combination of Spring AOP and Spring Integration to generate messages without the Java code knowing anything about RabbitMQ, JMS, or even Spring Integration. That said, what I'm using to generate the messages is contained in its own .jar, and it re-used by several other areas of the application. I currently have the messaging system set up such that the channels on which messages are sent are specified by the code that calls the system (i.e., channels are generated automatically based on the external method invocation) by specifying the channel name in the message header and using a header-value router to create the channels if they don't exist. My issue comes in on the endpoint of these channels - the intention of the current structure is to allow Spring to change to any messaging structure as requirements specify or change. I know how to take a static channel and use outbound channel converters/gateways to send it to a pre-specified RabbitMQ/JMS queue and process from there; what I'm struggling with is how to tell Spring that I need every channel created by the router to have a RabbitMQ (or whatever other messaging system gets implemented) outbound channel adapter that's dynamically generated based on the channel name since we don't know channel names beforehand.
Is this possible? And if not, would you mind providing input as to what could perhaps be a better way?
Thanks ahead of time!
Here's a basic template of what my config file looks like - I have an initial channel ("messageChannel") which gets sent to a publish-subscribe-channel and queuing channel depending on one of the message headers and is routed from there.
<!--Header value based channel configurations-->
<int:channel id="messageChannel" />
<int:channel id="queue" />
<int:publish-subscribe-channel id="topic" />
<!--Header-based router to route to queue or topic channels-->
<int:header-value-router input-channel="messageChannel"
header-name="#{ T(some.class.with.StringConstants).CHANNEL_TYPE}" />
<!--Re-routes messages according to their destination and messaging type-->
<int:header-value-router input-channel="queue"
header-name="#{ T(some.class.with.StringConstants).MESSAGE_DESTINATION}" />
<int:header-value-router input-channel="topic"
header-name="#{ T(some.class.with.StringConstants).MESSAGE_DESTINATION}" />
<!--AOP configuration - picks up on any invocation of some.class.which.generates.Messages.generateMessage()
from a Spring-managed context.-->
<aop:config>
<aop:pointcut id="eventPointcut"
expression="execution(* some.class.which.generates.Messages.generateMessage(..))" />
<aop:advisor advice-ref="interceptor" pointcut-ref="eventPointcut"/>
</aop:config>
<int:publishing-interceptor id="interceptor" default-channel="messageChannel">
<int:method pattern="generateMessage" payload="#return" channel="messageChannel" />
</int:publishing-interceptor>
See the dynamic-ftp sample; it uses a dynamic router that creates new outbound endpoints/channels on demand.

How to restart the message consumer in Spring Integration?

My consumer, e.g. service activator that is consuming messages coming from ActiveMQ fromChannel should be restarted when exception occurs or ActiveMQ fails. How to do it for the following spring integration context ?
<!-- RECEIVER. message driven adapter -> jmsInChannel -> activator. -->
<si:channel id="fromChannel"/>
<int-jms:message-driven-channel-adapter id="messageDrivenAdapter"
channel="fromChannel" destination="forward" connection-factory="connectionFactory"
max-concurrent-consumers="2" auto-startup="true" acknowledge="auto" extract-payload="false" />
<si:service-activator id ="activator"
input-channel="fromChannel"
ref="messageService"
method="process"/>
<bean id="messageService" class="com.ucware.ucpo.forward.jms.MessageService"/>
My first idea was to use Retry Advice and add to a service but am not sure if this a right solution for unhandled exceptions. I also would like the receiver to restart if the ActiveMQ server is down.
The listener container within the message-driven-channel-adapter will automatically keep trying to reconnect when it loses connectivity to the broker.
If you set `acknowledge="transacted"' the message will be rolled back on an exception and the broker will resubmit it.
A stateful retry advice would allow you to give up and take some other action after some number of retries (but you can also configure that into ActiveMQ itself where it will send the message to a DLQ after some number of delivery attempts).
Reading your post I instantly thought of this video. Which gives a good insight on how to monitor and control SI application through itself.
Additionally you should have a look at ApplicationEvent documentation of SI.
Glueing that all together you could monitor the JMS message adapter with JMX and stop and restart it through sending an ApplicationEvent on issues. Regarding catching exceptions it depends on what Exceptions you actually want to handle. I'd create an errorChannel that receives exceptions being thrown by components and create a new service that restarts these components after receiving errors.
Following your idea leveraging Spring Retry's capabilites in SI.

How to stop exception propagation if jms broker is down when sending a message with spring integration?

I configured spring xml based interceptor, which sends a jms message to activemq queue on each invokation of some transactional method after it is commited. It's happening with the following xml code.
<jms:outbound-channel-adapter channel="filteredStakesChannel" destination="stakesQueue" delivery-persistent="true" explicit-qos-enabled="true" />
But if the activemq server is down i get connection refused exception, which is propagated and i don't want this to happen even if the jms delivery fails. Is this possible?
Should i use some error-channel?
The simplest solution is to make fileredStakesChannel an Executor channel and the send will run on a different thread.
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#executor-channel
http://static.springsource.org/spring-integration/reference/html/messaging-channels-section.html#channel-configuration-executorchannel
Use the <task/> namespace to define an executor to use.

Resources