@Override
  public void stop() throws Exception {
    if (stopping) {
      return;
    }

    stopping = true;

    if (logger.isDebugEnabled()) {
      logger.debug("Bridge " + this.name + " being stopped");
    }

    if (futureScheduledReconnection != null) {
      futureScheduledReconnection.cancel(true);
    }

    executor.execute(new StopRunnable());

    if (notificationService != null) {
      TypedProperties props = new TypedProperties();
      props.putSimpleStringProperty(new SimpleString("name"), name);
      Notification notification =
          new Notification(nodeUUID.toString(), CoreNotificationType.BRIDGE_STOPPED, props);
      try {
        notificationService.sendNotification(notification);
      } catch (Exception e) {
        ActiveMQServerLogger.LOGGER.broadcastBridgeStoppedError(e);
      }
    }
  }
  @Override
  public void pause() throws Exception {
    if (logger.isDebugEnabled()) {
      logger.debug("Bridge " + this.name + " being paused");
    }

    executor.execute(new PauseRunnable());

    if (notificationService != null) {
      TypedProperties props = new TypedProperties();
      props.putSimpleStringProperty(new SimpleString("name"), name);
      Notification notification =
          new Notification(nodeUUID.toString(), CoreNotificationType.BRIDGE_STOPPED, props);
      try {
        notificationService.sendNotification(notification);
      } catch (Exception e) {
        ActiveMQServerLogger.LOGGER.notificationBridgeStoppedError(e);
      }
    }
  }
  @Override
  public synchronized void start() throws Exception {
    if (started) {
      return;
    }

    started = true;

    stopping = false;

    activate();

    if (notificationService != null) {
      TypedProperties props = new TypedProperties();
      props.putSimpleStringProperty(new SimpleString("name"), name);
      Notification notification =
          new Notification(nodeUUID.toString(), CoreNotificationType.BRIDGE_STARTED, props);
      notificationService.sendNotification(notification);
    }
  }
  public synchronized void stop() {
    if (channelClazz == null) {
      return;
    }

    if (protocolHandler != null) {
      protocolHandler.close();
    }

    if (batchFlusherFuture != null) {
      batchFlusherFuture.cancel(false);

      flusher.cancel();

      flusher = null;

      batchFlusherFuture = null;
    }

    // serverChannelGroup has been unbound in pause()
    if (serverChannelGroup != null) {
      serverChannelGroup.close().awaitUninterruptibly();
    }

    if (channelGroup != null) {
      ChannelGroupFuture future = channelGroup.close().awaitUninterruptibly();

      if (!future.isSuccess()) {
        ActiveMQServerLogger.LOGGER.nettyChannelGroupError();
        Iterator<Channel> iterator = future.group().iterator();
        while (iterator.hasNext()) {
          Channel channel = iterator.next();
          if (channel.isActive()) {
            ActiveMQServerLogger.LOGGER.nettyChannelStillOpen(channel, channel.remoteAddress());
          }
        }
      }
    }

    // Shutdown the EventLoopGroup if no new task was added for 100ms or if
    // 3000ms elapsed.
    eventLoopGroup.shutdownGracefully(100, 3000, TimeUnit.MILLISECONDS);
    eventLoopGroup = null;

    channelClazz = null;

    for (Connection connection : connections.values()) {
      listener.connectionDestroyed(connection.getID());
    }

    connections.clear();

    if (notificationService != null) {
      TypedProperties props = new TypedProperties();
      props.putSimpleStringProperty(
          new SimpleString("factory"), new SimpleString(NettyAcceptorFactory.class.getName()));
      props.putSimpleStringProperty(new SimpleString("host"), new SimpleString(host));
      props.putIntProperty(new SimpleString("port"), port);
      Notification notification =
          new Notification(null, CoreNotificationType.ACCEPTOR_STOPPED, props);
      try {
        notificationService.sendNotification(notification);
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }

    paused = false;
  }
  public synchronized void start() throws Exception {
    if (channelClazz != null) {
      // Already started
      return;
    }

    if (useInvm) {
      channelClazz = LocalServerChannel.class;
      eventLoopGroup = new LocalEventLoopGroup();
    } else {
      int threadsToUse;

      if (nioRemotingThreads == -1) {
        // Default to number of cores * 3

        threadsToUse = Runtime.getRuntime().availableProcessors() * 3;
      } else {
        threadsToUse = this.nioRemotingThreads;
      }
      channelClazz = NioServerSocketChannel.class;
      eventLoopGroup =
          new NioEventLoopGroup(
              threadsToUse,
              new ActiveMQThreadFactory("activemq-netty-threads", true, getThisClassLoader()));
    }

    bootstrap = new ServerBootstrap();
    bootstrap.group(eventLoopGroup);
    bootstrap.channel(channelClazz);
    final SSLContext context;
    if (sslEnabled) {
      try {
        if (keyStorePath == null
            && TransportConstants.DEFAULT_TRUSTSTORE_PROVIDER.equals(keyStoreProvider))
          throw new IllegalArgumentException(
              "If \""
                  + TransportConstants.SSL_ENABLED_PROP_NAME
                  + "\" is true then \""
                  + TransportConstants.KEYSTORE_PATH_PROP_NAME
                  + "\" must be non-null "
                  + "unless an alternative \""
                  + TransportConstants.KEYSTORE_PROVIDER_PROP_NAME
                  + "\" has been specified.");
        context =
            SSLSupport.createContext(
                keyStoreProvider,
                keyStorePath,
                keyStorePassword,
                trustStoreProvider,
                trustStorePath,
                trustStorePassword);
      } catch (Exception e) {
        IllegalStateException ise =
            new IllegalStateException("Unable to create NettyAcceptor for " + host + ":" + port);
        ise.initCause(e);
        throw ise;
      }
    } else {
      context = null; // Unused
    }

    final AtomicBoolean warningPrinted = new AtomicBoolean(false);

    ChannelInitializer<Channel> factory =
        new ChannelInitializer<Channel>() {
          @Override
          public void initChannel(Channel channel) throws Exception {
            ChannelPipeline pipeline = channel.pipeline();
            if (sslEnabled) {
              SSLEngine engine = context.createSSLEngine();

              engine.setUseClientMode(false);

              if (needClientAuth) engine.setNeedClientAuth(true);

              // setting the enabled cipher suites resets the enabled protocols so we need
              // to save the enabled protocols so that after the customer cipher suite is enabled
              // we can reset the enabled protocols if a customer protocol isn't specified
              String[] originalProtocols = engine.getEnabledProtocols();

              if (enabledCipherSuites != null) {
                try {
                  engine.setEnabledCipherSuites(
                      SSLSupport.parseCommaSeparatedListIntoArray(enabledCipherSuites));
                } catch (IllegalArgumentException e) {
                  ActiveMQServerLogger.LOGGER.invalidCipherSuite(
                      SSLSupport.parseArrayIntoCommandSeparatedList(
                          engine.getSupportedCipherSuites()));
                  throw e;
                }
              }

              if (enabledProtocols != null) {
                try {
                  engine.setEnabledProtocols(
                      SSLSupport.parseCommaSeparatedListIntoArray(enabledProtocols));
                } catch (IllegalArgumentException e) {
                  ActiveMQServerLogger.LOGGER.invalidProtocol(
                      SSLSupport.parseArrayIntoCommandSeparatedList(
                          engine.getSupportedProtocols()));
                  throw e;
                }
              } else {
                engine.setEnabledProtocols(originalProtocols);
              }

              // Strip "SSLv3" from the current enabled protocols to address the POODLE exploit.
              // This recommendation came from
              // http://www.oracle.com/technetwork/java/javase/documentation/cve-2014-3566-2342133.html
              String[] protocols = engine.getEnabledProtocols();
              Set<String> set = new HashSet<>();
              for (String s : protocols) {
                if (s.equals("SSLv3") || s.equals("SSLv2Hello")) {
                  if (!warningPrinted.get()) {
                    ActiveMQServerLogger.LOGGER.disallowedProtocol(s);
                  }
                  continue;
                }
                set.add(s);
              }
              warningPrinted.set(true);
              engine.setEnabledProtocols(set.toArray(new String[0]));

              SslHandler handler = new SslHandler(engine);

              pipeline.addLast("ssl", handler);
            }
            pipeline.addLast(protocolHandler.getProtocolDecoder());
          }
        };
    bootstrap.childHandler(factory);

    // Bind
    bootstrap.childOption(ChannelOption.TCP_NODELAY, tcpNoDelay);
    if (tcpReceiveBufferSize != -1) {
      bootstrap.childOption(ChannelOption.SO_RCVBUF, tcpReceiveBufferSize);
    }
    if (tcpSendBufferSize != -1) {
      bootstrap.childOption(ChannelOption.SO_SNDBUF, tcpSendBufferSize);
    }
    if (backlog != -1) {
      bootstrap.option(ChannelOption.SO_BACKLOG, backlog);
    }
    bootstrap.option(ChannelOption.SO_REUSEADDR, true);
    bootstrap.childOption(ChannelOption.SO_REUSEADDR, true);
    bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
    bootstrap.childOption(ChannelOption.ALLOCATOR, PartialPooledByteBufAllocator.INSTANCE);
    channelGroup =
        new DefaultChannelGroup("activemq-accepted-channels", GlobalEventExecutor.INSTANCE);

    serverChannelGroup =
        new DefaultChannelGroup("activemq-acceptor-channels", GlobalEventExecutor.INSTANCE);

    if (httpUpgradeEnabled) {
      // the channel will be bound by the Web container and hand over after the HTTP Upgrade
      // handshake is successful
    } else {
      startServerChannels();

      paused = false;

      if (notificationService != null) {
        TypedProperties props = new TypedProperties();
        props.putSimpleStringProperty(
            new SimpleString("factory"), new SimpleString(NettyAcceptorFactory.class.getName()));
        props.putSimpleStringProperty(new SimpleString("host"), new SimpleString(host));
        props.putIntProperty(new SimpleString("port"), port);
        Notification notification =
            new Notification(null, CoreNotificationType.ACCEPTOR_STARTED, props);
        notificationService.sendNotification(notification);
      }

      if (batchDelay > 0) {
        flusher = new BatchFlusher();

        batchFlusherFuture =
            scheduledThreadPool.scheduleWithFixedDelay(
                flusher, batchDelay, batchDelay, TimeUnit.MILLISECONDS);
      }

      ActiveMQServerLogger.LOGGER.startedAcceptor(host, port, protocolsString);
    }
  }