Package nexj.core.rpc.jms

Source Code of nexj.core.rpc.jms.JMSSender

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.rpc.jms;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;

import javax.jms.BytesMessage;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.StreamMessage;
import javax.jms.XAConnection;
import javax.jms.XASession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.resource.ResourceException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;

import nexj.core.integration.IntegrationException;
import nexj.core.integration.SecureSender;
import nexj.core.integration.io.ObjectOutput;
import nexj.core.meta.integration.Channel;
import nexj.core.meta.integration.channel.jms.MessageQueue;
import nexj.core.monitoring.ThreadLocalCounter;
import nexj.core.rpc.RPCException;
import nexj.core.rpc.TransferObject;
import nexj.core.runtime.Initializable;
import nexj.core.runtime.InvocationContext;
import nexj.core.runtime.ThreadContextHolder;
import nexj.core.scripting.GlobalEnvironment;
import nexj.core.scripting.Symbol;
import nexj.core.util.Binary;
import nexj.core.util.J2EEUtil;
import nexj.core.util.Logger;
import nexj.core.util.PropertyIterator;
import nexj.core.util.Undefined;

/**
* JMS client and server adapter.
*/
public class JMSSender implements Initializable, SecureSender
{
   // constants

   /**
    * The message properties property: TransferObject.
    */
   public final static String PROPERTIES = "properties";
  
   /**
    * The message priority property: 0..9.
    */
   public final static String PRIORITY = "priority";
  
   /**
    * The message persistence flag property: boolean.
    */
   public final static String PERSISTENT = "persistent";
  
   /**
    * The message time-to-live property: long.
    */
   public final static String TTL = "ttl";

   /**
    * The message type property: String.
    */
   public final static String TYPE = "type";
  
   /**
    * The message reply-to destination name property: String.
    */
   public final static String REPLY_TO = "replyTo";
  
   /**
    * The message source node property: String.
    */
   public final static String NODE = "node";

   /**
    * The message UOW state: String.
    */
   public final static String STATE = "state";

   /**
    * Symbol used to store JMS exception
    */
   protected final static Symbol ASYNC_EXCEPTION = Symbol.define("sys:async-exception");

   // attributes

   /**
    * The JMS engine
    */
   private EngineHelper m_jmsStrategy;

   /**
    * The connection factory name.
    */
   protected String m_sConnectionFactory;

   /**
    * The destination name.
    */
   protected String m_sDestination;

   /**
    * The connection user name.
    */
   protected String m_sUser;

   /**
    * The connection password.
    */
   protected String m_sPassword;

   /**
    * The destination type.
    */
   protected String m_sTypeName = "destination";

   /**
    * The enablement flag.
    */
   protected boolean m_bEnabled = J2EEUtil.isContained();

   // associations

   /**
    * The message queue channel.
    */
   protected MessageQueue m_channel;

   /**
    * The naming context.
    */
   protected Context m_namingContext;

   /**
    * The connection factory.
    */
   protected ConnectionFactory m_connectionFactory;

   /**
    * The destination.
    */
   protected Destination m_destination;

   /**
    * The transaction manager.
    */
   protected TransactionManager m_txManager;

   /**
    * Counter of messages sent since the creation of this component
    */
   protected ThreadLocalCounter m_sentCounter = new ThreadLocalCounter();

   /**
    * The class logger.
    */
   protected final static Logger s_logger = Logger.getLogger(JMSSender.class);

   // operations

   /**
    * Sets the message queue channel.
    * @param channel The message queue channel to set.
    */
   public void setChannel(MessageQueue channel)
   {
      m_channel = channel;
   }

   /**
    * @return The message queue channel.
    */
   public MessageQueue getChannel()
   {
      return m_channel;
   }

   /**
    * Sets the connection factory name.
    * @param sConnectionFactory The connection factory name to set.
    */
   public void setConnectionFactory(String sConnectionFactory)
   {
      m_sConnectionFactory = sConnectionFactory;
   }

   /**
    * @return The connection factory name.
    */
   public String getConnectionFactory()
   {
      return m_sConnectionFactory;
   }
  
   /**
    * @return The connection factory object.
    */
   public ConnectionFactory getConnectionFactoryObject()
   {
      return m_connectionFactory;
   }

