Package hermes.impl.jms

Source Code of hermes.impl.jms.ThreadLocalSessionManager

/*
* Copyright 2003,2004 Colin Crist
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package hermes.impl.jms;

import hermes.Domain;
import hermes.HermesException;
import hermes.config.DestinationConfig;
import hermes.config.SessionConfig;
import hermes.impl.ConnectionManager;
import hermes.impl.DestinationManager;
import hermes.util.JMSUtils;

import java.io.EOFException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicSession;
import javax.jms.TransactionRolledBackException;

import org.apache.log4j.Logger;

/**
* Manager for sessions, holds the thread local producers, consumers, sessions
* and (if configured), destinations. Implements reconnect via the connect()
* method but does not in itself dictate the reconect policy, that is left to
* the implementor of Hermes that calls this. Asynchronous message listeners are
* <b>not</b> supported as this functionality is managed via the dispatchers at
* the DefaultHermesImpl layer.
*
* @author colincrist@hermesjms.com
* @version $Id: ThreadLocalSessionManager.java,v 1.1 2004/07/21 20:25:40
*          colincrist Exp $
*/

public class ThreadLocalSessionManager extends AbstractSessionManager
{
   private static final Logger log = Logger.getLogger(ThreadLocalSessionManager.class);

   private int sessions = 0;
   private long asyncSessionCloseTimeout = 30 * 1000;
   private ThreadLocal sessionTL = new ThreadLocal();
   // private ThreadLocal queueProducerTL = new ThreadLocal();
   private ThreadLocal producerTL = new ThreadLocal();
   private ThreadLocal consumersTL = new ThreadLocal();
   private ThreadLocal consumersWithSelectorTL = new ThreadLocal();
   private Thread dispatchThread;
   private boolean doReconnectConsumers = false;
   /**
    * SessionManager constructor
    */
   public ThreadLocalSessionManager(SessionConfig config, DestinationManager destinationManager)
   {
      super(destinationManager, config);
   }

   public boolean isOpen()
   {
      return sessionTL.get() != null;
   }
  
 
   /**
    * Close the session, the session will be recreated on the next use of this
    * hermes in this thread
    */
   public synchronized void close() throws JMSException
   {
      if (sessionTL.get() != null)
      {
         closeConsumers((Map) consumersTL.get());
         closeConsumers((Map) consumersWithSelectorTL.get());
       
        
         try
         {
            getSession().close();
         }
         catch(JMSException ex)
         {
            log.info("closing session:" + ex.getMessage(), ex) ;
         }
        
         sessionTL.set(null);

         consumersTL.set(null);
         consumersWithSelectorTL.set(null);
         producerTL.set(null);

         sessions--;

         if (getConnectionManager().getType() == ConnectionManager.Policy.SHARED_CONNECTION)
         {
            if (sessions == 0)
            {
               log.debug("all sessions closed, closing Connection");

               getConnectionManager().close();
               getConnectionFactoryManager().close();
            }
         }
         else
         {
            log.debug("session closed, closing its Connection");

            getConnectionManager().close();
            getConnectionFactoryManager().close();
         }
      }
   }

   public void reconnect(String username, String password) throws JMSException
   {
      try
      {
         close() ;
      }
      catch (JMSException ex)
      {
         log.warn("when closing session: " + ex.getMessage(), ex) ;
      }
     
      getConnectionManager().reconnect(username, password) ;    
   }

   /**
    * Reconect the consumers in the map, keyed on destination
    */
   private void reconnect(Map consumers) throws JMSException
   {
      /*
       * for (Iterator iter = consumers.keySet().iterator(); iter.hasNext();) {
       * Destination dest = (Destination) iter.next(); String destName =
       * (isQueue(getConnection())) ? ((Queue) dest).getQueueName() : ((Topic)
       * dest).getTopicName(); DestinationConfig dConfig =
       * getDestinationConfig(destName); Domain domain; if ( dConfig != null) {
       * domain = Domain.getDomain(dConfig.getDomain()); } else { domain =
       * Domain.getDomain(dest); } try { MessageConsumer oldConsumer =
       * (MessageConsumer) consumers.get(dest); MessageConsumer newConsumer =
       * getConsumer(getDestination(destName, domain),
       * oldConsumer.getMessageSelector()); if (
       * oldConsumer.getMessageListener() != null) {
       * newConsumer.setMessageListener(oldConsumer.getMessageListener()); } }
       * catch (NamingException ex) { cat.error("unable to locate destination " +
       * destName + " in JNDI"); } }
       */
   }

