001/*
002 *  $Rev: 1405 $:     Revision of last commit
003 *  $Author: tgutwin $:  Author of last commit
004 *  $Date: 2020-11-08 11:07:46 -0800 (Sun, 08 Nov 2020) $:    Date of last commit
005 *  Copyright (C) 2001-2012 WebARTS Design,
006 *  North Vancouver Canada. All Rights Reserved.
007 *
008 *  Written by Tom Gutwin - WebARTS Design.
009 *  http://www..webarts.bc.ca
010 *
011 *  This program is free software; you can redistribute it and/or modify
012 *  it under the terms of the GNU General Public License as published by
013 *  the Free Software Foundation; either version 2 of the License, or
014 *  (at your option) any later version.
015 *
016 *  This program is distributed in the hope that it will be useful,
017 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
018 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
019 *  GNU General Public License for more details.
020 *
021 *  You should have received a copy of the GNU General Public License
022 *  along with this program; if not, write to the Free Software
023 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
024 */
025package ca.bc.webarts.tools;
026
027
028import ca.bc.webarts.widgets.Util;
029
030import java.awt.*;
031import java.awt.geom.Ellipse2D;
032import java.awt.geom.Rectangle2D;
033import java.io.File;
034import java.io.PrintWriter;
035import java.io.Writer;
036import java.io.OutputStreamWriter;
037import java.io.FileOutputStream;
038import java.sql.*;
039import java.text.SimpleDateFormat;
040import java.util.Date;
041import java.util.ArrayList;
042import java.util.Calendar;
043//import java.util.HashMap;
044import java.util.Iterator;
045import java.util.Locale;
046import java.util.Properties;
047import java.util.StringTokenizer ;
048import java.util.Vector;
049import java.text.NumberFormat;
050import javax.servlet.http.HttpSession;
051import javax.swing.event.TableModelEvent;
052import javax.swing.table.AbstractTableModel;
053
054import au.com.bytecode.opencsv.CSVReader;
055import au.com.bytecode.opencsv.CSVWriter;
056import jxl.*;
057import jxl.write.*;
058
059
060import org.logicalcobwebs.proxool.*;
061import org.logicalcobwebs.proxool.configuration.*;
062
063import org.jfree.data.*;
064import org.jfree.chart.*;
065import org.jfree.chart.annotations.CategoryTextAnnotation;
066import org.jfree.chart.axis.*;
067import org.jfree.chart.ChartUtilities;
068import org.jfree.chart.renderer.category.CategoryItemRenderer;
069import org.jfree.chart.renderer.category.LineAndShapeRenderer;
070import org.jfree.chart.renderer.category.BarRenderer;
071import org.jfree.chart.renderer.category.StackedBarRenderer;
072import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
073import org.jfree.chart.renderer.xy.StackedXYAreaRenderer;
074import org.jfree.chart.plot.*;
075import org.jfree.chart.entity.*;
076import org.jfree.chart.labels.*;
077import org.jfree.chart.urls.*;
078import org.jfree.chart.servlet.*;
079import org.jfree.data.category.DefaultCategoryDataset;
080import org.jfree.data.general.DefaultPieDataset;
081
082import org.w3c.dom.*;
083import org.apache.batik.dom.GenericDOMImplementation;
084import org.apache.batik.svggen.SVGGraphics2D;
085
086
087/**
088 *  A helper Class to encapsulate SQL queries.
089 *
090 * @author    TGutwin
091 */
092public class SqlQuery
093{
094  /**  A holder for this clients System File Separator.  */
095  public final static String SYSTEM_FILE_SEPERATOR = java.io.File.separator;
096
097  /**  A holder for this clients System line termination separator.  */
098  public final static String SYSTEM_LINE_SEPERATOR =
099                                           System.getProperty("line.separator");
100  public final static String DEFAULT_COLUMN_DELIMITOR = "|";
101
102  protected static boolean debugOut = false;
103
104  protected static ca.bc.webarts.tools.Log log_= Log.getInstance();
105
106  public final static short ORACLE_DB = 0;
107  public final static short POSTGRE_DB = 1;
108  public final static short MYSQL_DB = 2;
109  public final static short DB2_DB = 3;
110  public final static short DERBY_DB = 4;
111  public final static short HSQL_DB = 5;
112  public final static short ODBC_DB = 6;
113  public final static short ORACLEDEDICATED_DB = 7;
114  public final static short MARIADB_DB = 8;
115  public final static short OTHER_DB = 12;
116  public final static short DEFAULT_DB = MARIADB_DB;
117
118  protected final static String oraDbDriverName = "oracle.jdbc.OracleDriver";
119  protected final static String mysqlDbDriverName = "com.mysql.jdbc.Driver"; //"org.gjt.mm.mysql.Driver";
120  protected final static String mariadbDbDriverName = "org.mariadb.jdbc.Driver";
121  protected final static String pgDbDriverName = "org.postgresql.Driver";
122  protected final static String hsqlDbDriverName = "org.hsqldb.jdbcDriver";
123  protected final static String db2DbDriverName = "COM.ibm.db2.jdbc.app.DB2Driver";
124  protected final static String odbcDbDriverName = "sun.jdbc.odbc.JdbcOdbcDriver";
125  protected final static String proxoolDriverName = "org.logicalcobwebs.proxool.ProxoolDriver";
126  protected final static String derbyDbDriverName = "org.apache.derby.jdbc.ClientDriver";
127
128  protected final static String oraDbPort = "1521";
129  protected final static String pgDbPort = "5432";
130  protected final static String mysqlDbPort = "3306";
131  protected final static String mariadbDbPort = "3306";
132  protected final static String hsqlDbPort = "1476";
133  protected final static String db2DbPort = "50000";
134  protected final static String derbyDbPort = "1527";
135
136  /** Field signifying what DB type this query will access. **/
137  protected short dbType_ = DEFAULT_DB;
138
139  protected boolean useProxoolPool_ = false;
140  protected int proxoolMaximumConnectionCount_ = 10;
141  protected boolean oraDedicated_ = false;
142
143  protected static String columnDelimitor = DEFAULT_COLUMN_DELIMITOR;
144  protected String sqlSelect = "";
145  protected String sqlFrom = "";
146  protected String sqlFrom2 = "";
147  protected String sqlFrom3 = "";
148  protected String sqlFrom4 = "";
149  protected String sqlFrom5 = "";
150  protected String sqlWhere = "";
151  protected String sqlOrder = "";
152
153  protected String dbUser = "";
154  protected String dbPassword = "";
155  protected String dbDriverName = "oracle.jdbc.OracleDriver";
156  protected String dbIP = ""; //"edmfdpp1";
157  protected String dbPort = "";
158  protected String dbName = ""; //"FDPPRD";
159
160  protected String dbConnectString = "";
161  protected String testDbConnectString = "jdbc:oracle:thin:@//172.28.15.218:1521/MRSD";
162
163  protected Connection con = null;
164
165  protected long randLong = Math.round(Math.random()*10000000);
166  protected String randStr = String.valueOf(randLong);
167  protected static Calendar calendar_ = Calendar.getInstance();
168  protected static int yr_ = calendar_.get(Calendar.YEAR);
169  protected static int mo_ = calendar_.get(Calendar.MONTH)+1;
170  protected static int dy_ = calendar_.get(Calendar.DATE);
171
172
173  /**  Constructor for the SqlQuery object */
174  public SqlQuery()
175  {
176    /*
177    System.out.println("[ca.bc.webarts.SqlQuery > SqlQuery()]" +
178      (new java.util.Date()).toString());
179    */
180  }// -- Constructor
181
182
183  /**
184    * Set Method for class field 'columnDelimitor'.
185    *
186    * @param columnDelimitor is the value to set this class field to.
187    *
188    **/
189  public  void setColumnDelimitor(String columnDelimitor)
190  {
191    this.columnDelimitor = columnDelimitor;
192  }  // setColumnDelimitor Method
193
194
195  /**
196    * Get Method for class field 'columnDelimitor'.
197    *
198    * @return String - The value the class field 'columnDelimitor'.
199    *
200    **/
201  public static String getColumnDelimitor()
202  {
203    return columnDelimitor;
204  }  // getColumnDelimitor Method
205
206
207  /**
208    * Set Method for class field 'sqlOrder'.
209    *
210    * @param sqlOrder is the value to set this class field to.
211    *
212    **/
213  public  void setSqlOrder(String sqlOrder)
214  {
215    this.sqlOrder = sqlOrder;
216  }  // setSqlOrder Method
217
218
219  /**
220    * Get Method for class field 'sqlOrder'.
221    *
222    * @return String - The value the class field 'sqlOrder'.
223    *
224    **/
225  public String getSqlOrder()
226  {
227    return sqlOrder;
228  }  // getSqlOrder Method
229
230
231  /**
232    * Set Method for class field 'sqlWhere'.
233    *
234    * @param sqlWhere is the value to set this class field to.
235    *
236    **/
237  public  void setSqlWhere(String sqlWhere)
238  {
239    this.sqlWhere = sqlWhere;
240  }  // setSqlWhere Method
241
242
243  /**
244    * Get Method for class field 'sqlWhere'.
245    *
246    * @return String - The value the class field 'sqlWhere'.
247    *
248    **/
249  public String getSqlWhere()
250  {
251    return sqlWhere;
252  }  // getSqlWhere Method
253
254
255  /**
256    * Set Method for class field 'sqlFrom'.
257    *
258    * @param sqlFrom is the value to set this class field to.
259    *
260    **/
261  public  void setSqlFrom(String sqlFrom)
262  {
263    this.sqlFrom = sqlFrom;
264  }  // setSqlFrom Method
265
266
267  /**
268    * Get Method for class field 'sqlFrom'.
269    *
270    * @return String - The value the class field 'sqlFrom'.
271    *
272    **/
273  public String getSqlFrom()
274  {
275    return sqlFrom;
276  }  // getSqlFrom Method
277
278
279  /**
280    * Set Method for class field 'sqlFrom2'.
281    *
282    * @param sqlFrom2 is the value to set this class field to.
283    *
284    **/
285  public  void setSqlFrom2(String sqlFrom2)
286  {
287    this.sqlFrom2 = sqlFrom2;
288  }  // setSqlFrom Method
289
290
291  /**
292    * Get Method for class field 'sqlFrom2'.
293    *
294    * @return String - The value the class field 'sqlFrom2'.
295    *
296    **/
297  public String getSqlFrom2()
298  {
299    return sqlFrom2;
300  }  // getSqlFrom Method
301
302
303  /**
304    * Set Method for class field 'sqlFrom3'.
305    *
306    * @param sqlFrom3 is the value to set this class field to.
307    *
308    **/
309  public  void setSqlFrom3(String sqlFrom3)
310  {
311    this.sqlFrom3 = sqlFrom3;
312  }  // setSqlFrom Method
313
314
315  /**
316    * Get Method for class field 'sqlFrom3'. It is a 3rd tablename to select from.
317    *
318    * @return String - The value the class field 'sqlFrom3'.
319    *
320    **/
321  public String getSqlFrom3()
322  {
323    return sqlFrom3;
324  }  // getSqlFrom Method
325
326
327  /**
328    * Set Method for class field 'sqlFrom4'.
329    *
330    * @param sqlFrom4 is the value to set this class field to.
331    *
332    **/
333  public  void setSqlFrom4(String sqlFrom4)
334  {
335    this.sqlFrom4 = sqlFrom4;
336  }  // setSqlFrom Method
337
338
339  /**
340    * Get Method for class field 'sqlFrom4'. It is a 4thablename to select from.
341    *
342    * @return String - The value the class field 'sqlFrom4'.
343    *
344    **/
345  public String getSqlFrom4()
346  {
347    return sqlFrom4;
348  }  // getSqlFrom Method
349
350
351  /**
352    * Set Method for class field 'sqlFrom3'.
353    *
354    * @param sqlFrom5 is the value to set this class field to.
355    *
356    **/
357  public  void setSqlFrom5(String sqlFrom5)
358  {
359    this.sqlFrom5 = sqlFrom5;
360  }  // setSqlFrom Method
361
362
363  /**
364    * Get Method for class field 'sqlFrom3'. It is a 3rd tablename to select from.
365    *
366    * @return String - The value the class field 'sqlFrom3'.
367    *
368    **/
369  public String getSqlFrom5()
370  {
371    return sqlFrom5;
372  }  // getSqlFrom Method
373
374
375  /**
376    * Set Method for class field 'sqlSelect'.
377    *
378    * @param sqlSelect is the value to set this class field to.
379    *
380    **/
381  public  void setSqlSelect(String sqlSelect)
382  {
383    this.sqlSelect = sqlSelect;
384  }  // setSqlSelect Method
385
386
387  /**
388    * Get Method for class field 'sqlSelect'.
389    *
390    * @return String - The value the class field 'sqlSelect'.
391    *
392    **/
393  public String getSqlSelect()
394  {
395    return sqlSelect;
396  }  // getSqlSelect Method
397
398
399  /**
400    * Set Method for class field 'dbConnectString'.
401    *
402    * @param dbConnectString is the value to set this class field to.
403    *
404    **/
405  public  void setDbConnectString(String dbConnectString)
406  {
407    this.dbConnectString = dbConnectString;
408  }  // setDbConnectString Method
409
410
411  /**
412    * Get Method for class field 'dbConnectString'.
413    *
414    * @return String - The value the class field 'dbConnectString'.
415    *
416    **/
417  public String getDbConnectString()
418  {
419    String retVal = dbConnectString;
420
421    switch (dbType_)
422    {
423    case ORACLEDEDICATED_DB:
424    case ORACLE_DB:
425      if(oraDedicated_)
426        retVal = "jdbc:oracle:thin:@(DESCRIPTION="   +
427                       "(ADDRESS_LIST="              +
428                           "(ADDRESS=(PROTOCOL=TCP)" +
429                                    "(HOST="+
430                                      getDbIP()+")"  +
431                                    "(PORT="+
432                                      (!dbPort.equals("")?dbPort:oraDbPort)+")"    +
433                           ")"                       +
434                       ")"                           +
435                       "(CONNECT_DATA="              +
436                           "(SERVICE_NAME="          +
437                             getDbName()+")"         +
438                           "(SERVER=DEDICATED)"      +
439                       ")"                           +
440                     ")";
441      else
442        retVal = "jdbc:oracle:thin:@"+getDbIP()+":"+(!dbPort.equals("")?dbPort:oraDbPort)+":"+getDbName();
443      break;
444
445    case POSTGRE_DB:
446       retVal = "jdbc:postgresql://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:pgDbPort)+"/"+getDbName();
447      break;
448
449    case MYSQL_DB:
450      //jdbc:mysql://<hostname>[<:3360>]/<dbname>
451      retVal = "jdbc:mysql://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:mysqlDbPort)+"/"+getDbName();
452      break;
453
454    case MARIADB_DB:
455      //jdbc:mysql://<hostname>[<:3360>]/<dbname>
456      retVal = "jdbc:mariadb://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:mysqlDbPort)+"/"+getDbName();
457      break;
458
459    case HSQL_DB:
460      //jdbc:hsqldb:hsql://<server>[:<1476>]
461      retVal = "jdbc:hsqldb:hsql://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:hsqlDbPort);
462      break;
463
464    case DB2_DB:
465      // jdbc:db2://<host_name>:<port_number>/<database_name>
466      retVal = "jdbc:db2://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:db2DbPort)+"/"+getDbName();
467      break;
468
469    case ODBC_DB:
470      // jdbc:odbc:<alias>
471      retVal = "jdbc:odbc:"+getDbName();
472      break;
473
474    case DERBY_DB:
475       // jdbc:derby://<server>[:<port>]/<databaseName>[;<URL attribute>=<value>]
476       //jdbc:derby://warp4:1527/wTracker;create=true
477       retVal = "jdbc:derby://"+getDbIP()+":"+(!dbPort.equals("")?dbPort:derbyDbPort)+"/"+getDbName();
478      break;
479
480    case OTHER_DB:
481    default:
482      // use the defaults or what the user has set with the class set methods
483      retVal = dbConnectString;
484    }
485    return retVal;
486  }  // getDbConnectString Method
487
488
489  /**
490    * Set Method for class field 'dbDriverName'.
491    *
492    * @param dbDriverName is the value to set this class field to.
493    *
494    **/
495  public  void setDbDriverName(String dbDriverName)
496  {
497    this.dbDriverName = dbDriverName;
498  }  // setDbDriverName Method
499
500
501  /**
502    * Get Method for class field 'dbDriverName'.
503    *
504    * @return String - The value the class field 'dbDriverName'.
505    *
506    **/
507  public String getDbDriverName()
508  {
509    return dbDriverName;
510  }  // getDbDriverName Method
511
512
513  /**
514    * Set Method for class field 'dbPassword'.
515    *
516    * @param dbPassword is the value to set this class field to.
517    *
518    **/
519  public  void setDbPassword(String dbPassword)
520  {
521    this.dbPassword = dbPassword;
522  }  // setDbPassword Method
523
524
525  /**
526    * Get Method for class field 'dbPassword'.
527    *
528    * @return String - The value the class field 'dbPassword'.
529    *
530    **/
531  public String getDbPassword()
532  {
533    return dbPassword;
534  }  // getDbPassword Method
535
536
537  /**
538    * Set Method for class field 'dbUser'.
539    *
540    * @param dbUser is the value to set this class field to.
541    *
542    **/
543  public  void setDbUser(String dbUser)
544  {
545    this.dbUser = dbUser;
546  }  // setDbUser Method
547
548
549  /**
550    * Get Method for class field 'dbUser'.
551    *
552    * @return String - The value the class field 'dbUser'.
553    *
554    **/
555  public String getDbUser()
556  {
557    return dbUser;
558  }  // getDbUser Method
559
560
561  /**
562    * Get Method for class field 'dbIP'.  This method should get overridden in any extending classes.
563    *
564    * @return String - The value the class field 'dbIP'.
565    *
566    **/
567  public String getDbIP()
568  {
569    return this.dbIP;
570  }  // getDbIP Method
571
572
573  /**
574    * Set Method for class field 'dbIP'.
575    *
576    * @param dbIP is the value to set this class field to.
577    *
578    **/
579  public  void setDbIP(String dbIP)
580  {
581    this.dbIP = dbIP;
582  }  // setDbUser Method
583
584
585  /**
586    * Set Method for class field 'dbName'.
587    *
588    * @param dbName  The value the class field 'dbName'.
589    *
590    **/
591  public void setDbName(String dbName)
592  {
593     this.dbName = dbName;
594  }  // setDbName Method
595
596
597  /**
598    * Get Method for class field 'dbName'.
599    *
600    * @return String - The value the class field 'dbUser'.
601    *
602    **/
603  public String getDbName()
604  {
605    return this.dbName;
606  }  // getDbUser Method
607
608
609  /**
610   *  Executes a SQL statement onto the JDBC accessed <b>TEST</b>database
611   *  defined by the class driver and connection string.
612   *
613   * @param sql is the SQL to execute
614   * @return a StringBuffer containing the ResultSet, one result per line.
615   **/
616  public StringBuffer testDbQuery(String sql)
617  {
618    System.out.println("Query on test DB: ");
619    return query(sql, false);
620  }
621
622
623  /**
624   *  Converts a ResultSet StringBuffer to a String [][] that holds the results cell by cell ColumnxRow.
625   *  It also strips the 1st row with the column headers. For example results[4][8] would get col4 row 8 data.
626   *
627   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
628   * @return a String Array containing the ResultSet, colsxrows (Without the coulmn header 1st row.
629   **/
630  public static String [][] sbToDataArray(StringBuffer rs)
631  {
632    String [] rows = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
633    String [] columns = (rows[0]).split("\\"+getColumnDelimitor());
634    String [][] retVal = new String[columns.length][rows.length];
635    //System.out.println("Results array - Columns: "+columns.length+"   Rows:"+rows.length);
636    if (rs != null)
637    {
638      for (int row=0; row<rows.length; row++)
639      {
640        columns = rows[row].split("\\"+getColumnDelimitor());
641        //System.out.println("Row "+row+" =  "+java.util.Arrays.toString(columns));
642        for (int column=0; column<columns.length; column++)
643        {
644          retVal[column][row] = columns[column];
645          //retVal[column][row] = Util.tokenReplace(columns[column],"\n", " ");
646        }
647      }
648    }
649    if (rs.indexOf("\n")+1 == 0) retVal = null;
650    return retVal;
651  }
652
653
654  /**
655   *  Converts a ResultSet StringBuilder to a String [][] that holds the results cell by cell ColumnxRow.
656   *  It also strips the 1st row with the column headers. For example results[4][8] would get col4 row 8 data.
657   *
658   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
659   * @return a String Array containing the ResultSet, colsxrows (Without the coulmn header 1st row.
660   **/
661  public static String [][] sbToDataArray(StringBuilder rs)
662  {
663    String [] rows = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
664    String [] columns = (rows[0]).split("\\"+getColumnDelimitor());
665    String [][] retVal = new String[columns.length][rows.length];
666    //System.out.println("Results array - Columns: "+columns.length+"   Rows:"+rows.length);
667    if (rs != null)
668    {
669      for (int row=0; row<rows.length; row++)
670      {
671        columns = rows[row].split("\\"+getColumnDelimitor());
672        //System.out.println("Row "+row+" =  "+java.util.Arrays.toString(columns));
673        for (int column=0; column<columns.length; column++)
674        {
675          retVal[column][row] = columns[column];
676          //retVal[column][row] = Util.tokenReplace(columns[column],"\n", " ");
677        }
678      }
679    }
680    if (rs.indexOf("\n")+1 == 0) retVal = null;
681    return retVal;
682  }
683
684
685  /**
686   *  Converts a ResultSet StringBuffer to a String [][] that holds the results cell by cell RowxColumn.
687   *  It also strips the 1st row with the column headers. For example results[4][8] would get row4 col8 data.
688   *
689   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
690   * @return a String Array containing the ResultSet, rowsxcols (Without the coulmn headers in the 1st row).
691   **/
692  public static String [][] sbToDataRowArray(StringBuffer rs)
693  {
694    String [] rows = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
695    String [] columns = (rows[0]).split("\\"+getColumnDelimitor());
696    String [][] retVal = new String[rows.length][columns.length];
697    //System.out.println("Results array - Columns: "+columns.length+"   Rows:"+rows.length);
698    if (rs != null)
699    {
700      for (int row=0; row<rows.length; row++)
701      {
702        columns = (rows[row]).split("\\"+getColumnDelimitor());
703        //System.out.print("Row "+row+" =  "+java.util.Arrays.toString(columns));
704        for (int column=0; column<columns.length; column++)
705        {
706          retVal[row][column] = columns[column];
707        }
708      }
709    }
710    if (rs.indexOf("\n")+1 == 0) retVal = null;
711    return retVal;
712  }
713
714
715  /**
716   *  Converts a ResultSet StringBuilder to a String [][] that holds the results cell by cell RowxColumn.
717   *  It also strips the 1st row with the column headers. For example results[4][8] would get row4 col8 data.
718   *
719   * @param rs is the SQL reusltSet (in StringBuilder Form as returned from any of the query methods) to convert
720   * @return a String Array containing the ResultSet, rowsxcols (Without the coulmn headers in the 1st row).
721   **/
722  public static String [][] sbToDataRowArray(StringBuilder rs)
723  {
724    String [] rows = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
725    String [] columns = (rows[0]).split("\\"+getColumnDelimitor());
726    String [][] retVal = new String[rows.length][columns.length];
727    //System.out.println("Results array - Columns: "+columns.length+"   Rows:"+rows.length);
728    if (rs != null)
729    {
730      for (int row=0; row<rows.length; row++)
731      {
732        columns = (rows[row]).split("\\"+getColumnDelimitor());
733        //System.out.print("Row "+row+" =  "+java.util.Arrays.toString(columns));
734        for (int column=0; column<columns.length; column++)
735        {
736          retVal[row][column] = columns[column];
737        }
738      }
739    }
740    if (rs.indexOf("\n")+1 == 0) retVal = null;
741    return retVal;
742  }
743
744
745  /**
746   *  Converts a ResultSet StringBuffer to a String [] that holds one result per line.
747   *  It also strips the 1st row with the column headers
748   *
749   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
750   * @return a String Array containing the ResultSet, one result per line (Without the coulmn header 1st row.
751   **/
752  public static String [] sbToArray(StringBuilder rs)
753  {
754    String [] retVal = null;
755    if (rs != null && rs.indexOf("\n")+1 >0)
756      retVal = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
757    return retVal;
758  }
759
760
761  /**
762   *  Converts a ResultSet StringBuffer to a String [] that holds one result per line.
763   *  It also strips the 1st row with the column headers
764   *
765   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
766   * @return a String Array containing the ResultSet, one result per line (Without the coulmn header 1st row.
767   **/
768  public static String [] sbToArray(StringBuffer rs)
769  {
770    String [] retVal = null;
771    if (rs != null && rs.indexOf("\n")+1 >0)
772      retVal = (rs.substring(rs.indexOf("\n")+1)).toString().split("\n");
773    return retVal;
774  }
775
776
777  /**
778   *  Converts a ResultSet StringBuffer to a saved file that holds one result per line.
779   *
780   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
781   * @param fileName is the name of the file to save
782   * @return a String containing the filename if suucessful, null if not.
783   **/
784  public static String  sbToFile(StringBuffer rs, String fileName)
785  {
786    String retVal = null;
787    if (rs != null)
788      retVal = Util.writeStringToFile(rs.toString(), fileName);
789    return retVal;
790  }
791
792
793  /**
794   *  Converts a ResultSet StringBuffer to a saved CSV file that holds one result per line.
795   *
796   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
797   * @param fileName is the name of the file to save
798   * @return a String containing the filename if suucessful, null if not.
799   **/
800  public static String  sbToCsv(StringBuffer rs, String fileName)
801  {
802    //String noCommas = Util.tokenReplace(rs.toString(),",","(comma)");
803
804
805    String noCommas = rs.toString().replace(",","(comma)");
806    return sbToFile( new StringBuffer(noCommas.replace(getColumnDelimitor(),
807                                                         ",")),
808                     fileName);
809  }
810
811
812
813
814  public static WritableWorkbook  copyIntoWorkbook(StringBuffer sb, WritableWorkbook wbkIn, int shtPosition, String sheetName)
815     throws  java.io.IOException
816  {
817    //WritableWorkbook retVal = wbkIn;
818    System.out.println("\nCreating new sheet '"+sheetName+"' into existing workbook at position="+shtPosition);
819    WritableSheet sheet0 = wbkIn.createSheet(sheetName, shtPosition);
820    String[] data = null;
821    String sbStr = "";
822    try
823    {
824      if (sb !=null && sb.length()>0)
825      {
826        sbStr = sb.toString();
827
828        // remove empty columns with no heading at the end of a row
829        //sbStr=sbStr.replace(getColumnDelimitor()+"\n","\n");
830
831        String [] colHeadings = sbStr.substring(0,sbStr.indexOf("\n")).split("\\"+getColumnDelimitor());
832
833        data = sbToArray(sb); // One row per line
834        int numRows = data.length;
835        int numCols = colHeadings.length;
836
837        jxl.write.Number number = null;
838        int i=0;
839        int j=0;
840        Integer cellInt = null;
841        Float cellFloat = null;
842        Double cellDouble = null;
843        jxl.write.Label label = null;
844        boolean cellIsInt = false;
845        boolean cellIsFloat = false;
846        boolean cellIsDouble = false;
847
848        // Add Column Headings
849        //System.out.print("ColHeaders:");
850        for (i=0;i<numCols;i++)
851        {
852          label = new jxl.write.Label(i, 0, colHeadings[i]);
853          sheet0.addCell(label);
854          //System.out.print(" "+i+":"+colHeadings[i]);
855        }
856
857        // Add ResultData
858        String [] currRow = null;
859        for (j=0;j<numRows;j++)
860        {
861          if (data[j]!=null)
862          {
863            currRow = data[j].split("\\"+getColumnDelimitor());
864            numCols = currRow.length;
865            for (i=0;i<numCols;i++)
866            {
867              if (!currRow[i].equals("null"))
868              {
869                try
870                {
871                  cellIsInt = false;
872                  cellIsFloat = false;
873                  cellIsDouble = false;
874                    final String Digits     = "(\\p{Digit}+)";
875                    final String HexDigits  = "(\\p{XDigit}+)";
876                    // an exponent is 'e' or 'E' followed by an optionally
877                    // signed decimal integer.
878                    final String Exp        = "[eE][+-]?"+Digits;
879                    final String fpRegex    = ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
880                                                "[+-]?(" + // Optional sign character
881                                                "NaN|" +           // "NaN" string
882                                                "Infinity|" +      // "Infinity" string
883
884                    // A decimal floating-point string representing a finite positive
885                    // number without a leading sign has at most five basic pieces:
886                    // Digits . Digits ExponentPart FloatTypeSuffix
887                    //
888                    // Since this method allows integer-only strings as input
889                    // in addition to strings of floating-point literals, the
890                    // two sub-patterns below are simplifications of the grammar
891                    // productions from the Java Language Specification, 2nd
892                    // edition, section 3.10.2.
893
894                    // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
895                                                "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
896
897                    // . Digits ExponentPart_opt FloatTypeSuffix_opt
898                                                "(\\.("+Digits+")("+Exp+")?)|"+
899
900                    // Hexadecimal strings
901                                                "((" +
902                   // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
903                                                "(0[xX]" + HexDigits + "(\\.)?)|" +
904
905                   // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
906                                                "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
907
908                                                ")[pP][+-]?" + Digits + "))" +
909                                                "[fFdD]?))" +
910                                                "[\\x00-\\x20]*");// Optional trailing "whitespace"
911
912                   if (java.util.regex.Pattern.matches(fpRegex, currRow[i]))
913                   {
914                     cellDouble = Double.valueOf(currRow[i]); // Will not throw NumberFormatException
915                     cellIsDouble = true;
916                   }
917                   else
918                   {
919                     // Perform suitable alternative action
920                   }
921
922                  if (!cellIsDouble)
923                  {
924                    try
925                    {
926                       // my slow method
927                       cellInt = new Integer(currRow[i].trim());
928                       cellIsInt = true;
929                       if (!cellIsInt)
930                       {
931                         cellFloat= new Float(currRow[i].trim());
932                         cellIsFloat = true;
933                       }
934                    }
935                    catch (NumberFormatException numEx)
936                    {
937                       // thesae should already be set correctly, but ensure they are
938                      cellIsInt = false;
939                      cellIsFloat = false;
940                      cellIsDouble = false;
941                      // deal with this as a label below
942                      //System.out.println(currRow[i]+ " is NOT a number");
943                    }
944                  }
945
946                  if (cellIsInt)
947                  {
948                    number = new jxl.write.Number(i, j+1, cellInt);
949                    sheet0.addCell(number);
950                  }
951                  else if (cellIsFloat)
952                  {
953                    number = new jxl.write.Number(i, j+1, cellFloat);
954                    sheet0.addCell(number);
955                  }
956                  else if (cellIsDouble)
957                  {
958                    number = new jxl.write.Number(i, j+1, cellDouble);
959                    sheet0.addCell(number);
960                  }
961                  else
962                  {
963                    if (currRow[i].startsWith("="))
964                    {
965                      jxl.write.Formula formula =  new jxl.write.Formula(i, j+1, currRow[i]);
966                      sheet0.addCell(formula);
967                    }
968                    else
969                    {
970                      label = new jxl.write.Label(i, j+1, currRow[i]);
971                      sheet0.addCell(label);
972                    }
973                  }
974                }
975                catch (Exception ex)
976                {
977                  // something funky happened... don't add but keep processing
978                }
979              }
980              else // cell == null
981              {
982                // don't add
983              }
984            } // columns
985          }
986        }  // rows
987
988        //wbkIn.write();
989      }
990      else
991      {
992        System.out.println("Empty resultset StringBuffer?");
993      }
994    }
995    catch (Exception ex)
996    {
997      System.out.println("\nXLS File ERROR: A problem in the application has caused an error. "+ sheetName);
998      System.out.println("RawData: "+sbStr);
999      ex.printStackTrace();
1000    }
1001
1002    return wbkIn;
1003  }
1004
1005
1006  /**
1007   *  Adds a ResultSet StringBuffer into a jxl.Workbook Excel workbook (new or existing) with the specified sheet name.
1008   *
1009   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1010   * @param wbkIn is an existing jxlWorkbook to save the StringBuffer resultSet into - If this is null then it creates and returns a new Workbook
1011   * @param sheetName name of the new sheet in the workbook
1012   * @return a jxl.Workbook containing the data.
1013   **/
1014  public static WritableWorkbook  sbIntoWorkbook(StringBuffer sb, WritableWorkbook wbkIn, String sheetName) throws  java.io.IOException
1015  {
1016    //jxl.Sheet sht = sbToWorksheet(sb);
1017    if (sheetName == null || sheetName.trim().equals("")) sheetName = "Results";
1018
1019    if (wbkIn==null)
1020    {
1021      wbkIn = Workbook.createWorkbook(new File("."+File.separator+"sqlResultSet_"+sheetName+"-"+
1022                                              Calendar.getInstance().getTimeInMillis()+".xls"));
1023      System.out.println("\nwbkIn=null - IMPORTING into NEW workbook: "+"."+File.separator+"sqlResultSet_"+sheetName+"-"+
1024                                              Calendar.getInstance().getTimeInMillis()+".xls");
1025    }
1026    else
1027    {
1028      System.out.println("\nIMPORTING '"+sheetName+"' into existing workbook");
1029    }
1030
1031    String [] existingSheetNames = wbkIn.getSheetNames();
1032    boolean foundSheet = false;
1033    for (int i = 0; !foundSheet && i< existingSheetNames.length; i++)
1034      if (existingSheetNames[i].equals(sheetName)) foundSheet= true;
1035    if (foundSheet) sheetName = sheetName+"-"+Calendar.getInstance().getTimeInMillis();
1036
1037    //System.out.println("     SHEET(null?"+(sht==null?"yes":"no")+"): "+ sheetName);
1038    //wbkIn.importSheet(sheetName, existingSheetNames.length+1, sht);
1039    wbkIn = copyIntoWorkbook(sb, wbkIn, existingSheetNames.length+1, sheetName);
1040    //wbkIn.write();
1041    return wbkIn;
1042  }
1043
1044
1045  /**
1046   *  Adds a ResultSet StringBuffer into a NEW jxl.Workbook Excel workbook with the specified workbookName and sheetname.
1047   *
1048   * @param sb is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1049   * @param wbkName is the name of the new jxlWorkbook file to save
1050   * @param sheetName name of the new sheet in the workbook
1051   * @return a jxl.Workbook containing the data.
1052   **/
1053  public static WritableWorkbook  sbIntoWorkbook(StringBuffer sb, String wbkName, String sheetName) throws  java.io.IOException
1054  {
1055    //jxl.Sheet sht = sbToWorksheet(sb);
1056    if (sheetName == null || sheetName.trim().equals("")) sheetName = "Results";
1057    if (wbkName == null || wbkName.trim().equals(""))
1058      wbkName = "."+File.separator+"sqlResultSet_"+sheetName+"-"+
1059                Calendar.getInstance().getTimeInMillis()+".xls";
1060
1061    System.out.println("\nCreating *NEW* workbook - "+wbkName);
1062    WritableWorkbook wbkIn = Workbook.createWorkbook(new File(wbkName));
1063    return sbIntoWorkbook(sb, wbkIn, sheetName);
1064  }
1065
1066
1067  /**
1068   *  Converts a ResultSet StringBuffer to a saved jxl.Workbook Excel workbook with one sheet named 'Results' that holds one result per line.
1069   *
1070   * @param sb is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1071   * @return a jxl.Workbook containing the data.
1072   **/
1073  public static jxl.Workbook  sbToWorkbook(StringBuffer sb)
1074  {
1075    jxl.Workbook retVal = null;
1076    String  tempFilename = System.getProperty("java.io.tmpdir")+"tmpWrkSht-"+
1077                                              Calendar.getInstance().getTimeInMillis()+ ".xls";
1078    //System.out.println("Writing results to TEMP file: "+tempFilename);
1079    try
1080    {
1081      sbToXLS(sb, tempFilename);
1082      //Util.writeStringToFile(sqlResultSet.toString(),rsFilename + ".csv");
1083      retVal  =Workbook.getWorkbook(new java.io.File(tempFilename ));
1084    }
1085    catch( Exception ioEx)
1086    {
1087      System.out.println("\nFile ERROR: A problem in the application has caused an error. "+ tempFilename);
1088      ioEx.printStackTrace();
1089    }
1090    return retVal;
1091  }
1092
1093
1094  /**
1095   *  Converts a ResultSet StringBuffer to a saved jxl.Sheet Excel worksheet that holds one result per line.
1096   *
1097   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1098   * @return a jxl.Sheet containing the data.
1099   **/
1100  public static jxl.Sheet  sbToWorksheet(StringBuffer sb)
1101  {
1102    jxl.Sheet retVal = null;
1103    jxl.write.WritableWorkbook wbk = null;
1104    String  tempFilename = System.getProperty("java.io.tmpdir")+"tmpWrkSht-"+
1105                                              Calendar.getInstance().getTimeInMillis()+ ".xls";
1106    //System.out.println("Writing results to TEMP file: "+tempFilename);
1107    try
1108    {
1109      wbk=sbToWbk(sb, tempFilename);
1110      wbk.write();
1111      wbk.close();
1112      jxl.Workbook workbook = Workbook.getWorkbook(new java.io.File(tempFilename ));
1113      if (workbook!=null)
1114      {
1115        retVal = workbook.getSheet("Results");
1116      }
1117      else
1118        System.out.println("\nERROR saving results xls file: "+ tempFilename);
1119    }
1120    catch( Exception ioEx)
1121    {
1122      System.out.println("\nSqlQuery.sbToWorksheet(StringBuffer sb)");
1123      System.out.println("File ERROR: A problem in the application has caused an error. "+ tempFilename);
1124      System.out.println("            Could Not convert sb=\n"+ sb.toString());
1125      ioEx.printStackTrace();
1126    }
1127    return retVal;
1128  }
1129
1130
1131  /**
1132   *  Converts a ResultSet StringBuffer to a saved Excel file with one sheet named 'Results' that holds one result per line.
1133   *
1134   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1135   * @param fileName is the name of the file to save
1136   * @return a String containing the filename if suucessful, null if not.
1137   **/
1138  public static String  sbToXLS(StringBuffer sb, String fileName)
1139  {
1140    String retVal = null;
1141    String[] data = null;
1142
1143    try
1144    {
1145      if (sb !=null && sb.length()>0)
1146      {
1147        data = sbToArray(sb); // One row per line
1148        String [] colHeadings = sb.toString().substring(0,sb.toString().indexOf("\n")).split("\\"+getColumnDelimitor());
1149        int numRows = data.length;
1150        int numCols = colHeadings.length;
1151
1152        WritableWorkbook  workbook = Workbook.createWorkbook(new File(fileName));
1153        WritableSheet sheet0 = workbook.createSheet("Results", 0);
1154        jxl.write.Number number = null;
1155        int i=0;
1156        int j=0;
1157        Integer cellInt = null;
1158        Float cellFloat = null;
1159        Double cellDouble = null;
1160        jxl.write.Label label = null;
1161        boolean cellIsInt = false;
1162        boolean cellIsFloat = false;
1163        boolean cellIsDouble = false;
1164
1165        // Add Column Headings
1166        for (i=0;i<numCols;i++)
1167        {
1168          label = new jxl.write.Label(i, 0, colHeadings[i]);
1169          sheet0.addCell(label);
1170        }
1171
1172        // Add ResultData
1173        String [] currRow = null;
1174        for (j=0;j<numRows;j++)
1175        {
1176          if (data[j]!=null)
1177          {
1178            currRow = data[j].split("\\"+getColumnDelimitor());
1179            numCols = currRow.length;
1180            for (i=0;i<numCols;i++)
1181            {
1182              if (!currRow[i].equals("null"))
1183              {
1184                cellIsInt = false;
1185                cellIsFloat = false;
1186                cellIsDouble = false;
1187                  final String Digits     = "(\\p{Digit}+)";
1188                  final String HexDigits  = "(\\p{XDigit}+)";
1189                  // an exponent is 'e' or 'E' followed by an optionally
1190                  // signed decimal integer.
1191                  final String Exp        = "[eE][+-]?"+Digits;
1192                  final String fpRegex    = ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
1193                                              "[+-]?(" + // Optional sign character
1194                                              "NaN|" +           // "NaN" string
1195                                              "Infinity|" +      // "Infinity" string
1196
1197                  // A decimal floating-point string representing a finite positive
1198                  // number without a leading sign has at most five basic pieces:
1199                  // Digits . Digits ExponentPart FloatTypeSuffix
1200                  //
1201                  // Since this method allows integer-only strings as input
1202                  // in addition to strings of floating-point literals, the
1203                  // two sub-patterns below are simplifications of the grammar
1204                  // productions from the Java Language Specification, 2nd
1205                  // edition, section 3.10.2.
1206
1207                  // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
1208                                              "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
1209
1210                  // . Digits ExponentPart_opt FloatTypeSuffix_opt
1211                                              "(\\.("+Digits+")("+Exp+")?)|"+
1212
1213                  // Hexadecimal strings
1214                                              "((" +
1215                 // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
1216                                              "(0[xX]" + HexDigits + "(\\.)?)|" +
1217
1218                 // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
1219                                              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
1220
1221                                              ")[pP][+-]?" + Digits + "))" +
1222                                              "[fFdD]?))" +
1223                                              "[\\x00-\\x20]*");// Optional trailing "whitespace"
1224
1225                 if (java.util.regex.Pattern.matches(fpRegex, currRow[i]))
1226                 {
1227                   cellDouble = Double.valueOf(currRow[i]); // Will not throw NumberFormatException
1228                   cellIsDouble = true;
1229                 }
1230                 else
1231                 {
1232                   // Perform suitable alternative action
1233                 }
1234
1235                if (!cellIsDouble)
1236                {
1237                  try
1238                  {
1239                     // my slow method
1240                     cellInt = new Integer(currRow[i].trim());
1241                     cellIsInt = true;
1242                     if (!cellIsInt)
1243                     {
1244                       cellFloat= new Float(currRow[i].trim());
1245                       cellIsFloat = true;
1246                     }
1247                  }
1248                  catch (NumberFormatException numEx)
1249                  {
1250                    //System.out.println(currRow[i]+ " is NOT a number");
1251                  }
1252                }
1253
1254                if (cellIsInt)
1255                {
1256                  number = new jxl.write.Number(i, j+1, cellInt);
1257                  sheet0.addCell(number);
1258                }
1259                else if (cellIsFloat)
1260                {
1261                  number = new jxl.write.Number(i, j+1, cellFloat);
1262                  sheet0.addCell(number);
1263                }
1264                else if (cellIsDouble)
1265                {
1266                  number = new jxl.write.Number(i, j+1, cellDouble);
1267                  sheet0.addCell(number);
1268                }
1269                else
1270                {
1271                  label = new jxl.write.Label(i, j+1, Util.tokenReplace(Util.tokenReplace(currRow[i],"\r"," _ "),"\n"," _ "));
1272                  sheet0.addCell(label);
1273                }
1274
1275              }
1276              else // cell == null
1277              {
1278                // don't add
1279              }
1280            } // columns
1281          }
1282        }  // rows
1283
1284        workbook.write();
1285        workbook.close();
1286        System.out.println("XLS file "+fileName+" Successfully written");
1287        retVal = fileName;
1288      }
1289      else
1290      {
1291        System.out.println("XLS file "+fileName+" NOT written - NO Data.");
1292        retVal = null;
1293      }
1294    }
1295    catch (jxl.write.WriteException wEx)
1296    {
1297      wEx.printStackTrace();
1298      retVal = null;
1299    }
1300    catch (java.io.IOException ioEx)
1301    {
1302      ioEx.printStackTrace();
1303      retVal = null;
1304    }
1305
1306    return retVal;
1307  }
1308
1309  /**
1310   *  Converts a ResultSet StringBuffer to a saved Excel file with one sheet named 'Results' that holds one result per line.
1311   *
1312   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1313   * @param fileName is the name of the file to save
1314   * @return a String containing the filename if suucessful, null if not.
1315   **/
1316  public static WritableWorkbook  sbToWbk(StringBuffer sb, String fileName)
1317  {
1318    String retVal = null;
1319    String[] data = null;
1320    WritableWorkbook  workbook = null;
1321
1322    try
1323    {
1324      if (sb !=null && sb.length()>0)
1325      {
1326        data = sbToArray(sb); // One row per line
1327        String [] colHeadings = sb.toString().substring(0,sb.toString().indexOf("\n")).split("\\"+getColumnDelimitor());
1328        int numRows = data.length;
1329        int numCols = colHeadings.length;
1330
1331        workbook = Workbook.createWorkbook(new File(fileName));
1332        WritableSheet sheet0 = workbook.createSheet("Results", 0);
1333        jxl.write.Number number = null;
1334        int i=0;
1335        int j=0;
1336        Integer cellInt = null;
1337        Float cellFloat = null;
1338        Double cellDouble = null;
1339        jxl.write.Label label = null;
1340        boolean cellIsInt = false;
1341        boolean cellIsFloat = false;
1342        boolean cellIsDouble = false;
1343
1344        // Add Column Headings
1345        for (i=0;i<numCols;i++)
1346        {
1347          label = new jxl.write.Label(i, 0, colHeadings[i]);
1348          sheet0.addCell(label);
1349        }
1350
1351        // Add ResultData
1352        String [] currRow = null;
1353        for (j=0;j<numRows;j++)
1354        {
1355          if (data[j]!=null)
1356          {
1357            currRow = data[j].split("\\"+getColumnDelimitor());
1358            for (i=0;i<numCols;i++)
1359            {
1360              if (!currRow[i].equals("null"))
1361              {
1362                cellIsInt = false;
1363                cellIsFloat = false;
1364                cellIsDouble = false;
1365                  final String Digits     = "(\\p{Digit}+)";
1366                  final String HexDigits  = "(\\p{XDigit}+)";
1367                  // an exponent is 'e' or 'E' followed by an optionally
1368                  // signed decimal integer.
1369                  final String Exp        = "[eE][+-]?"+Digits;
1370                  final String fpRegex    = ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
1371                                              "[+-]?(" + // Optional sign character
1372                                              "NaN|" +           // "NaN" string
1373                                              "Infinity|" +      // "Infinity" string
1374
1375                  // A decimal floating-point string representing a finite positive
1376                  // number without a leading sign has at most five basic pieces:
1377                  // Digits . Digits ExponentPart FloatTypeSuffix
1378                  //
1379                  // Since this method allows integer-only strings as input
1380                  // in addition to strings of floating-point literals, the
1381                  // two sub-patterns below are simplifications of the grammar
1382                  // productions from the Java Language Specification, 2nd
1383                  // edition, section 3.10.2.
1384
1385                  // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
1386                                              "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
1387
1388                  // . Digits ExponentPart_opt FloatTypeSuffix_opt
1389                                              "(\\.("+Digits+")("+Exp+")?)|"+
1390
1391                  // Hexadecimal strings
1392                                              "((" +
1393                 // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
1394                                              "(0[xX]" + HexDigits + "(\\.)?)|" +
1395
1396                 // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
1397                                              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
1398
1399                                              ")[pP][+-]?" + Digits + "))" +
1400                                              "[fFdD]?))" +
1401                                              "[\\x00-\\x20]*");// Optional trailing "whitespace"
1402
1403                 if (java.util.regex.Pattern.matches(fpRegex, currRow[i]))
1404                 {
1405                   cellDouble = Double.valueOf(currRow[i]); // Will not throw NumberFormatException
1406                   cellIsDouble = true;
1407                 }
1408                 else
1409                 {
1410                   // Perform suitable alternative action
1411                 }
1412
1413                if (!cellIsDouble)
1414                {
1415                  try
1416                  {
1417                     // my slow method
1418                     cellInt = new Integer(currRow[i].trim());
1419                     cellIsInt = true;
1420                     if (!cellIsInt)
1421                     {
1422                       cellFloat= new Float(currRow[i].trim());
1423                       cellIsFloat = true;
1424                     }
1425                  }
1426                  catch (NumberFormatException numEx)
1427                  {
1428                    //System.out.println(currRow[i]+ " is NOT a number");
1429                  }
1430                }
1431
1432                if (cellIsInt)
1433                {
1434                  number = new jxl.write.Number(i, j+1, cellInt);
1435                  sheet0.addCell(number);
1436                }
1437                else if (cellIsFloat)
1438                {
1439                  number = new jxl.write.Number(i, j+1, cellFloat);
1440                  sheet0.addCell(number);
1441                }
1442                else if (cellIsDouble)
1443                {
1444                  number = new jxl.write.Number(i, j+1, cellDouble);
1445                  sheet0.addCell(number);
1446                }
1447                else
1448                {
1449                  label = new jxl.write.Label(i, j+1, currRow[i]);
1450                  sheet0.addCell(label);
1451                }
1452
1453              }
1454              else // cell == null
1455              {
1456                // don't add
1457              }
1458            } // columns
1459          }
1460        }  // rows
1461
1462        workbook.write();
1463        //workbook.close();
1464        System.out.println("XLS file "+fileName+" Successfully written");
1465        retVal = fileName;
1466      }
1467      else
1468      {
1469        System.out.println("XLS file "+fileName+" NOT written - NO Data.");
1470        retVal = null;
1471      }
1472    }
1473    catch (jxl.write.WriteException wEx)
1474    {
1475      wEx.printStackTrace();
1476      retVal = null;
1477    }
1478    catch (java.io.IOException ioEx)
1479    {
1480      ioEx.printStackTrace();
1481      retVal = null;
1482    }
1483
1484    return workbook;
1485  }
1486
1487
1488  /**
1489   *  Converts a ResultSet StringBuffer to a saved Excel file with one sheet named 'Results' that holds one result per line.
1490   *
1491   * @param rs is the SQL reusltSet (in StringBuffer Form as returned from any of the query methods) to convert
1492   * @param fileName is the name of the file to save
1493   * @return a String containing the filename if suucessful, null if not.
1494   **/
1495  public static WritableSheet  sbToSheet(StringBuffer sb, String fileName)
1496  {
1497    String retVal = null;
1498    String[] data = null;
1499    WritableWorkbook  workbook = null;
1500    WritableSheet sheet0 = null;
1501
1502    try
1503    {
1504      if (sb !=null && sb.length()>0)
1505      {
1506        data = sbToArray(sb); // One row per line
1507        String [] colHeadings = sb.toString().substring(0,sb.toString().indexOf("\n")).split("\\"+getColumnDelimitor());
1508        int numRows = data.length;
1509        int numCols = colHeadings.length;
1510
1511        workbook = Workbook.createWorkbook(new File(fileName));
1512        sheet0 = workbook.createSheet("Results", 0);
1513        jxl.write.Number number = null;
1514        int i=0;
1515        int j=0;
1516        Integer cellInt = null;
1517        Float cellFloat = null;
1518        Double cellDouble = null;
1519        jxl.write.Label label = null;
1520        boolean cellIsInt = false;
1521        boolean cellIsFloat = false;
1522        boolean cellIsDouble = false;
1523
1524        // Add Column Headings
1525        for (i=0;i<numCols;i++)
1526        {
1527          label = new jxl.write.Label(i, 0, colHeadings[i]);
1528          sheet0.addCell(label);
1529        }
1530
1531        // Add ResultData
1532        String [] currRow = null;
1533        for (j=0;j<numRows;j++)
1534        {
1535          if (data[j]!=null)
1536          {
1537            currRow = data[j].split("\\"+getColumnDelimitor());
1538            for (i=0;i<numCols;i++)
1539            {
1540              if (!currRow[i].equals("null"))
1541              {
1542                cellIsInt = false;
1543                cellIsFloat = false;
1544                cellIsDouble = false;
1545                  final String Digits     = "(\\p{Digit}+)";
1546                  final String HexDigits  = "(\\p{XDigit}+)";
1547                  // an exponent is 'e' or 'E' followed by an optionally
1548                  // signed decimal integer.
1549                  final String Exp        = "[eE][+-]?"+Digits;
1550                  final String fpRegex    = ("[\\x00-\\x20]*"+  // Optional leading "whitespace"
1551                                              "[+-]?(" + // Optional sign character
1552                                              "NaN|" +           // "NaN" string
1553                                              "Infinity|" +      // "Infinity" string
1554
1555                  // A decimal floating-point string representing a finite positive
1556                  // number without a leading sign has at most five basic pieces:
1557                  // Digits . Digits ExponentPart FloatTypeSuffix
1558                  //
1559                  // Since this method allows integer-only strings as input
1560                  // in addition to strings of floating-point literals, the
1561                  // two sub-patterns below are simplifications of the grammar
1562                  // productions from the Java Language Specification, 2nd
1563                  // edition, section 3.10.2.
1564
1565                  // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
1566                                              "((("+Digits+"(\\.)?("+Digits+"?)("+Exp+")?)|"+
1567
1568                  // . Digits ExponentPart_opt FloatTypeSuffix_opt
1569                                              "(\\.("+Digits+")("+Exp+")?)|"+
1570
1571                  // Hexadecimal strings
1572                                              "((" +
1573                 // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
1574                                              "(0[xX]" + HexDigits + "(\\.)?)|" +
1575
1576                 // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
1577                                              "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
1578
1579                                              ")[pP][+-]?" + Digits + "))" +
1580                                              "[fFdD]?))" +
1581                                              "[\\x00-\\x20]*");// Optional trailing "whitespace"
1582
1583                 if (java.util.regex.Pattern.matches(fpRegex, currRow[i]))
1584                 {
1585                   cellDouble = Double.valueOf(currRow[i]); // Will not throw NumberFormatException
1586                   cellIsDouble = true;
1587                 }
1588                 else
1589                 {
1590                   // Perform suitable alternative action
1591                 }
1592
1593                if (!cellIsDouble)
1594                {
1595                  try
1596                  {
1597                     // my slow method
1598                     cellInt = new Integer(currRow[i].trim());
1599                     cellIsInt = true;
1600                     if (!cellIsInt)
1601                     {
1602                       cellFloat= new Float(currRow[i].trim());
1603                       cellIsFloat = true;
1604                     }
1605                  }
1606                  catch (NumberFormatException numEx)
1607                  {
1608                    //System.out.println(currRow[i]+ " is NOT a number");
1609                  }
1610                }
1611
1612                if (cellIsInt)
1613                {
1614                  number = new jxl.write.Number(i, j+1, cellInt);
1615                  sheet0.addCell(number);
1616                }
1617                else if (cellIsFloat)
1618                {
1619                  number = new jxl.write.Number(i, j+1, cellFloat);
1620                  sheet0.addCell(number);
1621                }
1622                else if (cellIsDouble)
1623                {
1624                  number = new jxl.write.Number(i, j+1, cellDouble);
1625                  sheet0.addCell(number);
1626                }
1627                else
1628                {
1629                  label = new jxl.write.Label(i, j+1, currRow[i]);
1630                  sheet0.addCell(label);
1631                }
1632
1633              }
1634              else // cell == null
1635              {
1636                // don't add
1637              }
1638            } // columns
1639          }
1640        }  // rows
1641
1642        workbook.write();
1643        //workbook.close();
1644        System.out.println("XLS file "+fileName+" Successfully written");
1645        retVal = fileName;
1646      }
1647      else
1648      {
1649        System.out.println("XLS file "+fileName+" NOT written - NO Data.");
1650        retVal = null;
1651      }
1652    }
1653    catch (jxl.write.WriteException wEx)
1654    {
1655      wEx.printStackTrace();
1656      retVal = null;
1657    }
1658    catch (java.io.IOException ioEx)
1659    {
1660      ioEx.printStackTrace();
1661      retVal = null;
1662    }
1663
1664    return sheet0;
1665  }
1666
1667
1668  /** Converts a sql resultSet in the form of a deliminated string to a JSON format.
1669    *
1670    * @param content is the sql resultSet in the form of a deliminated string
1671    * @param separator the split char
1672    **/
1673  public static String csvToJSON(String content, String separator){ return Util.csvToJSON(content,  separator);}
1674
1675
1676    /** Converts a sql resultSet StringBuffer in the form of a default delimited string to a JSON format.
1677    *
1678    * @param contentSB is the sql resultSet in the form of a deliminated string
1679    **/
1680  public static String sbToJSON(StringBuffer contentSB){ return Util.csvToJSON(contentSB.toString(),  DEFAULT_COLUMN_DELIMITOR);}
1681
1682
1683
1684  /**
1685   *  Converts a ResultSet StringBuffer to a saved file that holds one result per line.
1686   *
1687   * @param rs is the SQL resultSet to convert
1688   * @param fileName is the name of the file to save
1689   * @return a String containing the filename if suucessful, null if not.
1690   **/
1691  public static String  resultSetToCSVFile(java.sql.ResultSet rs, String fileName, boolean includeColumnsHeaders)
1692  {
1693    String retVal = "";
1694
1695    try
1696    {
1697      CSVWriter csvW = new CSVWriter(new java.io.FileWriter(fileName), columnDelimitor.charAt(0));
1698      if (rs != null)
1699        csvW.writeAll(rs, includeColumnsHeaders);
1700
1701      if ( csvW!=null )
1702        csvW.close();
1703
1704      retVal = fileName;
1705    }
1706    catch ( Exception ex)
1707    {
1708      System.out.println("Could Not write CSV File: "+fileName);
1709    }
1710
1711    return retVal;
1712  }
1713
1714
1715  /**
1716    Set the database to use Oracle DB with a dedicated connection to the server. Use this method before doing db access calls.
1717   **/
1718  public void setUseOracleDedicatedDB()
1719  {
1720    this.dbType_=ORACLEDEDICATED_DB;
1721    oraDedicated_=true;
1722
1723    dbDriverName = oraDbDriverName;
1724    dbPort = oraDbPort;
1725    dbConnectString = getDbConnectString();
1726  }
1727
1728
1729  /**
1730    Set the database to use Oracle DB. Use this method before doing db access calls.
1731   **/
1732  public void setUseOracleDB()
1733  {
1734    this.dbType_=ORACLE_DB;
1735
1736    dbDriverName = oraDbDriverName;
1737    dbPort = oraDbPort;
1738    dbConnectString = getDbConnectString();
1739  }
1740
1741
1742  /**
1743    Set the database to use Oracle DB. Use this method before doing db access calls.
1744   **/
1745  public void setUseDb2DB()
1746  {
1747    this.dbType_=DB2_DB;
1748
1749    dbDriverName = db2DbDriverName;
1750    dbPort = db2DbPort;
1751    dbConnectString = getDbConnectString();
1752  }
1753
1754
1755  /**
1756    Set the database to use Oracle DB. Use this method before doing db access calls.
1757   **/
1758  public void setUseDerbyDB()
1759  {
1760    this.dbType_=DERBY_DB;
1761
1762    dbDriverName = derbyDbDriverName;
1763    dbPort = derbyDbPort;
1764    dbConnectString = getDbConnectString();
1765  }
1766
1767
1768  /**
1769    Set the database to use PG. Use this method before doing db access calls.
1770   **/
1771  public void setUsePostgreDB()
1772  {
1773    this.dbType_=POSTGRE_DB;
1774
1775    dbDriverName = pgDbDriverName;
1776    dbPort = pgDbPort;
1777    dbConnectString = getDbConnectString();
1778  }
1779
1780
1781  /**
1782    Set the database to use Mysql. Use this method before doing db access calls.
1783   **/
1784  public void setUseMysqlDB()
1785  {
1786    this.dbType_=MYSQL_DB;
1787
1788    dbDriverName = mysqlDbDriverName;
1789    dbPort = mysqlDbPort;
1790    dbConnectString = getDbConnectString();
1791  }
1792
1793
1794  /**
1795    Set the database to use Mysql. Use this method before doing db access calls.
1796   **/
1797  public void setUseMariadbDB()
1798  {
1799    this.dbType_=MARIADB_DB;
1800
1801    System.out.println("SqlQuery.setUseMariadbDB(): setting dbDriverName = "+mariadbDbDriverName);
1802    dbDriverName = mariadbDbDriverName;
1803    dbPort = mysqlDbPort;
1804    dbConnectString = getDbConnectString();
1805    System.out.println("SqlQuery.setUseMariadbDB(): dbConnectString = "+getDbConnectString());
1806  }
1807
1808
1809  /**
1810    Set the database to use PG. Use this method before doing db access calls.
1811   **/
1812  public void setUseHsqlDB()
1813  {
1814    this.dbType_=HSQL_DB;
1815
1816    dbDriverName = hsqlDbDriverName;
1817    dbPort = hsqlDbPort;
1818    dbConnectString = getDbConnectString();
1819  }
1820
1821
1822  /**
1823    Set the database to use the JDBC-ODBC bridge. Use this method before doing db access calls.
1824   **/
1825  public void setUseOdbcDB()
1826  {
1827    this.dbType_=ODBC_DB;
1828
1829    dbDriverName = odbcDbDriverName;
1830    dbPort = "";
1831    dbConnectString = getDbConnectString();
1832  }
1833
1834
1835  /**
1836   *  Sets the queries to be case insensitive.this is an Oracle Var as of 10gR2
1837   *  This is a very quick query.
1838   * <br /><br />
1839   **/
1840  public void setCaseInsensitive()
1841  {
1842    // this is an Oracle Var as of 10gR2
1843    String sql = "alter session set NLS_SORT=BINARY_CI";
1844
1845    StringBuffer rs = query(sql);
1846  }
1847
1848
1849  /**
1850   *  Sets the queries to be case sensitive.this is an Oracle Var as of 10gR2
1851   *  This is a very quick query.
1852   * <br /><br />
1853   **/
1854  public void setCaseSensitive()
1855  {
1856     // this is an Oracle Var as of 10gR2
1857    String sql = "alter session set NLS_SORT=BINARY";
1858
1859    StringBuffer rs = query(sql);
1860  }
1861
1862
1863  /**
1864   *  Tests the Production DB connection.
1865   *
1866   * @return boolean whether the DB is actively available.
1867   **/
1868  public boolean canConnect()
1869  {
1870    return canConnect(true);
1871  }
1872
1873
1874  /**
1875   *  Tests the DB connection.
1876   *
1877   * @param useProductionDb flags whether the production or test/developmentDB get used.
1878   * @return boolean whether the DB is actively available.
1879   **/
1880  public boolean canConnect(boolean useProductionDb)
1881  {
1882    boolean retVal = false;
1883    try
1884    {
1885      // Step 1. Load the JDBC driver
1886      Class.forName(dbDriverName);
1887
1888      // Step 2. Create a Connection object  - Now this is a class var
1889      // Connection con = null;
1890
1891      if (con == null || con.isClosed()) // else use the existing
1892        try
1893        {
1894          if (debugOut) System.out.println("  Testing JDBC Connection" );
1895          if (debugOut) System.out.println("    Using Driver: " + getDbDriverName());
1896          if (debugOut) System.out.println("      connectStr: " + getDbConnectString());
1897          if (debugOut) System.out.println("            user: " + getDbUser());
1898          if (debugOut) System.out.println("        password: " + getDbPassword());
1899          if (useProductionDb)
1900            con = DriverManager.getConnection(getDbConnectString(), getDbUser(), getDbPassword());
1901          else
1902            con = DriverManager.getConnection(this.testDbConnectString, getDbUser(), getDbPassword());
1903
1904          con.close();
1905
1906          retVal = true;
1907          if (debugOut) System.out.print("got connection to DB " + getDbName());
1908          if (debugOut) System.out.println(" with user " + getDbUser());
1909        }
1910        catch (SQLException e2)
1911        {
1912          // Exception when executing java.sql related commands, print error message to the console
1913          System.out.println(e2.toString());
1914          //e2.printStackTrace();
1915          System.out.println("Did not connect to DB... bailing out.");
1916          System.out.println("dbConnect = "+getDbConnectString()+" "+ getDbUser()+" / "+getDbPassword());
1917        }
1918    }
1919    catch (ClassNotFoundException e1)
1920    {
1921      // JDBC driver class not found, print error message to the console
1922      if (debugOut) System.out.println(e1.toString());
1923    }
1924    catch (SQLException e2)
1925    {
1926      // Exception when executing java.sql related commands, print error message to the console
1927      System.out.println(e2.toString());
1928      //System.out.println("SQL: "+ sql);
1929      e2.printStackTrace();
1930    }
1931    catch (Exception e3)
1932    {
1933      // other unexpected exception, print error message to the console
1934      System.out.println(e3.toString());
1935    }
1936
1937    return retVal;
1938  }
1939
1940
1941  /**
1942   *  Creates a delta timestamp for the current time to the passed timestamp in the form of
1943   *  'hour + "-" + min + "-" + sec + "-" + millis'.
1944   *
1945   * @return    The CurrentTimeStamp - fromTimeStamp value.
1946   */
1947  static public String getTimeDelta(String fromTimeStamp)
1948  {
1949    String currTimeStamp = createCurrentTimeStamp();
1950    String [] currSplits = currTimeStamp.split("-");
1951    String [] fromSplits = fromTimeStamp.split("-");
1952    int currMillis = Integer.parseInt(currSplits[3]);
1953    int currSec = Integer.parseInt(currSplits[2]);
1954    int currMin = Integer.parseInt(currSplits[1]);
1955    int currHr = Integer.parseInt(currSplits[0]);
1956    int fromMillis = Integer.parseInt(fromSplits[3]);
1957    int fromSec = Integer.parseInt(fromSplits[2]);
1958    int fromMin = Integer.parseInt(fromSplits[1]);
1959    int fromHr = Integer.parseInt(fromSplits[0]);
1960
1961    String millis = "000";
1962    String sec = "00";
1963    String min = "00";
1964    String hour = "00";
1965    int carryOver = 0;
1966
1967    if (currMillis-fromMillis>=0)
1968    {
1969      millis = String.valueOf(currMillis-fromMillis);
1970      carryOver = 0;
1971    }
1972    else
1973    {
1974      millis = String.valueOf(1000+currMillis-fromMillis );
1975      carryOver = 1;
1976    }
1977
1978    if (currSec-carryOver-fromSec>=0)
1979    {
1980      sec = String.valueOf(currSec-carryOver-fromSec);
1981      carryOver = 0;
1982    }
1983    else
1984    {
1985      sec = String.valueOf(60+currSec-carryOver-fromSec );
1986      carryOver = 1;
1987    }
1988
1989    if (currMin-carryOver-fromMin>=0)
1990    {
1991      min = String.valueOf(currMin-carryOver-fromMin);
1992      carryOver = 0;
1993    }
1994    else
1995    {
1996      min = String.valueOf(60+currMin-carryOver-fromMin );
1997      carryOver = 1;
1998    }
1999
2000    if (currHr-carryOver-fromHr>=0)
2001    {
2002      hour = String.valueOf(currHr-carryOver-fromHr);
2003      carryOver = 0;
2004    }
2005    else
2006    {
2007      hour = String.valueOf(60+currHr-carryOver-fromHr );
2008      carryOver = 1;
2009    }
2010
2011    return (String)hour + "-" + min + "-" + sec + "-" + millis;
2012  }
2013
2014
2015  /**
2016   *  Creates a timestamp for the current time in the form of
2017   *  'hour + "-" + min + "-" + sec + "-" + millis'.
2018   *
2019   * @return    The CurrentTimeStamp value.
2020   */
2021  static public String createCurrentTimeStamp()
2022  {
2023    String value = "";
2024    Calendar calendar = Calendar.getInstance();
2025    int currMillis = calendar.get(calendar.MILLISECOND);
2026    String millis = String.valueOf(currMillis);
2027    if (currMillis < 10)
2028    {
2029      millis = "00" + currMillis;
2030    }
2031    else if (currMillis < 100)
2032    {
2033      millis = "0" + currMillis;
2034    }
2035    int currSec = calendar.get(calendar.SECOND);
2036    String sec = String.valueOf(currSec);
2037    if (currSec < 10)
2038    {
2039      sec = "0" + currSec;
2040    }
2041    int currMin = calendar.get(calendar.MINUTE);
2042    String min = String.valueOf(currMin);
2043    if (currMin < 10)
2044    {
2045      min = "0" + currMin;
2046    }
2047    int currHr = calendar.get(calendar.HOUR);
2048    String hour = String.valueOf(currHr);
2049    if (currHr < 10)
2050    {
2051      hour = "0" + currHr;
2052    }
2053
2054    return (String)hour + "-" + min + "-" + sec + "-" + millis;
2055  }
2056
2057
2058  /**
2059   *  Executes a SQL statement onto the JDBC accessed <b>PRODUCTION</b> database
2060   *  defined by the class driver and connection string.
2061   *
2062   * @param sql is the SQL to execute
2063   * @return a StringBuffer containing the ResultSet, one result per line.
2064   **/
2065  public StringBuffer query(String sql)
2066  {
2067    return query(sql, true);
2068  }
2069
2070
2071  /**
2072   *  Executes a SQL statement onto the JDBC accessed database defined by the
2073   *  class driver and connection string.
2074   *  the resultSet is converted to a StringBuffer that looks similar:<pre>
2075   *   FISCAL_YEAR|SUBSTATION_CD|FEEDER|FEEDER_CUSTOMERS|DTOR|CUSTS_OUT|CUST_OUTAGE_MIN|DEMAND_MW
2076   *   2007|NVR|1260 NVR|218|P3835151.A|12|2172|null
2077   *   2007|NVR|1260 NVR|218|P3868231.A|12|3864|null
2078   *   2007|NVR|1261 NVR|2555|P3806671.B|152|21432|null
2079   *   </pre>
2080   *  <u><b>Other Helper Methods:</b></u><br />
2081   *  <ul>
2082   *    <li> the delimiter can be set with the
2083   *         {@link #setColumnDelimitor(String) setColumnDelimitor} method.</li>
2084   *    <li> the returned StringBuffer (resultSet) can be converted to an String array with the
2085   *         {@link #sbToArray(StringBuffer) sbToArray} method.</li>
2086   *    <li> you can (optionally) test the connection 1st with the
2087   *         {@link #canConnect() canConnect} method.</li>
2088   *  </ul>
2089   *
2090   * @param sql is the SQL to execute
2091   * @param useProductionDb flags whether the production or test/developmentDB get used.
2092   * @return a StringBuffer containing the ResultSet, one result per line and includes the columnNames as the 1st row.
2093   **/
2094  public StringBuffer query(String sql, boolean useProductionDb)
2095  {
2096    StringBuffer retVal = new StringBuffer("");
2097    Statement s = null;
2098    ResultSet rs = null;
2099    //boolean removeEOLs = true;
2100    if (sql != null && !sql.equals(""))
2101    {
2102      try
2103      {
2104        if(useProxoolPool_)
2105        {
2106          if (con == null || con.isClosed()) // else use the existing
2107          try
2108          {
2109            Class.forName(proxoolDriverName);
2110            Properties info = new Properties();
2111            info.setProperty("proxool.maximum-connection-count", ""+proxoolMaximumConnectionCount_);
2112            info.setProperty("proxool.house-keeping-test-sql", "select CURRENT_DATE");
2113            info.setProperty("user", getDbUser());
2114            info.setProperty("password",  getDbPassword());
2115            String alias = "pool";
2116            String driverClass = dbDriverName;
2117            String driverUrl = getDbConnectString();
2118            String url = "proxool." + alias + ":" + driverClass + ":" + driverUrl;
2119            try{ProxoolFacade.registerConnectionPool(url, info);}
2120            catch (ProxoolException pEx) {/* already registered */}
2121
2122            con = DriverManager.getConnection("proxool."+alias);
2123            if (debugOut) System.out.print("got Pooled connection to DB " + getDbName());
2124            if (debugOut) System.out.println(" with user " + getDbUser());
2125          }
2126          catch (SQLException e2)
2127          {
2128            // Exception when executing java.sql related commands, print error message to the console
2129            System.out.println(e2.toString());
2130            //e2.printStackTrace();
2131            System.out.println("Did not connect to ProxoolPool DB... bailing out.");
2132          }
2133        }
2134        else
2135        {
2136          // Step 1. Load the JDBC driver
2137          Class.forName(dbDriverName).newInstance();
2138
2139          // Step 2. Create a Connection object  - Now this is a class var
2140          // Connection con = null;
2141
2142          if (con == null || con.isClosed()) // else use the existing
2143            try
2144            {
2145              if (useProductionDb)
2146                con = DriverManager.getConnection(getDbConnectString(), getDbUser(), getDbPassword());
2147              else
2148                con = DriverManager.getConnection(getDbConnectString(), getDbUser(), getDbPassword());
2149
2150              if (debugOut) System.out.print("got connection to DB " + getDbName());
2151              if (debugOut) System.out.println(" with user " + getDbUser());
2152            }
2153            catch (SQLException e2)
2154            {
2155              // Exception when executing java.sql related commands, print error message to the console
2156              //System.out.println(e2.toString());
2157              System.out.println("SQLException: " + e2.getMessage());
2158              System.out.println("SQLState: " + e2.getSQLState());
2159              System.out.println("VendorError: " + e2.getErrorCode());
2160              e2.printStackTrace();
2161              System.out.println("Did not connect to DB... bailing out.");
2162              System.out.print(""+getDbName()+" DB Connection "+" ("+getDbUser()+":"+getDbPassword()+ "): ");
2163            }
2164        }
2165
2166        if (con != null)
2167        {
2168          // Step 3. Create a Statement object and call its executeUpdate
2169          // method to insert a record
2170          s = con.createStatement();
2171          if (debugOut) System.out.println("SQL Query: \n"+sql);
2172          String startTimeStamp = createCurrentTimeStamp();
2173          //System.out.println("Start Time = "+startTimeStamp);
2174          if (sql.toUpperCase().startsWith("INSERT")
2175              || sql.toUpperCase().startsWith("UPDATE")
2176              || sql.toUpperCase().startsWith("REPLACE")
2177              || sql.toUpperCase().startsWith("DELETE")
2178              || sql.toUpperCase().startsWith("DROP")
2179              || sql.toUpperCase().startsWith("CREATE")
2180            )
2181            s.executeUpdate(sql); // any query that returns nothing
2182          else
2183          {
2184            rs = s.executeQuery(sql);
2185            //System.out.println("End Time = "+createCurrentTimeStamp());
2186            //System.out.print("_#");
2187            if (debugOut) System.out.println("\nElapsed Time (hr-min-sec-milli) = "+getTimeDelta(startTimeStamp));
2188            if ( rs != null)
2189            {
2190              int numRows = 0;
2191              try
2192              {
2193                ResultSetMetaData rsmd = rs.getMetaData();
2194                //System.out.print("_#");
2195                int numCols = rsmd.getColumnCount();
2196                for (int i=1; i<= numCols; i++)
2197                {
2198                  retVal.append(rsmd.getColumnLabel(i));
2199                  if (i<numCols)  retVal.append(columnDelimitor);
2200                }
2201                retVal.append("\n");
2202                while (rs.next())
2203                {
2204                  for (int i=1; i<= numCols; i++)
2205                  {
2206                   //if (rs!=null && rs.getString(i)!=null && rs.getString(i).contains("\n")) System.out.println(rs.getString(i));
2207                   if (rs!=null && rs.getString(i)!=null && rs.getString(i).contains("\r\n"))
2208                   {
2209                     //System.out.println("!YES!");
2210                     retVal.append(rs.getString(i).replace("\r\n","[crlf]"));
2211                   }
2212                   else if (rs!=null && rs.getString(i)!=null && rs.getString(i).contains("\n"))
2213                   {
2214                     //System.out.println("!YES!");
2215                     retVal.append(rs.getString(i).replace("\n","[eol]"));
2216                   }
2217                   else
2218                   {
2219                     //System.out.println("!YES!");
2220                    retVal.append(rs.getString(i));
2221                   }
2222                    if (i<numCols)  retVal.append(columnDelimitor);
2223                  }
2224                  numRows++;
2225                  retVal.append("\n");
2226                }
2227              }
2228              catch (SQLException noResultsEx)
2229              {
2230                //System.out.println(noResultsEx.toString());
2231                retVal = new StringBuffer(noResultsEx.toString());
2232              }
2233              catch (java.lang.NullPointerException npEx)
2234              {
2235                //System.out.println(npEx.toString());
2236                retVal = new StringBuffer(npEx.toString());
2237              }
2238              catch (java.lang.OutOfMemoryError meapMemEx)
2239              {
2240                System.out.println(meapMemEx.toString());
2241                System.out.println("Truncating RS to "+numRows+" rows");
2242              }
2243              finally
2244              {
2245                rs.close();
2246              }
2247            }
2248          }
2249          // clean up
2250          //if (rs != null && !rs.isClosed()) rs.close();
2251          //if (s != null && !s.isClosed()) s.close();
2252          if (con != null && !con.isClosed()) con.close();
2253        }
2254      }
2255      catch (ClassNotFoundException e1)
2256      {
2257        // JDBC driver class not found, print error message to the console
2258        System.out.println(e1.toString());
2259      }
2260      catch (SQLException e2)
2261      {
2262        // Exception when executing java.sql related commands, print error message to the console
2263        System.out.println(e2.toString());
2264        System.out.println("SQL:\n"+ sql);
2265        //e2.printStackTrace();
2266      }
2267      catch (Exception e3)
2268      {
2269        // other unexpected exception, print error message to the console
2270        System.out.println(e3.toString());
2271      }
2272      finally
2273      {
2274        // close and clean up
2275        try{if (con != null && !con.isClosed()) con.close();}catch (Exception e6){}
2276      }
2277
2278    }
2279
2280    return retVal;
2281  }
2282
2283
2284  /**
2285   *  Converts the results from the 'query' method into a Comma Seperated String.
2286   *
2287   * @param  results   The sql results from the 'query' method
2288   * @return           the csv StringBuffer Value
2289   */
2290  public String convertSqlResultsToCSV(StringBuffer results)
2291  {
2292    StringBuffer retVal = new StringBuffer("");
2293    StringTokenizer tokens = new StringTokenizer(results.toString(),SYSTEM_LINE_SEPERATOR);
2294    String currentToken = "";
2295    StringTokenizer columnsTokens;
2296    String [] colNames = null;
2297    int numCols = 0;
2298    int i=0;
2299    // Get the Col names
2300    if (tokens.hasMoreTokens())
2301    {
2302      currentToken = tokens.nextToken();
2303      columnsTokens =  new StringTokenizer(currentToken,DEFAULT_COLUMN_DELIMITOR);
2304      colNames = new String[columnsTokens.countTokens()];
2305      while (columnsTokens.hasMoreTokens())
2306      {
2307        colNames[i] = columnsTokens.nextToken().trim();
2308        if (colNames[i].contains(","))
2309        {
2310          retVal.append("\"");
2311          retVal.append(colNames[i]);
2312          retVal.append("\"");
2313        }
2314        else
2315          retVal.append(colNames[i]);
2316        if (columnsTokens.hasMoreTokens()) retVal.append(",");
2317        i++;
2318      }
2319      retVal.append("\n");
2320    }
2321    numCols = i;
2322    String currentColValue = "";
2323    while (tokens.hasMoreTokens())
2324    {
2325      currentToken = tokens.nextToken();
2326      columnsTokens =  new StringTokenizer(currentToken,DEFAULT_COLUMN_DELIMITOR);
2327      while (columnsTokens.hasMoreTokens())
2328      {
2329        currentColValue = columnsTokens.nextToken().trim();
2330        //if (currentColValue.contains("PREPLANNED")) System.out.println(currentColValue);
2331        if (currentColValue!=null && currentColValue.contains(","))
2332        {
2333          retVal.append("\"");
2334
2335          if (currentColValue!=null && currentColValue.contains("\r\n"))
2336          {
2337            retVal.append((currentColValue!=null?currentColValue.replace("\r\n","[crlf]"):null));
2338          }
2339          else if (currentColValue!=null && currentColValue.contains("\n"))
2340          {
2341            retVal.append((currentColValue!=null?currentColValue.replace("\n","[eol]"):null));
2342          }
2343          else
2344          retVal.append(currentColValue);
2345
2346          retVal.append("\"");
2347        }
2348        else if (currentColValue!=null && currentColValue.contains("\r\n"))
2349        {
2350          retVal.append((currentColValue!=null?currentColValue.replace("\r\n","[crlf]"):null));
2351        }
2352        else if (currentColValue!=null && currentColValue.contains("\n"))
2353        {
2354          retVal.append((currentColValue!=null?currentColValue.replace("\n","[eol]"):null));
2355        }
2356        else
2357          retVal.append(currentColValue);
2358
2359        if (columnsTokens.hasMoreTokens()) retVal.append(",");
2360      }
2361      retVal.append("\n");
2362    }
2363    return retVal.toString();
2364  }
2365
2366
2367  /**
2368   *  Converts the results from the 'query' method into an xls file.
2369   *
2370   * @param  results   The sql results from the 'query' method
2371   * @param  xlsFilename   The resulting xls filename
2372   * @return           the xls filename
2373   */
2374  public boolean convertSqlResultsToXLS(StringBuffer results, String xlsFilename)
2375  {
2376    boolean retVal = true;
2377    try
2378    {
2379      jxl.write.WritableWorkbook workbook = Workbook.createWorkbook(new File(xlsFilename));
2380      jxl.write.WritableSheet sheet = workbook.createSheet("sqlResults", 0);
2381
2382      StringTokenizer tokens = new StringTokenizer(results.toString(),"\n");
2383      String currentToken = "";
2384      StringTokenizer columnsTokens;
2385      String [] colNames = null;
2386      boolean removeEOLs = true;
2387      int numCols = 0;
2388      int i=0;
2389      int currCol=0;
2390      int rows=0;
2391      // Get the Col names
2392      if (tokens.hasMoreTokens())
2393      {
2394        currentToken = tokens.nextToken();
2395        columnsTokens =  new StringTokenizer(currentToken,"|");
2396        colNames = new String[columnsTokens.countTokens()];
2397        while (columnsTokens.hasMoreTokens())
2398        {
2399          colNames[i] = columnsTokens.nextToken().trim();
2400          sheet.addCell(new jxl.write.Label(i, rows, colNames[i]));
2401          i++;
2402        }
2403      }
2404      numCols = i;
2405      String currentColValue = "";
2406      double currentColDbl = 0.0;
2407      boolean isDouble = false;
2408      // write the data
2409      while (tokens.hasMoreTokens())
2410      {
2411        rows++;
2412        currCol=0;
2413        currentToken = tokens.nextToken();
2414        columnsTokens =  new StringTokenizer(currentToken,"|");
2415        while (columnsTokens.hasMoreTokens())
2416        {
2417          isDouble = false;
2418          currentColValue = columnsTokens.nextToken().trim();
2419          try
2420          {
2421            currentColDbl = Double.parseDouble(currentColValue);
2422            isDouble = true;
2423          }
2424          catch (NumberFormatException numEx)
2425          {
2426            isDouble = false;
2427          }
2428          if (isDouble)
2429            sheet.addCell(new jxl.write.Number(currCol++, rows, currentColDbl));
2430          else
2431            if ( removeEOLs)
2432              sheet.addCell(new jxl.write.Label(currCol++, rows, (currentColValue!=null?currentColValue.replace("\n","\\n"):null)));
2433            else
2434            sheet.addCell(new jxl.write.Label(currCol++, rows, currentColValue));
2435        }
2436      }
2437      workbook.write();
2438      workbook.close();
2439    }
2440    catch (java.io.IOException ioEx)
2441    {
2442      retVal = false;
2443    }
2444    catch (jxl.write.WriteException jlWriteEx)
2445    {
2446      retVal = false;
2447    }
2448
2449    return retVal;
2450  }
2451
2452
2453  /**
2454   * Save chart as SVG file.
2455   * Required libs: Apache Batik (batik-svggen.jar, batik-dom.jar, dom.jar).
2456   *
2457   * @param chart JFreeChart to save.
2458   * @param fileName Name of file to save chart in.
2459   * @param width Width of chart graphic.
2460   * @param height Height of chart graphic.
2461   * @throws Exception if failed.
2462   */
2463  public void saveChartToSVG(JFreeChart chart,
2464                              String fileName,
2465                              int width,
2466                              int height)
2467  {
2468    if (chart != null)
2469    {
2470      if (fileName == null)
2471      {
2472        fileName = "chart.svg";
2473      }
2474      try
2475      {
2476        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
2477        Document document = domImpl.createDocument(null, "svg", null);
2478        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
2479        chart.draw(svgGenerator, new Rectangle2D.Double(0, 0, width, height), null);
2480
2481        boolean useCSS = true;
2482        File newSVGFile = new File(fileName);
2483        newSVGFile.createNewFile();
2484        Writer out = new OutputStreamWriter(new FileOutputStream(newSVGFile),"UTF-8");
2485        svgGenerator.stream(out, useCSS);
2486      }
2487      catch (Exception ex)
2488      {
2489        System.out.println("Exception - " + ex.toString());
2490        ex.printStackTrace(System.out);
2491      }
2492    }
2493  }//saveChartToSVG()
2494
2495
2496  /**
2497   * A helper method to take the reaults from a DBquery and parse them into a
2498   * CategoryDataset for use in making a chart. The SQL must produce a resultset
2499   * with the 1st column containing the categories. It must also have at least a
2500   * 2nd column that contains values to use to create the bar. a 3rd optional
2501   * column can be returned to ptrovide a name for the value in the 2nd column.
2502   * <br />
2503   * Example<pre>
2504   *
2505   * Coulmn1     Column2     Column3
2506   * Apr         10          task1
2507   * Apr         6           task2
2508   * Apr         8           task3
2509   * Apr         3           task4
2510   * Apr         25          task5
2511   * May         10          task1
2512   * May         6           task2
2513   * May         8           task3
2514   * May         3           task4
2515   * May         25          task5
2516   * Jun         10          task1
2517   * Jun         6           task2
2518   * Jun         8           task3
2519   * Jun         3           task4
2520   * Jun         25          task5
2521   * </pre><br />Would produce a stacked bar chart showing the the stacked
2522   * time spent on each task, categorized/grouped per month.
2523   *
2524   * @param sqlResults is the sqlresults to use as the basis for the dataset
2525   * @return the resultant dataset from the results from the sql query
2526   **/
2527  private DefaultCategoryDataset createDatasetFromSqlResults(StringBuffer sqlResults)
2528  {
2529    DefaultCategoryDataset dataset = null;
2530
2531    try
2532    {
2533      if (sqlResults.length() > 0)
2534      {
2535        StringTokenizer tokens = new StringTokenizer(sqlResults.toString(),"\n");
2536        String currentToken = "";
2537        StringTokenizer columnsTokens;
2538        String  colVal = null;
2539        int numCols = 0;
2540        int i=0;
2541
2542        // *****************************************
2543        // Create the Main Dataset for the task bars
2544        // *****************************************
2545        dataset = new DefaultCategoryDataset();
2546        double value;
2547        java.lang.Comparable rowKey;
2548        java.lang.Comparable columnKey;
2549        int j=0;
2550        // Get Rid of the Column Headings
2551        if (tokens.hasMoreTokens())  currentToken = tokens.nextToken();
2552
2553        // go through the resultRows ( one row per item in a group)
2554        while (tokens.hasMoreTokens())
2555        {
2556          currentToken = tokens.nextToken();
2557          //System.out.println(currentToken);
2558          columnsTokens =  new StringTokenizer(currentToken,columnDelimitor);
2559          //System.out.println("Num columns: "+columnsTokens.countTokens());
2560          if (columnsTokens.hasMoreTokens())
2561          {
2562            columnKey = columnsTokens.nextToken().trim();
2563            value = Double.parseDouble(columnsTokens.nextToken().trim());
2564            if (columnsTokens.hasMoreTokens())
2565              rowKey = columnsTokens.nextToken().trim();
2566            else
2567              rowKey = "";
2568            dataset.addValue(value, rowKey, columnKey);
2569          }
2570          i++;
2571        }
2572      }
2573    }
2574    catch (Exception e)
2575    {
2576      System.out.println("Exception - " + e.toString());
2577      e.printStackTrace(System.out);
2578      dataset = null;
2579    }
2580
2581    return dataset;
2582  }
2583
2584
2585  /**
2586   * Generates a JFreeChart Categorized Bar Chart based on the SQL that is passed
2587   * in and executed.  The SQL must produce a resultset with the 1st column
2588   * containing the categories. It must also have  a 2nd column that
2589   * contains values to use to create the bar. The 3rd column is the name
2590   * for the col2 value<br>
2591   *
2592   * Example<pre>
2593   *
2594   * Coulmn1     Column2     Column3
2595   * Apr         10          task1
2596   * Apr         6           task2
2597   * Apr         8           task3
2598   * Apr         3           task4
2599   * Apr         25          task5
2600   * May         10          task1
2601   * May         6           task2
2602   * May         8           task3
2603   * May         3           task4
2604   * May         25          task5
2605   * Jun         10          task1
2606   * Jun         6           task2
2607   * Jun         8           task3
2608   * Jun         3           task4
2609   * Jun         25          task5
2610   * </pre><br />Would produce a bar chart showing the column2 bars grouped by
2611   *  month (column1).
2612   *
2613   * @return the filename for the genetated chart.
2614   **/
2615  public String generateCategoryBarChart(String sql,
2616                                         HttpSession session,
2617                                         PrintWriter pw,
2618                                         String chartTitle,
2619                                         String xAxisTitle,
2620                                         String yAxisTitle,
2621                                         boolean showLegend)
2622  {
2623    String filename = "";
2624    int chartdX = 800;
2625    int chartdY = 600;
2626    Color chartBackgroundFromColor = new Color(220,255,255);
2627    Color chartBackgroundToColor = new Color(160,255,240);
2628    try {
2629      //  Retrieve SQL Results
2630      StringBuffer sqlResults = this.query(sql);
2631
2632      System.out.println("Finished Bar Chart Query");
2633      //System.out.println("Results: ");
2634      //System.out.println(sqlResults.toString());
2635
2636      //  Throw a custom NoDataException if there is no data
2637      if (sqlResults.length() == 0)
2638      {
2639        System.out.println("No data has been found");
2640        //throw new NoDataException();
2641      }
2642
2643      StringTokenizer tokens = new StringTokenizer(sqlResults.toString(),"\n");
2644      String currentToken = "";
2645      StringTokenizer columnsTokens;
2646      String  colVal = null;
2647      int numCols = 0;
2648      int i=0;
2649
2650      // *****************************************
2651      // Create the Main Dataset for the task bars
2652      // *****************************************
2653      DefaultCategoryDataset dataset = new DefaultCategoryDataset();
2654      double value;
2655      java.lang.Comparable rowKey;
2656      java.lang.Comparable columnKey;
2657      int j=0;
2658      // Get Rid of the Column Headings
2659      if (tokens.hasMoreTokens())  currentToken = tokens.nextToken();
2660
2661      // go through the resultRows ( one row per item in a group)
2662      while (tokens.hasMoreTokens())
2663      {
2664        currentToken = tokens.nextToken();
2665        //System.out.println(currentToken);
2666        columnsTokens =  new StringTokenizer(currentToken,"|");
2667        //System.out.println("Num columns: "+columnsTokens.countTokens());
2668        if (columnsTokens.hasMoreTokens())
2669        {
2670          columnKey = columnsTokens.nextToken().trim();
2671          value = Double.parseDouble(columnsTokens.nextToken().trim());
2672          rowKey = columnsTokens.nextToken().trim();
2673          dataset.addValue(value, rowKey, columnKey);
2674        }
2675        i++;
2676      }
2677
2678      // ***********************************************
2679      // Create the Main Plot
2680      // ***********************************************
2681      BarRenderer renderer = new BarRenderer();
2682      StandardCategoryToolTipGenerator generator = new StandardCategoryToolTipGenerator();
2683      //renderer.setBaseLabelGenerator(generator);
2684      renderer.setBaseItemLabelsVisible(new java.lang.Boolean(true), true);
2685      //renderer.setItemURLGenerator(new StandardCategoryURLGenerator("/goto.jsp?page=ProjectUpdate","&task","&month"));
2686
2687      // org.jfree.text.TextBlock.calculateDimensions(Ljava/awt/Graphics2D;)Ljava/awt/geom/Dimension2D;
2688      renderer.setBaseToolTipGenerator(generator);
2689
2690      CategoryAxis categoryAxis = new CategoryAxis(xAxisTitle);
2691      categoryAxis.setTickLabelsVisible(true);
2692      //categoryAxis.setLabelAngle(3.1415);
2693      ValueAxis valueAxis = new NumberAxis(yAxisTitle);
2694
2695      CategoryPlot plot = new CategoryPlot(dataset, categoryAxis, valueAxis, renderer);
2696      plot.setOrientation(PlotOrientation.VERTICAL);
2697      plot.setRangeGridlinesVisible(true);
2698      plot.setDomainGridlinesVisible(false);
2699
2700
2701      // Creat the Charty based on the Plot
2702      JFreeChart chart = new JFreeChart(chartTitle,
2703                                        JFreeChart.DEFAULT_TITLE_FONT,
2704                                        plot,
2705                                        showLegend); // draw legend
2706      //chart.getLegend().setAnchor(chart.getLegend().EAST);
2707      chart.setBackgroundPaint(
2708          new GradientPaint(
2709              0,
2710              0,
2711              chartBackgroundFromColor,
2712              chartdX,
2713              chartdY,
2714              chartBackgroundToColor));
2715
2716      //find a place to save the chart graphic
2717      String saveDir = ".";
2718      //System.out.println("Final Chart Dir: "+saveDir);
2719
2720      //  Write the chart image to the temporary directory
2721      ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
2722
2723      filename = ServletUtilities.saveChartAsPNG(chart,
2724                                                 chartdX,
2725                                                 chartdY,
2726                                                 info,
2727                                                 session);
2728
2729      //  Write the image map to the PrintWriter
2730      ChartUtilities.writeImageMap(pw, filename, info, false);
2731      pw.flush();
2732
2733      //System.out.println("Moving chart to file: "+filename);
2734      ca.bc.webarts.widgets.Util.moveFile(
2735          System.getProperty("java.io.tmpdir")+filename,
2736          saveDir);
2737
2738//    } catch (NoDataException e) {
2739//      System.out.println(e.toString());
2740//      filename = "public_nodata_500x300.png";
2741    } catch (Exception e) {
2742      System.out.println("Exception - " + e.toString());
2743      e.printStackTrace(System.out);
2744      filename = "public_error_500x300.png";
2745    }
2746    return filename;
2747  }
2748
2749
2750
2751  /**
2752   * Generates a JFreeChart Pie Chart based on the SQL that is passed
2753   * in and executed.  The SQL must produce a resultset with the 1st column
2754   * containing the categories. It must also have  a 2nd column that
2755   * contains values to use to create the pie.<br>
2756   *
2757   * Example<pre>
2758   *
2759   * Coulmn1     Column2
2760   * Apr         10
2761   * May         10
2762   * Jun         10
2763   * </pre><br />Would produce a pie chart showing the time spent each month.
2764   *
2765   * @return the filename for the genetated chart.
2766   **/
2767  public String generatePieChart(String sql,
2768                                 HttpSession session,
2769                                 PrintWriter pw,
2770                                 String chartTitle,String xAxisTitle,String yAxisTitle)
2771  {
2772    int chartdX = 640;
2773    int chartdY = 480;
2774    Color chartBackgroundFromColor = new Color(220,255,255);
2775    Color chartBackgroundToColor = new Color(160,255,240);
2776    String filename = "";
2777    try {
2778      //  Retrieve SQL Results
2779      StringBuffer sqlResults = this.query(sql);
2780
2781      System.out.println("Finished Pie Query");
2782      //System.out.println("Results: ");
2783      //System.out.println(sqlResults.toString());
2784
2785      //  Throw a custom NoDataException if there is no data
2786      if (sqlResults.length() == 0)
2787      {
2788        System.out.println("No data has been found");
2789        //throw new NoDataException();
2790      }
2791
2792      //  Create and populate a CategoryDataset
2793      StringTokenizer tokens = new StringTokenizer(sqlResults.toString(),"\n");
2794      String currentToken = "";
2795      StringTokenizer columnsTokens;
2796      String  colVal = null;
2797      int numCols = 0;
2798      int i=0;
2799      DefaultPieDataset dataset = new DefaultPieDataset();
2800      double value;
2801      java.lang.Comparable rowKey;
2802      // Get Rid of the Column Headings
2803      if (tokens.hasMoreTokens())  currentToken = tokens.nextToken();
2804
2805      // go through the resultRows
2806      while (tokens.hasMoreTokens())
2807      {
2808        currentToken = tokens.nextToken();
2809        columnsTokens =  new StringTokenizer(currentToken,"|");
2810        while (columnsTokens.hasMoreTokens())
2811        {
2812          rowKey = columnsTokens.nextToken().trim();
2813          value = Double.parseDouble(columnsTokens.nextToken().trim());
2814          dataset.setValue(rowKey, value);
2815        }
2816        i++;
2817      }
2818
2819      PiePlot plot = new PiePlot(dataset);
2820      plot.setShadowXOffset(15.0);
2821      plot.setShadowYOffset(18.0);
2822      plot.setShadowPaint(new Color(210,210,210));
2823      JFreeChart chart = new JFreeChart(chartTitle,
2824                                        JFreeChart.DEFAULT_TITLE_FONT,
2825                                        plot,
2826                                        false);
2827      chart.setBackgroundPaint(
2828          new GradientPaint(
2829              0,
2830              0,
2831              chartBackgroundFromColor,
2832              chartdX,
2833              chartdY,
2834              chartBackgroundToColor));
2835
2836      //find a place to save the chart graphic
2837      String saveDir = ".";
2838      //System.out.println("Final Chart Dir: "+saveDir);
2839
2840      //  Write the chart image to the temporary directory
2841      ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
2842
2843      filename = ServletUtilities.saveChartAsPNG(chart, 640, 480, info, session);
2844
2845      //  Write the image map to the PrintWriter
2846      ChartUtilities.writeImageMap(pw, filename, info, false);
2847      pw.flush();
2848
2849      //System.out.println("Moving chart to file: "+System.getProperty("java.io.tmpdir")+filename);
2850      ca.bc.webarts.widgets.Util.moveFile(
2851          System.getProperty("java.io.tmpdir")+filename,
2852          saveDir);
2853
2854//    } catch (NoDataException e) {
2855//      System.out.println(e.toString());
2856//      filename = "public_nodata_500x300.png";
2857    } catch (Exception e) {
2858      System.out.println("Exception - " + e.toString());
2859      e.printStackTrace(System.out);
2860      filename = "public_error_500x300.png";
2861    }
2862    return filename;
2863  }
2864
2865
2866
2867  public static void main(String [] args)
2868  {
2869    StringBuffer helpMsg = new StringBuffer(SYSTEM_LINE_SEPERATOR);
2870    helpMsg.append("---  WebARTS Database Query Helper Class  ---------------------\n");
2871    helpMsg.append("---------------------------------------------------------------\n");
2872    helpMsg.append(SYSTEM_LINE_SEPERATOR);
2873    helpMsg.append("ca.bc.webarts.tools.SqlQuery dbType server dbName username password sql\n");
2874
2875    SqlQuery instance = new SqlQuery();
2876    if (args ==null || args.length<4)
2877    {
2878      System.out.println(helpMsg.toString());
2879    }
2880    else
2881    {
2882      if (args[0].toLowerCase().equals("oracle"))
2883        instance.setUseOracleDB();
2884      else if (args[0].toLowerCase().equals("oraclededicated"))
2885        instance.setUseOracleDedicatedDB();
2886      else if (args[0].toLowerCase().equals("mysql"))
2887        instance.setUseMysqlDB();
2888      else if (args[0].toLowerCase().equals("hsql"))
2889        instance.setUseHsqlDB();
2890      else if (args[0].toLowerCase().equals("postgre"))
2891        instance.setUsePostgreDB();
2892      else if (args[0].toLowerCase().equals("derby"))
2893        instance.setUseDerbyDB();
2894      else if (args[0].toLowerCase().equals("db2"))
2895        instance.setUseDb2DB();
2896      else if (args[0].toLowerCase().equals("odbc"))
2897        instance.setUseOdbcDB();
2898
2899      if (args.length >2)
2900      {
2901        instance.setDbIP(args[1]);
2902        instance.setDbName(args[2]);
2903        instance.setDbUser(args[3]);
2904        instance.setDbPassword(args[4]);
2905        if (args.length >5)
2906        {
2907          StringBuffer sql = null;
2908          int i = 5;
2909
2910          while (i < args.length)
2911          {
2912            sql = new StringBuffer();
2913            for (; i < args.length; i++)
2914            {
2915              //String [] splits = args[i].split(" |;");
2916              // build the sql query until a ';' is found
2917              sql.append(args[i]);
2918              sql.append(" ");
2919              //System.out.print(args[i] + " ");
2920              if (args[i].endsWith(";"))
2921                break;
2922            }
2923
2924            System.out.print("Executing SQL query: ");
2925            System.out.println(sql.toString());
2926            System.out.print("DB Connection ("+instance.getDbUser()+":"+instance.getDbPassword()+ "): ");
2927            System.out.println(instance.getDbConnectString());
2928            StringBuffer sqlResultSet = instance.query(sql.toString());
2929            System.out.println(sqlResultSet.toString());
2930            i++;
2931          }
2932        }
2933      }
2934    }
2935  }
2936
2937}// -- end class ca.bc.webarts.SqlQuery
2938