text: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.alipay.sofa.ark.container.session;
  
  import com.alipay.sofa.ark.common.log.ArkLogger;
  import com.alipay.sofa.ark.common.log.ArkLoggerFactory;
  import com.alipay.sofa.ark.common.thread.CommonThreadPool;
  import com.alipay.sofa.ark.common.thread.ThreadPoolManager;
  import com.alipay.sofa.ark.common.util.AssertUtils;
  import com.alipay.sofa.ark.common.util.EnvironmentUtils;
  import com.alipay.sofa.ark.common.util.PortSelectUtils;
  import com.alipay.sofa.ark.common.util.StringUtils;
  import com.alipay.sofa.ark.exception.ArkRuntimeException;
  import com.alipay.sofa.ark.spi.constant.Constants;
  import com.alipay.sofa.ark.spi.service.session.TelnetServerService;
  import com.google.inject.Singleton;
  import java.util.concurrent.atomic.AtomicBoolean;
  
  import static com.alipay.sofa.ark.spi.constant.Constants.DEFAULT_SELECT_PORT_SIZE;
  import static com.alipay.sofa.ark.spi.constant.Constants.DEFAULT_TELNET_PORT;
  import static com.alipay.sofa.ark.spi.constant.Constants.TELNET_PORT_ATTRIBUTE;
  import static com.alipay.sofa.ark.spi.constant.Constants.TELNET_SERVER_ENABLE;
  
  /**
   * {@link TelnetServerService}
   *
   * @author qilong.zql
   * @since 0.4.0
   */
  @Singleton
  public class StandardTelnetServerImpl implements TelnetServerService {
  
      private static final ArkLogger LOGGER                  = ArkLoggerFactory.getDefaultLogger();
  
      private static final int       WORKER_THREAD_POOL_SIZE = 2;
  
      private int                    port                    = -1;
  
      private AtomicBoolean          shutdown                = new AtomicBoolean(false);
  
      private boolean                enableTelnetServer      = EnvironmentUtils.getProperty(
                                                                 TELNET_SERVER_ENABLE, "true")
                                                                 .equalsIgnoreCase("true");
  
      private NettyTelnetServer      nettyTelnetServer;
  
      public StandardTelnetServerImpl() {
          if (enableTelnetServer) {
              String telnetPort = EnvironmentUtils.getProperty(TELNET_PORT_ATTRIBUTE);
              try {
                  if (!StringUtils.isEmpty(telnetPort)) {
                      port = Integer.parseInt(telnetPort);
                  } else {
                      port = PortSelectUtils.selectAvailablePort(DEFAULT_TELNET_PORT,
                          DEFAULT_SELECT_PORT_SIZE);
                  }
              } catch (NumberFormatException e) {
                  LOGGER.error(String.format("Invalid port in %s", telnetPort), e);
                  throw new ArkRuntimeException(e);
              }
          }
      }
  
      @Override
      public void run() {
          AssertUtils.isTrue(port > 0, "Telnet port should be positive integer.");
          try {
              LOGGER.info("Listening on port: " + port);
              CommonThreadPool workerPool = new CommonThreadPool()
                  .setCorePoolSize(WORKER_THREAD_POOL_SIZE).setDaemon(true)
                  .setThreadPoolName(Constants.TELNET_SERVER_WORKER_THREAD_POOL_NAME);
              ThreadPoolManager.registerThreadPool(Constants.TELNET_SERVER_WORKER_THREAD_POOL_NAME,
                  workerPool);
              nettyTelnetServer = new NettyTelnetServer(port, workerPool.getExecutor());
              nettyTelnetServer.open();
          } catch (InterruptedException e) {
              LOGGER.error("Unable to open netty telnet server.", e);
              throw new ArkRuntimeException(e);
          }
      }
  
      @Override
      public void shutdown() {
          if (shutdown.compareAndSet(false, true)) {
              try {
                  if (nettyTelnetServer != null) {
                      nettyTelnetServer.close();
                      nettyTelnetServer = null;
                  }
              } catch (Throwable t) {
                  LOGGER.error("An error occurs when shutdown telnet server.", t);
                  throw new ArkRuntimeException(t);
              }
          }
      }
  
      @Override
      public void init() throws ArkRuntimeException {
          if (enableTelnetServer) {
              run();
          } else {
              LOGGER.warn("Telnet server is disabled.");
          }
      }
  
      @Override
      public void dispose() throws ArkRuntimeException {
          if (enableTelnetServer) {
              shutdown();
          }
      }
  
      @Override
      public int getPriority() {
          return HIGHEST_PRECEDENCE;
      }
  }