JMS, MDB, EJB problem
Hi everybody,
I have a question and want to get help from you.
one stateless bean and one mdb bean on the same container.
Expected stateless bean send message to the queue and mdb get respond by onMessage call simultaneous (ie. one prefer situation send one message and retreive one message).
However, the output is stateless bean send message, the mdb will not get message until the stateless bean close the session.
Thanks all you help first.
[481 byte] By [
TaurusLeea] at [2007-11-27 7:52:56]

# 2
Hi jitenb,
Thanks you for your reply.
I try to add commit() on the code. But "Cannot perform commit or rollback on an XASession" error and halt.
Attached cllient., producer and consumer code for your reference.
client.java
import javax.ejb.EJB;
import javax.ejb.NoSuchEJBException;
public class client{
@EJB(name="ProducerRemote")
private static ProducerRemote producer;
public static void main(String[] args){
client clt=new client();
clt.run();
System.exit(0);
}
public void run(){
try{
producer.run(100);
}catch(Exception exp){
exp.printStackTrace();
}
}
}
ProducerRemote.java
import javax.ejb.Remote;
@Remote
public interface ProducerRemote{
public void run(int numberoftry);
}
ProducerBeam.java
import java.util.logging.Logger;
import javax.ejb.*;
import javax.jms.*;
import javax.annotation.*;
@Stateless
@Remote({ProducerRemote.class})
public class ProducerBean implements ProducerRemote{
static final Logger logger=Logger.getLogger("ProducerBean");
Connection connection=null;
@Resource(mappedName="jms/ConnectionFactory")
private ConnectionFactory connectionFactory;
@Resource
private SessionContext sc;
@Resource(mappedName="jms/Topic")
private Topic topic;
public ProducerBean(){}
@PostConstruct
public void makeConnection(){
try{
connection=connectionFactory.createConnection();
}catch(Throwable thw){
logger.severe("ProducerBean.makeConnection:Exception:"+thw.toString());
}
}
public void run(int numberoftry){
Session session=null;
MessageProducer producer=null;
TextMessage msg=null;
int counter=0;
try{
session=connection.createSession(true,0);
producer=session.createProducer(topic);
msg=session.createTextMessage();
while(counter<numberoftry){
msg.setText("Item:"+counter);
logger.info("PRODUCER: Setting message text to :"+msg.getText());
producer.send(msg);
session.commit();
counter++;
}
}catch(Throwable thw){
logger.severe("ProducerBean.run:Excepton:"+thw.toString());
sc.setRollbackOnly();
}finally{
if(session!=null){
try{
session.close();
}catch(JMSException jmsexp){
}
}
}
}
@PreDestroy
public void endConnection() throws RuntimeException{
if(connection!=null){
try{
connection.close();
}catch(Exception exp){
exp.printStackTrace();
}
}
}
}
ConsumerBean.java
import javax.ejb.*;
import javax.jms.*;
import javax.annotation.Resource;
import java.util.logging.Logger;
@MessageDriven(mappedName="jms/Topic",activationConfig={
@ActivationConfigProperty(propertyName="subscriptionDurability",propertyValue="Durable"),
@ActivationConfigProperty(propertyName="clientId",propertyValue="MyID"),
@ActivationConfigProperty(propertyName="subscriptionName",propertyValue="MySub")})
public class ConsumerBean implements MessageListener{
static final Logger logger=Logger.getLogger("ConsumerBean");
@Resource
public MessageDrivenContext mdc;
public ConsumerBean(){}
public void onMessage(Message inMessage){
TextMessage msg=null;
try{
if(inMessage instanceof TextMessage){
msg=(TextMessage)inMessage;
logger.info("CONSUMER BEAN: Message received: "+msg.getText());
}else{
logger.warning("Message of wrong type: "+inMessage.getClass().getName());
}
}catch(JMSException jmsexp){
logger.severe("ConsumerBean.onMessage: JMSExcepton: "+jmsexp.toString());
jmsexp.printStackTrace();
mdc.setRollbackOnly();
}catch(Throwable thrw){
logger.severe("ConsumerBean.onMessage:Exception:"+thrw.toString());
thrw.printStackTrace();
}
}
}>
# 3
When JMS resources are used within a global transaction there is special transactional behavior
associated with message production and consumption.When the code calls send() the message
is not actually sent until the transaction commits.Because EJB 3.0 business methods run in a
container-managed transaction by default, that means the messages produced in the session bean
run() method will not be sent to the MDB until the run() method completes.
If you want to force the message send to happen before the run() method completes, you'll need
to use bean-managed transactions or not use transactions at all. If you issue the send outside the
context of a transaction, it will be sent to the destination immediately.
--ken
ksaksa at 2007-7-12 19:34:11 >

# 5
> 1. not use transaction at all.
> but I read the document said "When you create a
> session in an enterprise bean, the container ignores
> the arguments you specify, because it manages all
> transactional properties for enterprise beans.".
> this means even change
> session=connection.createSession(false,...) will not
> help?
Right, don't change that part of the code. What you need to change is the
EJB transaction properties.By default every Session/MDB has
container-managed transactions and transaction attribute REQUIRED.
You can change that by using the TransactionManagement and TransactionAttribute
annotations.One way is to just mark the specific business method with
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
That means there are no global transactions used in the method.
> . use bean-managed transactions.
>where can I set it?
To use bean-managed transactions, add the following to the class-level of the bean :
@TransactionManagement(TransactionManagementType.BEAN)
Then you can use the UserTransaction object to begin,commit, and rollback transactions
within the method.You can acquire UserTransaction by injecting it :
@Resource private UserTransaction ut;
ksaksa at 2007-7-12 19:34:11 >
