Message redelivery in Spring with JBOSS - java

I am using Spring SimpleMessageListenerConatiner where acknowledgement mode is 2 (client acknowledge) and Queue is Solace.
When I am throwing runtime exception from my unit test, means standalone spring config, messages are redelivering without any issue, but same code is not working when I am deploying my application in JBOSS.
public class MyListener implements MessageListener {
public void onMessage(Message message) {
try {
throw new ConnectionException("Error in Connection");
} catch (ConnectionException e) {
LOGGER.error("Throwing exception...");
throw new MyRuntimeException("Throwing exception");
} finally {
LOGGER.info("Done...");
}
}
Spring config is:
<bean id="solaceMessageListener" class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="solaceConnectionFactory"/>
<property name="destinationName" value="QueueName"/>
<property name="messageListener" ref="myListener"/>
<property name="concurrency" value="1"/>
<property name="destinationResolver" ref="destinationResolver" />
<property name="sessionAcknowledgeMode" value="2"/>
</bean>
Constaint:
1. I cannot use DefaultMessageListenerContainer
2. Session Transacted true is working but we have not to use it.

Related

"Consumer Closed" when acknowledging message with JmsTemplate receive method

I have an activemq queue where messages are being sent to and the application uses Spring JmsTemplate receiveSelected(selector) to receive the messages synchronously. Message is processed before it is acknowledged. If the broker or the application shuts down before acknowledging the message while it is being processed the message needs to be resent or redelivered without getting lost. My understanding is with client_acknowledgement messages gets resent if not acknowledged also.
Configuration
<bean id="jmsConnection" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="broker" value="tcp://localhost:61616" />
<property name="redeliveryPolicy" ref="redeliveryPolicy" />
</bean>
Redelivery Policy:
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="initialRedeliveryDelay" value="1000" />
<property name="redeliveryDelay" value="10000" />
<property name="maximumRedeliveries" value="2" />
<property name="useExponentialBackOff" value="true" />
<property name="backOffMultiplier" value="5" />
</bean>
JmsTemplate:
<bean id="jmstemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory">
<bean class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnection" />
</bean>
</property>
<property name="receiveTimeout" value="5000"/>
<property name="defaultDestinationName" value="messageQueue"/>
<property name="explicitQosEnabled" value="true"/>
<property name="sessionAcknowledgeMode" value="2"/>
<property name="sessionTransacted" value="false"/>
</bean>
Session call back to receive message:
Object getProcessedMessageObject {
return jmsTemplate.execute(session -> {
#Override
public Object doInJms (Session session) throws JMSException {
Object tmp = null;
MapMessage msg = (MapMessage) jmsTemplate.receiveSelected(selector);
try {
if (msg != null) {
MapMessage receivedMsg = msg;
tmp = processMsg(receivedMsg) if (tmp != null) {
msg.acknowledge();
}
}
} catch (JMSException) {
throw new RuntimeException();
} return tmp;
}
});
}
I am getting "Consumer is closed" when msg.acknowledge() is called. When I stop and restart my application the messages are not redelivered as they are not acknowledged. I'm trying to understand what I am missing and how to make it work.

Could not get JDBC Connection - Connection Closing Issue

On production environment I got following error.
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (The Network Adapter could not establish the connection)
When I connect through toad, it said ORA-12541 no listener error. The issue resolved after restart of linstener.
But the actual issue may be that lot of connections opened by the web application and it is not closing that. Following are my code and configuration.
I am using EcllipseLink, dbcp2 for connections
<persistence-unit name="persistance-unit" transaction-type="RESOURCE_LOCAL">
<class>com.company.model.Characteristic</class>
...
<!--more classes -->
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="false"/>
</properties>
</persistence-unit>
dbcp2 settings
<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxIdle" value="10" />
<property name="maxTotal" value="200" />
<property name="maxWaitMillis" value="60000" />
<property name="validationQuery" value="select 1 from dual" />
<property name="validationQueryTimeout" value="10" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="true" />
</bean>
Connection Factory
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistance-unit"/>
<property name="dataSource" ref="datasource"/>
<property name="jpaVendorAdapter">
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
</bean>
Transaction Management
Abstract GenericDao
public abstract class GenericDao<T> implements IGenericDao<T> {
#PersistenceContext
protected EntityManager entityManager
private Class<T> type
public GenericDao() {
Type t = getClass().getGenericSuperclass()
ParameterizedType pt = (ParameterizedType) t
type = (Class) pt.getActualTypeArguments()[0]
}
#Override
public T save(final T t) {
this.entityManager.persist(t)
return t
}
public def saveObj(def t) {
try {
this.entityManager.persist(t)
}catch(e){
log.info("Error occured: ", e)
}
return t
}
#Override
public void delete(final Object id) {
this.entityManager.remove(this.entityManager.getReference(type, id))
}
#Override
public T find(final Object id) {
return (T) this.entityManager.find(type, id)
}
#Override
public T update(final T t) {
return this.entityManager.merge(t)
}
#Override
public def executeNamedQuery(String namedQueryName, Map<String, Object> queryParams)
{
List results = null
try {
Query query = entityManager.createNamedQuery(namedQueryName)
if (queryParams) {
addPrametersToQuery(query, queryParams)
}
results = query.getResultList()
} catch (NoResultException e) {
} catch (Exception e) {
log.error("Error occured: ", e)
throw e
}
return results
}
}
Dao component using that Generic Dao
#Component("characteristicDao")
class CharacteristicDao extends GenericDao<Characteristic> implements ICharacteristicDao {
public def getCharacteristics(String name){
log.info("Entering getCharacteristics")
Characteristic characteristic = (PrmCharacteristic) executeQueryWithSingleResult("select b from Characteristic b where b.name=:name", [name:name])
log.info("Exiting getCharacteristics")
return characteristic
}
}
I use CharacteristicDao component to interact with database. Similarly I have other dao also. I have just given one example.
I use #Transactional in service for the transaction. Any master can help me please what I am doing wrong.

Spring / WebLogic - JMS message not redelivered on failure

I am using WerbLogic 10.3.5 and Spring 3.0 to implement a JMS queue. I have the following Spring configuration:
<!-- JMS Configuration -->
<bean id="paymentlistener" class="com.myproject.service.impl.PaymentListener"/>
<bean id="paymentlistenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="10"/>
<property name="connectionFactory" ref="paymentConnectionFactory"/>
<property name="destination" ref="paymentQueue"/>
<property name="messageListener" ref="paymentlistener"/>
</bean>
<bean id="paymentQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/paymentResponseHandlerQueue"/>
<property name="jndiTemplate" ref="jndiTemplate"/>
</bean>
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
</props>
</property>
</bean>
<bean id="paymentConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="jndiName" value="jms/paymentResponseHandlerConnectionFactory"/>
</bean>
<bean id="jmsDestinationResolver" class="org.springframework.jms.support.destination.JndiDestinationResolver">
<property name="jndiTemplate" ref="jndiTemplate"/>
<property name="cache" value="true"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="paymentConnectionFactory"/>
<property name="destinationResolver" ref="jmsDestinationResolver"/>
<property name="defaultDestination" ref="paymentQueue"/>
<property name="sessionAcknowledgeModeName" value="DUPS_OK_ACKNOWLEDGE"/>
<property name="sessionTransacted" value="true"/>
</bean>
My message creation code looks like this:
MessageCreator messageCreator = new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
logger.debug("Session ack mode: " + session.getAcknowledgeMode());
return session.createObjectMessage(payment);
}
};
jmsTemplate.send("jms/paymentResponseHandlerQueue", messageCreator);
And my listener looks like this:
#Override
public void onMessage(Message message) { // , Session session
if (!(message instanceof ObjectMessage)) {
throw new IllegalStateException("The PaymentListener queue expects an object message");
}
ObjectMessage objectMessage = (ObjectMessage) message;
try {
logger.debug("Is Message redelivered:" + objectMessage.getJMSRedelivered ());
if (objectMessage.getObject() instanceof CreditCardPaymentDTO) {
logger.debug("Object is of type CreditCardPaymentDTO");
// The user that just logged in
CreditCardPaymentDTO payment = (CreditCardPaymentDTO) objectMessage.getObject();
otpCollectorDAO.savePayment(payment);
}
} catch (JMSException e) {
logger.error(e);
throw new RuntimeException(e);
} catch (PaymentResponseException e) {
logger.error(e);
throw new RuntimeException(e);
}
}
The message is being created correctly, and the onMessage() method of my listener is being called, but if the logic fails and I throw a RuntimeException(), the message does not get redelivered. I've tried many slight variations of the above code (eg. setting sessionAcknowledgeModeName=SESSION_TRANSACTED and explicitly rolling back the transaction), but the message is never re-queued. What is the trick to getting failed messages to redeliver?
I believe you need to set sessionTransacted to true for the DefaultMessageListenerContainer:
<bean id="paymentlistenerContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
...
<property name="sessionTransacted" value="true"/>
</bean>
You can find here relevant reference documentation.