   /**
    * Create the session for this thread. Not that if consumers exist (during a
    * reconnect for example) then they will be recreated and the
    * MessageListener's reconnected. Possibly a bit dodgy.
    */
   public synchronized void connect() throws JMSException
   {
      boolean connected = false;
      boolean firstConnect = (sessionTL.get() == null) ? true : false;
      int attempts = 0;
      JMSException throwThis = null; // this goes against my better
      // judgements...
      while (!connected)
      {
         try
         {
            Connection conn = (Connection) parent.getObject();
            Session session = createSession();

            sessionTL.set(session);
            connected = true;

            if (doReconnectConsumers)
            {
               //
               // Tidy up and reconnect any MessageConsumers.

               Map consumers = (Map) consumersTL.get();
               Map consumersWithSelector = (Map) consumersWithSelectorTL.get();

               consumersTL.set(new HashMap());

               if (consumers != null)
               {
                  reconnect(consumers);
               }

               if (consumersWithSelector != null)
               {
                  reconnect(consumersWithSelector);
               }

               if (!firstConnect && session.getTransacted())
               {
                  throwThis = new TransactionRolledBackException("reconnect has forced transaction rollback");
               }
            }
         }
         catch (JMSException ex)
         {
            synchronized (this)
            {
               if (getReconnects() == -1 || attempts < getReconnects())
               {
                  attempts++;

                  log.error("connect failed (" + attempts + "): " + ex.getMessage());

                  try
                  {
                     Thread.sleep(getReconnectTimeout());
                  }
                  catch (InterruptedException ex2)
                  {
                     log.error("unexpected: " + ex2.getMessage(), ex);
                  }
               }
               else
               {
                  //
                  // If the linked exception is an EOFException we've probably lost connection to the broker
                  // so force a reconnect.
                 
                  if (ex.getLinkedException() != null && ex.getLinkedException() instanceof EOFException)
                  {
                     try
                     {
                        getParent().close() ;
                     }
                     catch (JMSException ex2)
                     {
                        // Ignore.
                     }
                  }
                  else
                  {
                     throw ex;
                  }
               }
            }
         }
      }

      if (throwThis != null)
      {
         throw throwThis;
      }
   }

   public void closeConsumers(final Map consumers)
   {
      if (consumers != null)
      {
         for (final Iterator iter = consumers.entrySet().iterator(); iter.hasNext();)
         {
            final Map.Entry entry = (Map.Entry) iter.next();
            final Destination d = (Destination) entry.getKey();
            final MessageConsumer consumer = (MessageConsumer) entry.getValue();

            try
            {
               log.debug("closing consumer for " + JMSUtils.getDestinationName(d));

               consumer.close();
            }
            catch (JMSException e)
            {
               log.error("closing consumer: " + e.getMessage(), e);
            }
         }
      }
   }

   public void closeConsumer(final Destination d, String selector) throws JMSException
   {
      final Map map = selector == null ? (Map) consumersTL.get() : (Map) consumersWithSelectorTL.get() ;

      if (map != null)
      {
         final MessageConsumer consumer = (MessageConsumer) map.remove(d);

         if (consumer != null)
         {
            log.debug("closing consumer for " + JMSUtils.getDestinationName(d));

            consumer.close();
         }
      }
      else
      {
         log.debug("no consumer found to close for " + JMSUtils.getDestinationName(d));
      }
   }

   /**
    * Get a consumer for a destination. The consumer is cached thread local.
    */
   public MessageConsumer getConsumer(final Destination d) throws JMSException
   {
      return getConsumer(d, null);
   }

