001/*
002 *  $Source: /cvsroot2/open/projects/WebARTS/ca/bc/webarts/servlet/DbXmlXsl.java,v $
003 *  $Name:  $
004 *  $Revision: 1.3 $
005 *  $Date: 2005-04-10 11:53:16 -0700 (Sun, 10 Apr 2005) $
006 *  $Locker:  $
007 */
008/*
009 *  Copyright (C) 2001 WebARTS Design, North Vancouver Canada
010 *  http://www.webarts.bc.ca
011 *
012 *  This program is free software; you can redistribute it and/or modify
013 *  it under the terms of the GNU General Public License as published by
014 *  the Free Software Foundation; either version 2 of the License, or
015 *  (at your option) any later version.
016 *
017 *  This program is distributed in the hope that it will be useful,
018 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
019 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
020 *  GNU General Public License for more details.
021 *
022 *  You should have received a copy of the GNU General Public License
023 *  along with this program; if not, write to the Free Software
024 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
025 */
026
027package ca.bc.webarts.servlet;
028
029import db2xml.util.DB2XMLException;
030import db2xml.util.JDBCXMLProperties;
031import db2xml.util.XMLOutput;
032
033import db2xml.xml.JDBCXML;
034import db2xml.xml.XMLDocument;
035
036import java.io.File;
037import java.io.FileInputStream;
038import java.io.FileWriter;
039import java.io.InputStream;
040import java.io.IOException;
041import java.io.OutputStream;
042import java.io.PrintWriter;
043import java.io.Writer;
044
045import java.net.InetAddress;
046import java.net.MalformedURLException;
047import java.net.UnknownHostException;
048import java.net.URL;
049import java.net.URLConnection;
050
051import java.util.Calendar;
052import java.util.Enumeration;
053import java.util.Hashtable;
054import java.util.Vector;
055
056import javax.servlet.GenericServlet;
057import javax.servlet.ServletConfig;
058import javax.servlet.ServletException;
059import javax.servlet.ServletRequest;
060import javax.servlet.ServletResponse;
061
062import javax.servlet.http.HttpServlet;
063import javax.servlet.http.HttpServletRequest;
064import javax.servlet.http.HttpServletResponse;
065
066import javax.xml.parsers.DocumentBuilder;
067import javax.xml.parsers.DocumentBuilderFactory;
068import javax.xml.parsers.ParserConfigurationException;
069
070import javax.xml.transform.Result;
071import javax.xml.transform.Source;
072import javax.xml.transform.stream.StreamResult;
073import javax.xml.transform.stream.StreamSource;
074import javax.xml.transform.Transformer;
075import javax.xml.transform.TransformerConfigurationException;
076import javax.xml.transform.TransformerException;
077import javax.xml.transform.TransformerFactory;
078import javax.xml.transform.dom.DOMSource;
079
080import org.w3c.dom.Document;
081
082import org.xml.sax.SAXException;
083
084
085
086
087/**
088 * The class <code>DbXmlXsl</code> provides a server side engine for processing
089 * a variety of XML/XSL tasks based on a SQL db query, or a saved XML file. <P>
090 *
091 * The XSL processing syntax assumes the Xalan package from
092 * <a href="http://xml.apache.org">xml.apache.org</A>.<P>
093 * All funtional options are accessible via the parameters passed to it.
094 * <P>The db SQL to XML extraction is provided by the GNU
095 * <A href="http://www-1.informatik.fh-wiesbaden.de/~turau/DB2XM">DB2XML library
096 * </A> of  Java classes.
097 *
098 * This servlet has the following capabilities:
099 * <OL>
100 *   <LI> query a specified jdbc URL with a specified SQL statement and provide
101 *   the result set in XML,
102 *   <LI> transform the XMLResultSet using a specified XSL transform,
103 *   <LI> save the XMLResultSet to a specified filename,
104 *   <LI> transform XML (either from the above query, specified file, or parameter)
105 *   with a XSL template
106 *   <UL>
107 *     <LI> XSL template specified by the caller
108 *     <LI> to a html table representation of the data (default if a transformation
109 *     is requested without a XSL file specified)
110 *   </UL>
111 *
112 *   <LI> return the generated XML document with MIME type
113 *     <code>text/xml</code></LI></OL>
114 *   .
115
116 *  <BR><BR><B>DbXmlXsl usage</B>:<BR>
117 *   <pre>http://servername/DbXmlXsl?parameterList</PRE>where parameter list is
118 *    a list of acceptable servlet parameter name value pairs separated
119 *  by the &amp; character.<BR>This servlet will accept the following
120 *  parameters:  <UL>
121 *      <LI>dbQuery - the SQL to hit the db with
122 *      <LI>saveXmlFile - true or false to save or not save the resultant xml
123 *  from the dbQuery
124 *      <LI>fileBaseDir - base dir for the xml save
125 *      <LI>xslTransform - true or false to do or not do a transform
126 *      <LI>xslURL - a URL to the xsl
127 *      <LI>xmlURL - a URL to the xsl
128 *      <LI>numXmlFiles - does mor than 1 transform at a time by taking the
129 *  urls you give and appending a number to the end of them to get the
130 *  sequence of urls
131 *      <LI>xmlSource - directory based source for your xml on this server
132 *      <LI>jdbcDriverClass - overrides the default to visit a different db
133 *  with your dbQuery string
134 *      <LI>jdbcURL - overrides the default to visit a different db
135 *      <LI>jdbcUsername - overrides the default to visit a different db
136 *      <LI>jdbcPassword - overrides the default to visit a different db
137 *      <LI>dumpDebug - DOES not do the db Query or transform...
138 *  just dumps the info it would have used
139 *  </UL><BR>You can get this servlet to do a transform on its own
140 *  (without a db query) by specifying the xslURL, xmlURL, and xslTransform.
141 *  <BR>As Follows:
142 *  <PRE>/DbXmlXsl?xslURL=http://yoururl&amp;xmlURL=http://yoururl&amp;xslTransform=true</PRE>
143 *  <BR>Have Fun!<BR>
144 *  Tom Gutwin P.Eng.
145 *
146 * @author    Tom Gutwin P.Eng
147 */
148public class DbXmlXsl extends HttpServlet
149{
150
151  /**
152   * The Default XSL template to use (in the form of a URL)
153   */
154  String DEFAULT_XSL_STYLESHEET_URL = "http://warp2.webarts.bc.ca/xml/FancyXmlTreeViewer.xsl";
155  /** A holder for this Servers System File Separator. **/
156  private static final String SYSTEM_FILE_SEPERATOR = File.separator;
157  /**
158   * Description of the Field
159   */
160  private JDBCXML jx_ = null;
161  /**
162   * Description of the Field
163   */
164  private static JDBCXMLProperties map_ = null;
165  private static String db2XmlPropFile_ = "db2xml.properties";
166  /**
167   * Description of the Field
168   */
169  private String xmlFileOutputName_ = "DbXmlXsl";
170  /**
171   * Description of the Field
172   */
173  private String xmlFileOutputDir_ = SYSTEM_FILE_SEPERATOR+"xml";
174  /**
175   * Description of the Field
176   */
177  private String fileBaseDir_ = SYSTEM_FILE_SEPERATOR;
178  /**
179   * The URL of this servlet
180   */
181  private String servletUrlStr_ = "/DbXmlXsl";
182
183  private boolean dumpDebug_ = true;
184
185  /**
186   * This Servers Host Internet Address.
187   **/
188  private String myHost_ = null;
189  /**
190   * This Servers Host port.
191   **/
192  private String myPort_ = null;
193
194  public String usageHtml_ = "<BR><BR><B>DbXmlXsl usage</B>:<BR>\n"+
195    "<pre>http://servername/DbXmlXsl?parameterList</PRE>where parameter list is"+
196    " a list of acceptable servlet parameter name value pairs separated " +
197    "by the &amp; character.<BR>\nThis servlet will accept the following "+
198    "parameters:\n  <UL>\n"+
199    "    <LI>dbQuery - the SQL to hit the db with\n"+
200    "    <LI>saveXmlFile - true or false to save or not save the resultant xml "+
201    "from the dbQuery\n"+
202    "    <LI>fileBaseDir - base dir for the xml save\n"+
203    "    <LI>xslTransform - true or false to do or not do a transform\n"+
204    "    <LI>xslURL - a URL to the xsl\n"+
205    "    <LI>xmlURL - a URL to the xsl\n"+
206    "    <LI>numXmlFiles - does mor than 1 transform at a time by taking the "+
207    "urls you give and appending a number to the end of them to get the "+
208    "sequence of urls\n"+
209    "    <LI>xmlSource - directory based source for your xml on this server\n"+
210    "    <LI>jdbcDriverClass - overrides the default to visit a different db "+
211    "with your dbQuery string\n"+
212    "    <LI>jdbcURL - overrides the default to visit a different db\n"+
213    "    <LI>jdbcUsername - overrides the default to visit a different db\n"+
214    "    <LI>jdbcPassword - overrides the default to visit a different db\n"+
215    "    <LI>dumpDebug - DOES not do the db Query or transform... "+
216    "just dumps the info it would have used\n"+
217    "</UL><BR>\nYou can get this servlet to do a transform on its own "+
218    "(without a db query) by specifying the xslURL, xmlURL, and xslTransform."+
219    "<BR>\nAs Follows:<PRE>/DbXmlXsl?xslURL=http://yoururl&amp;xmlURL"+
220    "=http://yoururl&amp;xslTransform=true</PRE><BR>\nHave Fun!<BR>"+
221    "Tom Gutwin P.Eng.";
222
223
224  /**
225   * Creates a timestamp for the current time in the form of 'hour + "-" + min +
226   * "-" + sec + "-" + millis'.
227   *
228   * @return   The CurrentTimeStamp value.
229   */
230  public static String createCurrentTimeStamp()
231  {
232    String value = "";
233    Calendar calendar_ = Calendar.getInstance();
234    int currMillis = calendar_.get(calendar_.MILLISECOND);
235    String millis = String.valueOf(currMillis);
236    if (currMillis < 10)
237    {
238      millis = "00" + currMillis;
239    }
240    else if (currMillis < 100)
241    {
242      millis = "0" + currMillis;
243    }
244    int currSec = calendar_.get(calendar_.SECOND);
245    String sec = String.valueOf(currSec);
246    if (currSec < 10)
247    {
248      sec = "0" + currSec;
249    }
250    int currMin = calendar_.get(calendar_.MINUTE);
251    String min = String.valueOf(currMin);
252    if (currMin < 10)
253    {
254      min = "0" + currMin;
255    }
256    int currHr = calendar_.get(calendar_.HOUR_OF_DAY);
257    String hour = String.valueOf(currHr);
258    if (currHr < 10)
259    {
260      hour = "0" + currHr;
261    }
262
263    return (String) hour + "-" + min + "-" + sec + "-" + millis;
264  }
265
266
267  /**
268   * Initializes the servlet and loads some db2xml init data. The init method is
269   * called once, automatically, by the network service each time it loads the
270   * servlet. It is guaranteed to finish before any service requests are accepted.
271   * <br>
272   * The JDBCXML properties are read from a file named <code>db2xml.properties</code>
273   * if an Servlet Init Parm - 'db2XmlPropFile' was not specified. This default
274   * file must be placed in a server config directory or other suitable directory.
275   *
276   * @param config                servlet configuration information
277   * @exception ServletException  if an error occured during initialization
278   */
279  public void init(ServletConfig config) throws ServletException
280  {
281    super.init(config); // invoked on GenericServlet and saves a reference of
282    // the config for later use
283    String initProp = getInitParameter("db2XmlPropFile");
284    String fileOutputDir = getInitParameter("fileOutputDir");
285    String fileBaseDir = getInitParameter("fileBaseDir");
286    myPort_ = getInitParameter("hostPort");
287    try
288    {
289      myHost_ = InetAddress.getLocalHost().getHostAddress();
290      System.out.println("DbXmlXsl Servlet init(): myHost: "+myHost_);
291      System.out.println("DbXmlXsl Servlet init(): myPort: "+myPort_);
292      if (db2XmlPropFile_ != null && !db2XmlPropFile_.equals(""))
293      {
294        System.out.println("DbXmlXsl Servlet init(): Reading db2xml "+
295        "properties file from " + initProp);
296        db2XmlPropFile_ = initProp;
297        map_ = new JDBCXMLProperties(db2XmlPropFile_);
298      }
299      else
300      {
301        // read from the default location
302        map_ = new JDBCXMLProperties();
303      }
304
305      if (fileBaseDir != null && !fileBaseDir.equals(""))
306      {
307        System.out.println("DbXmlXsl Servlet init(): File Base Dir:  "+
308        "" + fileBaseDir);
309        fileBaseDir_ = fileBaseDir;
310        if (!fileBaseDir_.endsWith(SYSTEM_FILE_SEPERATOR))
311          fileBaseDir_ += SYSTEM_FILE_SEPERATOR;
312      }
313
314      if (fileOutputDir != null && !fileOutputDir.equals(""))
315      {
316        System.out.println("DbXmlXsl Servlet init(): File Output:  "+
317        "" + fileOutputDir);
318        xmlFileOutputDir_ = fileOutputDir;
319      }
320
321      servletUrlStr_ =  getServletName();
322    }
323    catch (DB2XMLException e)
324    {
325      throw new ServletException("2: " + e.getMessage());
326    }
327        catch (UnknownHostException e2)
328    {
329      throw new ServletException("2: " + e2.getMessage());
330    }
331
332  }
333
334
335  /**
336   * A method to generate an XML Document based on the result set from an SQL query
337   * on a db. All db parameters are passed in the method parameters.
338   *
339   * @param jdbcDriverClass   the DriverClass name to override the defaults
340   * @param jdbcUrl           the URL name to override the defaults
341   * @param jdbcUser          the User name to override the defaults
342   * @param jdbcUserPassword  the Password to override the defaults
343   * @param sqlStatement      the SQL to execute
344   *
345   * @return                  The result query as an XML doc
346   */
347  public static XMLDocument db2XmlDocument(String jdbcDriverClass,
348    String jdbcUrl,
349    String jdbcUser,
350    String jdbcUserPassword,
351    String sqlStatement) throws DB2XMLException
352  {
353    XMLDocument retVal = null;
354    JDBCXMLProperties map = null;
355    if (map_ != null)
356      map = map_;
357    else
358      map = new JDBCXMLProperties(); // uses the defaults
359
360    if (jdbcDriverClass != null && !jdbcDriverClass.equals("") &&
361      jdbcUrl != null && !jdbcUrl.equals("") &&
362      jdbcUser != null &&
363      jdbcUserPassword != null &&
364      sqlStatement != null)
365    {
366      map.setProperty("driverClass", jdbcDriverClass);
367      map.setProperty("dbUrl", jdbcUrl);
368      map.setProperty("user", jdbcUser);
369      map.setProperty("password", jdbcUserPassword);
370      map.setProperty("dbQuery", sqlStatement);
371
372      JDBCXML jx = new JDBCXML(map);
373      try
374      {
375        jx.generateXML();
376        retVal = jx.getXMLDocument();
377      }
378      catch (Exception ex)
379      {
380      }
381      if (jx != null)
382      {
383        jx.closeDatabase();
384      }
385    }
386    return retVal;
387  }
388
389
390  /**
391   * A method to generate an XML Document based on the result set from an
392   * SQL query on a the default db and username. All db parameters are
393   * retrieved the from db2XmlPropFile_ field.
394   *
395   * @param sqlStatement      the SQL to execute
396   *
397   * @return                  The result query as an XML doc
398   */
399  public static XMLDocument db2XmlDocument(String sqlStatement)
400                     throws DB2XMLException
401  {
402    JDBCXMLProperties map = null;
403    if (map_ != null)
404      map = map_;
405    else if (db2XmlPropFile_ != null && !db2XmlPropFile_.equals(""))
406      map = new JDBCXMLProperties(db2XmlPropFile_);
407    else
408      map = new JDBCXMLProperties();
409
410    return db2XmlDocument(sqlStatement, map);
411  }
412
413
414  /**
415   * A method to generate an XML Document based on the result set from an
416   * SQL query on a the default db and username. All db parameters are
417   * retrieved the passed map parameter.
418   *
419   * @param sqlStatement      the SQL to execute
420   * @param map               The properties map to use for this query.
421   *
422   * @return                  The result query as an XML doc
423   */
424  public static XMLDocument db2XmlDocument(String sqlStatement,
425                                           JDBCXMLProperties map)
426                     throws DB2XMLException
427  {
428    XMLDocument retVal = null;
429    if (sqlStatement != null)
430    {
431      map.setProperty("dbQuery", sqlStatement);
432
433      JDBCXML jx = new JDBCXML(map);
434      try
435      {
436        jx.generateXML();
437        retVal = jx.getXMLDocument();
438      }
439      catch (Exception ex)
440      {
441      }
442      if (jx != null)
443      {
444        jx.closeDatabase();
445      }
446    }
447    return retVal;
448  }
449
450
451  /**
452   * Writes the passed in XMLDocument to the specified XML file.
453   *
454   * @param xmlFilename  the resultant XMLfilename
455   * @param xmlDoc       The XML Documewnt to write out
456   *
457   * @see #db2XmlDocument(String)
458   */
459  public static void writeXmlFile(String xmlFilename, XMLDocument xmlDoc)
460              throws IOException, DB2XMLException
461  {
462    JDBCXMLProperties map = null;
463    if (map_ != null)
464      map = map_;
465    else if (db2XmlPropFile_ != null && !db2XmlPropFile_.equals(""))
466      map = new JDBCXMLProperties(db2XmlPropFile_);
467    else
468      map = new JDBCXMLProperties();
469    writeXmlFile(xmlFilename, xmlDoc, map);
470  }
471
472
473  /**
474   * Writes the passed in XMLDocument to the specified XML file.
475   *
476   * @param xmlFilename  the resultant XMLfilename
477   * @param xmlDoc       The XML Documewnt to write out
478   * @param map          The properties map to use for th DB2XML usage.
479   */
480  public static void writeXmlFile(String xmlFilename,
481                                  XMLDocument xmlDoc,
482                                  JDBCXMLProperties map)
483              throws IOException, DB2XMLException
484  {
485    XMLOutput xmlOut = null;
486    PrintWriter fileOut = new PrintWriter(new FileWriter(xmlFilename));
487    xmlOut = new XMLOutput(map, fileOut, xmlDoc);
488    xmlOut.writeToOutput();
489  }
490
491
492  /**
493   * Performs the XSL transform on the XML.
494   *
495   * @param xmlUrl     The URL for the XML data
496   * @param xslUrl     The URL for the XSL data
497   * @param outWriter  The output writer to dump the output from the transform
498   * @param params other parameters to pass directly to the transform
499   */
500  public static void doTransform(URL xmlUrl,
501                                 URL xslUrl,
502                                 PrintWriter outWriter,
503                                 Hashtable params)
504              throws IOException,
505                     TransformerConfigurationException,
506                     TransformerException,
507                     IOException,
508                     ParserConfigurationException,
509                     SAXException
510  {
511    if (xmlUrl != null && xslUrl != null && outWriter != null)
512    {
513      InputStream xmlStream = xmlUrl.openStream();
514      InputStream xslStream = xslUrl.openStream();
515      if (xmlStream != null && xslStream != null)
516      {
517        doTransform(xmlStream, xslStream, outWriter, params);
518      }
519    }
520  }
521
522
523  /**
524   * Performs the XSL transform on the XML.
525   *
526   * @param xmlStream  The Stream of XML data
527   * @param xslStream  The Stream of XSL data
528   * @param outStream  The Stream to dump the output from the transform
529   * @param params other parameters to pass directly to the transform
530   */
531  public static void doTransform(InputStream xmlStream,
532                          InputStream xslStream,
533                          OutputStream outStream,
534                          Hashtable params)
535              throws TransformerConfigurationException,
536                     TransformerException,
537                     IOException,
538                     ParserConfigurationException,
539                     SAXException
540  {
541    doTransform(xmlStream, xslStream, new PrintWriter(outStream), params);
542  }
543
544
545  /**
546   * Performs the XSL transform on the XML.
547   *
548   * @param xmlStream  The Stream of XML data
549   * @param xslStream  The Stream of XSL data
550   * @param outWriter  The OutputPrinter to dump the output from the transform
551   * @param params other parameters to pass directly to the transform
552   */
553  public static void doTransform(InputStream xmlStream,
554                          InputStream xslStream,
555                          PrintWriter outWriter,
556                          Hashtable params)
557              throws TransformerConfigurationException,
558                     TransformerException,
559                     IOException,
560                     ParserConfigurationException,
561                     SAXException
562  {
563    //System.setProperty("javax.xml.transform.TransformerFactory","bla.bla");
564
565    TransformerFactory tFactory = TransformerFactory.newInstance();
566    if(false && tFactory.getFeature(DOMSource.FEATURE))
567    {
568      System.out.println("Using A Dom Parser");
569      //Instantiate a DocumentBuilderFactory.
570      DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
571
572      // And setNamespaceAware, which is required when parsing xsl files
573      dFactory.setNamespaceAware(true);
574
575      //Use the DocumentBuilderFactory to create a DocumentBuilder.
576      DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
577
578      //Use the DocumentBuilder to parse the XSL stylesheet.
579      Document xslDoc = dBuilder.parse(xslStream);
580
581      // Use the DOM Document to define a DOMSource object.
582      DOMSource xslDomSource = new DOMSource(xslDoc);
583
584      // Set the systemId: note this is actually a URL, not a local filename
585      //xslDomSource.setSystemId(xmlFileOutputDir_);
586
587      // Process the stylesheet DOMSource and generate a Transformer.
588      Transformer transformer = tFactory.newTransformer(xslDomSource);
589
590      //Use the DocumentBuilder to parse the XML input.
591      Document xmlDoc = dBuilder.parse(xmlStream);
592
593      // Use the DOM Document to define a DOMSource object.
594      DOMSource xmlDomSource = new DOMSource(xmlDoc);
595
596      // Set the base URI for the DOMSource so any relative URIs it contains can
597      // be resolved.
598      //xmlDomSource.setSystemId(xmlFileOutputDir_);
599
600      String name = null;
601      for (Enumeration myEnum = params.keys(); myEnum.hasMoreElements();)
602      {
603        name = (String)myEnum.nextElement();
604        transformer.setParameter(name, (String)params.get(name));
605      }
606
607      transformer.transform(xmlDomSource, new StreamResult(outWriter));
608    }
609    else
610    { // use the default SAX parser
611      // Get the XML input document and the stylesheet.
612      Source xslSource = new StreamSource(xslStream);
613      // Generate the transformer.
614      Transformer transformer = tFactory.newTransformer(xslSource);
615
616      String name = null;
617      for (Enumeration myEnum = params.keys(); myEnum.hasMoreElements();)
618      {
619        name = (String)myEnum.nextElement();
620        transformer.setParameter(name, (String)params.get(name));
621      }
622
623      // StreamSource wants either a reader or an inputStream
624      Source xmlSource = new StreamSource(xmlStream);
625      // Perform the transformation, sending the output to the response.
626      transformer.transform(xmlSource, new StreamResult(outWriter));
627    }
628  }
629
630
631  /**
632   * Handles Post Requests by simply calling the doGet Method.
633   *
634   * @param req                   HttpServletRequest that encapsulates the
635   *                              request to the servlet
636   * @param res                   HttpServletResponse that encapsulates the
637   *                              response from the servlet
638   * @exception ServletException  if the request could not be handled
639   * @exception IOException       in case of an write error while handling
640   *                              request
641   */
642  public void doPost(HttpServletRequest req, HttpServletResponse res)
643     throws ServletException, IOException
644  {
645    doGet(req, res);
646  }
647
648
649  /**
650   * Performs the HTTP GET operation. This is the universal entry point to this
651   * servlets functions. <P>
652   *
653   * It provides many options for how things are processed:
654   * <UL>
655   *   <LI> db/sql --> XML file</LI>
656   *   <LI> db/sql --> XML returned to http response outputstream</LI>
657   *   <LI> db/sql --> XML --> XSL (specified by the caller)
658   *   <UL>default transforms available
659   *     <LI> XML --> html tree representation</LI>
660   *     <LI> XML --> html table representation</LI>
661   *     <LI> XML --> comma separated value listing</LI>
662   *   </UL>
663   *   </LI>
664   *   <LI> XML file --> XSL</LI>
665   *   <LI> XML data from a passed parameter --> XSL</LI>
666   * </UL>
667   * The XSL template can be specified:
668   * <UL>
669   *   <LI> As a URL to a XSL file</LI> or as
670   *   <LI> XSL data from a passed parameter</LI>
671   * </UL>
672   * The parameters used/passed that control the operation are:
673   * <UL>
674   *   <LI> dbQuery (valid sql query) default = ""</LI>
675   *   <LI> xslTransform (true/false) default = "true"</LI>
676   *   <LI> xslURL (a valid URL to an xsl file) default = "file://./defaultHtmlTable.xsl"
677   *   </LI>
678   *   <LI> saveXmlFile (true/false) default = "false"</LI>
679   *   <LI> xmlURL (a valid URL to an xml file) default = ""</LI>
680   *   <LI> xmlSource (valid xml) default = ""</LI>
681   *   <LI>
682   *   <OL>The following jdbc parametyers can be spec'd to override the defaults
683   *     set in the db2xml.properties file.
684   *     <LI> jdbcDriverClass (a driver package.classname) default = ""</LI>
685   *     <LI> jdbcURL (the url of the db to query) default = ""</LI>
686   *     <LI> jdbcUsername (the username to connect with) default = ""</LI>
687   *     <LI> jdbcPassword (the password to connect with) default = ""</LI>
688   *   </OL>
689   *   </LI>
690   *   <LI> </LI>
691   *   <LI> </LI>
692   *   <LI> </LI>
693   * </UL>
694   *
695   *
696   * @param req                   HttpServletRequest that encapsulates the
697   *                              request to the servlet.
698   * @param res                   HttpServletResponse that encapsulates the
699   *                              response from the servlet.
700   * @exception ServletException  if the request could not be handled.
701   * @exception IOException       in case of an write error while handling
702   *                              request.
703   */
704  public void doGet(HttpServletRequest req, HttpServletResponse res)
705     throws IOException, ServletException
706  {
707    Hashtable otherParams = new Hashtable();
708
709    // define a simple Vector of all acceptable parms so we can use the
710    // '.contains' method to quickly check if a param is expected
711    Vector definedParamKeys = new Vector();
712    definedParamKeys.add("dbQuery");
713    definedParamKeys.add("xslTransform");
714    definedParamKeys.add("saveXmlFile");
715    definedParamKeys.add("xslURL");
716    definedParamKeys.add("xmlURL");
717    definedParamKeys.add("numXmlFiles");
718    definedParamKeys.add("xmlSource");
719    definedParamKeys.add("jdbcDriverClass");
720    definedParamKeys.add("jdbcURL");
721    definedParamKeys.add("jdbcUsername");
722    definedParamKeys.add("jdbcPassword");
723    definedParamKeys.add("dumpDebug");
724    definedParamKeys.add("fileBaseDir");
725
726    //These properties should be set in a servlet environment
727    //regardless of the values defined in the property file
728    map_.setProperty("out", "stream");
729    map_.setProperty("el.binfields", "ignore");
730    map_.setBooleanProperty("el.protectStrings", true);
731    map_.setProperty("genDTD", "no");
732
733    // get the input parameters
734    String dbQuery = req.getParameter("dbQuery");
735    String xslTransformStr = req.getParameter("xslTransform");
736    String xslURL = req.getParameter("xslURL");
737    String saveXmlFileStr = req.getParameter("saveXmlFile");
738    String xmlURL = req.getParameter("xmlURL");
739    String numXmlFilesStr = req.getParameter("numXmlFiles");
740    String xmlSource = req.getParameter("xmlSource");
741    String jdbcDriverClass = req.getParameter("jdbcDriverClass");
742    String jdbcURL = req.getParameter("jdbcURL");
743    String jdbcUsername = req.getParameter("jdbcUsername");
744    String jdbcPassword = req.getParameter("jdbcPassword");
745    String dumpDebugStr = req.getParameter("dumpDebug");
746    String fileBaseDir = req.getParameter("fileBaseDir");
747
748    // now get any other params that were passed, so we can forward them to the
749    // transformer
750    Enumeration myEnum = req.getParameterNames();
751    String name = null;
752    while (myEnum.hasMoreElements())
753    {
754      name = (String) myEnum.nextElement();
755      if (!definedParamKeys.contains(name))
756        otherParams.put(name, req.getParameter(name));
757    }
758
759    String contentTypeStr = "text/html";
760    boolean proceed = true;
761    boolean useXmlSource = false;
762    String errorMsg = "unknown";
763    String xmlFileOutputName = xmlFileOutputName_;
764
765    // cast parameters to appropriate types and validate at the same time
766    boolean saveXmlFile =
767      (saveXmlFileStr != null ? saveXmlFileStr.equals("true") : false);
768    boolean doXslTransform =
769      (xslTransformStr != null ? xslTransformStr.equals("true") : true);
770    dumpDebug_ =
771      (dumpDebugStr != null ? dumpDebugStr.equals("true") : false);
772    int numXmlFiles = 1;
773    if (numXmlFilesStr != null && !numXmlFilesStr.equals(""))
774    {
775      numXmlFiles = Integer.parseInt(numXmlFilesStr);
776    }
777
778    //Parameter validation
779    boolean doDbQuery = (dbQuery != null ? !dbQuery.equals("") : false);
780    boolean streamXmlOut =
781      (doDbQuery && !saveXmlFile && !doXslTransform ? true : false);
782
783    // confirm BaseDir info
784    if (fileBaseDir != null && !fileBaseDir.equals(""))
785    {
786      fileBaseDir_ = fileBaseDir;
787      if (!fileBaseDir_.endsWith(SYSTEM_FILE_SEPERATOR))
788        fileBaseDir_ += SYSTEM_FILE_SEPERATOR;
789    }
790
791    // confirm xsl info
792    if (xslURL == null || xslURL.equals(""))
793    {
794      xslURL = DEFAULT_XSL_STYLESHEET_URL;
795    }
796
797    // confirm xml data source
798    if (!doDbQuery)
799    {
800      dbQuery = "";
801      if (saveXmlFile)
802      {
803        proceed = false;
804        errorMsg = "Request to Save the XML to file BUT " +
805                   "no dbQuery parameter was specified."+usageHtml_;
806      }
807      else
808      {
809        // we better make sure there is valid XML coming from somewhere else
810        if ((xmlURL == null || xmlURL.equals("")))
811        {
812          if (xmlSource == null || xmlSource.equals(""))
813          {
814            // no XML found
815            proceed = false;
816            errorMsg = "At least one source for the XML must be specified: " +
817                       "dbQuery, xmlURL or xmlSource."+usageHtml_;
818          }
819          else
820          {
821            useXmlSource = true;
822          }
823        }
824        else  //valid xmlURL
825        {
826          // do nothing here ... save the actual processing for later
827        }
828      }
829    }
830    else // we are doing a dbQuery
831    {
832      if (!streamXmlOut)
833      {
834        if(!doXslTransform)
835        {
836          // we have been asked to send the output to a file so validate the
837          // filename
838          if(xmlURL == null || xmlURL.equals(""))
839          {
840            // XML output filename not spec'd so bug out
841            proceed = false;
842            errorMsg = "Request to Save the XML to file BUT " +
843                       "no xmlURL parameter was specified."+usageHtml_;
844          }
845        }
846      }
847      else
848      {
849        contentTypeStr = "text/xml";
850      }
851    }
852    // by now we have
853    // the proceed flag init and
854    // a valid Xml data Source and
855    // an xsl data source URL set up and
856    // the returned contentType is set
857
858    // lets do the work for the request
859    PrintWriter out = res.getWriter();
860    String absoluteFilename = "";
861
862    if (proceed)
863    {
864      res.setStatus(HttpServletResponse.SC_OK);
865      XMLDocument xmlDoc = null;
866      try
867      {
868        if (doDbQuery)
869        {
870          // query the db and return the XML
871          xmlDoc = db2XmlDocument(dbQuery);
872          if (saveXmlFile)
873          {
874            absoluteFilename = xmlFileOutputDir_ + this.SYSTEM_FILE_SEPERATOR +
875              convertSystemDependantPath(parseIntoUrl(xmlURL));
876            writeXmlFile(absoluteFilename, xmlDoc);
877            xmlURL = "file:///"+ absoluteFilename;
878          }
879          else
880          {
881            // we need to Pump the XMLOutput from the xmlDoc into an InputStream
882            // for now just dump into a temp file that we can read from.
883            String tmp = System.getProperty("java.io.tmpdir");
884            if (tmp == null || tmp.equals(""))
885              tmp = "." + SYSTEM_FILE_SEPERATOR;
886            else
887            {
888              if (!(tmp.trim().endsWith(SYSTEM_FILE_SEPERATOR)))
889              {
890                tmp = tmp.trim() + SYSTEM_FILE_SEPERATOR;
891              }
892            }
893            absoluteFilename = tmp + xmlFileOutputName_ + "TempStream.xml";
894            writeXmlFile(absoluteFilename, xmlDoc);
895            xmlURL = "file:///"+ absoluteFilename;
896          }
897
898        }
899        else // no db query specified
900        {
901          absoluteFilename = parseIntoUrl(xmlURL).toString();
902          // we only have to do something if we are going to Stream
903          if (streamXmlOut)
904          {
905            // not implemented yet
906            xmlDoc = new XMLDocument(map_);
907            // the xmlDoc will now have to be filled with the data from
908            // either the xmlSource or xmlURL
909          }
910        }
911
912        /* Now the XML is is place.. so send something back to the requester */
913        /* ***************************************************************** */
914        if (dumpDebug_)
915        {
916          res.setContentType("text/html");
917          out.write("<HTML>\n");
918          out.write("<Head>\n");
919          out.write("<title>" + getServletName() +
920                    " - Debug Output</TITLE></head>\n");
921          out.write("<body>\n<h2>" + getServletName() +
922                    " - Debug Output</h2>\n");
923          out.write("<H4>Request was:" + "</H4>" + req.getQueryString() +
924                    "<H4>Request Parms are:</H4><OL>");
925          String parm;
926          String val;
927          for (Enumeration parmEnum = req.getParameterNames();
928               parmEnum.hasMoreElements(); )
929          {
930            parm = (String) parmEnum.nextElement();
931            val = req.getParameter(parm);
932            out.write("<LI>"+parm + " : " + val + "</LI>");
933          }
934          out.write("</OL>\n<B>Other Settings</B><BR>\n");
935          out.write((saveXmlFile?"Saved ":"UnSaved ")+"XML File=" +
936                     absoluteFilename + "<BR>\n");
937          out.write("doXslTransform = " +doXslTransform + "<BR>\n");
938          out.write("users current dir = " +System.getProperty("user.dir") +
939            "<BR>\n");
940          out.write("XML URL = " + parseIntoUrl(xmlURL) + "<BR>\n");
941          out.write("XSL URL = " +parseIntoUrl(xslURL) + "<BR>\n");
942          for (Enumeration parmEnum = otherParams.keys();
943               parmEnum.hasMoreElements(); )
944          {
945            parm = (String) parmEnum.nextElement();
946            val = (String)otherParams.get(parm);
947            out.write(" - "+parm + " : " + val + "<BR>\n");
948          }
949          out.write(" " +
950                    "\n");
951          out.write("</body>\n</html>");
952        }
953        else  // now send something back to the Client
954        {
955          res.setContentType("text/html");
956          if (doXslTransform)
957          {
958            InputStream xmlStream = null;
959            InputStream xslStream = null;
960            if (numXmlFiles == 1)
961            {
962              URL in = parseIntoUrl(xmlURL);
963              URL trans = parseIntoUrl(xslURL);
964
965              if (!in.getProtocol().equals("file"))
966              {
967
968                URLConnection inConnection = in.openConnection();
969                URLConnection transConnection = trans.openConnection();
970
971                // test for access
972                try
973                {
974                  xmlStream = inConnection.getInputStream();
975                  xslStream = transConnection.getInputStream();
976                }
977                catch (IOException ex)
978                {
979                  try
980                  {
981                    xmlStream = in.openStream();
982                    xslStream = trans.openStream();
983                  }
984                  catch (Exception ex2)
985                  {
986                    errorMsg = ex2.getMessage() +
987                      "<BR>Unable to complete the transformation because I "+
988                      "cannot read one of the required files:<BR>" +
989                      "Please check the xmlURL and the xslURL.<BR>"+
990                      "xml=" + in.toExternalForm() +
991                      "<BR>xsl=" + trans.toExternalForm()+usageHtml_ ;
992                    proceed = false;
993                  }
994                }
995              }
996              else
997              { //get a file Input stream
998                xmlStream = new FileInputStream(fileBaseDir_ + xmlURL);
999                xslStream = new FileInputStream(fileBaseDir_ + xslURL);
1000              }
1001
1002              if (xmlStream != null && xslStream != null && proceed)
1003                doTransform(xmlStream, xslStream, out, otherParams);
1004              else
1005              {
1006                if (proceed)
1007                {
1008                  errorMsg = "Unable to complete the transformation because " +
1009                    "I cannot read one of the required files:<BR>" +
1010                    "Please check the xmlURL and the xslURL."+usageHtml_;
1011                  proceed = false;
1012                }
1013              }
1014            }
1015            else
1016            {
1017              // build in the capability to process more than 1 xml/xsl in line
1018              // produce 1 output report based on a number of xml files
1019              for (int i=1; i <= numXmlFiles; i++)
1020              {
1021                //alter the URL names we are looking for
1022                xmlStream = parseIntoUrl(xmlURL+i+".xml").openStream();
1023                xslStream = parseIntoUrl(xslURL+i+".xsl").openStream();
1024                doTransform(xmlStream, xslStream, out, otherParams);
1025              }
1026            }
1027          }
1028          else if (streamXmlOut)
1029          {
1030            res.setContentType("text/xml");
1031
1032            // send the XML straight back to the client
1033            // yet to implement
1034          }
1035          else
1036          {
1037            if (saveXmlFile)
1038            {
1039              res.setContentType("text/html");
1040              out.write("<HTML>\n");
1041              out.write("<Head>\n");
1042              out.write("<title>" + getServletName() +
1043                        " - Completed</TITLE></head>\n");
1044              out.write("<body>\n<h2>" + getServletName() +
1045                        " - Completed</h2>\n");
1046              out.write("<H4>File Saved Successfully:</H4>");
1047              out.write("XML File=" + absoluteFilename + "<BR>\n");
1048              out.write("XML URL = " + parseIntoUrl(xmlURL) + "<BR>\n");
1049              out.write("</body>\n</html>");
1050
1051            }
1052            else // error ... an error response is provided below
1053            {
1054              errorMsg = "One of the following 3 output options was not " +
1055                "specified/completed:\n<OL><LI>XSL Transformation<LI>Stream " +
1056                "the XML Results back without transformation<LI>Save the XML " +
1057                "to a file.</OL>"+usageHtml_;
1058              proceed = false;
1059            }
1060          }
1061        }
1062      }
1063      catch (Exception e)
1064      {
1065          out.write("<H3>DbXmlXsl threw an exception on the server:</H3>" +
1066          "<H4>query was:</H4>" + dbQuery +
1067          "<H4>Request was:" + "</H4>" + req.getQueryString() +
1068          "<H4>Request Parms are:</H4>");
1069
1070        String parm;
1071        String val;
1072        for (Enumeration parmEnum = req.getParameterNames();
1073             parmEnum.hasMoreElements(); )
1074        {
1075          parm = (String) parmEnum.nextElement();
1076          val = req.getParameter(parm);
1077          out.write(parm + " : " + val + "<BR>");
1078        }
1079          out.write("</OL>\n<B>Other Settings</B><BR>\n");
1080          out.write((saveXmlFile?"Saved ":"UnSaved ")+"XML File=" +
1081                     absoluteFilename + "<BR>\n");
1082          out.write("doXslTransform = " +doXslTransform + "<BR>\n");
1083          out.write("users current dir = " +System.getProperty("user.dir") +
1084            "<BR>\n");
1085          out.write("XML URL = " + parseIntoUrl(xmlURL) + "<BR>\n");
1086          out.write("XSL URL = " +parseIntoUrl(xslURL) + "<BR>\n");
1087          for (Enumeration parmEnum = otherParams.keys();
1088               parmEnum.hasMoreElements(); )
1089          {
1090            parm = (String) parmEnum.nextElement();
1091            val = (String)otherParams.get(parm);
1092            out.write(" - "+parm + " : " + val + "<BR>\n");
1093          }
1094          out.write(" " +
1095                    "\n");
1096        out.write("<H4>error message:</H4>" + e.getMessage() + "<BR><PRE>");
1097        e.printStackTrace(out);
1098        out.write("</PRE><HR>"+usageHtml_+"</body></html>");
1099      }
1100    }
1101
1102    if (!proceed)
1103    {
1104      res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
1105      res.setContentType("text/html");
1106      out.write("<HTML>\n");
1107      out.write("<Head>\n");
1108      out.write("<title>" + getServletName() +
1109                " - Request Not Completed</TITLE></head>\n");
1110      out.write("<body>\n<h2>" + getServletName() +
1111                " - Request Not Completed</h2>\n");
1112      out.write("<H4>Request was:" + "</H4>" + req.getQueryString() +
1113                "<H4>Request Parms are:</H4>");
1114      String parm;
1115      String val;
1116      for (Enumeration parmEnum = req.getParameterNames();
1117           parmEnum.hasMoreElements(); )
1118      {
1119        parm = (String) parmEnum.nextElement();
1120        val = req.getParameter(parm);
1121        out.write(parm + " : " + val + "<BR>");
1122      }
1123      out.write("<HR>\n");
1124      out.write("<P>Possible error: " + errorMsg + "\n");
1125      out.write("<P>Please review/correct the request parameters " +
1126                "and resubmit.\n");
1127      out.write("</body>\n</html>");
1128    }
1129    out.flush();
1130
1131  }
1132
1133
1134  /**
1135   * Parses a String representation of a URL or absolute file path and converts
1136   * it into a URL.<P>This method is a bit forgiving... if the string is not
1137   * a correctlty formatted http, ftp, or file URL it will assume it is a file
1138   * URL and create the returned URL as such.
1139   *
1140   * @param value is the String to convert into a URL.
1141   *
1142   * @return the Valid URL for the Executable or null if this method failed to
1143   *         convert the passed in string.
1144   *
1145   * @throws MalformedURLException if the passed in String is not a URL
1146   **/
1147  private URL parseIntoUrl(String value)
1148     throws MalformedURLException
1149  {
1150    URL retVal = null;
1151    if (value != null)
1152    {
1153      if (value.toLowerCase().startsWith("http:/") ||
1154          value.toLowerCase().startsWith("ftp:/")  ||
1155          value.toLowerCase().startsWith("file:/"))
1156      {
1157        // the following throws a MalformedURLException if value is bad
1158        retVal = new URL(value);
1159      }
1160      else // assume it is a http:// path
1161      {
1162        try
1163        {
1164          String tempPath = value; // Assume Un*x ... no replacement needed
1165          if (SYSTEM_FILE_SEPERATOR.equals("\\"))
1166          {
1167            /* Replace the file separators with the forward slash */
1168            tempPath = ""; // start from scratch
1169            for ( int i = 0; i < value.length(); i++)
1170            {
1171              if (value.charAt(i) != SYSTEM_FILE_SEPERATOR.charAt(0) )
1172              {
1173                tempPath += value.substring(i,i+1);
1174              }
1175              else
1176              {
1177                tempPath += "/";
1178              }
1179            }
1180          }
1181          retVal = new URL("file://" + fileBaseDir_ + tempPath);
1182        }
1183        catch (NullPointerException badUrl)
1184        {
1185          throw new MalformedURLException("Can't parse the location URL from the " +
1186            "file path provided.");
1187        }
1188      }
1189    }
1190    return retVal;
1191  }
1192
1193
1194  /**
1195   * Converts the path component of a URL to the native relative file path.
1196   *
1197   * @param the url to use to convert.
1198   *
1199   * @return the converted path string. It will return a "" if the URL does not
1200   *         include a filepath portion.
1201   **/
1202  public String convertSystemDependantPath(URL url)
1203  {
1204    String retVal = "";
1205
1206    // First check if we need to do the '/' conversion
1207    if (url != null && SYSTEM_FILE_SEPERATOR.equals("\\"))
1208    {
1209      // yup... we have to switch 'em
1210      // gotta use getFile instead of getPath which is a jdk 1.3 method
1211      String tempPath = url.getFile();
1212      for ( int i = 0; i < tempPath.length();i++)
1213      {
1214        if (tempPath.charAt(i) != '/' )
1215        {
1216          retVal += tempPath.substring(i,i+1);
1217        }
1218        else
1219        {
1220          if (i != 0)
1221            retVal += "\\";
1222        }
1223      }
1224    }
1225    else if (url != null)
1226      // It is a Un*x path (no conversion needed)
1227      retVal = url.getFile().substring(1);
1228
1229    return retVal;
1230  }
1231}