users@glassfish.java.net

Re: Findings for “Cannot allocate more connections” exception.

From: <glassfish_at_javadesktop.org>
Date: Mon, 28 Sep 2009 06:28:26 PDT

Hi,

I have a similar problem but I don't have the possibility (i think) to use one connection for the transaction instead of opening and closing it for each message to push into the JMS.

Here I will describe my situation; I have a Java EE application on Glassfish using JPA (toplink) as persistence layer. When an entity is changed an update needs to be send to some clients. For this a JMS Topic is created which the clients read from.

On the JPA entity I added a EntityListener annotation, the implementation of this class handles the PostPersist, the implementation pushes a message into the JMS Topic like this:

public class EntityListenerImpl {

        @PostPersist
        public void postPersist(Object entity) {
        String entityName = entity.getClass().getName();
        Long entityId = ((HasId) entity).getId();
                // changemessage is my own class holding entity information which can be serialized
        ChangeMessage changeMessage = new ChangeMessage(entityName, entityId);
        
        InitialContext initialContext;
        TopicConnection connection = null;
        TopicSession session = null;
        TopicPublisher publisher = null;
        
        try {
            // get a connection and session for the topic
            initialContext = new InitialContext();
            TopicConnectionFactory connectionFactory = (TopicConnectionFactory) initialContext.lookup("jms/TopicConnectionFactory");
            
            connection = connectionFactory.createTopicConnection();
            session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);

            // look up the topic
            Topic topic = (Topic) initialContext.lookup("jms/HtChangeNotification");
            connection.start();

            // get a publisher for the topic
            publisher = session.createPublisher(topic);
            publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

            // publish the message
            ObjectMessage message = session.createObjectMessage();
            message.setObject(changeMessage);

            publisher.publish(message);

            connectionFactory = null;
            if (initialContext != null) {
                initialContext.close();
            }

        } catch (Throwable ex) {
            LogFactory.getLog(getClass()).error("Error", ex);
        } finally {
            if (publisher != null) {
                try {
                    publisher.close();
                    publisher = null;
                } catch (JMSException ex) {
                    LogFactory.getLog(getClass()).error("Error", ex);
                }
            }

            if (session != null) {
                try {
                    session.close();
                    session = null;
                } catch (JMSException ex) {
                    LogFactory.getLog(getClass()).error("Error", ex);
                }
            }
            
            if (connection != null) {
                try {
                    connection.close();
                    connection = null;
                } catch (JMSException ex) {
                    LogFactory.getLog(getClass()).error("Error", ex);
                }
            }
        }
    }

As far as I know I can't control the lifecycle of the entity listener and thus not of the JMS connection. Creating a private variable for a connection also seems like a risk because I don't know if the application server uses an entity listener instance per thread, domain instance, when it garbage collected etc...

What would be the correct way to do this?

Chris
[Message sent by forum member 'sisirhc' (chriswesdorp_at_gmail.com)]

http://forums.java.net/jive/thread.jspa?messageID=366053