I have the following convertor:
#Component
public class EventConverter implements MessageConverter {
#Override
public Object fromMessage(Message message) throws JMSException, MessageConversionException {
// ...DO SOMETHING HERE
}
#Override
public Message toMessage(Object eventObject, Session session) throws JMSException, MessageConversionException {
// ... DO ANOTHER THING HERE
}
My beans definition looks like this:
<!-- Message converter - to convert between out Event class and JMS message -->
<bean id="eventConverter"
class="com.shared.events.common.handlers.EventConverter" />
<bean id="redeliveryConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq_url}" />
<property name="redeliveryPolicy" ref="redeliveryPolicy" />
<property name="nonBlockingRedelivery" value="true" />
</bean>
<bean id="redeliveryCachingConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="redeliveryConnectionFactory"
p:sessionCacheSize="10" />
<!-- Redelivery: retry after 3sec, 6sec,9sec,12sec,15sec finally put in
DLQ -->
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="queue" value="*" />
<property name="initialRedeliveryDelay" value="0" />
<property name="redeliveryDelay" value="3000" />
<property name="maximumRedeliveryDelay" value="3600000" />
<property name="maximumRedeliveries" value="5" />
<property name="useExponentialBackOff" value="true" />
<property name="backOffMultiplier" value="1" />
</bean>
<!-- A JmsTemplate instance that uses the cached connection and destination -->
<bean id="redeliveryJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="redeliveryCachingConnectionFactory" />
<property name="messageConverter" ref="eventConverter" />
<property name="sessionTransacted" value="true" />
</bean>
<!-- EDIT EDIT EDIT -->
<!-- The Spring message listener container configuration -->
<jms:listener-container container-type="default"
destination-type="queue" connection-factory="redeliveryConnectionFactory"
acknowledge="transacted" concurrency="5" cache="consumer"> <!-- remove prefetch on production -->
<jms:listener destination="accountStatsQueue" ref="accountStatsService"
method="onMessage" />
<!-- Listeners -->
<bean id="accountStatsService" class="com.service.AccountStatsService" />
<!-- Destinations -->
<bean id="accountStatsQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="AccountStatsQueue" />
the toMessage() function is being called straight from my EventConverter which is great.
The problem is that the fromMessage() is not being called from my EventConvertor.
(btw: org.springframework.jms.support.converter.SimpleMessageConverter does get called on fromMessage() , Its like my EventConverter is not overriding it in the specific function - fromMessage().)
Any ideas?
Related
I have defined a queue - blah.queue and have defined the dead-letter-routing-key for it. However, when I have a poison message which fails with a Exception, the same message is requeued and reattempted (in an infinite loop).
I would expect that after 3 retries, the message should be put on the exchange with the dead-letter-routing-key. But that doesn't seem to be happening.
I have the following settings:
<rabbit:queue name="blah.queue" auto-delete="false" durable="true">
<rabbit:queue-arguments>
<entry key="x-dead-letter-exchange" value="" />
<entry key="x-dead-letter-routing-key" value="blah.queue.dlq.route" />
<entry key="x-ha-policy" value="all" />
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:direct-exchange name="${rabbit.idesk.exchange}">
<rabbit:bindings>
<rabbit:binding queue="blah.queue" key="blah.route" />
</rabbit:bindings>
</rabbit:direct-exchange>
<bean id="myConsumer" class="com.ankit.CustomConsumer" />
<bean id="myConsumerMessageListenerAdapter" class="org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter">
<constructor-arg ref="myConsumer" />
<constructor-arg ref="myMessageConverter" />
</bean>
<bean id="myConsumerMessageListenerContainer" class="org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer">
<property name="queueNames" value="blah.queue" />
<property name="connectionFactory" ref="queueConnectionFactory" />
<property name="messageListener" ref="myConsumerMessageListenerAdapter" />
<property name="errorHandler" ref="loggingErrorHandler" />
<property name="adviceChain">
<list>
<ref bean="retryAdvice" />
</list>
</property>
</bean>
<bean id="loggingErrorHandler" class="org.springframework.scheduling.support.TaskUtils.LoggingErrorHandler" />
<bean id="myMessageConverter"
class="org.springframework.amqp.support.converter.JsonMessageConverter">
<property name="classMapper">
<bean class="com.ankit.queue.mapper.NamedClassMapper">
<constructor-arg
value="com.ankit.dto.EventDTO" />
</bean>
</property>
<property name="createMessageIds" value="true" />
</bean>
<bean id="retryAdvice" class="org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptorFactoryBean">
<property name="messageRecoverer" ref="rejectAndDontRequeueRecoverer" />
<property name="retryOperations" ref="retryTemplate" />
</bean>
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy" ref="simpleRetryPolicy" />
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.FixedBackOffPolicy">
<property name="backOffPeriod" value="5000" />
</bean>
</property>
</bean>
<bean id="simpleRetryPolicy" class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="3" />
</bean>
Do you not see the WARN message from the recoverer?
#Override
public void recover(Message message, Throwable cause) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Retries exhausted for message " + message, cause);
}
throw new ListenerExecutionFailedException("Retry Policy Exhausted",
new AmqpRejectAndDontRequeueException(cause), message);
}
Turn on DEBUG logging to watch the retry behavior.
I have a Websphere MQ and a java app receiveng messages from it. I want to make redelivering system if any exceptions is thrown .
Is there a way to add redeliveryDelay in my configuration spring xml?
here's my spring configuration:
<!-- JMS CONNECTION FACTORY -->
<bean id="MQFactory" class="com.ibm.mq.jms.MQConnectionFactory">
<property name="transportType">
<util:constant static-field="com.ibm.msg.client.wmq.WMQConstants.WMQ_CM_CLIENT" />
</property>
<property name="queueManager" value="${queueManager}" />
<property name="hostName" value="${hostName}" />
<property name="port" value="${port}" />
<property name="channel" value="${channel}" />
</bean>
<bean id="JmsConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="MQFactory" />
<property name="username" value="${username}" />
<property name="password" value="${username}" />
</bean>
<!-- JMS LISTENER -->
<bean id="Listener" class="jms.impl.Listener"></bean>
<!-- JMS CONTAINER -->
<bean id="JmsContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="JmsConnectionFactory" />
<property name="destinationName" value="${destination}" />
<property name="messageListener" ref="Listener" />
<property name="autoStartup" value="false" />
<property name="concurrentConsumers" value="${jms.consumers}" />
<property name="sessionTransacted" value="true" />
</bean>
I'm trying to integrate Atomikos transaction manager into a Spring Integration program that forwards JMS from ActiveMQ to a WebMethods ESB.
The spring integration part only retrieves JMs from local ActiveMQ broker and sends them to a distant ESB broker.
When I test the nominal case, JMS is sent well and passes through the ESB and is dispatched to the subscribers then.
When I test the case where ESB sending fails, I have an issue : the JMS is never published back. I suppose it's a transaction issue because the transaction should have been rolled back when program tried to publish on ESB broker but it seems not.
Here's my spring config :
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<!-- Atomikos Transaction Manager Defintion (JTA) -->
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close" depends-on="atomikosConnectionFactorySource,connectionFactoryDestination">
<property name="transactionTimeout" value="300" />
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<bean id="jmsXaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL" value="${source.java.naming.provider.url}" />
<property name="userName" value="${source.username}" />
<property name="password" value="${source.passwd}" />
</bean>
<bean id="atomikosConnectionFactorySource" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
init-method="init" destroy-method="close">
<property name="poolSize" value="1" />
<property name="uniqueResourceName" value="activemq" />
<property name="xaConnectionFactory" ref="jmsXaConnectionFactory" />
</bean>
<bean id="connectionFactorySource"
class="org.springframework.jms.connection.SingleConnectionFactory">
<property name="targetConnectionFactory" ref="jmsXaConnectionFactory" />
<property name="clientId" value="CustomerOrderForwarderID" />
<property name="reconnectOnException" value="true" />
</bean>
<!-- Destination JNDI Context -->
<bean id="jndiTemplateDestination" class="org.springframework.jndi.JndiTemplate"
lazy-init="true">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${destination.java.naming.factory.initial}</prop>
<prop key="java.naming.provider.url">${destination.java.naming.provider.url}</prop>
<prop key="java.naming.factory.url.pkgs">${destination.java.naming.factory.url.pkgs}</prop>
</props>
</property>
</bean>
<!-- Destination Connection factory -->
<bean id="customerOrderXAConnectionFactoryDestination" class="org.springframework.jndi.JndiObjectFactoryBean"
lazy-init="true">
<property name="jndiTemplate" ref="jndiTemplateDestination" />
<property name="jndiName"
value="${destination.java.naming.factory.connection}" />
<property name="lookupOnStartup" value="false" />
<property name="proxyInterface" value="javax.jms.XAConnectionFactory" />
</bean>
<bean id="connectionFactoryDestination" class="com.atomikos.jms.AtomikosConnectionFactoryBean"
init-method="init" destroy-method="close">
<property name="poolSize" value="100" />
<property name="uniqueResourceName" value="esb" />
<property name="xaConnectionFactory" ref="customerOrderXAConnectionFactoryDestination" />
<property name="localTransactionMode" value="true" />
</bean>
<bean id="ddr" class="com.adeo.transverse.jms.forwarder.customerorder.DynamicDestinationResolver" />
<bean id="userCredentialsConnectionFactoryDestination"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter" lazy-init="true">
<property name="targetConnectionFactory">
<ref bean="connectionFactoryDestination" />
</property>
<property name="username" value="${destination.username}" />
<property name="password" value="${destination.passwd}" />
</bean>
Here's the integration part :
<!-- In bridge -->
<jms:message-driven-channel-adapter
id="StoreStockMotionSourceJmsAdapter" channel="bridgeChannelStoreStockMotionEnricher"
container="jmsContainerSourceStoreStockMotion" />
<!-- Channel -->
<si:channel id="bridgeChannelStoreStockMotionEnricher" />
<jms:outbound-channel-adapter id="StoreStockMotionDestinationJmsAdapter"
channel="bridgeChannelStoreStockMotionEnricher" jms-template="jmsTemplateStoreStockMotionDestination" />
<bean id="jmsTemplateStoreStockMotionDestination" class="org.springframework.jms.core.JmsTemplate">
<property name="transactionManager" ref ="transactionManager"/>
<property name="connectionFactory" ref="userCredentialsConnectionFactoryDestination" />
<property name="defaultDestinationName" value="${StoreStockMotion.destination.topic}" />
<property name="defaultDestination" ref="StoreStockMotionDestinationTopic" />
<property name="pubSubDomain" value="true"/>
</bean>
<!-- Topic JMS for published message -->
<bean id="StoreStockMotionDestinationTopic" class="org.springframework.jndi.JndiObjectFactoryBean" lazy-init="true">
<property name="jndiTemplate">
<ref bean="jndiTemplateDestination" />
</property>
<property name="jndiName">
<value>${StoreStockMotion.destination.topic}</value>
</property>
</bean>
<!-- Topic JMS for Subscribing Message -->
<bean id="jmsContainerSourceStoreStockMotion"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
lazy-init="true">
<property name="connectionFactory" ref="connectionFactorySource" />
<property name="destinationName" value="${StoreStockMotion.source.topic}" />
<property name="subscriptionDurable" value="true" />
<!-- 2 is client acknowledge -->
<property name="sessionAcknowledgeMode" value="2" />
<property name="durableSubscriptionName" value="${StoreStockMotion.source.subname}" />
<property name="sessionTransacted" value="false" />
<property name="pubSubDomain" value="true"/>
</bean>
Source and Destination are both encapsulated in XA connection factories and transactionManager handles the two transactions. Any idea what's missing ?
Below is spring's application file & i have defined inbound channel in that.
Accessing that channel by initializing the object of SourcePollingChannelAdapter.
But i want to access that object using the reference from another bean.
How can i do that. Can someone please guide me.
Something like this:
<bean id="DataAccessController"
class="com.canaldigital.tsi.dao.controller.DataAccessControllerImpl">
<property name="sftpAdapterAutoCreate" ref="sftpAdapterAutoCreate" />
</bean>
ApplicationContext.xml
<bean id="defaultSftpSessionFactory"
class="org.springframework.integration.sftp.session.DefaultSftpSessionFactory">
<property name="host" value="${sftp.host}"/>
<property name="user" value="${sftp.username}"/>
<!-- <property name="password" value="${sftp.password}"/> -->
<property name="port" value="${sftp.serverPort}"/>
<!-- <property name="privateKey" value="${sftp.private.keyfile}"/> -->
<property name="privateKey" value="classpath:IBS_KEYS/id_rsa.txt"/>
<property name="privateKeyPassphrase" value="${sftp.passphrase}"/>
</bean>
<bean id="sftpSessionFactory" class="org.springframework.integration.file.remote.session.CachingSessionFactory">
<constructor-arg ref="defaultSftpSessionFactory" />
<!-- <property name="sessionCacheSize" value="10"/>
<property name="sessionWaitTimeout" value="1000"/> -->
</bean>
<int-sftp:inbound-channel-adapter id="sftpAdapterAutoCreate"
session-factory="sftpSessionFactory"
channel="requestSFTPDKDEVChannel"
filename-pattern="*.*"
remote-directory="/home/oracle/"
preserve-timestamp="true"
local-directory="C:/temp/"
auto-create-local-directory="true"
temporary-file-suffix=".writing"
delete-remote-files="true">
<int:poller fixed-rate="1000" time-unit="SECONDS" />
</int-sftp:inbound-channel-adapter>
<int:channel id="requestSFTPDKDEVChannel">
<int:queue/>
</int:channel>
Test.java
SourcePollingChannelAdapter adapter = context1
.getBean("sftpAdapterAutoCreate",SourcePollingChannelAdapter.class);
adapter.start();
I'm building a web application, which uses the Spring Framework 4.1.3 and using Jersey for the RESTful web service.
I want to connect to a Redis server and I'm using Spring Data Redis with the Jedis driver.
This is how my Beans.xml file looks like:
<!-- Jedis ConnectionFactory -->
<bean id="jedisConnFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="server" p:port="6379" p:use-pool="true"
/>
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory"
/>
This is the Servlet with the access to the Redis server:
import javax.annotation.Resource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
#Path("/")
public class RoutesServlet {
#Autowired
private RedisTemplate<String, String> template;
// inject the template as ListOperations
#Resource(name="redisTemplate")
private ListOperations<String, String> listOps;
#GET
#Produces("text/plain")
public String index() {
listOps.leftPush("user", "name");
...
At this point I'm getting a NullPointerException. I'm guessing the #Resource annotation is not working properly for some reason. Any ideas?
UPDATE:
This is my full Beans.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<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
xmlns:p="http://www.springframework.org/schema/p"
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">
<!-- Initialization for data source -->
<!--bean id="dataSource" class="db.mysql.DBConn"> </bean -->
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/insider" />
<property name="username" value="root" />
<property name="password" value="" />
<property name="jmxEnabled" value="true" />
<property name="testWhileIdle" value="false" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="SELECT 1" />
<property name="testOnReturn" value="false" />
<property name="validationInterval" value="30000" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="maxActive" value="100" />
<property name="initialSize" value="10" />
<property name="maxWait" value="10000" />
<property name="removeAbandonedTimeout" value="60" />
<property name="minEvictableIdleTimeMillis" value="30000" />
<property name="minIdle" value="10" />
<property name="logAbandoned" value="true" />
<property name="removeAbandoned" value="true" />
<property name="jdbcInterceptors"
value="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer" />
</bean>
<!-- Definition for categoryJDBCTemplate bean -->
<bean id="categoryJDBCTemplate" class="db.mysql.CategoryJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for itemJDBCTemplate bean -->
<bean id="itemJDBCTemplate" class="db.mysql.ItemJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for userJDBCTemplate bean -->
<bean id="userJDBCTemplate" class="db.mysql.UserJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for reviewJDBCTemplate bean -->
<bean id="reviewJDBCTemplate" class="db.mysql.ReviewJDBCTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Jedis ConnectionFactory -->
<bean id="jedisConnFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="server" p:port="6379" p:use-pool="true"
/>
<!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory"
/>
</beans>
I believe it is simply so that the bean with the name redisTemplate is of type RedisTemplate. One way to retrieve the ListOperations is to do the following:
public class RedisExample {
// Just use the RedisTemplate - don't inject the ListOperations
private final RedisTemplate<String, String> redisTemplate;
// Use constructor injection (preferred over field injection)
#Autowired
public RedisExample(final RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public void addLink(String userId, URL url) {
// Here is the trick:
// You can either retrieve the ListOperations this way
ListOperations<String, String> listOps = redisTemplate.opsForList();
listOps.leftPush(userId, url.toExternalForm());
// or, you can retrieve it this way
redisTemplate.boundListOps(userId).leftPush(url.toExternalForm());
}
}
The example shows that you should inject a ListOperations bean with the name redisTemplate. Since there is no such bean the injection fails. Simply remove the #Resource annotation (and the field) and use the code as described above.