   /**
    * Get a consumer for a destination and a selector. The consumer is cached
    * thread local.
    */
   public MessageConsumer getConsumer(final Destination d, final String selector) throws JMSException
   {
      MessageConsumer consumer = null;
      Map<Destination, MessageConsumer> map;

      if (selector != null)
      {
         map = (Map) consumersWithSelectorTL.get();
        
         if (map != null) {
           if (map.get(d) != null) {
             if (!map.get(d).getMessageSelector().equals(selector)) {
               map.remove(d).close() ; ;
             }
           }
         }

      }
      else
      {
         map = (Map) consumersTL.get();

      }

      if (map == null)
      {
         map = new HashMap();

         if (selector != null)
         {
            consumersWithSelectorTL.set(map);

         }
         else
         {
            consumersTL.set(map);
         }
      }

      if (map.containsKey(d) )
      {
         consumer = (MessageConsumer) map.get(d);
      
      }
      else
      {
         final DestinationConfig dConfig = getDestinationConfig(d);
         Domain domain;

         if (dConfig != null)
         {
            domain = Domain.getDomain(dConfig.getDomain());
         }
         else
         {
            domain = Domain.getDomain(d);
         }

         if (domain == Domain.QUEUE)
         {
            try
            {
               if (selector == null)
               {
                  consumer = getSession().createConsumer(d);
               }
               else
               {
                  consumer = getSession().createConsumer(d, selector, true);
               }
            }
            catch (NoSuchMethodError ex)
            {
               log.debug("JMS 1.1 interface failed, trying 1.0.2b");
            }
            catch (AbstractMethodError ex)
            {
               log.debug("JMS 1.1 interface failed, trying 1.0.2b");
            }
            catch (JMSException t)
            {
               //
               // WebSphereMQ hack, it does not correctly support JMS 1.1

               if (d.getClass().getName().equals("com.ibm.mq.jms.MQQueue"))
               {
                  log.debug("createConsumer() failed with WMQ via JMS 1.1 call, falling back to 1.0.2b call") ;
               }
               else
               {
                  throw t;
               }
            }

            if (consumer == null)
            {
               if (selector == null)
               {
                  consumer = ((QueueSession) getSession()).createReceiver((Queue) d);
               }
               else
               {
                  consumer = ((QueueSession) getSession()).createReceiver((Queue) d, selector);
               }
            }
         }
         else
         {
            if (dConfig != null && dConfig.isDurable())
            {
               try
               {
                  if (selector == null)
                  {
                     consumer = getSession().createDurableSubscriber((Topic) d, dConfig.getClientID());
                  }
                  else
                  {
                     consumer = getSession().createDurableSubscriber((Topic) d, dConfig.getClientID(), selector, true);
                  }
               }
               catch (NoSuchMethodError ex)
               {
                  log.debug("JMS 1.1 interface failed, trying 1.0.2b");
               }
               catch (AbstractMethodError ex)
               {
                  log.debug("JMS 1.1 interface failed, trying 1.0.2b");
               }

               if (consumer == null)
               {
                  if (selector == null)
                  {
                     consumer = ((TopicSession) getSession()).createDurableSubscriber((Topic) d, dConfig.getClientID());
                  }
                  else
                  {
                     consumer = ((TopicSession) getSession()).createDurableSubscriber((Topic) d, dConfig.getClientID(), selector, true);
                  }
               }
            }
            else
            {
               try
               {
                  if (selector == null)
                  {
                     consumer = getSession().createConsumer(d);
                  }
                  else
                  {
                     consumer = getSession().createConsumer(d, selector, true);
                  }
               }
               catch (NoSuchMethodError ex)
               {
                  log.debug("JMS 1.1 interface failed, trying 1.0.2b");
               }
               catch (AbstractMethodError ex)
               {
                  log.debug("JMS 1.1 interface failed, trying 1.0.2b");
               }

               if (consumer == null)
               {
                  if (selector == null)
                  {
                     consumer = ((TopicSession) getSession()).createSubscriber((Topic) d);
                  }
                  else
                  {
                     consumer = ((TopicSession) getSession()).createSubscriber((Topic) d, selector, true);
                  }
               }
            }
         }

         map.put(d, consumer);
      }

      return consumer;
   }

   public MessageProducer getProducer() throws JMSException
   {
      MessageProducer producer = (MessageProducer) producerTL.get();

      if (producer == null)
      {
         try
         {
            /**
             * Begin WebMethods Enterprise Hack. When using this provider with a
             * JMS 1.1 interface some of the 1.1 methods match and some do not.
             */

            if (getSession().getClass().getName().equals("com.wm.broker.jms.QueueSession"))
            {
               log.debug("WebMethods session creation hack is active");
            }
            else
            {
               producer = getSession().createProducer(null);
               log.debug("producer created using JMS 1.1 interface");
            }
         }
         catch (NoSuchMethodError ex)
         {
            // NOP
         }
         catch (AbstractMethodError ex)
         {
            // NOP
         }
         finally
         {
            try
            {
               if (producer == null)
               {
                  producer = createQueueProducer();
               }
            }
            catch (Throwable t)
            {
               log.debug("cannot create a QueueSender: " + t.getMessage(), t);
               log.debug("trying a TopicPublisher");

               producer = createTopicProducer();
            }

            producerTL.set(producer);
         }
      }

      return producer;
   }

   /**
    * Get the session itself, note that if no session is available then
    * connect() is invoked to create one.
    */
   public synchronized Session getSession() throws JMSException
   {
      Session rval = (Session) sessionTL.get();

      if (rval == null)
      {
         connect();

         synchronized (this)
         {
            sessions++;
         }

         rval = (Session) sessionTL.get();
      }

      return rval;
   }

   public void unsubscribe(String name) throws JMSException
   {
      try
      {
         try
         {
            getSession().unsubscribe(name);
         }
         catch (NoSuchMethodError ex)
         {
            ((TopicSession) getSession()).unsubscribe(name);
         }
         catch (AbstractMethodError ex)
         {
            ((TopicSession) getSession()).unsubscribe(name);
         }
      }
      catch (Throwable ex)
      {
         log.error(ex.getMessage(), ex);

         throw new HermesException("Session " + getId() + " cannot unsubscribe: " + ex.getMessage());
      }
   }
}
TOP

Related Classes of hermes.impl.jms.ThreadLocalSessionManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.