   /**
    * Sets the destination name.
    * @param sDestination The destination name to set.
    */
   public void setDestination(String sDestination)
   {
      m_sDestination = sDestination;
   }

   /**
    * @return The destination name.
    */
   public String getDestination()
   {
      return m_sDestination;
   }

   /**
    * @return The destination object.
    */
   public Destination getDestinationObject()
   {
      return m_destination;
   }

   /**
    * Sets the transaction manager.
    * @param txManager The transaction manager to set.
    */
   public void setTransactionManager(TransactionManager txManager)
   {
      m_txManager = txManager;
   }

   /**
    * @return The transaction manager.
    */
   public TransactionManager getTransactionManager()
   {
      return m_txManager;
   }
  
   /**
    * Sets the enablement flag.
    * @param bEnabled The enablement flag to set.
    */
   public void setEnabled(boolean bEnabled)
   {
      m_bEnabled = bEnabled;
   }

   /**
    * @return The enablement flag.
    */
   public boolean isEnabled()
   {
      return m_bEnabled;
   }

   /**
    * Sets the connection user name.
    * @param sUser The connection user name to set.
    */
   public void setUser(String sUser)
   {
      m_sUser = sUser;
   }

   /**
    * @return The connection user name.
    */
   public String getUser()
   {
      return m_sUser;
   }

   /**
    * Sets the connection password.
    * @param sPassword The connection password to set.
    */
   public void setPassword(String sPassword)
   {
      m_sPassword = sPassword;
   }

   /**
    * @see nexj.core.runtime.Initializable#initialize()
    */
   public void initialize() throws Exception
   {
      if (m_channel.isBroadcast())
      {
         m_sTypeName = "topic";
      }
      else
      {
         m_sTypeName = "queue";
      }
     
      if (m_sConnectionFactory == null)
      {
         m_sConnectionFactory = m_channel.getConnectionFactory();

         if (m_sConnectionFactory == null || m_sConnectionFactory.startsWith("class:"))
         {
            m_sConnectionFactory = J2EEUtil.JNDI_ENV_PREFIX + "jms/cf/" + m_channel.getName();
         }
      }

      if (m_channel.getConnectionFactory() != null && m_channel.getConnectionFactory().contains("SonicMQ"))
      {
         m_jmsStrategy = new SonicMQEngineHelper();
      }
      else
      {
         m_jmsStrategy = new GenericEngineHelper();
      }
     
      if (m_sDestination == null)
      {
         m_sDestination = m_channel.getDestination();

         if (m_sDestination == null || m_sDestination.startsWith("class:"))
         {
            m_sDestination = J2EEUtil.JNDI_ENV_PREFIX + "jms/" + m_sTypeName + '/' + m_channel.getName();
         }
      }

      if (m_sUser == null)
      {
         m_sUser = m_channel.getUser();
      }

      if (m_sPassword == null)
      {
         m_sPassword = m_channel.getPassword();
      }

      if (m_bEnabled)
      {
         if (s_logger.isInfoEnabled())
         {
            s_logger.info("Binding to " + m_sTypeName + " \"" +
               m_sDestination + "\" (CF=\"" + m_sConnectionFactory + "\")");
         }

         m_namingContext = new InitialContext();

         try
         {
            bind();
         }
         catch (Exception e)
         {
            s_logger.error("Failed to bind to " + m_sTypeName + " \"" +
               m_sDestination + "\" (CF=\"" + m_sConnectionFactory + "\")", e);
         }
      }
   }

   /**
    * Binds to the connection factory and the queue.
    */
   protected synchronized void bind() throws NamingException, JMSException
   {
      m_connectionFactory = (ConnectionFactory)m_namingContext.lookup(m_sConnectionFactory);
      m_destination = (Destination)m_namingContext.lookup(m_sDestination);
   }

   /**
    * @see nexj.core.integration.Sender#createOutput()
    */
   public ObjectOutput createOutput()
   {
      return new ObjectOutput();
   }

   /**
    * @see nexj.core.integration.Sender#prepare(nexj.core.rpc.TransferObject, nexj.core.rpc.TransferObject, nexj.core.meta.integration.Message)
    */
   public void prepare(TransferObject raw, TransferObject tobj, nexj.core.meta.integration.Message message) throws IntegrationException
   {
   }

