Package org.xmlBlaster.engine.admin.extern

Source Code of org.xmlBlaster.engine.admin.extern.TelnetGateway

/*------------------------------------------------------------------------------
Name:      TelnetGateway.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
Comment:   Main manager class for administrative commands
------------------------------------------------------------------------------*/
package org.xmlBlaster.engine.admin.extern;

import java.util.logging.Logger;
import java.util.logging.Level;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.engine.ServerScope;
import org.xmlBlaster.engine.admin.CommandManager;
import org.xmlBlaster.engine.admin.I_ExternGateway;
import org.xmlBlaster.engine.admin.SetReturn;
import org.xmlBlaster.engine.qos.AddressServer;
import org.xmlBlaster.engine.qos.ConnectQosServer;
import org.xmlBlaster.engine.qos.ConnectReturnQosServer;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.MsgUnit;
import org.xmlBlaster.util.Timestamp;
import org.xmlBlaster.util.I_Timeout;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.key.QueryKeyData;

import remotecons.RemoteServer;
import remotecons.ifc.CommandHandlerIfc;
import remotecons.wttools.ConnectionServer;

import java.util.LinkedList;
import java.util.StringTokenizer;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.io.IOException;

/**
* The gateway from outside telnet connections to inside CommandManager.
* <p />
* @author xmlBlaster@marcelruff.info
* @since 0.79f
* @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/admin.telnet.html">admin.telnet requirement</a>
* @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/admin.commands.html">admin.commands requirement</a>
*/
public final class TelnetGateway implements CommandHandlerIfc, I_ExternGateway, I_Timeout
{
   private String ME;
   private ServerScope glob;
   private static Logger log = Logger.getLogger(TelnetGateway.class.getName());
   private CommandManager commandManager;
   private int port;
   private RemoteServer rs;
   private final String CRLF = "\r\n";
   private static int instanceCounter = 0;
   private boolean isShutdown = true;

   private boolean isLogin = false;
   private ConnectReturnQosServer connectRetQos;
   private String loginName = "";
   private String sessionId;

   private Set telnetInstancesSet;

   private Timestamp timerKey;
   private long sessionTimeout = 3600000L; // autologout after 1 hour

   private ConnectionServer connectionServer;
   private AddressServer addressServer;

   private String lastCommand = "";

   /**
    * Default port to access xmlBlaster with telnet for administration (2702).
    */
   public static final int TELNET_PORT = 2702;

   public TelnetGateway() {
      instanceCounter++;
   }

   /**
    * Creates the remote console server.
    * <p />
    * Is called by CommandManager on startup
    * @return true if started and active
    */
   public boolean initialize(ServerScope glob, CommandManager commandManager) throws XmlBlasterException {
      initializeVariables(glob, commandManager, true);
      return initListener();
   }

   /**
    * @param isBootstrap The first instance has no timer set
    * @return true if started and active
    */
   private boolean initializeVariables(ServerScope glob, CommandManager commandManager, boolean isBootstrap) {
      this.glob = glob;

      this.ME = "TelnetGateway" + instanceCounter + this.glob.getLogPrefixDashed();
      this.telnetInstancesSet = new HashSet();
      this.commandManager = commandManager;
      this.sessionTimeout = glob.getProperty().get("admin.remoteconsole.sessionTimeout", sessionTimeout);
      this.sessionTimeout = glob.getProperty().get("admin.remoteconsole.sessionTimeout[" + glob.getId() + "]", sessionTimeout);
      this.port = glob.getProperty().get("admin.remoteconsole.port", TELNET_PORT); // 0 == off
      this.port = glob.getProperty().get("admin.remoteconsole.port[" + glob.getId() + "]", this.port);
      if (this.port <= 1000) {
         if (log.isLoggable(Level.FINE)) log.fine("No telnet gateway configured, port=" + port + " try '-admin.remoteconsole.port " + TELNET_PORT + "' if you want one");
         return false;
      }

      if (!isBootstrap) { // Ignore the first bootstrap instance
         if (sessionTimeout > 0L) {
            log.info("New connection from telnet client accepted, session timeout is " + Timestamp.millisToNice(sessionTimeout));
            timerKey = glob.getTelnetSessionTimer().addTimeoutListener(this, sessionTimeout, null);
         }
         else
            log.info("Session for " + loginName + " lasts forever, requested expiry timer was 0");
      }
      return true;
   }

