0

I'm working with JMS API simplified version 2.0 and I have a problem. I send a message through

messageProducer = context.createProducer();

messageProducer.send(destination,message);

Before doing that I create the message through this code

ObjectMessage msg = context.createObjectMessage();

TemporaryQueue tempQueue = context.createTemporaryQueue();

messageConsumer = context.createConsumer(tempQueue);

msg.setObject(foo);

msg.setJMSReplyTo(tempQueue); 

msg.setJMSCorrelationID(getRandomString()); 

the message is correctly received to the MDB.

In the mdb I create a response string

TextMessage msg = context.createTextMessage();

msg.setText("message response");
msg.setJMSCorrelationID(); here the id correlation of the object received

and then create the message to send

JMSProducer messageProducer = context.createProducer();

messageProducer.send(ReceiverTemporaryDestination, msg);

Unfortunately the program freeze to the following function in JMS side

Message msg = messageConsumer.receive();

I have understand why it doesn't work correctly. When I use a temporary queue it seems that the connection get closed before the sending of the response message. How can I solve the problem? Does exist a way to don't close the connection?

JSM Class

@Stateless
public class BookingManagerBean implements BookingManagerBeanInterface
{
    @EJB
    private UtilBeanInterface utilBean;
    @EJB
    private ReservationManagerBeanInterface reservationBean;

    @Inject
    @JMSConnectionFactory("jms/reservationProcessorQueueFactory")
    private JMSContext context;

    @Resource(mappedName = "jms/bookingProcessorQueueReceiver")
    private Queue bookingProcessorQueueReceiver;

    private JMSProducer messageProducer = null;
    private JMSConsumer messageConsumer = null;

    private String id_reservation = null;

    private Map<String,Object> map;

    @Override
    public String purchase(Route r, UserCredential u, int passengers, int  luggages, double price, int points)
    {                         
        Reservation reserv = reservationBean.addReservation(r, u, passengers, luggages, (float) price);

        try
        {
            sendMessageToBookingProcessorBean(reserv, points); // invia il messaggio contenente la prenotazione e il numero di punti utilizzati                             

            receiveMessageFromBookingProcessorBean();
        }
        catch(JMSException jmse)
        {
            System.err.println("An error occured " + jmse.toString());
            return (id_reservation);
        }

        return id_reservation;
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void sendMessageToBookingProcessorBean(Object messageData, int points) throws JMSException
    {                                  
        messageProducer = context.createProducer();

        messageProducer.send(bookingProcessorQueueReceiver,createMessageForBookingProcessorBean(messageData, points));   
    }

    private Message createMessageForBookingProcessorBean(Object messageData, int points) throws JMSException
    {              
        ObjectMessage msg = context.createObjectMessage();

        TemporaryQueue tempQueue = context.createTemporaryQueue();

        messageConsumer = context.createConsumer(tempQueue);

        map = new HashMap<>();

        map.put("reservation", (Reservation) messageData);
        map.put("used_points", (Integer) points);

        msg.setObject((Serializable) map);

        msg.setJMSReplyTo(tempQueue); //setta  la coda temporanea dove arriverà la risposta
        msg.setJMSCorrelationID(utilBean.getRandomString()); //setta l'id 

        return msg;
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void receiveMessageFromBookingProcessorBean() throws JMSException
    {
        Message msg = messageConsumer.receive(10000); 

        if(msg instanceof TextMessage)
        {
            TextMessage response = (TextMessage)msg;

            this.id_reservation = response.getText();
        }
    }

}

MDB

@MessageDriven(mappedName = "jms/bookingProcessorQueueReceiver", 
               activationConfig = {@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
                                   @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class BookingProcessorBean implements MessageListener
{   
    @EJB
    private ReservationManagerBeanInterface reservationManagerBean;
    @EJB
    private RouteManagerBeanInterface routeManagerBean;
    @EJB
    private SenderMailBeanInterface senderMailBean;
    @EJB
    private UserManagerBeanInterface userManagerBean;
    @EJB
    private GetterFidelityPointsBeanInterface getterFidelityPointsBean;

    @PersistenceContext
    private EntityManager em;

    @Inject
    @JMSConnectionFactory("jms/reservationProcessorQueueFactory")
    @JMSSessionMode(JMSContext.AUTO_ACKNOWLEDGE)
    private JMSContext context;

    Reservation reserv = null;

    private HashMap<String, Object> map = null;

    int points;

    @Override
    public void onMessage(Message message)
    {                                  
        try
        {       
            ObjectMessage om = (ObjectMessage) message;

            System.out.println(om.getJMSReplyTo());
            System.out.println(om.getJMSCorrelationID());


            map = (HashMap<String,Object>) om.getObject();

            reserv = (Reservation) map.get("reservation");
            points = (Integer) map.get("used_points");

            System.out.println("Processing reservation...");

            UserCredential user = reserv.getUsername(); 

            user.getReservationsList().add(reserv); 

            userManagerBean.updateFidelityPoints(user, points); 
            userManagerBean.addFidelityPoints(user, getterFidelityPointsBean.getFidelityPointsByRoute(reserv.getRoute())); 

            routeManagerBean.updateSeatsRoute(reserv); 

            reserv.setId(reservationManagerBean.generateIDReservation()); 

            storeInDb(reserv, user, reserv.getRoute()); 

            senderMailBean.sendEmail(reserv);

            TemporaryQueue tempQueue = (TemporaryQueue) om.getJMSReplyTo();

            sendIdReversationToBookingManagerBean(tempQueue, reserv.getId(), om.getJMSCorrelationID()); //prende la destinazione temporanea ed il messaggio per la risposta
        }
        catch(UnsupportedEncodingException uee)
        {
            System.err.println("An error occured during the sending of the confirmation mail to " + reserv.getUsername().getEmail());
        }
        catch(MessagingException me)
        {
            System.err.println("An error occured during the sending of the email to " + reserv.getUsername().getEmail());
        }
        catch(JMSException e)
        {
            System.err.println("An error occured during the processing of the booking " + reserv.getId());
        }
    }

    private void storeInDb(Reservation r, UserCredential u, Route route)
    {        
        em.persist(r);
        em.merge(u);
        em.merge(route);
    }

    private Message createMessageForBookingManagerBean(String id_reservation, String id_correlation) throws JMSException
    {
        TextMessage msg = context.createTextMessage();

        msg.setText(id_reservation);
        msg.setJMSCorrelationID(id_correlation);

        return msg;
    }

    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    private void sendIdReversationToBookingManagerBean(Destination ReceiverDestination, String id_reservation, String id_correlation) throws JMSException
    {
        JMSProducer messageProducer = context.createProducer();

        messageProducer.send(ReceiverDestination, createMessageForBookingManagerBean(id_reservation, id_correlation));
    }
}
eng_mazzy
  • 1,049
  • 4
  • 23
  • 39

2 Answers2

1

You cannot send and receive messages in one transaction if you are working in a Java EE application. The message will not be delivered to receivers before the transaction is committed. So if your code for sending the original request and receiving the response from the MDB is in one transaction the response should not be received because the MDB should even not get the request as the transaction has not been committed before.

Robert Panzer
  • 1,419
  • 12
  • 14
1

If you are sending message from EJB make sure that sending/reciving method has @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED), because as Robert said it cannot be in one transaction.

UPDATE

Change the following in your code: In BookingManagerBean add not supported to public method not to the private one:

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public String purchase(Route r, UserCredential u, int passengers, int  luggages,    double price, int points)
Gas
  • 17,601
  • 4
  • 46
  • 93