users@glassfish.java.net

Re: ok for session bean to keep connection reference & leak reclamation ?

From: <glassfish_at_javadesktop.org>
Date: Thu, 22 May 2008 15:01:47 PDT

Yep, my code is based on the J2EE tutorial example. Can you confirm that the coding practice is indeed OK (code and stack trace below)?

If this can be considered a bug, it is a case of the leak detector not being smart enough to tell that the connection is still in use. I suspect that a colleague who setup the server may have left leak detection turned on in the sun-resources.xml/ant script:

          connection-leak-reclaim="false" [b]connection-leak-timeout-in-seconds="60"[/b] [i](should be 0)[/i]


public class HubToFabRouterSBean implements HubToFabRouterLocal
{

    @Resource(name = "jms/HubFactoryRef")
    private ConnectionFactory connectionFactory;

    @Resource
    private SessionContext sessionContext;
    
    private Connection connection = null;

    private static final int NUM_QUEUES = 2;
    
    public static final String WORK_ORDER_DEST_SEA01 = "jms/HubToFabSEA01Queue";
    public static final String WORK_ORDER_DEST_NYC01 = "jms/HubToFabNYC01Queue";
    
    @Resource(mappedName = WORK_ORDER_DEST_SEA01)
    private Queue queueSEA01;

    @Resource(mappedName = WORK_ORDER_DEST_NYC01)
    private Queue queueNYC01;
    
    private Map<String, Queue> queueMap;
    
    /**
     * Friendly name of the server sending messages;
     * this value will be inserted into the Linx request XML.
     */
    @Resource(name = "senderName")
    private String senderName;
    

    /**
     * Creates the connection.
     */
[b] @PostConstruct
    public void makeConnection()[/b]
    {
        try
        {
            [b]connection = connectionFactory.createConnection();[/b] }
        catch (Throwable ex)
        {
            logger.log(Level.SEVERE, "Unable to get JMS connection.", ex);
        }
        
        // Create a hash map for queue name validation.

        queueMap = new HashMap<String, Queue>(NUM_QUEUES);
        queueMap.put(WORK_ORDER_DEST_SEA01, queueSEA01);
        queueMap.put(WORK_ORDER_DEST_NYC01, queueNYC01);
    }
    

[b] public Map<String, String> sendAll(String messageText, long tranId)
    {[/b]
        Session session = null;
        MessageProducer producer = null;
        TextMessage message = null;
        
        // Map of sent queue-name/message ID pairs.
        
        Map<String, String> sentMessageMap = new HashMap<String, String>(NUM_QUEUES);

        try
        {
            // Within an EJB, transactions are container managed.

            // If an exception is thrown, the session won't be committed and
            // none of the messages will be delivered.
            
            session = connection.createSession(true, 0);

            // Send a message to each queue.
            
            Set<Entry<String, Queue>> entrySet = queueMap.entrySet();
            for (Entry<String, Queue> entry : entrySet)
            {
                Queue queue = entry.getValue();
                producer = session.createProducer(queue);
                message = session.createTextMessage();

                message.setText(messageText);
            
                producer.send(message);
                
                logger.logJMS(Level.FINE, "JMS message sent from EJB " + this.getClass().getSimpleName() + ".", message);
                sentMessageMap.put(entry.getKey(), message.getJMSMessageID());
            }
            
            return sentMessageMap;
        }
        catch(Throwable ex)
        {
            // Transaction is automatically rolled-back when the container gets the exception.
            
            logger.logJMS(Level.SEVERE, ex.getMessage(), message, ex);
            
            // Throw a runtime exception to roll-back the session's transaction.

            throw new MessageNotSentException(queueNames, ex);
        }
        finally
        {
            try
            {
                session.close();
            }
            catch (Throwable ex)
            {
                logger.log(Level.SEVERE, "Error closing JMS session.", ex);
            }
        }
    }


    /**
     * Closes the connection.
     */
   [b] @PreDestroy
    public void endConnection()
    {[/b] try
        {
            [b]connection.close();[/b]
        }
        catch (Throwable ex)
        {
            logger.log(Level.SEVERE, "Error closing JMS connection.", ex);
        }
    }
}



[#|2008-05-21T14:10:15.639-0700|WARNING|sun-appserver9.1|javax.enterprise.resource.resourceadapter|_ThreadID=23;_ThreadName=Timer-32;ConnectionPoolName=jms/HubPool;_RequestID=85a25449-e617-43a3-8a4b-76f4b3a4002d;|[b]A potential connection leak detected for connection pool jms/HubPool[/b]. The stack trace of the thread is provided below :
com.sun.enterprise.resource.AbstractResourcePool.setResourceStateToBusy(AbstractResourcePool.java:301)
com.sun.enterprise.resource.AbstractResourcePool.getResourceFromPool(AbstractResourcePool.java:778)
com.sun.enterprise.resource.AbstractResourcePool.getUnenlistedResource(AbstractResourcePool.java:652)
com.sun.enterprise.resource.AbstractResourcePool.internalGetResource(AbstractResourcePool.java:594)
com.sun.enterprise.resource.AbstractResourcePool.getResource(AbstractResourcePool.java:443)
com.sun.enterprise.resource.PoolManagerImpl.getResourceFromPool(PoolManagerImpl.java:248)
com.sun.enterprise.resource.PoolManagerImpl.getResource(PoolManagerImpl.java:176)
com.sun.enterprise.connectors.ConnectionManagerImpl.internalGetConnection(ConnectionManagerImpl.java:327)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:235)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:165)
com.sun.enterprise.connectors.ConnectionManagerImpl.allocateConnection(ConnectionManagerImpl.java:158)
com.sun.messaging.jms.ra.ConnectionFactoryAdapter._allocateConnection(ConnectionFactoryAdapter.java:179)
com.sun.messaging.jms.ra.ConnectionFactoryAdapter.createConnection(ConnectionFactoryAdapter.java:166)
com.sun.messaging.jms.ra.ConnectionFactoryAdapter.createConnection(ConnectionFactoryAdapter.java:148)
com.ilmn.dam.hub.jms.HubToFabRouterSBean.makeConnection(HubToFabRouterSBean.java:86)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
com.sun.ejb.containers.interceptors.BeanCallbackInterceptor.intercept(InterceptorManager.java:728)
com.sun.ejb.containers.interceptors.CallbackChainImpl.invokeNext(InterceptorManager.java:517)
com.sun.ejb.containers.interceptors.InterceptorManager.intercept(InterceptorManager.java:221)
com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:563)
com.sun.ejb.containers.StatelessSessionContainer.access$100(StatelessSessionContainer.java:111)
com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:772)
com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:199)
com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:486)
com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:1675)
com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1229)
com.sun.ejb.containers.EJBLocalObjectInvocationHandler.invoke(EJBLocalObjectInvocationHandler.java:195)
com.sun.ejb.containers.EJBLocalObjectInvocationHandlerDelegate.invoke(EJBLocalObjectInvocationHandlerDelegate.java:127)
$Proxy82.sendAll(Unknown Source)
com.ilmn.hub.servlet.FabRouterDelegate.sendAll(FabRouterDelegate.java:103)
...
[Message sent by forum member 'frenchdrip' (frenchdrip)]

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