   // Hack into remotecons to allow shutdown (marcel)
   public void register(remotecons.wttools.ConnectionServer server) {
      this.connectionServer = server;
   }

   private void stopTimer() {
      if (this.timerKey != null && glob.hasTelnetSessionTimer()) {
         this.glob.getTelnetSessionTimer().removeTimeoutListener(this.timerKey);
         this.timerKey = null;
      }
   }

   protected void finalize() {
      stopTimer();
      disconnect();
   }

   /**
    * We are notified when this session expires.
    * @param userData You get bounced back your userData which you passed
    *                 with Timeout.addTimeoutListener()
    */
   public final void timeout(Object userData)
   {
      synchronized (this) {
         timerKey = null;
         if (isLogin)
            log.warning("Session timeout " + Timestamp.millisToNice(sessionTimeout) + " for telnet client " + loginName + " occurred, autologout.");
         else
            log.warning("Session timeout " + Timestamp.millisToNice(sessionTimeout) + " for not authorized telnet client occurred, autologout.");
      }
      //disconnect(); This happens automatically in Authenticate.java at the same time
      connectRetQos = null;
      if (connectionServer != null)
         connectionServer.shutdown()// Hack into remotecons to allow shutdown (marcel)
   }

   private synchronized void disconnect() {
      if (isLogin) {
         if (connectRetQos != null) {
            try {
               glob.getAuthenticate().disconnect(this.addressServer, connectRetQos.getSecretSessionId(), null);
            }
            catch (org.xmlBlaster.util.XmlBlasterException e) {
               log.warning(e.getMessage());
            }
            log.info("Logout of '" + loginName + "', telnet connection destroyed");
            connectRetQos = null;
         }
         else
            log.info("Connection from not authorized telnet client destroyed");
      }
      isLogin = false;
   }

   private boolean initListener() throws XmlBlasterException {
      if (this.port > 1000) {
         createRemoteConsole(port);
         log.info("Started remote console server for administration, try 'telnet " + glob.getLocalIP() + " " + port + "' to access it and type 'help'.");
         return true;
      }

      if (log.isLoggable(Level.FINE)) log.fine("No telnet gateway configured, port=" + port + " try '-admin.remoteconsole.port " + TELNET_PORT + "' if you want one");
      return false;
   }

   /**
    * Creates a server which is accessible with telnet.
    * This allows you to access xmlBlaster and query for example the free memory:
    * <pre>
    *  telnet 192.168.1.2 2702
    *  mem
    * </pre>
    * Enter 'help' for all available commands.
    */
   private void createRemoteConsole(int port) throws XmlBlasterException {
      if (port > 1000) {
         rs = new RemoteServer();
         rs.setServer_port(port);
         rs.setAs_daemon(true);
         LinkedList ll = new LinkedList();
         ll.add(this);
         try {
           rs.initialize(ll);
         } catch (IOException e) {
           //e.printStackTrace();
           if (log.isLoggable(Level.FINE)) log.fine("Initializing of remote console on port=" + port + " failed:" + e.toString());
           throw new XmlBlasterException(glob, ErrorCode.INTERNAL_UNKNOWN, ME, "Initializing of remote telnet console on port=" + port + " failed:" + e.toString());
         }
      }
   }

