Package net.timewalker.ffmq3.common.connection

Source Code of net.timewalker.ffmq3.common.connection.AbstractConnection

/*
* This file is part of FFMQ.
*
* FFMQ is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* FFMQ is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FFMQ; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package net.timewalker.ffmq3.common.connection;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.jms.Connection;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionMetaData;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.IllegalStateException;
import javax.jms.InvalidClientIDException;
import javax.jms.JMSException;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.Topic;

import net.timewalker.ffmq3.FFMQException;
import net.timewalker.ffmq3.common.session.AbstractSession;
import net.timewalker.ffmq3.utils.ErrorTools;
import net.timewalker.ffmq3.utils.StringTools;
import net.timewalker.ffmq3.utils.id.IntegerID;
import net.timewalker.ffmq3.utils.id.IntegerIDProvider;
import net.timewalker.ffmq3.utils.id.UUIDProvider;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <p>Base implementation for a JMS connection</p>
*/
public abstract class AbstractConnection implements Connection
{
    private static final Log log = LogFactory.getLog(AbstractConnection.class);
   
    // ID and client ID handling
    protected String id = UUIDProvider.getInstance().getUUID();
    protected String clientID;
    private static ConnectionMetaData metaData = new ConnectionMetaDataImpl();
   
    // Runtime
    protected boolean started;
    protected boolean closed;
    private ExceptionListener exceptionListener;
    private Set temporaryQueues = new HashSet();
    private Set temporaryTopics = new HashSet();
    protected IntegerIDProvider idProvider = new IntegerIDProvider();
    protected Object externalAccessLock = new Object();
    private Object exceptionListenerLock = new Object();
   
    // Children
    private Map sessions = new Hashtable();
   
    /**
     * Constructor
     */
    public AbstractConnection( String clientID )
    {
        this.clientID = clientID;
    }
   
    /**
     * Test if the connection is closed
     */
    public boolean isClosed()
    {
      synchronized (externalAccessLock)
      {
        return closed;
      }
    }
   
    /**
     * Get the connection id
     * @return the id
     */
    public String getId()
    {
        return id;
    }

    /* (non-Javadoc)
     * @see javax.jms.Connection#getClientID()
     */
    public String getClientID() throws JMSException
    {
      synchronized (externalAccessLock)
    {
          if (clientID == null)
              throw new InvalidClientIDException("Client ID not set");
          return clientID;
    }
    }

    /* (non-Javadoc)
     * @see javax.jms.Connection#getMetaData()
     */
    public ConnectionMetaData getMetaData()
    {
        return metaData;
    }

    /* (non-Javadoc)
     * @see javax.jms.Connection#setClientID(java.lang.String)
     */
    public void setClientID(String clientID) throws JMSException
    {
      synchronized (externalAccessLock)
    {
        checkNotClosed();
          if (StringTools.isEmpty(clientID))
              throw new InvalidClientIDException("Empty client ID");
          if (this.clientID != null)
              throw new IllegalStateException("Client ID is already set"); // [JMS SPEC]
          this.clientID = clientID;
    }
    }

    /* (non-Javadoc)
     * @see javax.jms.Connection#getExceptionListener()
     */
    public ExceptionListener getExceptionListener()
    {
      synchronized (exceptionListenerLock)
      {
        return exceptionListener;
      }
    }

    /* (non-Javadoc)
     * @see javax.jms.Connection#setExceptionListener(javax.jms.ExceptionListener)
     */
    public void setExceptionListener(ExceptionListener listener) throws JMSException
    {
      synchronized (exceptionListenerLock)
      {
        checkNotClosed();
        this.exceptionListener = listener;
      }
    }
   
    /**
     * Triggered when a JMSException is internally catched
     */
    public void exceptionOccured( JMSException exception )
    {
        try
        {
          synchronized (exceptionListenerLock)
          {
            if (exceptionListener != null)
              exceptionListener.onException(exception);
          }
        }
        catch (Exception e)
        {
            log.error("Exception listener failed",e);
        }
    }
   
    /**
     * Register a temporary queue name
     */
    public void registerTemporaryQueue( String queueName )
    {
        synchronized (temporaryQueues)
        {
            temporaryQueues.add(queueName);   
        }
    }
   