   /**
    * @see nexj.core.integration.Sender#send(nexj.core.rpc.TransferObject)
    */
   public void send(TransferObject tobj) throws IntegrationException
   {
      send(Collections.singletonList(tobj));
   }

   /**
    * Sends a collection of messages to the destination.
    * @param col Collection of objects implementing the Envelope interface.
    * @throws RPCException if a sending error has occurred.
    */
   public void send(final Collection col)
   {
      if (!m_channel.isSendable())
      {
         throw new RPCException("err.rpc.notSender", new Object[]{m_channel.getName()});
      }

      if (s_logger.isDebugEnabled())
      {
         s_logger.debug("Sending " + col.size() + " message(s) on channel \"" +
            m_channel.getName() + "\" to destination \"" + m_sDestination + "\"");

         if (s_logger.isDumpEnabled())
         {
            int nCount = 0;

            for (Iterator itr = col.iterator(); itr.hasNext();)
            {
               s_logger.dump("Message [" + nCount++ + "]: " + ((TransferObject)itr.next()));
            }
         }
      }

      if (m_bEnabled)
      {
         boolean bRetry = true;
         ConnectionFactory factory;
         Destination destination;

         synchronized (this)
         {
            if (m_destination == null)
            {
               try
               {
                  bind();
               }
               catch (Exception t)
               {
                  s_logger.error("Failed to bind to " + m_sTypeName + " \"" +
                     m_sDestination + "\" (CF=\"" + m_sConnectionFactory + "\")", t);

                  throw new RPCException("err.rpc.jms", t);
               }
            }

            factory = m_connectionFactory;
            destination = m_destination;
         }

      retry:
         do
         {
            try
            {
               Connection connection = null;
               Session session = null;
               MessageProducer producer = null;

               try
               {
                  if (m_sUser == null)
                  {
                     connection = factory.createConnection();
                  }
                  else
                  {
                     connection = factory.createConnection(m_sUser, m_sPassword);
                  }

                  session = m_jmsStrategy.createSession(connection);
                  producer = session.createProducer(destination);
                  bRetry = false;

                  for (Iterator itr = col.iterator(); itr.hasNext();)
                  {
                     TransferObject tobj = (TransferObject)itr.next();
                     Boolean persistent = (Boolean)tobj.findValue(PERSISTENT);
                     int nPersistenceMode =
                        ((persistent == null) ? m_channel.isPersistent() : persistent.booleanValue()) ?
                        DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
                     Number priority = (Number)tobj.findValue(PRIORITY);
                     int nPriority = (priority == null) ? m_channel.getPriority() : priority.intValue();
                     Number ttl = (Number)tobj.findValue(TTL);
                     long lTTL = (ttl == null) ? m_channel.getTimeToLive() : ttl.longValue();

                     m_sentCounter.add(1);
                     producer.send(createMessage(session, tobj), nPersistenceMode, nPriority, lTTL);
                  }
               }
               finally
               {
                  if (producer != null)
                  {
                     try
                     {
                        producer.close();
                     }
                     catch (Exception e)
                     {
                        s_logger.error("Error closing the producer for destination \"" + m_sDestination + "\"", e);
                     }
                  }

                  if (session != null)
                  {
                     try
                     {
                        m_jmsStrategy.closeSession(session);
                     }
                     catch (Exception e)
                     {
                        s_logger.error("Error closing the session for connection factory \"" +
                           m_sConnectionFactory + "\"", e);
                     }
                  }

                  if (connection != null)
                  {
                     try
                     {
                        connection.close();
                     }
                     catch (Exception e)
                     {
                        s_logger.error("Error closing the connection for connection factory \"" +
                           m_sConnectionFactory + "\"", e);
                     }
                  }
               }
            }
            catch (Exception e)
            {
               if (bRetry)
               {
                  bRetry = false;
                 
                  for (Throwable x = e.getCause(); x != null; x = x.getCause())
                  {
                     if (x instanceof ResourceException || x instanceof IOException)
                     {
                        // The connection factory is stale, get a new one
  
                        if (s_logger.isInfoEnabled())
                        {
                           s_logger.info("Rebinding the stale " + m_sTypeName + " \"" +
                              m_sDestination + "\" (CF=\"" + m_sConnectionFactory + "\")");
                        }

                        try
                        {
                           synchronized (this)
                           {
                              if (m_connectionFactory == factory &&
                                 m_destination == destination)
                              {
                                 bind();
                              }

                              factory = m_connectionFactory;
                              destination = m_destination;
                           }
                        }
                        catch (Exception mx)
                        {
                           s_logger.error("Failed to bind to " + m_sTypeName + " \"" +
                              m_sDestination + "\" (CF=\"" + m_sConnectionFactory + "\")", mx);

                           throw new RPCException("err.rpc.jms", e);
                        }

                        continue retry;
                     }
                  }
               }

               throw new RPCException("err.rpc.jms", e);
            }
         }
         while (bRetry);
      }
      else
      {
         boolean bDone = false;

         if (m_channel.isReceivable())
         {
            if (m_txManager != null)
            {
               try
               {
                  if (m_txManager.getStatus() == Status.STATUS_ACTIVE)
                  {
                     Transaction tx = m_txManager.getTransaction();

                     tx.registerSynchronization(new Synchronization()
                     {
                        public void beforeCompletion()
                        {
                        }

                        public void afterCompletion(int nStatus)
                        {
                           if (nStatus == Status.STATUS_COMMITTED)
                           {
                              receive(col);
                           }
                        }
                     });
                  }
                  else
                  {
                     receive(col);
                  }
               }
               catch (Throwable t)
               {
                  s_logger.error("Error receiving the JMS message on channel \"" +
                     m_channel.getName() + "\"", t);
               }

               bDone = true;
            }
         }

         if (!bDone && s_logger.isDebugEnabled())
         {
            s_logger.debug("Channel \"" + m_channel.getName() + "\" is disabled, ignoring the messages.");
         }
      }
   }