   /**
    * Enforced by "remotecons.CommandHandlerIfc"
    */
   public String handleCommand(String cmd) {
      try {
         if (cmd == null || cmd.length() < 1) {
            lastCommand = "";
            return getErrorText("Ignoring your empty command.");
         }
         cmd = cmd.trim();
         if (cmd.length() < 1) {
            lastCommand = "";
            return getErrorText("Ignoring your empty command.");
         }

         if (cmd.equalsIgnoreCase("quit")) {
            lastCommand = "";
            stopTimer();
            disconnect();
            return null; // handled by internal Handler
         }

         // Commands without login:

         if (cmd.equalsIgnoreCase("time")) {
            lastCommand = cmd;
            return ""+new java.util.Date()+CRLF;
         }

         if (cmd.toUpperCase().startsWith("MEM")) {
            lastCommand = cmd;
            Runtime rt = Runtime.getRuntime();
            return ""+rt.totalMemory()+"/"+rt.freeMemory()+CRLF;
         }

         StringTokenizer st = new StringTokenizer(cmd, " ");
         if (!st.hasMoreTokens()) {
            lastCommand = cmd;
            return getErrorText("Ignoring your empty command.");
         }
         String cmdType = st.nextToken();
         cmdType = cmdType.trim();

         if (!st.hasMoreTokens()) {
            if (cmdType.equalsIgnoreCase("GET") ||
                cmdType.equalsIgnoreCase("SET") ||
                cmdType.equalsIgnoreCase("CONNECT")) {
               lastCommand = cmd;
               return getErrorText("Ignoring your empty command '" + cmd + "'");
            }
            if (cmdType.equalsIgnoreCase("echo")) {
               lastCommand = cmd;
               return null;
            }
         }

         String query = cmd.substring(cmdType.length()).trim();

         if (cmd.equalsIgnoreCase("maxMemStr")) {
            lastCommand = cmd;
            long usedMem = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
            String freeMem = Global.byteString(Global.heapMemoryUsage-usedMem);
           
            String ret;
            if (Global.totalPhysicalMemorySize > 0) // JDK >= 1.5
               ret = "Physical RAM size is " + Global.byteString(Global.totalPhysicalMemorySize) + "," +
                  " this JVM has currently " + freeMem + " free available and may use max " + Global.byteString(Global.heapMemoryUsage) +
                  " and max " + Global.maxFileDescriptorCount + " file descriptors";
            else
               ret = "This JVM has currently " + freeMem + " free available and may use max " + Global.byteString(Global.heapMemoryUsage);
            return ret + "\r\n";
         }

         if (cmdType.equalsIgnoreCase("CONNECT")) {
            if (!st.hasMoreTokens()) {
               lastCommand = cmd;
               return getErrorText("Please give me a login name and password to connect: '" + cmd + " <name> <passwd>'");
            }
            String loginName = st.nextToken();
            if (!st.hasMoreTokens()) {
               lastCommand = cmd;
               return getErrorText("Please give me a password to connect: '" + cmd + " <passwd>'");
            }
            String passwd = st.nextToken();
            connect(loginName, passwd); // throws Exception or sets isLogin=true 
            log.info("Successful login for telnet client '" + loginName + "', session timeout is " +
                     Timestamp.millisToNice(sessionTimeout));
            lastCommand = cmd;
            return "Successful login for user " + loginName + ", session timeout is " +
                     Timestamp.millisToNice(sessionTimeout) + CRLF;
         }

         if (!isLogin) {
            lastCommand = cmd;
            return getErrorText("Please login first with 'connect <loginName> <password>'");
         }

         // Commands with login only:

         if (cmd.equalsIgnoreCase("gc")) {
            lastCommand = cmd;
            System.gc();
            return "OK\r\n";
         }

         if (cmd.toUpperCase().startsWith("EXIT")) {
            lastCommand = cmd;
            return
              "\r\nYou are going to shutdown remote JVM!\r\n"+
              "Are you sure to do this and stop xmlBlaster? (yes/no): ";
         }

         if (cmd.equalsIgnoreCase("yes")) {
            if (lastCommand.trim().startsWith("exit")) {
               System.exit(0);
            }
         }

         if (cmd.equalsIgnoreCase("no")) {
            if (lastCommand.trim().toUpperCase().startsWith("EXIT")) {
               lastCommand = "";
               return CRLF;
            }
         }

         lastCommand = "";

         if (log.isLoggable(Level.FINE)) log.fine("Invoking cmdType=" + cmdType + " query=" + query + " from '" + cmd + "'");

         if (cmdType.equalsIgnoreCase("GET")) {
            QueryKeyData keyData = new QueryKeyData(this.glob);
            keyData.setOid("__cmd:" + query);
            MsgUnit[] msgs = commandManager.get(this.addressServer, sessionId, keyData, null);
            if (msgs.length == 0) return "NO ENTRY FOUND: " + cmd + CRLF;
            StringBuffer sb = new StringBuffer(msgs.length * 40);
            for (int ii=0; ii<msgs.length; ii++) {
               MsgUnit msg = msgs[ii];
               if ("text/plain".equalsIgnoreCase(msg.getKeyData().getContentMime()))
                  sb./*append(msg.getKey()).append("=").*/append(msg.getContentStr()).append(CRLF);
               else
                  sb.append(msg.toXml());
            }
            return sb.toString() + CRLF;
         }
         else if (cmdType.equalsIgnoreCase("SET")) {
            SetReturn ret = commandManager.set(this.addressServer, sessionId, query);
            if (ret == null) return "NO ENTRY SET: " + ret.commandWrapper.getCommand() + CRLF;
            return ((ret.commandWrapper==null) ? "" : ret.commandWrapper.getCommandStripAssign() + "=") + ret.returnString + CRLF;
         }
         else {
            return null;
            //return getErrorText("Ignoring unknown command '" + cmdType + "' of '" + cmd + "'" + CRLF);
         }
      }
      catch (XmlBlasterException e) {
         if (log.isLoggable(Level.FINE)) log.fine(e.toString());
         return CRLF + e.toString() + CRLF + CRLF;
      }
   }

