HtmlResourceHandler.java

/*
** Module   : HtmlResourceHandler.java
** Abstract : delivers main page to AJAX clients
**
** Copyright (c) 2013-2023, Golden Code Development Corporation.
**
** -#- -I- --Date-- ----------------------Description--------------------------
** 001 MAG 20131105 First version based on jetty 9.1
** 002 MAG 20140206 Set Cache-Control header.
** 003 SBI 20180405 Changed to use template key and value provider.
** 004 SBI 20191120 Changed to specify UTF-8 encoding to read html templates.
** 005 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
*/
/*
** 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.web;

import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.logging.*;

import javax.servlet.*;
import javax.servlet.http.*;

import com.goldencode.p2j.util.logging.*;
import org.eclipse.jetty.http.*;
import org.eclipse.jetty.server.handler.*;
import org.eclipse.jetty.server.*;

import com.goldencode.p2j.util.*;

/**
 * jetty Handler which delivers HTML resource files.
 * This class provide a method to parse the HTML text and
 * substitute placeholder's. 
 */
public abstract class HtmlResourceHandler
extends AbstractHandler
{
   /** Logger. */
   private static final CentralLogger LOG = CentralLogger.get(HtmlResourceHandler.class.getName());

   /** The root portion of the target request name (part of the URL). */
   private String targetRoot = null;
   
   /** The html skeleton page. */
   private String skeletonPage = null;
   
   /**
    * Constructor.
    *
    * @param    targetRoot
    *           Prefix for all URLs relating to this page.
    * @param    skeletonPage
    *           Fully qualified resource name of the HTML file which should be used.
    */
   public HtmlResourceHandler(String targetRoot, String skeletonPage)
   {
      this.targetRoot   = targetRoot;
      this.skeletonPage = skeletonPage;
   }
   
   /**
    * Return the main page for AJAX clients.
    *    
    * @param   target 
    *          The target of the request - either a URI or a name.
    * @param   base
    *          The base request.
    * @param   request
    *          The object or a wrapper of the request.
    * @param   response 
    *          The object or a wrapper of the response. 
    */
   public void handle(String              target, 
                      Request             base,
                      HttpServletRequest  request, 
                      HttpServletResponse response)
   throws IOException, 
          ServletException
   {
      if (!base.isHandled() && target.equalsIgnoreCase(targetRoot))
      {
         generateMainPage(base, response);
      }
   }
      
   /**
    * Use the skeleton main page to generate a response.
    *
    * @param   base
    *          The details and state the request.
    * @param   response 
    *          The details and state of the response.
    *           
    * @throws  IOException
    *          ServletException
    *          If any error conditions occur.
    */
   private void generateMainPage(Request base, HttpServletResponse response)
   throws IOException, 
          ServletException
   {
      // produce the page contents
      response.setContentType(MimeTypes.Type.TEXT_HTML.asString());
      response.setStatus(HttpServletResponse.SC_OK);
      response.setHeader(HttpHeader.CACHE_CONTROL.asString(), 
                         "no-cache, no-store, must-revalidate");
      response.setDateHeader(HttpHeader.EXPIRES.asString(), 0); // Proxies.      
      
      PrintWriter writer = response.getWriter();
      
      Map<String, Supplier<String>> templateKeys = getTemplateKeys(base);
      
      try
      {
         InputStream is = this.getClass().getResourceAsStream(skeletonPage);
         
         TemplateHelper.fill(is, templateKeys, writer, "UTF-8");
      }
      catch (IOException ioe)
      {
         LOG.logp(Level.SEVERE,
                  "HtmlResourceHandler.generateMainPage()",
                  "",
                  "IOException!",
                  ioe);
      }
      finally
      {
         // mark the request as handled
         base.setHandled(true);
      }
   }
   
   /**
    * Generates a map of template keys with their value suppliers in order to fill gaps in
    * the html skeleton template page.
    * 
    * @param    base
    *           The request
    * 
    * @return   The target map of template keys with their value suppliers
    */
   protected abstract Map<String, Supplier<String>> getTemplateKeys(Request base);
   
   
   /**
    * Holds a map of template keys with their value suppliers.
    */
   protected class HtmlTemplateKeysProvider
   {
      /** The map of template keys with their value suppliers */
      private final Map<String, Supplier<String>> templateKeys;

      /** The request */
      private final Request request;

      /**
       * Creates this html template keys provider.
       * 
       * @param    request
       *           The request
       */
      public HtmlTemplateKeysProvider(Request request)
      {
         this.request = request;
         this.templateKeys = new HashMap<>();
      }

      /**
       * Returns the request associated with this html template keys provider.
       * 
       * @return   The request
       */
      public Request getRequest()
      {
         return request;
      }

      /**
       * Returns the map of template keys with their value suppliers.
       * 
       * @return   The map of template keys with their value suppliers
       */
      public Map<String, Supplier<String>> getTemplateKeys()
      {
         return templateKeys;
      }

      /**
       * Add new key and its value provider.
       * 
       * @param    key
       *           The key
       * @param    getter
       *           The value provider
       */
      public void add(String key, Supplier<String> getter)
      {
         templateKeys.put(key, getter);
      }
   }
}