   /**
    * Creates a new message from an object implementing Envelope.
    * @param session The JMS session.
    * @param tobj The message transfer object.
    * @throws JMSException if an error occurs.
    */
   protected Message createMessage(Session session, TransferObject tobj) throws JMSException
   {
      Object obj = tobj.findValue(BODY);
      Message message;

      if (obj == null)
      {
         message = session.createMessage();
      }
      else if (obj instanceof String)
      {
         message = session.createTextMessage((String)obj);
      }
      else if (obj instanceof Binary)
      {
         BytesMessage bytes = session.createBytesMessage();

         bytes.writeBytes(((Binary)obj).getData());
         message = bytes;
      }
      else if (obj instanceof TransferObject && isMapMessage((TransferObject)obj))
      {
         MapMessage map = session.createMapMessage();

         for (PropertyIterator itr = ((TransferObject)obj).getIterator(); itr.hasNext();)
         {
            itr.next();
            map.setObject(itr.getName(), convert(itr.getValue()));
         }

         message = map;
      }
      else if (obj instanceof Collection && isStreamMessage((Collection)obj))
      {
         StreamMessage stm = session.createStreamMessage();

         for (Iterator itr = ((Collection)obj).iterator(); itr.hasNext();)
         {
            stm.writeObject(convert(itr.next()));
         }

         message = stm;
      }
      else
      {
         message = session.createObjectMessage((java.io.Serializable)obj);
      }

      Object correlationId = tobj.findValue(CORRELATION_ID);

      if (correlationId != null)
      {
         if (!(correlationId instanceof String))
         {
            if (correlationId instanceof Binary)
            {
               correlationId = ((Binary)correlationId).toString();
            }
            else
            {
               throw new RPCException("err.rpc.jms.correlationIdType");
            }
         }

         message.setJMSCorrelationID((String)correlationId);
      }

      String sType = (String)tobj.findValue(TYPE);

      if (sType != null)
      {
         message.setJMSType(sType);
      }

      Object replyTo = tobj.findValue(REPLY_TO);

      if (replyTo == null)
      {
         if (m_channel.getReplyQueue() != null)
         {
            message.setJMSReplyTo(getDestination(m_channel.getReplyQueue()));
         }
      }
      else if (replyTo instanceof Destination)
      {
         message.setJMSReplyTo((Destination)replyTo);
      }
      else if (replyTo instanceof Channel)
      {
         message.setJMSReplyTo(getDestination((Channel)replyTo));
      }
      else
      {
         message.setJMSReplyTo(getDestination((String)replyTo));
      }

      TransferObject properties = (TransferObject)tobj.findValue(PROPERTIES);

      if (properties != null)
      {
         for (PropertyIterator itr = properties.getIterator(); itr.hasNext();)
         {
            String sName = (String)itr.next();
            Object value = itr.getValue();

            if (value instanceof BigDecimal)
            {
               message.setDoubleProperty(sName, ((BigDecimal)value).doubleValue());
            }
            else
            {
               message.setObjectProperty(sName, value);
            }
         }
      }

      if (!m_channel.isLoopback() && m_channel.isBroadcast() &&
         !message.propertyExists(NODE))
      {
         message.setStringProperty(NODE, J2EEUtil.NODE_ID);
      }

      return message;
   }

