public synchronized void freeze(final CoreRemotingConnection connectionToKeepOpen) {
    if (!started) return;
    failureCheckAndFlushThread.close(false);

    for (Acceptor acceptor : acceptors) {
      try {
        acceptor.pause();
      } catch (Exception e) {
        HornetQServerLogger.LOGGER.errorStoppingAcceptor();
      }
    }
    HashMap<Object, ConnectionEntry> connectionEntries =
        new HashMap<Object, ConnectionEntry>(connections);

    // Now we ensure that no connections will process any more packets after this method is
    // complete then send a disconnect packet
    for (Entry<Object, ConnectionEntry> entry : connectionEntries.entrySet()) {
      RemotingConnection conn = entry.getValue().connection;

      if (conn.equals(connectionToKeepOpen)) continue;

      if (HornetQServerLogger.LOGGER.isTraceEnabled()) {
        HornetQServerLogger.LOGGER.trace("Sending connection.disconnection packet to " + conn);
      }

      if (!conn.isClient()) {
        conn.disconnect(false);
        connections.remove(entry.getKey());
      }
    }
  }
 public synchronized void allowInvmSecurityOverride(HornetQPrincipal principal) {
   defaultInvmSecurityPrincipal = principal;
   for (Acceptor acceptor : acceptors) {
     if (acceptor.isUnsecurable()) {
       acceptor.setDefaultHornetQPrincipal(principal);
     }
   }
 }
  public void stop(final boolean criticalError) throws Exception {
    if (!started) {
      return;
    }

    failureCheckAndFlushThread.close(criticalError);

    // We need to stop them accepting first so no new connections are accepted after we send the
    // disconnect message
    for (Acceptor acceptor : acceptors) {
      if (HornetQServerLogger.LOGGER.isDebugEnabled()) {
        HornetQServerLogger.LOGGER.debug("Pausing acceptor " + acceptor);
      }
      acceptor.pause();
    }

    if (HornetQServerLogger.LOGGER.isDebugEnabled()) {
      HornetQServerLogger.LOGGER.debug("Sending disconnect on live connections");
    }

    HashSet<ConnectionEntry> connectionEntries = new HashSet<ConnectionEntry>(connections.values());

    // Now we ensure that no connections will process any more packets after this method is complete
    // then send a disconnect packet
    for (ConnectionEntry entry : connectionEntries) {
      RemotingConnection conn = entry.connection;

      if (HornetQServerLogger.LOGGER.isTraceEnabled()) {
        HornetQServerLogger.LOGGER.trace("Sending connection.disconnection packet to " + conn);
      }

      conn.disconnect(criticalError);
    }

    for (Acceptor acceptor : acceptors) {
      acceptor.stop();
    }

    acceptors.clear();

    connections.clear();

    if (managementService != null) {
      managementService.unregisterAcceptors();
    }

    threadPool.shutdown();

    if (!criticalError) {
      boolean ok = threadPool.awaitTermination(10000, TimeUnit.MILLISECONDS);

      if (!ok) {
        HornetQServerLogger.LOGGER.timeoutRemotingThreadPool();
      }
    }

    started = false;
  }
    public void handlePacket(final Packet packet) {
      if (packet.getType() == PacketImpl.PING) {
        Ping ping = (Ping) packet;

        if (config.getConnectionTTLOverride() == -1) {
          // Allow clients to specify connection ttl
          entry.ttl = ping.getConnectionTTL();
        }

        // Just send a ping back
        channel0.send(packet);
      } else if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY
          || packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) {
        SubscribeClusterTopologyUpdatesMessage msg =
            (SubscribeClusterTopologyUpdatesMessage) packet;

        if (packet.getType() == PacketImpl.SUBSCRIBE_TOPOLOGY_V2) {
          channel0
              .getConnection()
              .setClientVersion(
                  ((SubscribeClusterTopologyUpdatesMessageV2) msg).getClientVersion());
        }

        final ClusterTopologyListener listener =
            new ClusterTopologyListener() {
              public void nodeUP(
                  final long uniqueEventID,
                  final String nodeID,
                  final Pair<TransportConfiguration, TransportConfiguration> connectorPair,
                  final boolean last) {
                // Using an executor as most of the notifications on the Topology
                // may come from a channel itself
                // What could cause deadlocks
                entry.connectionExecutor.execute(
                    new Runnable() {
                      public void run() {
                        if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
                          channel0.send(
                              new ClusterTopologyChangeMessage_V2(
                                  uniqueEventID, nodeID, connectorPair, last));
                        } else {
                          channel0.send(
                              new ClusterTopologyChangeMessage(nodeID, connectorPair, last));
                        }
                      }
                    });
              }

              public void nodeDown(final long uniqueEventID, final String nodeID) {
                // Using an executor as most of the notifications on the Topology
                // may come from a channel itself
                // What could cause deadlocks
                entry.connectionExecutor.execute(
                    new Runnable() {
                      public void run() {
                        if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
                          channel0.send(new ClusterTopologyChangeMessage_V2(uniqueEventID, nodeID));
                        } else {
                          channel0.send(new ClusterTopologyChangeMessage(nodeID));
                        }
                      }
                    });
              }

              @Override
              public String toString() {
                return "Remote Proxy on channel "
                    + Integer.toHexString(System.identityHashCode(this));
              }
            };

        if (acceptorUsed.getClusterConnection() != null) {
          acceptorUsed.getClusterConnection().addClusterTopologyListener(listener);

          rc.addCloseListener(
              new CloseListener() {
                public void connectionClosed() {
                  acceptorUsed.getClusterConnection().removeClusterTopologyListener(listener);
                }
              });
        } else {
          // if not clustered, we send a single notification to the client containing the node-id
          // where the server is connected to
          // This is done this way so Recovery discovery could also use the node-id for
          // non-clustered setups
          entry.connectionExecutor.execute(
              new Runnable() {
                public void run() {
                  String nodeId = server.getNodeID().toString();
                  Pair<TransportConfiguration, TransportConfiguration> emptyConfig =
                      new Pair<TransportConfiguration, TransportConfiguration>(null, null);
                  if (channel0.supports(PacketImpl.CLUSTER_TOPOLOGY_V2)) {
                    channel0.send(
                        new ClusterTopologyChangeMessage_V2(
                            System.currentTimeMillis(), nodeId, emptyConfig, true));
                  } else {
                    channel0.send(new ClusterTopologyChangeMessage(nodeId, emptyConfig, true));
                  }
                }
              });
        }
      } else if (packet.getType() == PacketImpl.NODE_ANNOUNCE) {
        NodeAnnounceMessage msg = (NodeAnnounceMessage) packet;

        Pair<TransportConfiguration, TransportConfiguration> pair;
        if (msg.isBackup()) {
          pair = new Pair<TransportConfiguration, TransportConfiguration>(null, msg.getConnector());
        } else {
          pair =
              new Pair<TransportConfiguration, TransportConfiguration>(
                  msg.getConnector(), msg.getBackupConnector());
        }
        if (isTrace) {
          HornetQLogger.LOGGER.trace(
              "Server "
                  + server
                  + " receiving nodeUp from NodeID="
                  + msg.getNodeID()
                  + ", pair="
                  + pair);
        }

        if (acceptorUsed != null) {
          ClusterConnection clusterConn = acceptorUsed.getClusterConnection();
          if (clusterConn != null) {
            clusterConn.nodeAnnounced(
                msg.getCurrentEventID(), msg.getNodeID(), pair, msg.isBackup());
          } else {
            HornetQLogger.LOGGER.debug("Cluster connection is null on acceptor = " + acceptorUsed);
          }
        } else {
          HornetQLogger.LOGGER.debug(
              "there is no acceptor used configured at the CoreProtocolManager " + this);
        }
      } else if (packet.getType() == PacketImpl.BACKUP_REGISTRATION) {
        BackupRegistrationMessage msg = (BackupRegistrationMessage) packet;
        ClusterConnection clusterConnection = acceptorUsed.getClusterConnection();

        if (clusterConnection.verify(msg.getClusterUser(), msg.getClusterPassword())) {
          try {
            server.startReplication(
                rc, clusterConnection, getPair(msg.getConnector(), true), msg.isFailBackRequest());
          } catch (HornetQException e) {
            channel0.send(new BackupRegistrationFailedMessage(e));
          }
        } else {
          channel0.send(new BackupRegistrationFailedMessage(null));
        }
      }
    }
  public synchronized void start() throws Exception {
    if (started) {
      return;
    }

    ClassLoader tccl =
        AccessController.doPrivileged(
            new PrivilegedAction<ClassLoader>() {
              public ClassLoader run() {
                return Thread.currentThread().getContextClassLoader();
              }
            });

    // The remoting service maintains it's own thread pool for handling remoting traffic
    // If OIO each connection will have it's own thread
    // If NIO these are capped at nio-remoting-threads which defaults to num cores * 3
    // This needs to be a different thread pool to the main thread pool especially for OIO where we
    // may need
    // to support many hundreds of connections, but the main thread pool must be kept small for
    // better performance

    ThreadFactory tFactory =
        new HornetQThreadFactory(
            "HornetQ-remoting-threads-" + server.toString() + "-" + System.identityHashCode(this),
            false,
            tccl);

    threadPool = Executors.newCachedThreadPool(tFactory);

    ClassLoader loader = Thread.currentThread().getContextClassLoader();

    for (TransportConfiguration info : acceptorsConfig) {
      try {
        Class<?> clazz = loader.loadClass(info.getFactoryClassName());

        AcceptorFactory factory = (AcceptorFactory) clazz.newInstance();

        // Check valid properties

        if (info.getParams() != null) {
          Set<String> invalid =
              ConfigurationHelper.checkKeys(
                  factory.getAllowableProperties(), info.getParams().keySet());

          if (!invalid.isEmpty()) {
            HornetQServerLogger.LOGGER.invalidAcceptorKeys(
                ConfigurationHelper.stringSetToCommaListString(invalid));

            continue;
          }
        }

        String protocol =
            ConfigurationHelper.getStringProperty(
                TransportConstants.PROTOCOL_PROP_NAME,
                TransportConstants.DEFAULT_PROTOCOL,
                info.getParams());

        ProtocolManager manager = protocolMap.get(protocol);
        if (manager == null) {
          throw HornetQMessageBundle.BUNDLE.noProtocolManagerFound(protocol);
        }
        ClusterConnection clusterConnection = lookupClusterConnection(info);

        Acceptor acceptor =
            factory.createAcceptor(
                clusterConnection,
                info.getParams(),
                new DelegatingBufferHandler(),
                manager,
                this,
                threadPool,
                scheduledThreadPool,
                manager);

        if (defaultInvmSecurityPrincipal != null && acceptor.isUnsecurable()) {
          acceptor.setDefaultHornetQPrincipal(defaultInvmSecurityPrincipal);
        }

        acceptors.add(acceptor);

        if (managementService != null) {
          acceptor.setNotificationService(managementService);

          managementService.registerAcceptor(acceptor, info);
        }
      } catch (Exception e) {
        HornetQServerLogger.LOGGER.errorCreatingAcceptor(e, info.getFactoryClassName());
      }
    }

    for (Acceptor a : acceptors) {
      a.start();
    }

    // This thread checks connections that need to be closed, and also flushes confirmations
    failureCheckAndFlushThread =
        new FailureCheckAndFlushThread(RemotingServiceImpl.CONNECTION_TTL_CHECK_INTERVAL);

    failureCheckAndFlushThread.start();

    started = true;
  }