Package org.jboss.jms.server.connectionmanager

Source Code of org.jboss.jms.server.connectionmanager.SimpleConnectionManager

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This 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.1 of
  * the License, or (at your option) any later version.
  *
  * This software 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 this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.jms.server.connectionmanager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;

import javax.jms.JMSException;

import org.jboss.jms.server.ConnectionManager;
import org.jboss.jms.server.endpoint.ConnectionEndpoint;
import org.jboss.logging.Logger;
import org.jboss.messaging.util.Util;
import org.jboss.remoting.Client;
import org.jboss.remoting.ClientDisconnectedException;
import org.jboss.remoting.ConnectionListener;

/**
* @author <a href="tim.fox@jboss.com">Tim Fox</a>
* @author <a href="ovidiu@jboss.org">Ovidiu Feodorov</a>
* @version <tt>$Revision: 2133 $</tt>
*
* $Id: SimpleConnectionManager.java 2133 2007-02-02 06:38:23Z ovidiu.feodorov@jboss.com $
*/
public class SimpleConnectionManager implements ConnectionManager, ConnectionListener
{
   // Constants ------------------------------------------------------------------------------------

   private static final Logger log = Logger.getLogger(SimpleConnectionManager.class);

   // Static ---------------------------------------------------------------------------------------

   private static boolean trace = log.isTraceEnabled();

   // Attributes -----------------------------------------------------------------------------------

   // Map<jmsClientVMID<String> - Map<remotingClientSessionID<String> - ConnectionEndpoint>>
   protected Map jmsClients;

   // Map<remotingClientSessionID<String> - jmsClientVMID<String>
   protected Map remotingSessions;

   // Set<ConnectionEndpoint>
   protected Set activeConnectionEndpoints;

   // Constructors ---------------------------------------------------------------------------------

   public SimpleConnectionManager()
   {
      jmsClients = new HashMap();
      remotingSessions = new HashMap();
      activeConnectionEndpoints = new HashSet();
   }

   // ConnectionManager implementation -------------------------------------------------------------

   public synchronized void registerConnection(String jmsClientVMID,
                                               String remotingClientSessionID,
                                               ConnectionEndpoint endpoint)
   {   
      Map endpoints = (Map)jmsClients.get(jmsClientVMID);
     
      if (endpoints == null)
      {
         endpoints = new HashMap();
         jmsClients.put(jmsClientVMID, endpoints);
      }
     
      endpoints.put(remotingClientSessionID, endpoint);
     
      remotingSessions.put(remotingClientSessionID, jmsClientVMID);

      activeConnectionEndpoints.add(endpoint);
     
      log.debug("registered connection " + endpoint + " as " +
                Util.guidToString(remotingClientSessionID));
   }

   public synchronized ConnectionEndpoint unregisterConnection(String jmsClientVMId,
                                                               String remotingClientSessionID)
   {
      Map endpoints = (Map)jmsClients.get(jmsClientVMId);
     
      if (endpoints != null)
      {
         ConnectionEndpoint e = (ConnectionEndpoint)endpoints.remove(remotingClientSessionID);

         if (e != null)
         {
            endpoints.remove(e);
            activeConnectionEndpoints.remove(e);
         }

         log.debug("unregistered connection " + e + " with remoting session ID " +
               Util.guidToString(remotingClientSessionID));
        
         if (endpoints.isEmpty())
         {
            jmsClients.remove(jmsClientVMId);
         }
        
         remotingSessions.remove(remotingClientSessionID);
        
         return e;
      }
      return null;
   }

   public synchronized void handleClientFailure(String remotingSessionID, boolean clientToServer)
   {
      String jmsClientID = (String)remotingSessions.get(remotingSessionID);

      if (jmsClientID != null)
      {
         log.warn(this + " cannot look up remoting session ID " + remotingSessionID);
      }

      log.warn("A problem has been detected " +
         (clientToServer ?
            "with the connection to remote client ":
            "trying to send a message to remote client ") +
         remotingSessionID + ". It is possible the client has exited without closing " +
         "its connection(s) or there is a network problem. All connection resources " +
         "corresponding to that client process will now be removed.");

      // Remoting only provides one pinger per invoker, not per connection therefore when the pinger
      // dies we must close ALL connections corresponding to that jms client ID.

      // TODO (ovidiu) In case the error was detected while trying to send a callback, I am assuming
      //      that the whole TCP/IP connection is hosed, so I close everything that's on it. Is this
      //      OK? Maybe we want to be a little bit more selective.

      Map endpoints = (Map)jmsClients.get(jmsClientID);

      if (endpoints != null)
      {
         List sces = new ArrayList();

         for(Iterator i = endpoints.entrySet().iterator(); i.hasNext(); )
         {
            Map.Entry entry = (Map.Entry)i.next();
            ConnectionEndpoint sce = (ConnectionEndpoint)entry.getValue();
            sces.add(sce);
         }

         // Now close the end points - this will result in a callback into unregisterConnection
         // to remove the data from the jmsClients and sessions maps.
         // Note we do this outside the loop to prevent ConcurrentModificationException

         for(Iterator i = sces.iterator(); i.hasNext(); )
         {
            ConnectionEndpoint sce = (ConnectionEndpoint)i.next();

            try
            {
               sce.closing();
               sce.close();
               log.debug("cleared up state for connection " + sce);
            }
            catch (JMSException e)
            {
               log.error("Failed to close connection", e);
            }
         }
      }
   }

   public synchronized List getActiveConnections()
   {
      // I will make a copy to avoid ConcurrentModification
      ArrayList list = new ArrayList();
      list.addAll(activeConnectionEndpoints);
      return list;
   }

   // ConnectionListener implementation ------------------------------------------------------------

   /**
    * Be aware that ConnectionNotifier uses to call this method with null Throwables.
    *
    * @param t - plan for it to be null!
    */
   public void handleConnectionException(Throwable t, Client client)
   { 
      if (t instanceof ClientDisconnectedException)
      {
         // This is OK
         if (trace) { log.trace(this + " notified that client " + client + " has disconnected"); }
         return;
      }
      else
      {
         if (trace) { log.trace(this + " detected failure on client " + client, t); }
      }

      String remotingSessionID = client.getSessionId();
     
      if (remotingSessionID != null)
      {
         handleClientFailure(remotingSessionID, true);
      }
   }
  
   // MessagingComponent implementation ------------------------------------------------------------
  
   public void start() throws Exception
   {
      //NOOP
   }
  
   public void stop() throws Exception
   {
      //NOOP
   }

   // Public ---------------------------------------------------------------------------------------

   /*
    * Used in testing only
    */
   public synchronized boolean containsRemotingSession(String remotingClientSessionID)
   {
      return remotingSessions.containsKey(remotingClientSessionID);
   }

   /*
    * Used in testing only
    */
   public synchronized Map getClients()
   {
      return Collections.unmodifiableMap(jmsClients);
   }


   public String toString()
   {
      return "ConnectionManager[" + Integer.toHexString(hashCode()) + "]";
   }

   // Package protected ----------------------------------------------------------------------------

   // Protected ------------------------------------------------------------------------------------

   // Private --------------------------------------------------------------------------------------

   // Inner classes --------------------------------------------------------------------------------

}
TOP

Related Classes of org.jboss.jms.server.connectionmanager.SimpleConnectionManager

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.