# WebClientBuilder.java

    /*
    ** Module   : WebClientBuilder.java
    ** Abstract : build and start a process for the web client
    **
    ** Copyright (c) 2014-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------Description----------------------------------
    ** 001 CA  20140206 First version, extracted from ClientBuilder.
    ** 002 MAG 20140711 Enable/Disable clipboard.
    ** 003 MAG 20140722 Implement remote launcher.
    ** 004 GES 20150312 Added support for the GUI web client.
    ** 005 GES 20150710 Modified/added configuration processing for GUI, clipboard flag is ChUI-only.
    ** 006 CA  20160205 Changed to use ServerKeyStore.getStore().
    ** 007 GES 20160203 Added trusted mode support.
    **     SBI 20160321 Added maxBinaryMessage, maxTextMessage, maxIdleTime websocket's parameters
    **                  and set the web client embedded mode "client:web:embedded".
    ** 008 CA  20160428 Added command-line configuration options for web-clients.
    ** 009 SBI 20160427 Added graphicsCached parameter to turn off the graphics cache for testing.
    ** 010 HC  20201116 Added renderer web client option.
    **     SBI 20210331 Added client:gui:taskBarStyle.
    **     SBI 20210514 Added delayBetweenTriesToConnect, tryToConnectMessage and serverUnavailableMessage
    **         20210516 Added pingPongInterval, maxLostPings and delayBetweenPingTries.
    **         20210517 Added connectionRestoredMessage.
    **         20210914 Added enableDebugLogging.
    **     SBI 20211003 Added http configuration settings for the web client.
    **     EVL 20211222 Added implementation to pass options to client driver from server via socket.
    **     EVL 20220105 Improvements for Windows specific options passing via socket for web client.
    **     TJD 20220527 Support for text-metrics cache controlled by server
    ** 011 SBI 20230306 Changed remoteStart by adding new parameters to perform allocation of network ports
    **                  for spawned clients.
    ** 012 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
    ** 013 GBB 20230825 Cleanup for client:web:embedded.
    ** 014 GBB 20231101 Adding new option client:web:useLocalStorage from directory configs.
    ** 015 GBB 20231113 Cleanup for web:referrer:url. Adding new option client:web:broadcastChannelPingTimeout.
    ** 016 GBB 20240709 Removing fields and methods for sending options via temp socket. Instead of adding the
    **                  options to cmd in addClientOptions create PostInitOptions wrapper and store it in map
    **                  UUID_OPTIONS for later retrieval by the client. The logic for creating the bootstrap
    **                  override values moved to WebClientSpawner.prepareBootstrapValues.
    ** 017 GBB 20240719 Null check for project token.
    ** 018 GBB 20240730 Get the project token from the web parameters instead of resolving each time.
    ** 019 CA  20250221 Added constants for the spawner modes.
    */
    /*
    ** 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 java.util.*;

    import com.goldencode.p2j.util.*;

    /**
     * This class is used to create and spawn a web client process using a {@link ProcessBuilder}
     * instance.  A special small tools are designed for Linux / Windows OS in order to spawn the
     * process on the OS user account.  Both tools are written in C using specific OS API and are
     * build as executable using ant native target.  The source code and the make file for this tools
     * are available in the /src/native process directory.  The password is provided vis stdin
     * redirection on both platforms.  The command line parameters for the spawned process are
     * constructed from default parameters stored in directory and some specific parameters stored
     * inside a {@link WebClientBuilderParameters} structure.
     */
    public class WebClientBuilder
    extends ClientBuilder
    {
       /** Map of client uuid and options. */
       static final Map<String, PostInitOptions> UUID_OPTIONS = new HashMap<>();

       /** A Java Bean containing specific parameters */
       private final WebClientBuilderParameters params;

       /**
        * Constructor.
        *
        * @param   params
        *          The specific parameters for this client.
        */
       public WebClientBuilder(WebClientBuilderParameters params)
       {
          this.params = params;
       }

       /**
        * Returns the {@link WebClientBuilderParameters} used for building the client.
        *
        * @return   See above.
        */
       @Override
       public WebClientBuilderParameters getParams()
       {
          return params;
       }

       /**
        * Prepares options to be sent to the client after a session is established. Don't use for options
        * critical for initial client configuration.
        */
       @Override
       protected void addClientOptions()
       {
          WebClientBuilderOptions dirOptions = params.getDirOptions();
          if (dirOptions.getProjectToken() != null)
          {
             command.add(ConfigItem.PROJECT_TOKEN.fullOption() + "=" + dirOptions.getProjectToken());
          }

          if (params.getSsoFwdUser() != null)
          {
             command.add(ConfigItem.SSO_SUBJECT_ID.fullOption() + "=" + params.getSsoFwdUser());
          }
          if (params.getStorageId() != null)
          {
             command.add(ConfigItem.SSO_STORAGE_ID.fullOption() + "=" + params.getStorageId());
          }

          UUID_OPTIONS.put(this.params.getUuid(), new PostInitOptions(dirOptions.getDriverType(),
                                                                      remote,
                                                                      dirOptions.getOverriddenOptions(),
                                                                      params.getFirstWebOverrides(),
                                                                      params.getDirWebOverrides(),
                                                                      params.getRuntimeWebOverrides(),
                                                                      params.getLastWebOverrides()));
       }

       /**
        * Get the spawn arguments.  Web chui clients call the {@code spawn} tool using the
        * {@code spawn 0 <user> <workdir> <command> [args]} syntax.
        * <p>
        * As these arguments are already built into the {@link ClientBuilder#command} list, it just
        * returns the already build list with a "1" prefix.
        *
        * @return   See above.
        */
       @Override
       protected List<String> getSpawnArguments()
       {
          List<String> cmd = new ArrayList<>();

          if (params.isTrusted())
          {
             // mode 0 (passwordless/trusted, uses the NativeSecureConnection)
             initNativeSecureConnection(cmd);
          }
          else
          {
             // add mode 1 (userid/password authentication at OS level)
             cmd.add(ClientSpawner.MODE_AUTH_PASSWORD);
          }

          // the entire command
          cmd.addAll(command);

          return cmd;
       }

       /**
        * A wrapper class for all configurations applicable to the specific request for client spawn, that
        * need to be applied after the client is initialized.
        */
       static class PostInitOptions
       {
          /** The web driver type. */
          private WebDriverType driverType;

          /** Indicator for a remote spawn. */
          private boolean remote;

          /** The map of runtime derived options. */
          private Map<String, String> runtimeOptions;

          /** The bootstrap config overrides to be applied first. Lowest priority. */
          private List<String> firstWebOverrides;

          /** The bootstrap config overrides coming from directory. */
          private List<String> dirWebOverrides;

          /** The bootstrap config overrides compiled runtime. */
          private List<String> runtimeWebOverrides;

          /** The bootstrap config overrides to be applied last. Highest priority. */
          private List<String> lastWebOverrides;

          /**
           * Constructor.
           *
           * @param   driverType
           *          The web driver type.
           * @param   remote
           *          Indicator for a remote spawn.
           * @param   runtimeOptions
           *          The map of runtime derived options.
           * @param   firstWebOverrides
           *          The bootstrap config overrides to be applied first. Lowest priority.
           * @param   dirWebOverrides
           *          The bootstrap config overrides coming from directory.
           * @param   runtimeWebOverrides
           *          The bootstrap config overrides compiled runtime.
           * @param   lastWebOverrides
           *          The bootstrap config overrides to be applied last. Highest priority.
           */
          PostInitOptions(WebDriverType driverType,
                          boolean remote,
                          Map<String, String> runtimeOptions,
                          List<String> firstWebOverrides,
                          List<String> dirWebOverrides,
                          List<String> runtimeWebOverrides,
                          List<String> lastWebOverrides)
          {
             this.driverType = driverType;
             this.remote = remote;
             this.runtimeOptions = runtimeOptions;
             this.firstWebOverrides = firstWebOverrides;
             this.dirWebOverrides = dirWebOverrides;
             this.runtimeWebOverrides = runtimeWebOverrides;
             this.lastWebOverrides = lastWebOverrides;
          }

          /**
           * Getter for {@link #driverType}.
           *
           * @return  See above.
           */
          public WebDriverType getDriverType()
          {
             return driverType;
          }

          /**
           * Getter for {@link #remote}.
           *
           * @return  See above.
           */
          public boolean getRemote()
          {
             return remote;
          }

          /**
           * Getter for {@link #runtimeOptions}.
           *
           * @return  See above.
           */
          public Map<String, String> getRuntimeOptions()
          {
             return runtimeOptions;
          }

          /**
           * Returns all bootstrap overrides merged in the right order. Uses the directory values, stored
           * on receiving the spawn request.
           *
           * @return  See above.
           */
          public List<String> getWebOverrides()
          {
             return getWebOverrides(dirWebOverrides);
          }

          /**
           * Returns all bootstrap overrides merged in the right order. Uses the directory values provided as
           * parameter (could be a list created after the project token is set).
           *
           * @param   dirOverrides
           *          The bootstrap overrides derived from directory values to be used in the final list.
           *
           * @return  See above.
           */
          public List<String> getWebOverrides(List<String> dirOverrides)
          {
             List<String> allWebOverrides = new ArrayList<>();
             if (firstWebOverrides != null)
             {
                allWebOverrides.addAll(firstWebOverrides);
             }
             if (dirOverrides != null)
             {
                allWebOverrides.addAll(dirOverrides);
             }
             if (runtimeWebOverrides != null)
             {
                allWebOverrides.addAll(runtimeWebOverrides);
             }
             if (lastWebOverrides != null)
             {
                allWebOverrides.addAll(lastWebOverrides);
             }
             return allWebOverrides;
          }
       }
    }