001/*
002 * CreateDBTables.java
003 * Copyright (c) 2002 Tom B. Gutwin P.Eng.
004 *
005 * This program is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU General Public License
007 * as published by the Free Software Foundation; either version 2
008 * of the License, or any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program; if not, write to the Free Software
017 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
018 */
019
020package ca.bc.webarts.tools;
021
022import ca.bc.webarts.widgets.WrapperApp;
023import java.io.*;
024
025import java.sql.*;
026import javax.swing.*;
027import javax.swing.event.*;
028
029
030
031/**
032 *  A class to help build a whack of db tables based on a txt file.<BR />
033 *  This App Gets called like: java ca.bc.webarts.tools.CreateDBTables -test
034 *  false -f IEEEDBTables.txt IEEEVANC
035 *
036 * @author     tgutwin
037 * @created    July 8, 2002
038 */
039
040public class CreateDBTables extends JApplet
041{
042
043  /** **/
044  static int dbIndex = 1;
045  /** */
046  final static String[] jdbcDriverName = {"org.postgresql.Driver",
047                                          "COM.ibm.db2.jdbc.app.DB2Driver",
048                                          "org.postgresql.Driver"};
049  /** */
050  private static String[] dbBrandName = {"PostgreSQL","DB2","PostgreSQL"};
051  /** */
052  private static String[] dbServerName = {"warp2","Aurora1","warp2"};
053  /** */
054  private static String[] dbServerPort = {"5432","6790","5432"};
055  /** */
056  private static String[] dbName = {"test","sample","test"};
057  /** */
058  private static String[] dbUserId = {"tgutwin","tgutwin","tgutwin"};
059  /** */
060  private static String[] dbUserPassword = {"18BoogieWoogie",
061                                            "GetYourOwnPassword",
062                                            "18BoogieWoogie"};
063  /** */
064  private static String[] dbURL = {
065            "jdbc:postgresql://" + dbServerName[0] + ":" + dbServerPort[0] + "/" + dbName[0],
066            "jdbc:db2://"        + dbServerName[1] + ":" + dbServerPort[1] + "/" + dbName[1],
067            "jdbc:postgresql://" + dbServerName[2] + ":" + dbServerPort[2] + "/" + dbName[2]};
068  /** */
069  final static String adminEmail = "webadmin@webarts.bc.ca";
070  /** */
071  final static String adminEmailURL = "<A HREF=\"" + adminEmail + "\">" + adminEmail + "</A>";
072  /** */
073  final static String jdbcDriverErrorMsg = "Sorry, a JDBC Driver ERROR occurred.  I won't be able to process you request";
074  /** */
075  final static String sqlErrorMsg = "Sorry, a SQL ERROR occurred.  I won't be able to process your request";
076  /** */
077  final static String reportErrorMsg = "Please copy the follwing information and email it to " + adminEmail;
078  /** */
079  final static String fileErrorMsg = "File Error";
080  /** */
081  static short numColumns = 0;
082  /** */
083  String tableNm_;
084  /** */
085  String testTableName = "testTable";
086  /** */
087  String[][] tableColumns;
088  /**
089   *  A flag to specify if the DROP command was specified on the commandline. If
090   *  this is true the tablename that is specified will be dropped from the DB.
091   */
092  boolean dropTable = false;
093
094  /**
095   *  A flag to specify if the f command was specified on the commandline. If
096   *  this is true the a input filename was specified on the commandline that
097   *  will be used to get the table info from.
098   */
099  boolean fileArgFlag = false;
100
101  /**
102   *  The filename that is specified on the commandline in conjunction with the
103   *  -f switch
104   */
105  String inFileName = "testTable.txt";
106
107  /** */
108  Connection con = null;
109  /**
110   *  Input <code>File</code> to read in the formname/dbtablecolumnname at
111   *  runtime.
112   */
113  FileReader fileReader = null;
114  /**  Tokenized version of the input config file <code>fileReader</code>  */
115  StreamTokenizer inputTokens;
116
117  /** */
118  static boolean DEBUG = true;
119
120  /**  Description of the Field */
121  static String[] inArgs;
122
123  /*
124  static
125  {
126    try
127    {
128       Class.forName(jdbcDriverName[0]);
129      System.out.println("We Registered The Driver!");
130    }
131    catch (Exception e)
132    {
133      System.out.println(jdbcDriverErrorMsg);
134      System.out.println(e);
135      System.out.println(reportErrorMsg);
136      System.exit(1);
137    }
138  }
139  */
140
141
142  /**
143   *  the method that return the programmers customized information about this
144   *  applet.
145   *
146   * @return    The appletInfo value
147   */
148  public String getAppletInfo()
149  {
150    return "Database Table Creator, Copyright (c) WebARTS Design 2000 - Tom Gutwin P.Eng.";
151  }
152
153
154  /**
155   *  the method that returns the information about the possible applet
156   *  parameters.
157   *
158   * @return    a table of Strings (String[][]) holding the input param name,
159   *      type and description
160   */
161  public String[][] getParameterInfo()
162  {
163    String[][] retVal = {
164        {"INPUTFILE",
165         "String",
166         "the string holding the filename to read the table data "}
167        };
168    return retVal;
169  }
170
171
172  /**
173   *  Initializes everything needed to start/run this applet. It gets called
174   *  upon 1st call of the applet. It performs the following initializations:
175   *
176   *  <UL>
177   *    <LI> <B>retrieves the codebase</B>
178   *    <LI> <B>retrieves the applet input parameters</B>
179   *    <LI> <B>sets the look and feel attribute</B>
180   *  </UL>
181   *
182   */
183  public void init()
184  {
185    setVisible(false);
186
187    /*
188     *  get the JApplets root pane & make a fix so this applet does not crash NS or IE
189     */
190    JRootPane rp = getRootPane();
191    rp.putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
192
193    TableCreator(inArgs);
194  }
195
196
197  /**
198   * @param  numSwitches  Description of the Parameter
199   * @param  switchArgs   Description of the Parameter
200   * @return              Description of the Return Value
201   */
202  private boolean parseSwitches(int numSwitches, String[][] switchArgs)
203  {
204    boolean retVal = true;
205    for (int i = 0; i < numSwitches; i++)
206    {
207      if (switchArgs[i][0].equals("-f"))
208      {
209        inFileName = switchArgs[i][1];
210        fileArgFlag = true;
211      }
212      if (switchArgs[i][0].equals("-test"))
213      {
214        if (switchArgs[i][1].equals("true"))
215        {
216          DEBUG = true;
217        }
218        else
219        {
220          DEBUG = false;
221        }
222      }
223    }
224    return retVal;
225  }
226
227
228  /**
229   * @return    Description of the Return Value
230   */
231  private boolean initFileTokens()
232  {
233    boolean retVal = true;
234
235    try
236    {
237      System.out.println("Tokenizing file " + inFileName);
238      fileReader = new FileReader(inFileName);
239
240      inputTokens = new StreamTokenizer(fileReader);
241      inputTokens.eolIsSignificant(true);
242      inputTokens.lowerCaseMode(true);
243      inputTokens.slashSlashComments(true);
244      inputTokens.slashStarComments(true);
245    }
246    catch (FileNotFoundException e)
247    {
248      System.err.println(fileErrorMsg);
249      System.err.println(reportErrorMsg);
250      System.err.println("e.printStackTrace()");
251      retVal = false;
252    }
253    catch (java.lang.NullPointerException e)
254    {
255      System.err.println(fileErrorMsg);
256      System.err.println(reportErrorMsg);
257      System.err.println("e.printStackTrace()");
258      retVal = false;
259    }
260
261    return retVal;
262  }
263
264
265  /**
266   * Reads one token from the inputTokens, if it is a StreamTokenizer.TT_WORD
267   * it is assumed to be the next table name and puts it in the class tableNm_
268   * field.
269   *
270   * @return    false if success, true if at EOF
271   */
272  private boolean getNextTableName()
273  {
274    //returns true if atEOF
275    boolean retVal = false;
276    String tempStr = "";
277    tableNm_ = testTableName;
278    int tempResult = 0;
279
280    try
281    {
282      tempResult = inputTokens.nextToken();
283      if (tempResult == StreamTokenizer.TT_WORD)
284      {
285        tempStr = inputTokens.sval;
286        System.out.println("Next Table=" + tempStr);
287        tempResult = inputTokens.nextToken();
288        // read the EOL
289      }
290      else
291      {
292        //       if(tempResult == StreamTokenizer.TT_EOF)
293        retVal = true;
294      }
295
296    }
297    catch (IOException ex)
298    {
299      System.err.println(fileErrorMsg);
300      System.err.println(reportErrorMsg);
301      System.err.println("getNextTableName reading file:" + inFileName);
302      retVal = true;
303    }
304    tableNm_ = tempStr;
305    return retVal;
306  }
307
308
309  /**
310   *  A method to fill the <code>tableColumns</code> static array with the
311   *  column information. This information goes directly into the SQL statement
312   *  that is used to create the table.
313   *
314   * @return    The nextTable value
315   */
316  private short getNextTable()
317  {
318    numColumns = 0;
319    tableColumns = new String[250][3];
320    tableColumns[0][0] = "Column1";
321    tableColumns[0][1] = "SMALLINT";
322    tableColumns[0][2] = "NOT NULL";
323
324    int tempResult = 0;
325    int numFields = 0;
326
327    System.out.println("Getting Table Column data...");
328    try
329    {
330      do // while not(EOF, NUMBER)
331      {
332        System.out.println("Col #"+numColumns);
333        do // while not(EOL,EOF, NUMBER)
334        {
335          System.out.println("Col - "+numColumns);
336          tempResult = inputTokens.nextToken();
337          if (tempResult == StreamTokenizer.TT_WORD)
338          {
339            if (inputTokens.sval.trim().equals("notnull"))
340            {
341              tableColumns[numColumns][numFields++] = "NOT NULL";
342            }
343
344            // CHAR
345            else if (inputTokens.sval.equals("char") || inputTokens.sval.equals("varchar"))
346            {
347              tableColumns[numColumns][numFields] = inputTokens.sval;
348              tempResult = inputTokens.nextToken();
349              if (tempResult == StreamTokenizer.TT_NUMBER)
350              {
351                tableColumns[numColumns][numFields++] += "(" + inputTokens.nval + ")";
352                tempResult = inputTokens.nextToken();
353              }
354              else
355              {
356                tableColumns[numColumns][numFields++] += "(254)";
357              }
358            }
359
360            // datalink URL
361            else if (inputTokens.sval.equals("datalink"))
362            {
363              tableColumns[numColumns][numFields++] = inputTokens.sval + " LINKTYPE URL ";
364            }
365
366            // CLOB
367            else if (inputTokens.sval.equals("clob"))
368            {
369              tableColumns[numColumns][numFields] = inputTokens.sval;
370              tempResult = inputTokens.nextToken();
371              if (tempResult == StreamTokenizer.TT_NUMBER)
372              {
373                tableColumns[numColumns][numFields++] += "(" + new Integer((int) inputTokens.nval) + " K)";
374                tempResult = inputTokens.nextToken();
375              }
376              else
377              {
378                tableColumns[numColumns][numFields++] += "(500 K)";
379              }
380            }
381            else
382            {
383              tableColumns[numColumns][numFields++] = inputTokens.sval;
384            }
385          }
386        } while (   !(tempResult == StreamTokenizer.TT_NUMBER) &&
387                    tempResult != StreamTokenizer.TT_EOL &&
388                    tempResult != StreamTokenizer.TT_EOF);
389        numFields = 0;
390        numColumns++;
391      } while (!(tempResult == StreamTokenizer.TT_NUMBER) &&
392          tempResult != StreamTokenizer.TT_EOF);
393      if (tempResult == StreamTokenizer.TT_NUMBER)
394      {
395        tempResult = inputTokens.nextToken();
396        // read and discard the next EOL
397        numColumns--;
398      }
399
400    }
401    catch (IOException ex)
402    {
403      System.err.println(fileErrorMsg);
404      System.err.println(reportErrorMsg);
405      System.err.println("getNextTable reading file:" + inFileName);
406    }
407    return numColumns;
408  }
409
410
411  /**
412   * @param  table    Description of the Parameter
413   * @param  cols     Description of the Parameter
414   * @param  numCols  Description of the Parameter
415   * @return          Description of the Return Value
416   */
417  private boolean createTable(String table, String[][] cols, short numCols)
418  {
419
420    String sqlString;
421    String columnString = "";
422    boolean retVal = true;
423
424    for (int i = 0; i < numCols; i++)
425    {
426      if (cols[i][1] == null)
427      {
428        cols[i][1] = "SMALLINT";
429      }
430      if (cols[i][2] == null)
431      {
432        cols[i][2] = " ";
433      }
434    }
435
436    for (int i = 0; i < numCols; i++)
437    {
438      columnString += cols[i][0] + " " + cols[i][1] + " " + cols[i][2];
439      if (i + 1 < numCols)
440      {
441        columnString += ",\n";
442      }
443    }
444    sqlString = "CREATE TABLE " + table + " ( \n" + columnString + ",\nPrimary KEY(" + cols[0][0] + ") \n)";
445
446    if (!DEBUG)
447    {
448      try
449      {
450        Statement stmt = con.createStatement();
451
452        ResultSet rs;
453        System.out.println("ExecutingSQL = " + sqlString);
454        rs = stmt.executeQuery(sqlString);
455
456        rs.close();
457        stmt.close();
458
459      }
460      catch (SQLException e)
461      {
462        System.err.println(sqlErrorMsg);
463        System.err.println(reportErrorMsg);
464        System.err.println(e.toString());
465        System.err.println("Puked While Creating Table:" + table);
466        //  e.printStackTrace();
467        retVal = false;
468      }
469    }
470    else
471    {
472      System.out.println("SQL = " + sqlString);
473    }
474    return retVal;
475  }
476
477
478  /**
479   * Constructor.
480   *
481   * @param  argv  Description of the Parameter
482   */
483  public void TableCreator(String argv[])
484  {
485    boolean switchError = false;
486
487    /*
488     *  get the commandline parms
489     */
490    switch (argv.length)
491    {
492        case 0:
493          dbIndex = 0;
494          //dbName[0] = "sample";
495          System.out.println("NO Commandline DB specified. Using -->" +
496                              dbName[dbIndex]);
497          break;
498
499        case 1:
500          /*
501           *  database name
502           */
503          dbName[0] = argv[0];
504          System.out.println("Using DB -->" + dbName[0]);
505          break;
506
507        case 2:
508          /*
509           *  -DROP database name
510           */
511          if (!argv[0].equals("-DROP"))
512          {
513            switchError = true;
514          }
515          dropTable = true;
516          dbName[0] = argv[argv.length - 1];
517          System.out.println("Using DB -->" + dbName[0]);
518          break;
519
520        default:
521          /*
522           *  get the command switches
523           */
524          String[][] switches = new String[argv.length][2];
525          int i = 0;
526          int k = 0;
527          while (i < argv.length - 1)
528          {
529            switches[k][0] = argv[i++];
530            switches[k++][1] = argv[i++];
531          }
532          parseSwitches((int) ((argv.length - 1) / 2), switches);
533          dbName[0] = argv[argv.length - 1];
534          System.out.println("Using DB -->" + dbName[0]);
535    }
536
537    try
538    {
539      Class.forName(jdbcDriverName[dbIndex]);
540      System.out.println("We Registered The Driver!");
541
542
543      //  construct the URL ( sample is the database name )
544      boolean tableCreated = true;
545      boolean atEOF = false;
546      //  connect to database with userid and password
547      System.out.println("Connecting:");
548      System.out.println("            "+dbURL[dbIndex]);
549      System.out.println("            "+dbUserId[dbIndex]);
550      con = DriverManager.getConnection(dbURL[dbIndex], dbUserId[dbIndex], dbUserPassword[dbIndex]);
551      System.out.println("Connected.");
552
553      if (!con.isClosed())
554      {
555        /*
556         *  read the nput file to get the next Itablename and columns
557         */
558        initFileTokens();
559
560        while (!atEOF && tableCreated)
561        {
562
563          atEOF = getNextTableName();
564          numColumns = getNextTable();
565          tableCreated = false;
566          if (!atEOF && tableNm_.length() > 0 && numColumns > 0)
567          {
568            tableCreated = createTable(tableNm_, tableColumns, numColumns);
569          }
570          else
571          {
572            if (!atEOF)
573            {
574              System.err.println(fileErrorMsg);
575              System.err.println(reportErrorMsg);
576              System.err.println("DBName = " + dbName + ", " + "Table Name =" + tableNm_ + ",     " + numColumns + " columns.");
577              atEOF = true;
578            }
579          }
580
581          if (tableCreated && !DEBUG)
582          {
583            // retrieve data from the database
584            System.out.println("Retrieve some data from the database...");
585            Statement stmt = con.createStatement();
586            ResultSet rs = stmt.executeQuery("SELECT * from " + tableNm_);
587
588            System.out.println("Received results:");
589
590            // display the result set
591            // rs.next() returns false when there are no more rows
592            while (rs.next())
593            {
594              String a = rs.getString(1);
595
596              System.out.print(" entry= " + a);
597              System.out.print("\n");
598            }
599            System.out.print("---------------------\n");
600
601            rs.close();
602            stmt.close();
603            con.commit();
604          }
605          else
606          {
607            if (!DEBUG)
608            {
609              con.rollback();
610            }
611          }
612
613        }
614        con.close();
615
616      }
617      else
618      {
619        System.err.println("Lost the DB Connection");
620        System.err.println(reportErrorMsg);
621        System.exit(1);
622      }
623    }
624    catch (SecurityException e)
625    {
626      System.err.println("Input File is Not Readable");
627      System.err.println(reportErrorMsg);
628      e.printStackTrace(System.err);
629    }
630    catch (SQLException e)
631    {
632      System.err.println(sqlErrorMsg);
633      System.err.println(reportErrorMsg);
634      e.printStackTrace(System.err);
635
636    }
637    catch (Exception e)
638    {
639      System.out.println(jdbcDriverErrorMsg);
640      System.out.println(e);
641      System.out.println(reportErrorMsg);
642      e.printStackTrace(System.err);
643      System.exit(1);
644    }
645
646    System.out.println("Completed.");
647    try
648    {
649      if (con!=null && !con.isClosed())
650      {
651        con.close();
652      }
653    }
654    catch (SQLException ex)
655    {
656      System.err.println("SQLError while attempting to close a residual connection");
657    }
658  }
659
660
661  /**
662   *  This method gets called if this applet is envoked as an application.
663   *
664   * @param  argv  Description of the Parameter
665   */
666  public static void main(String argv[])
667  {
668//        TableCreator tc = new TableCreator(argv);
669
670    inArgs = argv;
671
672    /*
673     *  create an app frame that will start this applet inside it
674     */
675    WrapperApp app = new WrapperApp("DB Table Creator", new CreateDBTables());
676    app.pack();
677    app.setSize(800, 600);
678
679    /*
680     *  Put the opening app up
681     */
682    //  app.setVisible(true);
683    //  app.setScreenLocation(2,2,0,0);
684    app.dispose();
685    System.exit(0);
686  }
687}
688