    /**
     * Unregister a temporary queue name
     */
    public void unregisterTemporaryQueue( String queueName )
    {
        synchronized (temporaryQueues)
        {
          temporaryQueues.remove(queueName);   
        }
    }
   
    /**
     * Check if a temporary queue was registered with this connection
     */
    public boolean isRegisteredTemporaryQueue( String queueName )
    {
        synchronized (temporaryQueues)
        {
            return temporaryQueues.contains(queueName);   
        }
    }
   
    /**
     * Register a temporary topic name
     */
    public void registerTemporaryTopic( String topicName )
    {
      synchronized (temporaryTopics)
    {
        temporaryTopics.add(topicName);
    }
    }
   
    /**
     * Unregister a temporary topic name
     */
    public void unregisterTemporaryTopic( String topicName )
    {
        synchronized (temporaryTopics)
        {
            temporaryTopics.remove(topicName);   
        }
    }
   
    /**
     * Check if a temporary topic was registered with this connection
     */
    public boolean isRegisteredTemporaryTopic( String topicName )
    {
        synchronized (temporaryTopics)
        {
            return temporaryTopics.contains(topicName);   
        }
    }
   
    /**
     * Drop all registered temporary queues
     */
    private void dropTemporaryQueues()
    {
        synchronized (temporaryQueues)
    {
          Iterator remainingQueues = temporaryQueues.iterator();
          while (remainingQueues.hasNext())
          {
              String queueName = (String)remainingQueues.next();
              try
              {
                  deleteTemporaryQueue(queueName);
              }
              catch (JMSException e)
              {
                ErrorTools.log(e, log);
              }
          }
    }
    }
   
    /**
     * Delete a temporary queue
     */
    public abstract void deleteTemporaryQueue( String queueName ) throws JMSException;
   
    /**
     * Delete a temporary topic
     */
    public abstract void deleteTemporaryTopic( String topicName ) throws JMSException;

    /* (non-Javadoc)
     * @see javax.jms.Connection#close()
     */
    public final void close()
    {
      synchronized (externalAccessLock)
    {
          if (closed)
              return;
          closed = true;
          onConnectionClose();
    }
      onConnectionClosed();
    }
   
    protected void onConnectionClose()
    {
      // Close remaining sessions
        closeRemainingSessions();

        // Drop temporary queues
        dropTemporaryQueues();
    }
   
    protected void onConnectionClosed()
    {
        // Nothing
    }
   
    /**
     * Close remaining sessions
     */
    private void closeRemainingSessions()
    {
        if (sessions == null)
            return;
       
        List sessionsToClose = new ArrayList(sessions.size());
        synchronized (sessions)
        {
            sessionsToClose.addAll(sessions.values());
        }
        for (int n = 0 ; n < sessionsToClose.size() ; n++)
        {
            Session session = (Session)sessionsToClose.get(n);
            log.debug("Auto-closing unclosed session : "+session);
            try
            {
                session.close();
            }
            catch (JMSException e)
            {
                ErrorTools.log(e, log);
            }
        }
    }

    /**
     * Wake up all children consumers
     */
    protected final void wakeUpConsumers()
    {
        try
        {
          List sessionsSnapshot = new ArrayList(sessions.size());
            synchronized (sessions)
            {
              sessionsSnapshot.addAll(sessions.values());
            }
            for(int n=0;n<sessionsSnapshot.size();n++)
            {
                AbstractSession session = (AbstractSession)sessionsSnapshot.get(n);
                session.wakeUpConsumers();
            }
        }
        catch (JMSException e)
        {
          ErrorTools.log(e, log);
            exceptionOccured(e);
        }
    }
   
    /**
     * Lookup a registered session
     */
    public final AbstractSession lookupRegisteredSession( IntegerID sessionId )
    {
        return (AbstractSession)sessions.get(sessionId);
    }
   
    /**
     * Register a session
     */
    protected final void registerSession( AbstractSession sessionToAdd )
    {
      if (sessions.put(sessionToAdd.getId(),sessionToAdd) != null)
        throw new IllegalArgumentException("Session "+sessionToAdd.getId()+" already exists");
    }
   