   private final String getErrorText(String error) {
      String text = "ERROR-XmlBlaster telnet server: " + error + CRLF;
      if (isLogin) {
         text += "Try a 'get sysprop/?user.home' or 'set logging/?org.xmlBlaster=FINE' or just 'help'" + CRLF + CRLF;
      }
      else {
         text += "Try 'help'" + CRLF + CRLF;
      }
      log.info(error);
      return text;
   }

   /**
    * Enforced by "remotecons.CommandHandlerIfc"
    */
   public String help() {
      return CRLF +
             "  XmlBlaster telnet administration" + CRLF +
             "   connect [name] [passwd]  Login with your login name and password" + CRLF +
             "   get [query]              Get property or xmlBlaster state" + CRLF +
             "   set [query]              Set a property or change xmlBlaster setting" + CRLF +
             "   time                     Display current time on server" + CRLF +
             "   gc                       Run System.gc() command on remote system" + CRLF +
             "   mem [total|free]         Display amount of memory on remote system" + CRLF +
             "   maxMemStr                Display amount of memory on remote system" + CRLF +
             "   exit                     Call System.exit(0) on remote system" + CRLF +
             "  For query syntax see" + CRLF +
             "  http://www.xmlblaster.org/xmlBlaster/doc/requirements/admin.telnet.html" + CRLF +
             "  http://www.xmlblaster.org/xmlBlaster/doc/requirements/admin.commands.html" + CRLF + CRLF;
   }
   /**
    * Enforced by "remotecons.CommandHandlerIfc"
    */
   public String help(String cmd) {
      return "";
   }

   public CommandHandlerIfc getInstance() {
      //log.error(ME, "DEBUG ONLY: Entering getInstance(isShutdown="+isShutdown+", port="+this.port+")");
      if (isShutdown) return this; // Called on shutdown, we need to investigate and redesign the whole baby

      if (this.port <= 1000) {
         return null;
      }

      //!!!! register to CommandManager as it needs to destroy the timer?? what in cluster env?

      TelnetGateway telnetGateway = new TelnetGateway();
      telnetGateway.initializeVariables(glob, commandManager, false);
      this.telnetInstancesSet.add(telnetGateway);
      return telnetGateway;
   }