Read/write to database from quartz jobs - transactions not working

I have two Quartz (1.8.3) jobs, configured via Spring (2.5.6), one of them writes (send) to database, and one reads from it (check).
<bean id="scheduleFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="Check"/>
<ref bean="Send"/>
</list>
</property>
</bean>
<bean id="Send" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="sendMessage" />
</bean>
</property>
<property name="cronExpression" value="0 0/1 * * * ?" />
</bean>
<bean id="Check" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="checkAndUpdateStatus" />
</bean>
</property>
<property name="cronExpression" value="30 0/1 * * * ?" />
</bean>
Transaction manager is set up:
<tx:annotation-driven transaction-manager="TransactionManager"/>
In both jobs I explicitly run read/write operations in transactions like this:
#Override
public synchronized void sendMessage() {
try {
TransactionTemplate tt = new TransactionTemplate(ptm);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
statusDAO.update(status);
...
}
});
log.info("Status was updated");
} catch (Exception e) {
...
}
}
where ptm is a TransactionManager bean, injected via Spring.
I see "Status was updated" record in logs, but when I read this record from transactional read method it is outdated sometimes. Moreover, when I use an SQL editor to read this record it is outdated too.
I don't understand, why transactions dont work in this case, do you have any ideas?
Thanks.
For anyone that might be interested. This worked for me
<bean name="applicationDataCollectorControllerJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="org.mypckage.controller.jobs.ApplicationDataCollectorController" />
<property name="jobDataAsMap">
<map>
<!--<entry key="timeout" value="1" />-->
<entry key="genericService" value-ref="genericService" />
<entry key="applicationDataCollectorService" value-ref="applicationDataCollectorService" />
<entry key="transactionManager" value-ref="transactionManager" />
</map>
</property>
</bean>
--- in the scheduler bean---
#Override
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
getApplicationDataCollectorService().collectData(transactionManager);
}
----In the applicationDataCollectorService bean-----
public void collectData( org.springframework.transaction.jta.JtaTransactionManager transactionManager) {
try {
this.transactionManager = transactionManager;
testTransactionalSave();
} catch (Exception e) {
BUSY = false;
e.printStackTrace();
}
}
}
private void testTransactionalSave() throws Exception {
TransactionTemplate tt = new TransactionTemplate(transactionManager);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus ts) {
try {
ApplicationParameter appPara = null;
List<ApplicationParameter> appParaList = genericService.getListFromHQL("select o from ApplicationParameter as o order by o.id desc", false);
if (appParaList != null) {
if (appParaList.size() > 0) {
appPara = (ApplicationParameter) appParaList.get(0);
appPara.setLastBankStatementMailNum(appPara.getLastBankStatementMailNum() + 10);
appPara = (ApplicationParameter) genericService.mergeObject(appPara);
System.out.println(" num is now = " + appPara.getLastBankStatementMailNum());
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
Note: dont forget to declare transactionManager as private properties in both beans with public setter and getter for spring to wire it up. Any Questions? yemiosigbesan#gmail.com

Spring mail support - no subject

I have updated my libraries, and now e-mails are sent without subject. I don't know where this happened...
Mail API is 1.4.3., Spring 2.5.6. and Spring Integration Mail 1.0.3.RELEASE.
<!-- Definitions for SMTP server -->
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}" />
<property name="username" value="${mail.username}" />
<property name="password" value="${mail.password}" />
</bean>
<bean id="adminMailTemplate" class="org.springframework.mail.SimpleMailMessage" >
<property name="from" value="${mail.admin.from}" />
<property name="to" value="${mail.admin.to}" />
<property name="cc">
<list>
<value>${mail.admin.cc1}</value>
</list>
</property>
</bean>
<!-- Mail service definition -->
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="mail" ref="adminMailTemplate"/>
</bean>
And properties mail.host,mail.username,mail.password,mail.admin.from,mail.admin.to,
mail.admin.cc1.
Java class:
/** The sender. */
private MailSender sender;
/** The mail. */
private SimpleMailMessage mail;
public void sendMail() {
this.mail.setSubject("Subject");
this.mail.setText("msg body");
try {
getSender().send(this.mail);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}
public SimpleMailMessage getMail() {
return this.mail;
}
public void setMail(SimpleMailMessage mail) {
this.mail = mail;
}
public MailSender getSender() {
return this.sender;
}
public void setSender(MailSender mailSender1) {
this.sender = mailSender1;
}
Everything worked before, I am wondering if there may be any conflicts with new libraries.
Finally - I had the time to resolve this.
In pom.xml, I have added java mail dependency and remove exclusion for geronimo javamail in apache axis transport http dependency.
I expect it's something to do with the way that you're injecting a singleton SimpleMailMessage into your bean. This is not thread-safe, since every call to your sendMail method will be using the same underlying SimpleMailmessage object. It's quite possible that some implementation change in the new libraries now means this is broken.
SimpleMailMessage has a copy constructor, so you should do it like this:
<bean id="mailService" class="net.bbb.core.service.impl.MailServiceImpl">
<property name="sender" ref="mailSender"/>
<property name="template" ref="adminMailTemplate"/>
</bean>
and
private SimpleMailMessage template;
public void setTemplate(SimpleMailMessage template) {
this.template = template;
}
public void sendMail() {
SimpleMailMessage message = new SimpleMailMessage(template);
message.setSubject("Subject");
message.setText("msg body");
try {
getSender().send(message);
} catch (MailException e) {
log.error("Error sending mail!",e);
}
}

Categories