/** {@inheritDoc} */
 public void doReady() {
   channelService = txnProxy.getService(ChannelServiceImpl.class);
   acceptFuture = acceptor.accept(new AcceptorListener());
   try {
     if (logger.isLoggable(Level.CONFIG)) {
       logger.log(Level.CONFIG, "listening on {0}", acceptor.getLocalAddress());
     }
   } catch (IOException ioe) {
     throw new RuntimeException(ioe.getMessage(), ioe);
   }
 }
  /** {@inheritDoc} */
  public void doShutdown() {
    final IoFuture<?, ?> future = acceptFuture;
    acceptFuture = null;
    if (future != null) {
      future.cancel(true);
    }

    if (acceptor != null) {
      try {
        acceptor.close();
      } catch (IOException e) {
        logger.logThrow(Level.FINEST, e, "closing acceptor throws");
        // swallow exception
      }
    }

    if (asyncChannelGroup != null) {
      asyncChannelGroup.shutdown();
      boolean groupShutdownCompleted = false;
      try {
        groupShutdownCompleted = asyncChannelGroup.awaitTermination(1, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
        logger.logThrow(Level.FINEST, e, "shutdown acceptor interrupted");
        Thread.currentThread().interrupt();
      }
      if (!groupShutdownCompleted) {
        logger.log(Level.WARNING, "forcing async group shutdown");
        try {
          asyncChannelGroup.shutdownNow();
        } catch (IOException e) {
          logger.logThrow(Level.FINEST, e, "shutdown acceptor throws");
          // swallow exception
        }
      }
    }
    logger.log(Level.FINEST, "acceptor shutdown");

    if (exporter != null) {
      try {
        exporter.unexport();
        logger.log(Level.FINEST, "client session server unexported");
      } catch (RuntimeException e) {
        logger.logThrow(Level.FINEST, e, "unexport server throws");
        // swallow exception
      }
    }

    for (ClientSessionHandler handler : handlers.values()) {
      handler.shutdown();
    }
    handlers.clear();

    flushContextsThread.interrupt();
  }
 /**
  * Returns the port this service is listening on for incoming client session connections.
  *
  * @return the port this service is listening on
  * @throws IOException if an IO problem occurs
  */
 public int getListenPort() throws IOException {
   return ((InetSocketAddress) acceptor.getLocalAddress()).getPort();
 }
  /**
   * Constructs an instance of this class with the specified properties.
   *
   * @param properties service properties
   * @param systemRegistry system registry
   * @param txnProxy transaction proxy
   * @throws Exception if a problem occurs when creating the service
   */
  public ClientSessionServiceImpl(
      Properties properties, ComponentRegistry systemRegistry, TransactionProxy txnProxy)
      throws Exception {
    super(properties, systemRegistry, txnProxy, logger);

    logger.log(Level.CONFIG, "Creating ClientSessionServiceImpl properties:{0}", properties);
    PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);

    try {
      appPort = wrappedProps.getRequiredIntProperty(StandardProperties.APP_PORT, 1, 65535);

      /*
       * Get the property for controlling session event processing.
       */
      eventsPerTxn =
          wrappedProps.getIntProperty(
              EVENTS_PER_TXN_PROPERTY, DEFAULT_EVENTS_PER_TXN, 1, Integer.MAX_VALUE);

      readBufferSize =
          wrappedProps.getIntProperty(
              READ_BUFFER_SIZE_PROPERTY, DEFAULT_READ_BUFFER_SIZE, 8192, Integer.MAX_VALUE);

      writeBufferSize =
          wrappedProps.getIntProperty(
              WRITE_BUFFER_SIZE_PROPERTY, DEFAULT_WRITE_BUFFER_SIZE, 8192, Integer.MAX_VALUE);

      /*
       * Export the ClientSessionServer.
       */
      int serverPort =
          wrappedProps.getIntProperty(SERVER_PORT_PROPERTY, DEFAULT_SERVER_PORT, 0, 65535);
      serverImpl = new SessionServerImpl();
      exporter = new Exporter<ClientSessionServer>(ClientSessionServer.class);
      try {
        int port = exporter.export(serverImpl, serverPort);
        serverProxy = exporter.getProxy();
        if (logger.isLoggable(Level.CONFIG)) {
          logger.log(Level.CONFIG, "export successful. port:{0,number,#}", port);
        }
      } catch (Exception e) {
        try {
          exporter.unexport();
        } catch (RuntimeException re) {
        }
        throw e;
      }

      /*
       * Get services and initialize service-related and other
       * instance fields.
       */
      identityManager = systemRegistry.getComponent(IdentityCoordinator.class);
      flushContextsThread.start();
      contextFactory = new ContextFactory(txnProxy);
      watchdogService = txnProxy.getService(WatchdogService.class);
      nodeMapService = txnProxy.getService(NodeMappingService.class);
      taskService = txnProxy.getService(TaskService.class);
      localNodeId = watchdogService.getLocalNodeId();
      watchdogService.addRecoveryListener(new ClientSessionServiceRecoveryListener());
      int acceptorBacklog =
          wrappedProps.getIntProperty(ACCEPTOR_BACKLOG_PROPERTY, DEFAULT_ACCEPTOR_BACKLOG);

      /*
       * Check service version.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              checkServiceVersion(VERSION_KEY, MAJOR_VERSION, MINOR_VERSION);
            }
          },
          taskOwner);

      /*
       * Store the ClientSessionServer proxy in the data store.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              dataService.setServiceBinding(
                  getClientSessionServerKey(localNodeId),
                  new ManagedSerializable<ClientSessionServer>(serverProxy));
            }
          },
          taskOwner);

      /*
       * Listen for incoming client connections.
       */
      InetSocketAddress listenAddress = new InetSocketAddress(appPort);
      AsynchronousChannelProvider provider =
          // TODO fetch from config
          AsynchronousChannelProvider.provider();
      asyncChannelGroup =
          // TODO fetch from config
          provider.openAsynchronousChannelGroup(Executors.newCachedThreadPool());
      acceptor = provider.openAsynchronousServerSocketChannel(asyncChannelGroup);
      try {
        acceptor.bind(listenAddress, acceptorBacklog);
        if (logger.isLoggable(Level.CONFIG)) {
          logger.log(Level.CONFIG, "bound to port:{0,number,#}", getListenPort());
        }
      } catch (Exception e) {
        logger.logThrow(Level.WARNING, e, "acceptor failed to listen on {0}", listenAddress);
        try {
          acceptor.close();
        } catch (IOException ioe) {
          logger.logThrow(Level.WARNING, ioe, "problem closing acceptor");
        }
        throw e;
      }
      // TBD: listen for UNRELIABLE connections as well?

    } catch (Exception e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Failed to create ClientSessionServiceImpl");
      }
      doShutdown();
      throw e;
    }
  }