001/*
002 *  $Id: MulaAjaxRestListener.java 997 2015-08-21 00:06:40Z tgutwin $
003 *  $HeadURL:  $
004 *  $Revision: 997 $
005 *  $LastChangedDate: 2015-08-20 17:06:40 -0700 (Thu, 20 Aug 2015) $
006 *  $LastChangedBy: tgutwin $
007 *  Copyright (c) 2014-2015 Tom B. Gutwin P.Eng. North Vancouver BC Canada
008 *
009 *  This program is free software; you can redistribute it and/or
010 *  modify it under the terms of the GNU General Public License
011 *  as published by the Free Software Foundation; either version 3
012 *  of the License, or any later version.
013 *
014 *  This program is distributed in the hope that it will be useful,
015 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
016 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 *  GNU General Public License for more details.
018 *
019 *  You should have received a copy of the GNU General Public License
020 *  along with this program; If not, see <http://www.gnu.org/licenses/>.
021 */
022package ca.bc.webarts.servlet;
023
024import ca.bc.webarts.tools.Log;
025import ca.bc.webarts.tools.InvestmentTrackerQuery;
026import ca.bc.webarts.widgets.Util;
027import ca.bc.webarts.widgets.ResultSetConverter;
028import ca.bc.webarts.tools.CategorizedStackedBarChart;
029
030import com.oreilly.servlet.ParameterParser;
031import com.oreilly.servlet.ParameterNotFoundException;
032import com.oreilly.servlet.ServletUtils;
033
034import java.text.DecimalFormat;
035import java.io.BufferedReader;
036import java.io.File;
037import java.io.FileNotFoundException;
038import java.io.FileOutputStream;
039import java.io.FileReader;
040import java.io.FileWriter;
041import java.io.FileInputStream;
042import java.io.IOException;
043import java.io.InputStream;
044import java.io.OutputStream;
045import java.net.InetAddress;
046import java.net.MalformedURLException;
047import java.net.URL;
048import java.net.UnknownHostException;
049import java.util.Calendar;
050import java.util.Date;
051import java.util.Enumeration;
052import java.util.TimeZone;
053import java.util.zip.ZipEntry;
054import java.util.zip.ZipOutputStream;
055
056import javax.servlet.*;
057import javax.servlet.http.*;
058
059import org.jfree.chart.servlet.ServletUtilities;
060import org.jfree.chart.plot.PlotOrientation;
061import org.jfree.chart.ChartRenderingInfo;
062import org.jfree.data.category.CategoryDataset;
063import org.jfree.chart.JFreeChart;
064import org.jfree.chart.entity.StandardEntityCollection;
065
066//import javax.json.Json;
067
068/**
069 * This class is a generic listener, implemented as a servlet, for responding to AJAX and/or Rest style requests from the mula webAPP.<br />
070 *
071 * @author     tgutwin
072 * @created    April 25, 2017
073 */
074public class MulaAjaxRestListener extends HttpServlet
075{
076  // implements SingleThreadModel
077
078  /** Class constant. **/
079  protected static final String className_ = "MulaAjaxRestListener";
080  private final static String SYSTEM_FILE_SEPERATOR = File.separator;
081  /**  Version String.  */
082  private final static String SERVLET_VERSION = Util.spacesToCapsInString("0.100.RC.4_[$Rev: 1086 $]");
083
084  public static final String CLIENT_SETTING_NAME_VIEWPORTWIDTH = "clientSetting.viewPortWidth";
085  public static final String CLIENT_SETTING_NAME_VIEWPORTHEIGHT = "clientSetting.viewPortHeight";
086  public static final String CLIENT_SETTING_NAME_BROWSER_NAME = "clientSetting.browserName";
087  public static final String CLIENT_SETTING_NAME_BROWSER_VERSION = "clientSetting.browserVersion";
088  public static final String CLIENT_SETTING_NAME_DEVICE_TYPE = "clientSetting.deviceType";
089
090  /**  Build String. (yymmddhhss)  */
091  private final static String BUILD_TAG = "@$BUILD_TAG$@";
092
093  private static String webServerHostName_ = "warp4.webarts.bc.ca";
094
095  private boolean debugOut_ = true;
096  protected static Log log_= Log.getInstance();
097
098  private int viewPortWidth_ = 0;
099  private int viewPortHeight_ = 0;
100  private String someParamYouWannaSet_ = "";
101
102  /** Control for rest response format XML(default) or JSON. **/
103  private boolean xmlResponse_ = false;
104
105  /** AJAX param - **/
106  private String debugOut = "";
107  private int viewPortWidth = 0;
108  private int viewPortHeight = 0;
109  private int chartWidth = 0;
110  private int chartHeight = 0;
111  private String browserName = "";
112  private String browserVersion = "";
113  private String invetmentTrackerCall = "";
114  private String portfolioName = "";
115  private String portfolioFormat = "";
116  private boolean portfolioRefresh = false;
117  private boolean xmlResponse = xmlResponse_;
118  private InvestmentTrackerQuery itq = null;
119  private String buyStockName = "";
120  private String buyStockSymbol = "";
121  private String stockSymbol = "";
122  private String marketSymbol = "";
123  private boolean isMutualFund = false;
124  private int portfolioId = 0;
125  private String buyDate = "";
126  private double numShare = 0.0;
127  private double mrkSharePrice = 0.0;
128  private double commish = 0.0;
129  private double fee = 0.0;
130
131
132  /**
133   *  Gets the ServletInfo attribute of the MulaAjaxRestListener object
134   *
135   * @return    The ServletInfo value
136   */
137  public String getServletInfo()
138  {
139    final String methodName = "getServletInfo";
140    return "WebARTS Design MulaAjaxRestListener servlet. Version:" + SERVLET_VERSION +
141        "  Build:" + BUILD_TAG;
142  }
143
144
145  /**
146   * The one time servlet init stuff goes here. It sets the derbyDBDir based on the following prioritized varables:
147   * <ol><li>context init param: derbyDBDir</li><li>servlet init param (from web.xml): derbyDBDir</li>
148   * <li>default hardcoded variable: derbyDBDir</li></ol>If defined in multiple places, the higher priority item will
149   * be used.
150   **/
151  public void init()
152  {
153    System.out.println("\n~~~~~~~~\n~~~~~~~~\nInitializing ca.bc.webarts.servlet.MulaAjaxRestListener\n~~~~~~~~\n~~~~~~~~");
154
155    boolean notFoundInit = true;
156    boolean notFoundContext = true;
157    java.util.Enumeration <String> initEnum = getInitParameterNames();
158    for (; notFoundInit && initEnum.hasMoreElements();)
159    {
160      if(initEnum.nextElement().equals("someParamYouWannaSet"))
161      {
162        notFoundInit = false;
163        /* Do something with the init param */
164        someParamYouWannaSet_ = getInitParameter("someParamYouWannaSet");
165        System.out.println("\n~~~~~~~~\n     INIT ServletParam: someParamYouWannaSet="+someParamYouWannaSet_);
166      }
167    }
168
169    //also check context
170    initEnum = getServletConfig().getServletContext().getInitParameterNames();
171    for (; notFoundContext && initEnum.hasMoreElements();)
172    {
173      if(initEnum.nextElement().equals("someParamYouWannaSet"))
174      {
175        notFoundContext = false;
176        /* Do something with the init param */
177        someParamYouWannaSet_ = getServletConfig().getServletContext().getInitParameter("derbyDBDir");
178        System.out.println("\n~~~~~~~~\n     INIT ContextParam: someParamYouWannaSet="+someParamYouWannaSet_);
179      }
180    }
181
182    if(notFoundInit && notFoundContext )
183    {
184      /* Set the default values */
185      //eagleDBDir_ = pEye_.getDerbyDBDir();
186    }
187
188    try
189    {
190      webServerHostName_ = InetAddress.getLocalHost().getHostName();
191    }
192    catch (UnknownHostException ex)
193    {
194      webServerHostName_ = "red.webarts.bc.ca";
195    }
196  }
197
198
199  /**  Override to close Things  **/
200  public void destroy()
201  {
202    super.destroy();
203  }
204
205
206
207  /**
208   * Returns the value of viewPortWidth_.
209   */
210  public int getViewPortWidth() {
211    return viewPortWidth_;
212  }
213
214
215  /**
216   * Sets the value of viewPortWidth_.
217   * @param viewPortWidth The value to assign viewPortWidth_.
218   */
219  public void setViewPortWidth(int viewPortWidth) {
220    this.viewPortWidth_ = viewPortWidth;
221  }
222
223
224  /**
225   * Returns the value of viewPortHeight_.
226   */
227  public int getViewPortHeight() {
228    return viewPortHeight_;
229  }
230
231
232  /**
233   * Sets the value of viewPortHeight_.
234   * @param viewPortWidth The value to assign viewPortWidth_.
235   */
236  public void setViewPortHeight(int viewPortHeight) {
237    this.viewPortHeight_ = viewPortHeight;
238  }
239
240
241  /**
242   * Returns the value of debugOut_.
243   */
244  public boolean getDebugOut()
245  {
246    return debugOut_;
247  }
248
249
250  /**
251   * Sets the value of debugOut_.
252   * @param debugOut The value to assign debugOut_.
253   */
254  public void setDebugOut(boolean debugOut)
255  {
256    this.debugOut_ = debugOut;
257    log_.setLogLevel((debugOut_?log_.DEBUG:log_.MINOR));
258  }
259
260
261  /**
262    * Get Method for class field 'xmlResponse'.
263    *
264    * @return boolean - The value the class field 'xmlResponse' XML (true) or JSON (false).
265    *
266    **/
267  public boolean getXmlResponse()
268  {
269    return xmlResponse_;
270  }  // getXmlResponse Method
271
272
273  /**
274    * Set Method for class field 'xmlResponse' that controls if teh rest response is in XML (true) or JSON (false).
275    *
276    * @param xmlResponse is the value to set this class field to XML (true) or JSON (false).
277    *
278    **/
279  public  void setXmlResponse(boolean xmlResponse)
280  {
281    this.xmlResponse_ = xmlResponse;
282  }  // setXmlResponse Method
283
284
285  /**
286   * streams to a zipped out stream (without creating a file).
287   * from: http://www.coderanch.com/t/276892/java-io/java/Stream-data-ZipOutputStream
288   * @param servletOutput is the stream to zip into
289   * @param dataName are the pseudo fileName that will get created in the zip (pseudo file) stream
290   * @param dataStream the data to zip
291   **/
292  private void streamZIP(OutputStream servletOut, String dataName, InputStream dataStream)
293  {
294    String[] dataNames = {dataName};
295    InputStream[] dataStreams = {dataStream};
296    streamZIP(servletOut, dataNames,dataStreams);
297  }
298
299
300  /**
301   * streams to a zipped out stream (without creating a file).
302   * from: http://www.coderanch.com/t/276892/java-io/java/Stream-data-ZipOutputStream
303   *
304   *  Sample servlet doGet...<br />
305   *  public void doGet(HttpServletRequest request,
306                        HttpServletResponse response) throws IOException{
307        response.setContentType("text/plain");
308        response.setHeader("Content-Disposition",
309                           "attachment;filename=downloadname.txt");
310        String[] dataNames = {dataName};
311        InputStream[] dataStreams = {dataStream};
312        OutputStream os = response.getOutputStream();
313        streamZIP(servletOut, dataNames,dataStreams);
314      }
315   *
316   *
317   * @param servletOutput is the stream to zip into
318   * @param dataNames are the pseudo fileNames that will get created in the zip (pseudo file) stream
319   * @param dataStreams the data to zip
320   **/
321  private void streamZIP(OutputStream servletOut,
322                        String[] dataNames,
323                        InputStream[] dataStreams)
324  {
325    ZipOutputStream zos = new ZipOutputStream(servletOut);
326    final int DATA_BLOCK_SIZE = 2048;
327    int byteCount;
328    byte[] data;
329
330    try
331    {
332      for(int i = 0; i < dataNames.length; i++)
333      {
334        ZipEntry ze = new ZipEntry(dataNames[i]);
335        zos.putNextEntry(ze);
336        data = new byte[DATA_BLOCK_SIZE];
337
338        while((byteCount = dataStreams[i].read(data, 0, DATA_BLOCK_SIZE)) != -1)
339        {
340          zos.write(data, 0, byteCount);
341        }
342
343        zos.flush();
344        zos.closeEntry();
345        dataStreams[i].close();
346      }
347      zos.close();
348    }
349    catch(Exception e)
350    {
351      System.err.println("Problem streaming zip data " + e.toString());
352    }
353  }
354
355
356  /** Parses the REST command string and prepares the response in XML format.
357    * @param restPath is the rest command part of the rest URL
358    * @return a string holding the XML rest response
359    **/
360  private String parseRestRequest(String restPath)
361  {
362    String restResponse = null;
363    System.out.println("REST Request: " +restPath);
364    String pre = "/";
365
366    DecimalFormat dfp = new DecimalFormat( "##0" );
367    DecimalFormat dfe = new DecimalFormat( "###0.000" );
368    if(restPath.equals(pre+"power/current"))
369    {
370      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
371      sb.append("</RestResponse>");
372    }
373    else if(restPath.equals(pre+"power/recent"))
374    {
375      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
376      sb.append("</RestResponse>");
377      restResponse = sb.toString();
378    }
379    else if(restPath.equals(pre+"energy/recent"))
380    {
381      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
382      sb.append("</RestResponse>");
383      restResponse = sb.toString();
384    }
385    else if(restPath.equals(pre+"energy/current"))
386    {
387      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
388      /*  Add In the response content  */
389      sb.append("</RestResponse>");
390      restResponse = sb.toString();
391    }
392    else if(restPath.equals(pre+"price/current"))
393    {
394      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
395      /*  Add In the response content  */
396      sb.append("</RestResponse>");
397      restResponse = sb.toString();
398    }
399    else if(restPath.equals(pre+"price/label/current"))
400    {
401      StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
402      /*  Add In the response content  */
403      sb.append("</RestResponse>");
404      restResponse = sb.toString();
405    }
406    return restResponse;
407  }
408
409
410  /** Parses any defined servlet params into the defined class vars. **/
411  private void parseParams(HttpServletRequest req)
412  {
413    /* http://www.servlets.com/cos/javadoc/com/oreilly/servlet/ParameterParser.html */
414    ParameterParser parser = new ParameterParser(req);
415    if(debugOut_)
416    {
417      System.out.println("\nRequest Params:");
418      Enumeration<String> parmNames = req.getParameterNames();
419      for (; parmNames.hasMoreElements();)
420      {
421        String currParamName = (String) parmNames.nextElement();
422        System.out.println("  "+currParamName+"="+req.getParameter(currParamName));
423      }
424    }
425
426    /* parse out the request params into class vars  */
427    debugOut = parser.getStringParameter("debugOut", "");
428    viewPortWidth =  parser.getIntParameter("viewPortWidth",0);
429    viewPortHeight =  parser.getIntParameter("viewPortHeight",0);
430    chartWidth =  parser.getIntParameter("chartWidth",0);
431    chartHeight =  parser.getIntParameter("chartHeight",0);
432    browserName = parser.getStringParameter("clientBrowser","");
433    browserVersion = parser.getStringParameter("clientBrowserVersion","");
434    xmlResponse = parser.getBooleanParameter("xmlResponse",xmlResponse_);
435    invetmentTrackerCall = parser.getStringParameter("invetmentTrackerCall","");
436    portfolioName = parser.getStringParameter("portfolioName","");
437    portfolioFormat = parser.getStringParameter("portfolioFormat","");
438    portfolioRefresh = parser.getBooleanParameter("portfolioRefresh",false);
439    stockSymbol = parser.getStringParameter("stockSymbol","");
440    buyStockSymbol = parser.getStringParameter("buyStockSymbol","");
441    buyStockName = parser.getStringParameter("buyStockName","");
442    isMutualFund = parser.getBooleanParameter("isMutualFund",false);
443    portfolioId =  parser.getIntParameter("portfolioId",0);
444    marketSymbol = parser.getStringParameter("marketSymbol","");
445    buyDate  = parser.getStringParameter("buyDate","");
446    numShare =  parser.getDoubleParameter("numShare",0.0);
447    mrkSharePrice =  parser.getDoubleParameter("mrkSharePrice",0.0f);
448    commish =  parser.getDoubleParameter("commish",0.0f);
449    fee =  parser.getDoubleParameter("fee",0.0f);
450
451   }
452
453
454  /** Convert a well-formed (but not necessarily valid) XML string into a JSON String. **/
455  private String xmlToJson(String xml)
456  {
457     String jsonStr = "";
458     if (xml== null || xml.length()<2) xml = "";
459     org.json.JSONObject jsonObj = org.json.XML.toJSONObject(xml);
460     if(jsonObj!= null) jsonStr = jsonObj.toString(2);
461     return jsonStr;
462   }
463
464
465  /**
466   *  This method handles the "GET" submission - it is used for Ajax calls to set webApp parameters using JQuery.
467   *
468   * @param  req                   Description of the Parameter
469   * @param  res                   Description of the Parameter
470   * @exception  ServletException  Description of the Exception
471   * @exception  IOException       Description of the Exception
472   */
473  public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
474  {
475    parseParams(req);
476
477    ServletOutputStream out = res.getOutputStream();
478    String conPath = req.getContextPath();
479    String restPath = req.getPathInfo();  // basically anything added to the end of the URL is considered a RESt request
480
481    if(debugOut_)
482    {
483      System.out.println("\n~~~~~~~~~~~~~~~~~~~~~~~~~~~");
484      System.out.println("MulaAjaxRestListener.doGet "+ "   debugOut="+debugOut);
485      System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~");
486    }
487
488    boolean ajaxCall = false;
489    boolean restRequest = false;
490    String ajaxResponse = "";
491    String restResponse = null;
492
493    res.setStatus(HttpServletResponse.SC_OK);  // default ids OK,, set again lower downif NOT
494
495    ajaxResponse = checkForAjaxRequest(req);
496    if (!ajaxResponse.equals("")) ajaxCall=true;
497
498    if(!ajaxCall) restResponse = checkForRestRequest(req);
499    if (restResponse!=null && !restResponse.equals("")) restRequest=true;
500
501    if(debugOut_) { System.out.println("ajaxCall="+ajaxCall+"   restRequest="+restRequest );}
502    /* * * * * *  * * * * * EMPTY * * * * *  * * * * *  */
503    /* ***********************************************  */
504    if( !ajaxCall && !restRequest) // EMPTY query and NO parms... it was *NOT* a JQuery Ajax call or a REST call, so just present some status back to user
505    {
506      sendServletAdminPage(req, res);
507    }
508
509    if(ajaxCall)
510    {
511      res.setContentType("text/plain");
512      if(out!=null  )
513      {
514        if (debugOut_)
515          System.out.println("AJAX REPLY("+ajaxResponse.length()+")="+ajaxResponse);
516        out.print(ajaxResponse);
517      }
518      else
519        System.out.println("HttpServletResponse.ServletOutputStream is NOT ready");
520    }
521    else if(restRequest)
522    {
523      if (xmlResponse_) res.setContentType("text/xml");
524      else res.setContentType("application/javascript");
525      if(restResponse!=null && !restResponse.equals(""))
526      {
527        res.setStatus(HttpServletResponse.SC_OK);
528      }
529      else
530      {
531        res.setStatus(HttpServletResponse.SC_NOT_FOUND);
532        restResponse = "<RestResponse succeeded=\"false\"><status>404</status></RestResponse>";
533      }
534      if(out!=null  )
535      {
536        if (!xmlResponse_) restResponse = xmlToJson(restResponse);
537        if (debugOut_)
538          System.out.println("REST REPLY("+restResponse.length()+")="+restResponse);
539        out.print(restResponse);
540      }
541      else
542        System.out.println("HttpServletResponse.ServletOutputStream is NOT ready");
543    }
544    out.flush();
545    res.flushBuffer();
546  }
547
548
549  /**
550   *  This method handles the "POST" submissions.
551   *
552   * @param  req                   Description of Parameter
553   * @param  res                   Description of Parameter
554   * @exception  ServletException  Description of Exception
555   * @exception  IOException       Description of Exception
556   */
557  public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
558  {
559    //parseParams(req);
560
561    StringBuffer postBody = new StringBuffer("");
562    String line = null;
563      BufferedReader reader = req.getReader();
564      while ((line = reader.readLine()) != null)
565        postBody.append(line+"\n");
566
567      String postReply = "";
568
569      // Do something with the posted message
570      // send it to a helper class if desired
571      /*String postReply = pEye_.newMessage(postBody.toString()); */
572
573      // send back an empty reply
574      if ((postReply==null || postReply.equals("")))
575      {
576        // send back a 200 with an empty body
577        res.setStatus(HttpServletResponse.SC_OK);
578        res.setContentLength(0);
579        postReply = "";
580        if (debugOut_) System.out.println("MulaAjaxRestListener.doPost: emptyreply from newMessage");
581      }
582
583      postReply = "\n"+postReply;
584      res.setContentType("application/xml");
585      res.setStatus(HttpServletResponse.SC_OK);
586      res.setContentLength(postReply.length());
587
588      ServletOutputStream out = res.getOutputStream();
589      if(out!=null  )
590      {
591        if (debugOut_) System.out.println("Attempting to HttpServletResponse REPLY("+postReply.length()+")="+postReply);
592        out.print(postReply);
593        out.flush();
594      }
595      else
596        System.out.println("HttpServletResponse.ServletOutputStream is NOT ready");
597
598      res.flushBuffer();
599  }
600
601
602  /** Parses the REST command string and prepares the response in XML format.
603    * @param restPath is the rest command part of the rest URL
604    * @return a string holding the XML rest response OR null if not a REST Request
605    **/
606  private String checkForRestRequest(HttpServletRequest req) throws ServletException, IOException
607  {
608    String restResponse = null;
609    String servletPath = req.getServletPath();
610    String restPath = req.getPathInfo();  // basically anything added to the end of the URL is considered a RESt request
611    String pre = "/";
612    boolean returnXml = xmlResponse_; // false means JSON
613
614    if (servletPath.equals("/rest") && restPath!=null && !restPath.equals("") )
615    {
616
617      DecimalFormat dfp = new DecimalFormat( "##0" );
618      DecimalFormat dfe = new DecimalFormat( "###0.000" );
619      if(restPath.equals(pre+"test"))
620      {
621        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
622        /*  Add In the response content  */
623        sb.append("<testNode className=\"");
624        sb.append(className_);
625        sb.append("\">");
626        sb.append("Hello");
627        sb.append("</testNode>");
628        sb.append("</RestResponse>");
629        restResponse = sb.toString();
630      }
631      if(restPath.equals(pre+"power/current"))
632      {
633        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
634        /*  Add In the response content  */
635        sb.append("</RestResponse>");
636        restResponse = sb.toString();
637      }
638      else if(restPath.equals(pre+"power/recent"))
639      {
640        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
641        /*  Add In the response content  */
642        sb.append("</RestResponse>");
643        restResponse = sb.toString();
644      }
645      else if(restPath.equals(pre+"energy/recent"))
646      {
647        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
648        /*  Add In the response content  */
649        sb.append("</RestResponse>");
650        restResponse = sb.toString();
651      }
652      else if(restPath.equals(pre+"energy/current"))
653      {
654        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
655        /*  Add In the response content  */
656        sb.append("</RestResponse>");
657        restResponse = sb.toString();
658      }
659      else if(restPath.equals(pre+"price/current"))
660      {
661        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
662        /*  Add In the response content  */
663        sb.append("</RestResponse>");
664        restResponse = sb.toString();
665      }
666      else if(restPath.equals(pre+"price/label/current"))
667      {
668        StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
669        /*  Add In the response content  */
670        sb.append("</RestResponse>");
671        restResponse = sb.toString();
672      }
673
674      // Database Queries
675      /*
676          - Dump the database tables directly to (JSON or ) XML using a REST call:
677            http://red.webarts.bc.ca:8080/powereye/rest/db/table/<tablename>
678              <tablename> can be reading, energy, load_device, load_type
679
680      or with the optional <number of rows>
681         positive number means sorted ascending (oldest 1st)
682         negative number means sorted descending (newest 1st)
683            http://red.webarts.bc.ca:8080/powereye/rest/db/table/<tablename>/100
684
685      These database calls are LOOOOooong so you might want to use a commandline URL query tool like
686      <a href="http://www.gnu.org/software/wget/">wget</a>, or perl or java or whatever.
687      */
688      else if(restPath.startsWith(pre+"db/table/"))
689      {
690        returnXml = true; // false means JSON
691        String content = "";
692        try
693        {
694          restResponse = "<RestResponse succeeded=\"false\"></RestResponse>";
695          int tblIndex = (pre+"db/table/").length();
696          int numRowsIndex = restPath.indexOf("/",tblIndex)+1; // /rest/db/table/reading/99
697          boolean numRowsWasSpecified = (numRowsIndex>0);
698          int numReadings =  (numRowsWasSpecified?Integer.parseInt(restPath.substring(numRowsIndex)):0); //0 means send all
699          boolean sortAscendingByDate = false;           // sort default is descending
700          if(numReadings<0) // negative numbers means ascending
701          {
702            sortAscendingByDate = true;
703            numReadings *= -1; // now normalize it to be a psitive rowCount
704          }
705          String tableName = (numRowsWasSpecified?restPath.substring(tblIndex,numRowsIndex-1):restPath.substring(tblIndex));
706
707          System.out.println("Dumping DB Table: "+tableName);
708          if(numRowsWasSpecified) System.out.println("         numRows: "+numReadings +" "+
709                                                    (sortAscendingByDate?"ascending":"descending"));
710          java.sql.ResultSet rs = null;
711          if(tableName.equalsIgnoreCase("reading"))
712            if(numRowsWasSpecified)
713            {
714              //rs = pEye_.dumpReadingTableToRS(sortAscendingByDate,(numReadings!=0?numReadings:-1));//dumpReadingTableToRS();
715            }
716            else
717            {
718              //rs = pEye_.dumpReadingTableToRS();
719            }
720          else if(tableName.equalsIgnoreCase("energy"))
721            if(numRowsWasSpecified)
722            {
723              //rs = pEye_.dumpEnergyTableToRS(sortAscendingByDate,(numReadings!=0?numReadings:-1));//dumpEnergyTableToRS();
724            }
725            else
726            {
727              //rs = pEye_.dumpEnergyTableToRS();
728            }
729          else if(tableName.equalsIgnoreCase("load_type"))
730            if(numRowsWasSpecified)
731            {
732              //rs = pEye_.dumpDBTableToRS("load_type",numReadings);//dumpLoadTypeTableToRS();
733            }
734            else
735            {
736              //rs = pEye_.dumpLoadTypeTableToRS();
737            }
738          else if(tableName.equalsIgnoreCase("load_device"))
739            if(numRowsWasSpecified)
740            {
741              //rs = pEye_.dumpDBTableToRS("load_device",numReadings);//dumpLoadDeviceTableToRS();
742            }
743            else
744            {
745              //rs = pEye_.dumpLoadDeviceTableToRS();
746            }
747
748          if(rs!=null)
749          {
750            ResultSetConverter rsc = new ResultSetConverter(rs);
751            if (returnXml) content = rsc.convertToXml().toXML().substring("<?xml version=\"1.0\"?>".length());
752            else content = rsc.convertToJson().toString();
753            StringBuilder sb = new StringBuilder("<RestResponse succeeded=\"true\">");
754            /*  Add In the response content  */
755              sb.append("<db table=\""+tableName+"\">");
756              sb.append(content);
757              sb.append("</db>");
758
759            sb.append("</RestResponse>");
760            restResponse = sb.toString();
761          }
762        }
763        catch(Exception ioEx)
764        {
765          restResponse = "<RestResponse succeeded=\"false\"></RestResponse>";
766        }
767      }
768    }
769
770    return restResponse;
771  }
772
773
774  /** Checks if this Request is an AJAX request and prepares the response in XML format.
775    * @param req the servlet request
776    * @return a string holding the response value to be returned OR null if not an expected/Valid AJAX Request
777    **/
778  private String checkForAjaxRequest(HttpServletRequest req) throws ServletException, IOException
779  {
780    String ajaxResponse = "";
781     // was  it a JQuery Ajax call for info...  (such as eagleDBDir_)
782    if (debugOut!=null &&!debugOut.equals("") )
783    {
784        debugOut_ =  Boolean.parseBoolean(debugOut);
785        setDebugOut(debugOut_);
786        //pEye_.setDebugOut(debugOut_);
787        System.out.println("MulaAjaxRestListener.doGet - debugOut_="+debugOut_);
788        ajaxResponse = ""+debugOut_;
789    }
790    else if (viewPortWidth!=0 )
791    {
792      // do something with the passed parms
793      viewPortWidth_=viewPortWidth;
794      req.getSession().setAttribute(CLIENT_SETTING_NAME_VIEWPORTWIDTH, viewPortWidth);
795      ajaxResponse = ""+viewPortWidth_;
796    }
797    else if (viewPortHeight!=0 )
798    {
799      // do something with the passed parms
800      viewPortHeight_=viewPortHeight;
801      req.getSession().setAttribute(CLIENT_SETTING_NAME_VIEWPORTHEIGHT, viewPortHeight);
802      ajaxResponse = ""+viewPortHeight_;
803    }
804    else if (browserName!=null &&!browserName.equals("") )
805    {
806      req.getSession().setAttribute(CLIENT_SETTING_NAME_BROWSER_NAME, browserName);
807      ajaxResponse = ""+browserName;
808    }
809    else if (browserVersion!=null &&!browserVersion.equals("") )
810    {
811      req.getSession().setAttribute(CLIENT_SETTING_NAME_BROWSER_VERSION, browserVersion);
812      ajaxResponse = ""+browserVersion;
813    }
814    // Ajax Call - invetmentTrackerCall
815    if (invetmentTrackerCall!=null && !invetmentTrackerCall.equals("")  )
816    {
817      System.out.println("Ajax Call - invetmentTrackerCall="+invetmentTrackerCall+"("+portfolioName+")"+(portfolioRefresh?" forcing a refresh":""));
818      HttpSession session = req.getSession(true);
819      System.out.println("  MulaAjaxRestListener SessionID: "+session.getId() );
820      if ( connectToITQ())
821      {
822        session.setAttribute("MulaAjaxRestListener.investmentTrackerQuery", itq);
823        /* queryPortfolio method HTML */
824        //http://10.0.0.253/mula/ajax/?invetmentTrackerCall=queryPortfolio&portfolioName=TFSA
825        if("queryPortfolio".equalsIgnoreCase(invetmentTrackerCall))
826        {
827          if(portfolioName!=null && !portfolioName.equals("")
828              && portfolioFormat!=null && portfolioFormat.equalsIgnoreCase("html"))
829          {
830            String portfolioTableID = "portfolioTable";
831            ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(itq.queryPortfolio(portfolioName,false)),
832                                                               portfolioTableID,
833                                                               "w3-table totals-table w3-striped w3-animate-bottom w3-hoverable w3-tiny ",
834                                                               "w3-theme-d3 w3-center",
835                                                               "",
836                                                               "w3-center",
837                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
838          }
839        }
840        /* queryPortfolio method XML*/
841        else if("queryPortfolio".equalsIgnoreCase(invetmentTrackerCall))
842        {
843          if(portfolioName!=null && !portfolioName.equals("")
844              && portfolioFormat!=null && portfolioFormat.equalsIgnoreCase("xml"))
845          {
846            ajaxResponse = itq.queryPortfolio(portfolioName);
847            //ResultSetConverter rsc = new ResultSetConverter(ajaxResponse);
848            //ajaxResponse = rsc.convertToXml().toXML().substring("<?xml version=\"1.0\"?>".length());
849          }
850        }
851        /* queryPortfolio method JSON (default)*/
852        else if("queryPortfolio".equalsIgnoreCase(invetmentTrackerCall))
853        {
854          if(portfolioName!=null && !portfolioName.equals("")
855              && (  portfolioFormat==null || portfolioFormat.equalsIgnoreCase("json") || portfolioFormat.equals("")))
856          {
857            ajaxResponse = itq.queryPortfolio(portfolioName);
858            ajaxResponse = Util.csvToJSON(ajaxResponse,"|");
859          }
860        }
861        /* loadStockDaily method */
862        else if("loadStockDaily".equalsIgnoreCase(invetmentTrackerCall))
863        {
864          float xchgRate =  itq.getCurrencyExchangeRateFromRDF();
865          ajaxResponse = itq.loadStockDaily();
866          try
867          {
868            ajaxResponse = Util.csvToJSON(ajaxResponse,"|");
869          }
870          catch(java.lang.ArrayIndexOutOfBoundsException aoobEx)
871          {
872            System.out.println("Exception:   MulaAjaxRestListener - csvToJSON for loadStockDaily ajaxResponse:");
873            System.out.println(ajaxResponse);
874            ajaxResponse = "null/null";
875          }
876        }
877        /* createPortfolioPerformanceChart method */
878        else if("createPortfolioPerformanceChart".equalsIgnoreCase(invetmentTrackerCall))
879        {
880          if(chartWidth==0) chartWidth = viewPortWidth_;
881          if(chartHeight==0) chartHeight = viewPortHeight_;
882          if(portfolioName!=null && !portfolioName.equals(""))
883          {
884            JFreeChart cbc = itq.createPortfolioPerformanceChart(portfolioName);
885            ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
886            ajaxResponse = ServletUtilities.saveChartAsPNG(cbc, chartWidth, chartHeight, info, session);
887          }
888          else
889          {
890            JFreeChart cbc = itq.createPortfolioPerformanceChart("");
891            ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
892            ajaxResponse = ServletUtilities.saveChartAsPNG(cbc, chartWidth, chartHeight, info, session);
893          }
894        }
895        /* createStockChart method */
896        else if("createStockChart".equalsIgnoreCase(invetmentTrackerCall))
897        {
898          if(chartWidth==0) chartWidth = viewPortWidth_;
899          if(chartHeight==0) chartHeight = viewPortHeight_;
900          if(stockSymbol!=null && !stockSymbol.equals(""))
901          {
902            JFreeChart cbc = itq.createPriceVolumeChart(stockSymbol);
903            ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
904            ajaxResponse = ServletUtilities.saveChartAsPNG(cbc, chartWidth, chartHeight, info, session);
905          }
906          else
907          {
908            JFreeChart cbc = itq.createPortfolioPerformanceChart("");
909            ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
910            ajaxResponse = ServletUtilities.saveChartAsPNG(cbc, chartWidth, chartHeight, info, session);
911          }
912        }
913        /* createExchangeChart method */
914        else if("createExchangeChart".equalsIgnoreCase(invetmentTrackerCall))
915        {
916          if(chartWidth==0) chartWidth = viewPortWidth_;
917          if(chartHeight==0) chartHeight = viewPortHeight_;
918          JFreeChart cbc = itq.createExchangeChart();
919          ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
920          ajaxResponse = ServletUtilities.saveChartAsPNG(cbc, chartWidth, chartHeight, info, session);
921        }
922        /* dumpPriceVolumeDataStr method  for the chart*/
923        else if("dumpPriceVolumeDataStr".equalsIgnoreCase(invetmentTrackerCall))
924        {
925          if(stockSymbol!=null && !stockSymbol.equals(""))
926          {
927            ajaxResponse = itq.dumpPriceVolumeDataStr(stockSymbol, 100);
928            ajaxResponse.replace('|','\t');
929            if(portfolioFormat.equalsIgnoreCase("json"))
930            {
931              ajaxResponse = Util.csvToJSON(ajaxResponse,"|");
932            }
933          }
934        }
935        /* queryBuyStock method */
936        else if("queryBuyStock".equalsIgnoreCase(invetmentTrackerCall))
937        {
938          if(buyStockSymbol!=null && !buyStockSymbol.equals("")
939              && buyStockName!=null && !buyStockName.equals("")
940            )
941          {
942            ajaxResponse = itq.queryBuyStock(buyStockSymbol, buyStockName, isMutualFund, portfolioId, marketSymbol,
943                                             buyDate, numShare, mrkSharePrice, commish, fee);
944          }
945        }
946        /* queryListStockMarket method */
947        else if("queryListStockMarket".equalsIgnoreCase(invetmentTrackerCall))
948        {
949           String adminTableID = "adminTable";
950           String csvStr = itq.queryListStockMarket();
951           ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(csvStr),
952                                                               false,
953                                                               adminTableID,
954                                                               "w3-table w3-striped w3-animate-top w3-hoverable w3-tiny ",
955                                                               "w3-theme-d3 w3-center",
956                                                               "",
957                                                               "w3-center",
958                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
959        }
960        /* queryListStockMarket method */
961        else if("queryListCurrencyExchangeRate".equalsIgnoreCase(invetmentTrackerCall))
962        {
963          String adminTableID = "adminTable";
964          String csvStr = itq.queryListCurrencyExchangeRate();
965          ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(csvStr),
966                                                               false,
967                                                               adminTableID,
968                                                               "w3-table w3-striped w3-animate-top w3-hoverable w3-tiny ",
969                                                               "w3-theme-d3 w3-center",
970                                                               "",
971                                                               "w3-center",
972                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
973       }
974        /* queryListStockMarket method */
975        else if("queryStockDaily".equalsIgnoreCase(invetmentTrackerCall))
976        {
977           String adminTableID = "adminTable";
978           String csvStr = itq.queryStockDaily();
979           ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(csvStr),
980                                                               false,
981                                                               adminTableID,
982                                                               "w3-table w3-striped w3-animate-top w3-hoverable w3-tiny ",
983                                                               "w3-theme-d3 w3-center",
984                                                               "",
985                                                               "w3-center",
986                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
987        }
988        /* queryListPortfolios method */
989        else if("queryListPortfolios".equalsIgnoreCase(invetmentTrackerCall))
990        {
991           String adminTableID = "adminTable";
992           String csvStr = itq.queryListPortfolios();
993           ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(csvStr),
994                                                               false,
995                                                               adminTableID,
996                                                               "w3-table w3-striped w3-animate-top w3-hoverable w3-tiny ",
997                                                               "w3-theme-d3 w3-center",
998                                                               "",
999                                                               "w3-center",
1000                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
1001       }
1002       /* queryListAllTransactions method */
1003       else if("queryListAllTransactions".equalsIgnoreCase(invetmentTrackerCall))
1004       {
1005           String adminTableID = "adminTable";
1006           String csvStr = itq.queryListAllTransactions();
1007           ajaxResponse = itq.htmlTableFormatResultSet(new StringBuilder(csvStr),
1008                                                               false,
1009                                                               adminTableID,
1010                                                               "w3-table w3-striped w3-animate-top w3-hoverable w3-tiny ",
1011                                                               "w3-theme-d3 w3-center",
1012                                                               "",
1013                                                               "w3-center",
1014                                                               "w3-btn w3-white w3-border w3-border-green w3-hover-aqua w3-round-xxlarge");
1015        }
1016        /* downloadStockDaily method */
1017        else if("downloadStockDaily".equalsIgnoreCase(invetmentTrackerCall))
1018        {
1019          if(portfolioName!=null && !portfolioName.equals("")
1020              && (  portfolioFormat==null || portfolioFormat.equalsIgnoreCase("csv") || portfolioFormat.equals("")))
1021          {
1022            float xchgRate =  itq.getCurrencyExchangeRateFromRDF();
1023            ajaxResponse = itq.queryPortfolio(portfolioName,true);
1024          }
1025          else if(portfolioName!=null && !portfolioName.equals("")
1026              && (  portfolioFormat!=null && portfolioFormat.equalsIgnoreCase("json") ))
1027          {
1028            float xchgRate =  itq.getCurrencyExchangeRateFromRDF();
1029            ajaxResponse = itq.queryPortfolio(portfolioName,true);
1030            try
1031            {
1032              ajaxResponse = Util.csvToJSON(ajaxResponse,"|");
1033            }
1034            catch(java.lang.ArrayIndexOutOfBoundsException aoobEx)
1035            {
1036              System.out.println("Exception:   MulaAjaxRestListener - csvToJSON for loadStockDaily ajaxResponse:");
1037              System.out.println(ajaxResponse);
1038              ajaxResponse = "null/null";
1039            }
1040          }
1041        }
1042      }
1043      else
1044      {
1045        System.out.println("/n/n------------------------------/nAjax connection to InvestmentTrackerQuery FAILED");
1046        ajaxResponse = "null/null";
1047      }
1048    }
1049
1050    return ajaxResponse;
1051  }
1052
1053
1054  /** Connects the InvestmentTrackerQuery helper. **/
1055  private boolean connectToITQ()
1056  {
1057    if(itq==null) itq=new InvestmentTrackerQuery();
1058
1059    return (itq!=null);
1060  }
1061
1062
1063
1064  /** Prepares and returns basic info page about the server. **/
1065  private void sendServletAdminPage(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
1066  {
1067    ServletOutputStream out = res.getOutputStream();
1068    ServletContext context = getServletContext();
1069    java.util.Properties sysProps = System.getProperties();
1070    TimeZone localTz = Calendar.getInstance().getTimeZone();
1071    int offset = localTz.getRawOffset();
1072    // shift Daylight savings hour if needed
1073    Date dateNow = new Date();
1074    boolean dst = localTz.inDaylightTime(dateNow);
1075    int dstOffset = localTz.getDSTSavings();
1076    //if(dst) offset = offset + dstOffset;
1077
1078    String prop = "";
1079
1080      // Send Back a response to be presented to the users browser
1081      res.setContentType("text/html");
1082      out.println("<html>\n");
1083      out.println("<head>\n");
1084      out.println("<title>MULA Ajax / REST Listener - Servlet Console</title>\n");
1085      out.println("<link rel=\"icon\"");
1086      out.println("     type=\"image/svg+xml\"");
1087      out.println("     href=\"../img/favicon.svg\" />");
1088      out.println("<style>");
1089      out.println("H1 { font-weight: bolder; background-color: #020; color: #ffffbb;  font-size: 200%}");
1090      out.println("H2 { font-weight: bolder; color: #ffff99;  font-size: 160%; text-decoration: underline}");
1091      out.println("H3 { font-weight: bolder; color: #ffff44;  font-size: 140%}");
1092      out.println("H4, H5 { color: #ffffff }");
1093      out.println("A { color: #ffaadd }");
1094      out.println("DT { font-weight: bolder }");
1095      out.println("LI { line-height: 125% }");
1096      out.println("BODY { background-color: #101066; color: #ffff44; font-size: 100%; line-height: 110% }");
1097      out.println(".val { color: #ffffff; font: \"Lucida Console\", Monaco, monospace  }");
1098      out.println("");
1099      out.println("");
1100      out.println("");
1101      out.println("</style>");
1102
1103      //out.println("<META HTTP-EQUIV=\"refresh\" content=\"2;URL=\"javascript:history.go(-2);\">\n");
1104      out.println("</head>\n");
1105      out.println("<body>");
1106      out.println("<h1>Web<i>ARTS</i> <a href=\""+req.getContextPath()+"\">Mula</a> Ajax / REST Listener</h1><h2>Servlet Console</h2>");
1107      out.println(getServletInfo());
1108      out.println(" <h3>Parameters</h3>");
1109      out.println("  <ul>");
1110      out.println("    <li>debug          = <span class=\"val\">"+debugOut_+"</span></li>");
1111       out.println("<br />");
1112      out.println("    <li>Servlet Init Params:");
1113      out.println("        <ul>");
1114
1115      java.util.Enumeration <String> initEnum = getInitParameterNames();
1116      String currParamName = "";
1117      for (; initEnum.hasMoreElements();)
1118      {
1119        currParamName = initEnum.nextElement();
1120        out.print("            <li>");
1121        out.print(currParamName+" = <span class=\"val\">"+getInitParameter(currParamName));
1122        out.println("</span></li>");
1123      }
1124      out.println("       </ul>");
1125      out.println("    </li>"); // servlet init params
1126
1127      out.println("<br />");
1128      out.println("    <li>Context Params for "+context.getServletContextName()+":");
1129      out.println("        <ul>");
1130        out.print("          <li>");
1131        out.print("ContextPath"+" = <span class=\"val\">"+context.getContextPath());
1132        out.println("</span></li>");
1133        out.print("          <li>");
1134        out.print("Real Path For Context Root"+" = <span class=\"val\">"+context.getRealPath("/"));
1135        out.println("</span></li>");
1136      out.println("       </ul>");
1137      out.println("  </li>"); // CONTEXT  params
1138
1139      out.println("<br />");
1140      out.println("  <li>Context <b>Init</b> Params:");
1141      out.println("      <ul>");
1142      initEnum = context.getInitParameterNames();
1143      currParamName = "";
1144      for (; initEnum.hasMoreElements();)
1145      {
1146        currParamName = initEnum.nextElement();
1147        out.print("          <li>");
1148        out.print(currParamName+" = <span class=\"val\">"+context.getInitParameter(currParamName));
1149        out.println("</span></li>");
1150      }
1151      out.println("       </ul>");
1152      out.println("    </li>"); // context init params
1153
1154      out.println("  </ul>");
1155
1156      out.println("<br /><br />");
1157      out.println("<h3>Server Status</h3>");
1158      out.println("  <ul>");
1159      out.println("    <li>Server name = <span class=\"val\">"+req.getServerName()+" ("+req.getLocalAddr()+")</span></li>");
1160      out.println("    <li>Server port = <span class=\"val\">"+req.getServerPort()+"</span></li>");
1161      out.println("    <li>WebApp Engine = <span class=\"val\">"+context.getServerInfo()+"</span></li>");
1162      out.println("    <li>Supported Servlet Version = <span class=\"val\">"+context.getMajorVersion()+"."+context.getMinorVersion()+"</span></li>");
1163
1164      if(context.getMajorVersion()>2 && context.getMinorVersion()>-1)
1165          out.println("      <ul><li>Effective Version = <span class=\"val\">"+
1166                      context.getEffectiveMajorVersion()+"."+context.getEffectiveMinorVersion()+"</span></li></ul>");
1167      out.println("      </li>");
1168      if(context.getMajorVersion()>2 && context.getMinorVersion()>0)
1169      {
1170        try {
1171          out.println("    <li>Logical Hostname = <span class=\"val\">"+context.getVirtualServerName()+"</span></li>");
1172        } catch (Exception ex) {}
1173      }
1174
1175      out.println("    <li>System Properties\n      <ul>");
1176      prop = "java.vendor";
1177      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1178      prop = "java.runtime.version";
1179      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1180      prop = "java.version";
1181      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1182      prop = "os.arch";
1183      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1184      prop = "os.name";
1185      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1186      prop = "os.version";
1187      out.println("       <li>"+prop+" = <span class=\"val\">"+sysProps.getProperty(prop)+"</span></li>");
1188
1189      out.println("      </ul>\n      </li>");
1190
1191      out.println("<br /><br />");
1192      out.println("<h3>Client Request</h3>");
1193      out.println("  <ul>");
1194      out.println("    <li>Client/proxy Host = <span class=\"val\">"+req.getRemoteHost()+" ("+req.getRemoteAddr()+")</span></li>");
1195      out.println("    <li>Client/proxy port = <span class=\"val\">"+req.getRemotePort()+"</span></li>");
1196      out.println("    <li>Protocol = <span class=\"val\">"+req.getProtocol()+"</span></li>");
1197      out.println("  </ul>");
1198
1199      out.println("<br /><br />");
1200      out.println("<h3>Client Parms Status</h3>");
1201      out.println("  <ul>");
1202      out.println("    <li>Browser = <span class=\"val\">"+req.getSession().getAttribute(CLIENT_SETTING_NAME_BROWSER_NAME)+" v"+
1203                  req.getSession().getAttribute(CLIENT_SETTING_NAME_BROWSER_VERSION)+"</span></li>");
1204      out.println("    <li>Device Type = <span class=\"val\">"+req.getSession().getAttribute(CLIENT_SETTING_NAME_DEVICE_TYPE)+"</span></li>");
1205      out.println("    <li>viewport.width = <span class=\"val\">"+req.getSession().getAttribute(CLIENT_SETTING_NAME_VIEWPORTWIDTH)+"</span></li>");
1206      out.println("    <li>viewport.height= <span class=\"val\">"+req.getSession().getAttribute(CLIENT_SETTING_NAME_VIEWPORTHEIGHT)+"</span></li>");
1207      out.println("  </ul>");
1208      out.println("<br /><br />");
1209      out.println("\n</body>\n</html>");
1210  }
1211}