# ClientDriver.java

    /*
    ** Module   : ClientDriver.java
    ** Abstract : general purpose client command line driver
    **
    ** Copyright (c) 2005-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- --JPRM-- ----------------------------------Description-----------------------------------
    ** 001 NVS 20050827   @22390 Created this production level client driver.
    ** 002 NVS 20060110   @23849 Now the omission of the application key is allowed and causes
    **                           StandardClient to be used.
    ** 003 GES 20060815   @28609 Refactored to remove duplicate code and share a common base class.
    ** 004 NVS 20061017   @30459 Switched to using connect() method instead of a callback approach.
    ** 005 GES 20061215   @31705 Changes in bootstrap config interface.
    ** 006 GES 20070111   @31780 Hard coded CHUI client processing here and removed some unnecessary
    **                           processing/dead code.
    ** 007 GES 20070112   @31811 Removed initial debug level (it wasn't being used downstream) and
    **                           added application args.
    ** 008 GES 20070115   @31826 Added support for conversation mode.
    ** 009 EVL 20070609   @34005 Adding explicit import of the class com.goldencode.p2j.net.Queue
    **                           to eliminate conflict with the same class from java.util package
    **                           to be able to compile for Java 6.
    ** 010 ECF 20071101   @35890 Refactored to accommodate net package mods. Eliminated
    **                           ClientBootstrap dependencies, integrated SessionManager.
    ** 011 GES 20080409   @37911 Initialize remote directory access after the session is started.
    ** 012 GES 20090720   @43239 Better error handling for throwables.
    ** 013 GES 20090723   @43356 More error handling improvements and docs.
    ** 014 GES 20091103   @44304 Added a logging facility for detailed debugging.
    ** 015 GES 20110928          Moved core logic into a common class so it can be easily shared.
    ** 016 MAG 20140131          For web clients redirect the stderr to a file.
    ** 017 MAG 20140224          For batch clients redirect the stderr to a file.
    ** 018 MAG 20140707          Implements remote launcher (broker) a special P2J client.
    ** 019 GES 20141228          Rework to eliminate application arguments and to extend the client
    **                           parameters to more use cases.
    ** 020 EVL 20160225          Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
    ** 021 GES 20210827          Added driver name initialization and diagnostics output.
    **     GES 20211004 Changed log file name timestamp replacement to be a sortable date instead of millis.
    **     EVL 20211222          Added implementation to get client driver options from server via socket.
    **     HC  20220307          Added net:http_client:disable_ssl_certificate_validation to allow disabling of SSL
    **                           certificate validation on HTTPS client connections.
    **     GBB 20221209          Path to the background process stderr log file to be read from configs.
    ** 022 GBB 20230512          Logging methods replaced by CentralLogger/ConversionStatus.
    ** 023 GBB 20230825          Adding an uncaught exceptions handler that logs before delegating to the
    **                           default one.
    ** 024 HC  20240222          Enabled JMX on FWD Client.
    ** 025 GBB 20240404          Close native Win terminal on ClientCore throwing exception.
    ** 026 GBB 20240415          Catch IllegalStateException on console termination (in Windows).
    ** 027 GBB 20240709          Removing methods related to receiving client options via socket.
    ** 028 GBB 20240729          Initialize CentralLogger after SecurityManager is created.
    ** 029 GBB 20240826          Removing single client.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.main;

    import com.goldencode.p2j.jmx.*;
    import com.goldencode.p2j.ui.chui.*;
    import com.goldencode.p2j.ui.client.chui.driver.console.*;
    import com.goldencode.p2j.ui.client.driver.*;
    import com.goldencode.p2j.util.*;
    import java.io.*;
    import java.net.Socket;
    import java.util.*;

    import com.goldencode.p2j.cfg.*;
    import com.goldencode.p2j.util.logging.*;
    import com.goldencode.util.*;

    import javax.management.*;

    /**
     * General purpose command line driver to start a client process based on a bootstrap
     * configuration file and/or command line parameters.
     * <p>
     * This driver performs a single logon to the server, invokes the application class and exits,
     * when the latter is done.
     * <p>
     * Configuration file can be plain (unencrypted) XML file or encrypted XML. If no password is
     * given with the command line, the file is assumed to be plain XML.
     * <p>
     * Zero, one or two configuration files can be given as parameters along with their respective
     * passwords. If not specified, it will default to "standard_client.xml" in the current
     * directory.
     * <p>
     * The two file approach is recommended as it allows for a natural way of separating common or
     * related configuration information (for all users or a group of users, normally supplied in the
     * first file), from the user-specific configuration information (usually supplied in the second
     * file). By merely specifying a different second file, another subject can use the application
     * while sharing the first configuration file.
     * <p>
     * All entries in the bootstrap configuration can be overridden by a command line parameter using
     * the "category:group:key=value" syntax (see below).
     * <p>
     * The full syntax of the command line is:
     * <p>
     * <code>
     * java ClientDriver [-?]
     *                   [<i>config1</i>]
     *                   [-p <i>config1_file_password</i>]
     *                   [<i>config2</i>]
     *                   [-p <i>config2_file_password</i>]
     *                   [-d <i>initial_debuglevel</i>]
     *                   [[[category:]group:]key=value]...
     * </code>
     * <p>
     * where arguments can be specified in any order.  The first password specified will be used
     * with the first config file specified and likewise with the second password and config file
     * respectively.
     * <p>
     * '-?' requests syntax help and exits.
     * <p>
     * Password can be given with the command line or entered interactively. One special value can
     * be used: "?" (which causes an interactive password prompt to be displayed).
     * <p>
     * Arguments in the form "category:group:key=value" are bootstrap configuration overrides. They
     * may be used to add or change values of the configuration keys in the specified category and
     * group. A short form of override (one that omits the category and group) is allowed after a
     * long form override and refers to the most recently specified category and group.
     */
    public class ClientDriver
    extends CommonDriver
    {
       /** Logger. Should be instantiated after setting the logger to client mode. */
       private static CentralLogger LOG;

       {
          // initialize our protected members

          driverName = "ClientDriver";
          defCfg = "standard_client.xml";
          maxCfg = 2;

          helptxt = new String[]
          {
             "-----------------------P2J Client Driver-----------------------",
             "",
             "Syntax:",
             "",
             "java ClientDriver -?",
             "                  [config1]",
             "                  [-p config1_file_password]",
             "                  [config2]",
             "                  [-p config2_file_password]",
             "                  [-d initial_debug_level]",
             "                  [parameter_overrides]",
             "",
             "Where:",
             "",
             "-?                    = displays this help screen",
             "config                = a relative or absolute filename of a valid",
             "                        bootstrap configuration file for this",
             "                        client",
             "config_file_password  = the password to use to decrypt the config",
             "                        file or '?' to force an interactive",
             "                        password prompt",
             "initial_debug_level   = an integer value that specifies the",
             "                        logging that should occur before server's",
             "                        main configuration (in the directory) can",
             "                        be read",
             "parameter_overrides   = configuration values that add to or",
             "                        replace values that can be specified in",
             "                        the bootstrap configuration; the override",
             "                        must take one of three forms:",
             "                           category:group:key=value",
             "                           group:key=value",
             "                           key=value",
             "                        (the shorter forms will use the most",
             "                        recently specified category and/or group",
             "                        as needed)",
             "",
             "All arguments can be specified in any order except '-?' which must",
             "always appear first. The first password specified will be used with ",
             "the first config file specified and likewise with the second password ",
             "and config file respectively."
          };
       }

       /**
        * Allows a subclass to check if the given configuration matches any
        * required values.  Edits may be made if needed.
        *
        * @param    bc
        *           The configuration to be checked.
        */
       protected void checkConfig(BootstrapConfig bc)
       {
          bc.setServer(false);

          String convo = null;

          try
          {
             convo = bc.getConfigItem("net", "queue", "conversation");
          }

          catch (ConfigurationException ce)
          {
             // ignore
          }

          // default to conversation mode if not specified
          if (convo == null)
          {
             bc.setConfigItem("net", "queue", "conversation", "true");
          }

          // either way, force start thread to false (this client is going to
          // use its main thread as the conversation thread so we don't need
          // to start one
          bc.setConfigItem("net", "queue", "start_thread", "false");
       }

       /**
        * Runs the primary application using the preprocessed configuration and
        * target object.
        *
        * @param    config
        *           The configuration to use.
        */
       protected void start(BootstrapConfig config)
       throws Exception
       {
          if (config.getBoolean("net", "http_client", "disable_ssl_certificate_validation", false))
          {
             Utils.disableClientSSLCertificateValidation();
          }

          if (config.getBoolean("client", "mode", "broker", false))
          {
             BrokerCore.start(config);
          }
          else
          {
             try
             {
                ClientCore.start(config, this::printDriverDetails);
             }
             catch (Throwable t)
             {
                if (PlatformHelper.isUnderWindowsFamily() &&
                   ThinClient.getInstance().getOutputManager().getInstanceDriver() instanceof ConsoleDriver)
                {
                   try
                   {
                      ConsoleHelper.terminate();
                   }
                   catch (Throwable nativeThrowable)
                   {
                      LOG.info("ConsoleHelper.terminate() execution has thrown an exception:", nativeThrowable);
                   }
                }
                throw  t;
             }
          }

          // ensure that remaining non-daemon threads don't stop us from closing
          System.exit(0);
       }

       /**
        * The command line entry point.
        *
        * @param     args
        *            The array of command-line parameters.
        */
       public static void main(String[] args)
       {
          CentralLogger.setMode(CentralLogger.Mode.CLIENT_BASE);
          LOG = CentralLogger.get(ClientDriver.class);

          setDefaultExceptionHandler(LOG);

          FwdClientJMX.init();

          ClientDriver client = new ClientDriver();

          // after our parent class processes the command line arguments, if there are no errors,
          // then the start() method will be called
          client.process(args);
       }
    }