I have a problem with some old EJB app. In this app, I have a bean named SqsMessageManager which is a @Singleton bean. In the @Postconstruct method, there is an SQS JMS message listener. When a message arrives, the onMessage is executed (this onMessage) is in another bean named SQSMessageReceiver which implements the MessageListener interface. The problem I have is related to the EntityManager. When the message arrives some other methods are executed which deal with some database logic. The exception I get is:
Exception Message : javax.persistence.TransactionRequiredException: JBAS011469: Transaction is required to perform this operation (either use a transaction or extended persistence context)
Here is the code: firs is the @Startup/Signleton bean:
@Startup
@Singleton
public class SqsMessageManager {
public SqsMessageManager() {
LOG.info(CLASS_NAME, "SqsMessageManager() - start");
}
private static final LoggerAbstract LOG;
static {
LOG = LoggerAbstract.getInstance();
}
private static final String CLASS_NAME = SqsMessageManager.class.getName();
private final Integer numberOfReceivers = 1;
public static com.amazon.sqs.javamessaging.SQSConnection connection = null;
public static Queue queue = null;
@Inject
SqsMessageReceiver sqsMessageReceiver;
@PreDestroy
public void end() {
LOG.info(CLASS_NAME, "SqsMessageManager end() - start");
if (connection != null) {
try {
connection.stop();
connection.close();
} catch (JMSException ex) {
LOG.error("Exception occured ", CLASS_NAME,
PrintStackTrace.printStackTrace(ex), "66310",
"Error occured in PreDestroy of SqsMessageManager:" + ex.getMessage());
ex.getStackTrace();
}
}
LOG.info(CLASS_NAME, "SqsMessageManager end() - end");
}
@PostConstruct
public void init() {
try {
LOG.info(CLASS_NAME, "init() - start");
...
....
connection = connectionFactory.createConnection();
if (connection != null) {
queue = connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createQueue("nonprod-mbo-sqs-api-hybridcollection-dev-mwcfgsend");
LOG.info(CLASS_NAME, "connection is not null");
//creaste threads with listeners
for (int i = 0; i < numberOfReceivers; i++) {
LOG.info(CLASS_NAME, "Registering listener: " + i);
connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(queue).setMessageListener(sqsMessageReceiver);
}
connection.start();
} else {
LOG.warning(CLASS_NAME, "Connection to the AWS SQS was not established");
}
} catch (Exception e) {
LOG.error("Exception occured ", CLASS_NAME,
PrintStackTrace.printStackTrace(e), "66310",
"Error occured in postconstruct of SqsMessageManager:" + e.getMessage());
e.getStackTrace();
}
LOG.info(CLASS_NAME, "init() - end");
}
}
The SQSMessageReceiver class:
package com.nielsen.engineering.mediaworks.metermgmt.services.itam;
...
...
import java.nio.charset.Charset;
import java.util.Date;
import javax.ejb.Stateless;
import javax.enterprise.context.Dependent;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@Dependent
public class SqsMessageReceiver implements MessageListener {
private static final LoggerAbstract LOG;
@PersistenceContext(unitName = "meterMgmtPU")
private EntityManager em;
static {
LOG = LoggerAbstract.getInstance();
}
private static final String CLASS_NAME = SqsMessageReceiver.class.getName();
public SqsMessageReceiver(){}
@Override
public void onMessage(Message message) {
LOG.info(CLASS_NAME, "Message received - start(), date: "+new Date());
Converter.EVENT_TYPE eventType = null;
String serviceType = null;
try {
if (message instanceof TextMessage) {
TextMessage txtMsg = (TextMessage) message;
LOG.debug(CLASS_NAME, "Received Command " + txtMsg);
String onMessageRequestXML = txtMsg.getText();
...
...
HouseholdUpdateService hus = new HouseholdUpdateService(em); <---------------- HERE is the problem
...
...
}
}
LOG.info(CLASS_NAME, new Date() + " Message received - end() ");
} catch (Exception e) {
LOG.error(
"Failed to Process the request for EVENT_TYPE - "
+ eventType,
CLASS_NAME,
PrintStackTrace.printStackTrace(e),
Propertyloader.getProperty(MMConstants.CCS_ERROR_CODE),
"Error occured while processing Request - "
+ e.getMessage());
}
}
}
I don't know exactly what is wrong because I'm mainly a JS developer but... As I understand the SqsMessageSender is started when the EJB app is deployed on the server and started. Then I can see that SqsMessageReceiver class is injected into SQSMessageManager but when data arrives in the SQS queue the exception is thrown.
What is the correct way to solve the problem?
In some other "Classes" which are MessageDrivenBeans, the EntityManager works well.