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;
      }
   }
}