   /**
    * Converts a framework primitive value to a JMS value.
    * @param value The value to convert.
    * @return The converted value.
    */
   public static Object convert(Object value)
   {
      if (value instanceof Binary)
      {
         return ((Binary)value).getData();
      }

      return value;
   }

   /**
    * Determines if a value can be converted to a JMS primitive.
    * @param value The value to test.
    * @return True if the value can be converted to a JMS primitive.
    */
   public static boolean isPrimitive(Object value)
   {
      if (value instanceof Number)
      {
         return value instanceof Integer ||
            value instanceof Long ||
            value instanceof Double ||
            value instanceof Float ||
            value instanceof Short ||
            value instanceof Byte;
      }

      return value instanceof String ||
         value instanceof Binary ||
         value instanceof byte[] ||
         value instanceof Boolean ||
         value instanceof Character;
   }

   /**
    * Determines if a transfer object can be represented as a JMS map message.
    * @param tobj The transfer object to test.
    * @return True if the transfer object can be represented as a JMS map message.
    */
   public static boolean isMapMessage(TransferObject tobj)
   {
      if (tobj.getClassName() != null ||
         tobj.getEventName() != null ||
         tobj.getOID() != null ||
         tobj.getVersion() != 0)
      {
         return false;
      }

      for (PropertyIterator itr = tobj.getIterator(); itr.hasNext();)
      {
         itr.next();

         if (!isPrimitive(itr.getValue()))
         {
            return false;
         }
      }

      return true;
   }

   /**
    * Determines if a collection can be represented as a JMS stream message.
    * @param col The collection to test.
    * @return True if the collection can be represented as a JMS stream message.
    */
   public static boolean isStreamMessage(Collection col)
   {
      for (Iterator itr = col.iterator(); itr.hasNext();)
      {
         if (!isPrimitive(itr.next()))
         {
            return false;
         }
      }

      return true;
   }

   /**
    * Gets a destination from a message queue metadata object.
    * @param mq The message queue metadata.
    * @return The destination object.
    * @throws RPCException if the channel is incompatible.
    */
   protected Destination getDestination(MessageQueue mq) throws RPCException
   {
      return ((JMSSender)mq.getSender().getInstance(null)).getDestinationObject();
   }

   /**
    * Gets a destination from a channel.
    * @param channel The channel.
    * @return The destination object.
    * @throws RPCException if the channel is incompatible.
    */
   protected Destination getDestination(Channel channel) throws RPCException
   {
      if (!(channel instanceof MessageQueue))
      {
         throw new RPCException("err.rpc.jms.channel", new Object[]{channel.getName()});
      }
     
      return getDestination((MessageQueue)channel);
   }

   /**
    * Gets a destination by channel name.
    * @param sChannel The channel name.
    * @return The destination object.
    * @throws RPCException if the channel is incompatible.
    */
   protected Destination getDestination(String sChannel) throws RPCException
   {
      return getDestination(m_channel.getType().getMetadata().getChannel(sChannel));
   }