   public String getName() {
      return "TelnetGateway";
   }

   /**
    * Login to xmlBlaster server.
    */
   public void connect(String loginName, String passwd) throws XmlBlasterException {
      if (log.isLoggable(Level.FINER)) log.finer("Entering login(loginName=" + loginName/* + ", qos=" + qos_literal */ + ")");

      if (loginName==null || passwd==null) {
         log.severe("login failed: please use no null arguments for login()");
         throw new XmlBlasterException(this.glob, ErrorCode.USER_ILLEGALARGUMENT, ME + ".connect", "login failed: please use 'connect loginName password'");
      }

      org.xmlBlaster.client.qos.ConnectQos clientConnectQos = new org.xmlBlaster.client.qos.ConnectQos(glob, loginName, passwd);
      clientConnectQos.setSessionTimeout(sessionTimeout);
      ConnectQosServer connectQos = new ConnectQosServer(glob, clientConnectQos.getData());
      this.addressServer = new AddressServer(glob, "NATIVE", glob.getId(), (java.util.Properties)null);
      connectQos.setAddressServer(this.addressServer);
      this.connectRetQos = glob.getAuthenticate().connect(connectQos);
      this.loginName = loginName;
      this.sessionId = connectRetQos.getSecretSessionId();
      isLogin = true;

      if (connectQos.getSessionTimeout() > 0L) {
         stopTimer();
         if (log.isLoggable(Level.FINE)) log.fine("Setting expiry timer for " + loginName + " to " + connectQos.getSessionTimeout() + " msec");
         timerKey = this.glob.getTelnetSessionTimer().addTimeoutListener(this, connectQos.getSessionTimeout(), null);
      }
      else
         log.info("Session for " + loginName + " lasts forever, requested expiry timer was 0");
   }

   public void shutdown() {
      //Thread.currentThread().dumpStack();
      if (log.isLoggable(Level.FINER)) log.finer("Invoking shutdown()");
      isLogin = false;
      if (this.glob.hasTelnetSessionTimer()) {
         stopTimer();
         this.glob.removeTelnetSessionTimer();
      }
      disconnect();
      if (this.telnetInstancesSet != null) {
         Iterator it = telnetInstancesSet.iterator();
         while(it.hasNext()) {
            TelnetGateway gw = (TelnetGateway)it.next();
            gw.shutdown();
         }
         this.telnetInstancesSet.clear();
         //telnetInstancesSet = null;
      }
      if (rs != null) {
         rs.disable();
         rs = null;
         if (log.isLoggable(Level.FINE)) log.fine("Shutdown done, telnet disabled.");
      }
      isShutdown = true;
   }

   /**
    * Dump state of this object into a XML ASCII string.
    */
   public final String toXml() {
      return toXml((String)null);
   }

   /**
    * Dump state of this object into a XML ASCII string.
    * @param extraOffset indenting of tags for nice output
    */
   public synchronized final String toXml(String extraOffset) {
      StringBuffer sb = new StringBuffer(1024);
      String offset = "\n ";
      if (extraOffset == null) extraOffset = "";
      offset += extraOffset;

      sb.append(offset).append("<telnetGateway");
      sb.append(" port='").append(this.port).append("'");
      sb.append(" loginName='").append(this.loginName).append("'");
      sb.append(" numInstances='").append((this.telnetInstancesSet != null)?this.telnetInstancesSet.size():0).append("'");
      sb.append(">");
      if (this.glob.hasTelnetSessionTimer()) {
         sb.append(offset).append(" <hasTimer/>");
      }
      sb.append(offset).append("</telnetGateway>");

      return sb.toString();
   }
}
TOP

Related Classes of org.xmlBlaster.engine.admin.extern.TelnetGateway

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.