    /**
     * Unregister a session
     */
    public final void unregisterSession( AbstractSession sessionToRemove )
    {
        if (sessions.remove(sessionToRemove.getId()) == null)
            log.warn("Unknown session : "+sessionToRemove);
    }
   
    /**
     * Check that the connection is not closed
     */
    protected final void checkNotClosed() throws JMSException
    {
    if (closed)
      throw new FFMQException("Connection is closed","CONNECTION_CLOSED");
    }
   
    /*
     * (non-Javadoc)
     * @see javax.jms.Connection#createConnectionConsumer(javax.jms.Destination, java.lang.String, javax.jms.ServerSessionPool, int)
     */
    public ConnectionConsumer createConnectionConsumer(Destination destination, String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException
    {
        throw new FFMQException("Unsupported feature","UNSUPPORTED_FEATURE");
    }

    /*
     * (non-Javadoc)
     * @see javax.jms.Connection#createDurableConnectionConsumer(javax.jms.Topic, java.lang.String, java.lang.String, javax.jms.ServerSessionPool, int)
     */
    public ConnectionConsumer createDurableConnectionConsumer(Topic topic, String subscriptionName, String messageSelector, ServerSessionPool sessionPool, int maxMessages) throws JMSException
    {
        throw new FFMQException("Unsupported feature","UNSUPPORTED_FEATURE");
    }

    /* (non-Javadoc)
     * @see java.lang.Object#finalize()
     */
    protected void finalize() throws Throwable
    {
        if (externalAccessLock != null && !closed)
        {
            log.warn("Connection was not properly closed, closing it now.");
            try
            {
                close();
            }
            catch (Throwable e)
            {
                log.error("Could not auto-close connection",e);
            }
        }
    }
   
    /**
     * Check if the connection is started
     * NOT SYNCHRONIZED TO AVOID DEADLOCKS
     */
    public boolean isStarted()
    {
       return started && !closed;
    }
   
    /**
     * Get the number of active sessions for this connection
     * @return the number of active sessions for this connection
     */
    public int getSessionsCount()
    {
      return sessions.size();
    }
   
    /**
     * Get the number of active producers for this connection
     * @return the number of active producers for this connection
     */
    public int getConsumersCount()
    {
      synchronized (sessions)
    {
        if (sessions.isEmpty())
          return 0;
   
        int total = 0;
        Iterator sessionsIterator = sessions.values().iterator();
      while (sessionsIterator.hasNext())
      {
        AbstractSession session = (AbstractSession)sessionsIterator.next();
        total += session.getConsumersCount();
      }
      return total;
    }
    }
   
    /**
     * Get the number of active producers for this connection
     * @return the number of active producers for this connection
     */
    public int getProducersCount()
    {
      synchronized (sessions)
    {
        if (sessions.isEmpty())
          return 0;
   
        int total = 0;
        Iterator sessionsIterator = sessions.values().iterator();
      while (sessionsIterator.hasNext())
      {
        AbstractSession session = (AbstractSession)sessionsIterator.next();
        total += session.getProducersCount();
      }
      return total;
    }
    }
   
    /*
     *  (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
        StringBuffer sb = new StringBuffer();
       
        sb.append("Connection[#");
        sb.append(id);
        sb.append("](started=");
        sb.append(started);
        sb.append(")");
       
        return sb.toString();
    }
   
    /**
   * Get a description of entities held by this object
   */
  public void getEntitiesDescription( StringBuffer sb )
  {
    sb.append(toString());
    sb.append("{");
    synchronized (sessions)
    {
      if (!sessions.isEmpty())
      {
        int pos = 0;
        Iterator sessionsIterator = sessions.values().iterator();
        while (sessionsIterator.hasNext())
        {
          AbstractSession session = (AbstractSession)sessionsIterator.next();
          if (pos++ > 0)
            sb.append(",");
          session.getEntitiesDescription(sb);
        }
      }
    }
    sb.append("}");
  }
}
TOP

Related Classes of net.timewalker.ffmq3.common.connection.AbstractConnection

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.