   /**
    * Forwards the messages to the receiver.
    * @param col The message collection.
    */
   protected void receive(Collection col)
   {
      nexj.core.runtime.Context contextSaved = ThreadContextHolder.getContext();

      for (Iterator itr = col.iterator(); itr.hasNext();)
      {
         TransferObject tobj = (TransferObject)itr.next();
         Transaction tx = null;

         try
         {
            // Clone the object graph
            ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
            ObjectOutputStream oos = new ObjectOutputStream(bos);

            oos.writeObject(tobj);
            oos.close();

            tobj = (TransferObject)new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())).readObject();
            bos = null;
            oos = null;

            if (m_channel.isTransactional())
            {
               m_txManager.begin();
               tx = m_txManager.getTransaction();
            }

            ((MessageListener)m_channel.getReceiver().getInstance(null))
               .onMessage(new TransferObjectMessage(tobj,
                  (contextSaved instanceof InvocationContext) ? (InvocationContext)contextSaved : null));

            if (tx != null)
            {
               switch (tx.getStatus())
               {
                  case Status.STATUS_ACTIVE:
                     if (tx == m_txManager.getTransaction())
                     {
                        m_txManager.commit();
                     }
                     else
                     {
                        tx.commit();
                     }

                     tx = null;
                     break;

                  case Status.STATUS_MARKED_ROLLBACK:
                     break;

                  default:
                     tx = null;
                     break;
               }
            }
         }
         catch (Throwable t)
         {
            s_logger.error("Error receiving the JMS message on channel \"" +
               m_channel.getName() + "\"", t);
           
            if (contextSaved != null)
            {
               GlobalEnvironment env = contextSaved.getMachine().getGlobalEnvironment();

               if (env.findVariable(ASYNC_EXCEPTION, Undefined.VALUE) != Undefined.VALUE)
               {
                  env.setVariable(ASYNC_EXCEPTION, t);
               }
            }
         }
         finally
         {
            if (tx != null)
            {
               try
               {
                  if (tx == m_txManager.getTransaction())
                  {
                     m_txManager.rollback();
                  }
                  else
                  {
                     tx.rollback();
                  }

               }
               catch (Throwable t)
               {
               }
            }

            ThreadContextHolder.setContext(contextSaved);
         }
      }
   }

   /**
    * @see nexj.core.integration.Sender#getSentCount()
    */
   public long getSentCount()
   {
      return m_sentCounter.get();
   }
  
   // inner classes
  
   /**
    * The inner abstract class that represents a helper strategy for a specific JMS engine.
    *
    * As different JMS engines require different approaches to handle JMS objects
    * (for example, SonicMQ sessions should be opened and closed in a different way
    * than that of other JMS engines) we have several classes that would implement
    * the strategy necessary for a specific JMS engine.
    */
   private interface EngineHelper
   {
      /**
       * Creates session from the given connection in a JMS engine specific way
       * @param connection - connection on which the method will create a session
       * @return the session created.
       */
      public Session createSession(Connection connection) throws Exception;

      /**
       * Closes the given session in a JMS provider specific way.
       * @param session - session to be closed.
       */
      public void closeSession(Session session) throws Exception;
   }

   /**
    * Generic JMS Engine strategy.
    */
   private class GenericEngineHelper implements EngineHelper
   {
      /**
       * @see nexj.core.rpc.jms.JMSSender.EngineHelper#createSession(javax.jms.Connection)
       */
      public Session createSession(Connection connection) throws Exception
      {
         return connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
      }

      /**
       * @see nexj.core.rpc.jms.JMSSender.EngineHelper#closeSession(javax.jms.Session)
       */
      public void closeSession(Session session) throws Exception
      {
         session.close();
      }
   }

   /**
    * SonicMQ specific JMS Engine strategy.
    */
   private class SonicMQEngineHelper implements EngineHelper
   {
      /**
       * @see nexj.core.rpc.jms.JMSSender.EngineHelper#createSession(javax.jms.Connection)
       */
      public Session createSession(Connection connection) throws Exception
      {
         Session session = null;

         if (m_channel.isTransactional() && connection instanceof XAConnection)
         {
            XASession xaSession = ((XAConnection)connection).createXASession();
            session = xaSession.getSession();
         }
         else
         {
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
         }

         return session;
      }

      /**
       * @see nexj.core.rpc.jms.JMSSender.EngineHelper#closeSession(javax.jms.Session)
       */
      public void closeSession(Session session) throws Exception
      {
      }
   }
}
TOP

Related Classes of nexj.core.rpc.jms.JMSSender

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.