# ReportWebServer.java

    /*
    ** Module   : ReportWebServer.java
    ** Abstract : Jetty-based web server for FWD Analytics web application.
    **
    ** Copyright (c) 2017-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------Description----------------------------------
    ** 001 ECF 20170418 First version.
    ** 002 TJD 20240506 Support for JS dependencies upgrades
    ** 003 ICP 20240722 Modified shutdown hook registration.
    */
    /*
    ** 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.report.server;

    import java.util.logging.*;

    import javax.servlet.http.HttpServletRequest;

    import com.goldencode.p2j.main.OrderedShutdownHooks;
    import org.eclipse.jetty.server.Request;
    import org.eclipse.jetty.server.handler.*;
    import org.eclipse.jetty.util.resource.Resource;

    import com.goldencode.p2j.cfg.*;
    import com.goldencode.p2j.web.*;

    /**
     * Secure, Jetty-based web server for FWD Analytics web application.
     */
    public final class ReportWebServer
    extends SecureWebServer
    {
       private static final String THIRD_PARTY_LIBRARY_FOLDER = "/3pl";
       static
       {
          OrderedShutdownHooks.registerShutdownHook(1, new AutoExport());

          // register service APIs
          ReportProtocol.registerRequestApi(ReportApi.class);
          ReportProtocol.registerRequestApi(CallGraphApi.class);
          ReportProtocol.registerRequestApi(AstApi.class);
          ReportProtocol.registerRequestApi(SourceListingApi.class);
       }

       /**
        * Constructor.
        *
        * @param   port
        *          Port number on which to listen.
        * @param   ksFileName
        *          Key store file name.
        * @param   ksPassword
        *          Key store password.
        * @param   kePassword
        *          Key entry password.
        */
       private ReportWebServer(int port, String ksFileName, String ksPassword, String kePassword)
       throws Exception
       {
          super(ksFileName, ksPassword, kePassword);

          // static content handler

          ResourceHandler rootHandler = new ResourceHandler();
          rootHandler.setDirectoriesListed(false);
          rootHandler.setWelcomeFiles(new String[] {"index.html"});

          ContextHandler rootContext = new ContextHandler();
          rootContext.setContextPath("/");
          rootContext.setBaseResource(Resource.newClassPathResource("com/goldencode/p2j/report/web/res"));
          rootContext.setHandler(rootHandler);

          addHandler(rootContext);
          addHandler(new DojoToolkitHandler());
          addHandler(new HandlerCollection(
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/bootstrap", "META-INF/resources/webjars/bootstrap/3.4.1"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/d3", "META-INF/resources/webjars/d3/4.13.0/build"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/jquery", "META-INF/resources/webjars/jquery/3.7.1"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/jquery-ui", "META-INF/resources/webjars/jquery-ui/1.13.2"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/cbtree", "cbtree-v0.9.4-0"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/adamwdraper-numeral-js", "adamwdraper-Numeral-js-7de892f"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/webcola", "webcola"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/jquery-loading-overlay", "jquery-loading-overlay-1.5.3"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/virtualscroller", "virtualscroller-1"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/webcola", "webcola"),
                new WebResourceHandler(THIRD_PARTY_LIBRARY_FOLDER, "/tabulator", "tabulator-master-2.12.0")));

          // add web socket handler
          BootstrapConfig config = new BootstrapConfig();
          config.setConfigItem("client", "web", "maxTextMessage", "65536");
          config.setConfigItem("client", "web", "maxBinaryMessage", "65536");
          config.setConfigItem("client", "web", "maxIdleTime", "36000000");  // 10 hours
          setBootstrapConfig(config);
          this.addWebSocketHandler("/api", ReportProtocol.class);

          // default handler
          addHandler(new DefaultHandler());

          startup(null, port);
          join();
       }

       /**
        * Command line interface to launch web server.
        *
        * @param   args
        *          Required arguments.
        *          <ul>
        *          <li>{@code -port <port number>}: provide port number on which to listen.</li>
        *          <li>{@code -ks <key store file>}: provide key store file name.</li>
        *          <li>{@code -kspw <key store password>}: provide key store password.</li>
        *          <li>{@code -kepw <key entry password>}: provide key entry password.</li>
        *          </ul>
        */
       public static void main(String[] args)
       {
          try
          {
             int port = SecureWebServer.DEFAULT_PORT;
             String ks = "";
             String kspw = "";
             String kepw = "";

             for (int i = 0; i < args.length; i++)
             {
                // test if there is at least 1 more arg string after this one
                if ((i + 1) != args.length)
                {
                   // process options that have a passed value
                   if ("-port".equals(args[i]))
                   {
                      String portArg = args[++i];
                      try
                      {
                         port = Integer.parseInt(portArg);
                      }
                      catch (NumberFormatException nfe)
                      {
                         LOG.warning(
                            String.format("NumberFormatException '%s' cannot be parsed as an integer.",
                                          portArg));
                      }
                   }
                   else if ("-ks".equals(args[i]))
                   {
                      ks = args[++i];
                   }
                   else if ("-kspw".equals(args[i]))
                   {
                      kspw = args[++i];
                   }
                   else if ("-kepw".equals(args[i]))
                   {
                      kepw = args[++i];
                   }
                }
             }

             new ReportWebServer(port, ks, kspw, kepw);
          }
          catch (Exception exc)
          {
             LOG.log(Level.SEVERE, exc.getMessage(), exc);
          }
       }

    }