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

}