Project Report: fawkez

Packagesummary org.jcoderz.phoenix.sqlparser

org.jcoderz.phoenix.sqlparser.SqlTransformer

LineHitsNoteSource
1  /*
2   * $Id: SqlTransformer.java 1011 2008-06-16 17:57:36Z amandel $
3   *
4   * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5   *
6   * Redistribution and use in source and binary forms, with or without
7   * modification, are permitted provided that the following conditions are
8   * met:
9   *
10   *    * Redistributions of source code must retain the above copyright
11   *      notice, this list of conditions and the following disclaimer.
12   *    * Redistributions in binary form must reproduce the above
13   *      copyright notice, this list of conditions and the following
14   *      disclaimer in the documentation and/or other materials
15   *      provided with the distribution.
16   *    * Neither the name of the jCoderZ.org Project nor the names of
17   *      its contributors may be used to endorse or promote products
18   *      derived from this software without specific prior written
19   *      permission.
20   *
21   * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24   * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25   * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30   * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32   */
33  package org.jcoderz.phoenix.sqlparser;
34  
35  import java.io.File;
36  import java.io.FileFilter;
37  import java.io.FileInputStream;
38  import java.io.FileNotFoundException;
39  import java.io.FileOutputStream;
40  import java.io.IOException;
41  import java.io.PrintWriter;
42  import java.util.ArrayList;
43  import java.util.Arrays;
44  import java.util.HashMap;
45  import java.util.Iterator;
46  import java.util.List;
47  import java.util.Map;
48  import javax.xml.bind.JAXBContext;
49  import javax.xml.bind.JAXBException;
50  import javax.xml.bind.Unmarshaller;
51  
52  import org.jcoderz.commons.util.Constants;
53  import org.jcoderz.commons.util.IoUtil;
54  import org.jcoderz.phoenix.sqlparser.jaxb.Index;
55  import org.jcoderz.phoenix.sqlparser.jaxb.SqlMetainf;
56  import org.jcoderz.phoenix.sqlparser.jaxb.Table;
57  
58  /**
59   * @author Albrecht Messner
60   */
61  public class SqlTransformer
62  {
63     private static final String DEFAULT_KEY = "default";
64     private static final int INITIAL = 0;
65     private static final int IN_CREATE = 1;
66     private final File mInputFile;
67     private final File mOutputFile;
68     private File mMetainfFile;
69     private final boolean mForce;
70     
71     private int mState;
72     private TokenType mObjectType;
73     private String mObjectName;
74  
75100    private final Map mIndexMap = new HashMap();
76100    private final Map mTableMap = new HashMap();
77  
78     /**
79      * Constructor.
80      * @param inFile the input file
81      * @param outFile the output file
82      * @param metainfFile file containing meta information
83      * @param force force transformation flag
84      */
85     public SqlTransformer (
86           String inFile, String outFile, String metainfFile, boolean force)
87100    {
88100       mInputFile = new File(inFile);
89100       mOutputFile = new File(outFile);
90100       if (metainfFile != null)
91        {
92100          mMetainfFile = new File(metainfFile);
93100          parseMetainfFile();
94        }
95100       mForce = force;
96100    }
97     
98     /**
99      * Executes transformation based on timestamp checking and force flag.
100      */
101     public void execute ()
102     {
103        try
104        {
105100          if (checkFiles())
106           {
107100             filterComments();
108           }
1090          else if (mForce)
110           {
1110             System.out.println("Forcing transformation...");
1120             filterComments();
113           }
114           else
115           {
1160             System.out.println(
117                    "Output file is newer than input file, skipping.");
118           }
119        }
120        // possible exceptions: FileNotFound, JAXB, IO, Parse
1210       catch (Exception e)
122        {
1230          System.err.println(
124                 "SQL Transformation failed for file " + mInputFile);
1250          throw new RuntimeException("SQL Transformation failed: " + e, e);
126100       }
127100    }
128     
129     /**
130      * Check status of input and output files.
131      * @return true if the transformation needs to be performed,
132      *       false otherwise
133      * @throws IOException if the input file does not exist
134      */
135     public boolean checkFiles ()
136           throws IOException
137     {
138100       boolean result = true;
139100       if (! mInputFile.exists())
140        {
1410          throw new IOException("Input file " + mInputFile + " does not exist.");
142        }
143        
14450       if (mOutputFile.exists()
145              && mInputFile.lastModified() < mOutputFile.lastModified())
146        {
1470          result = false;
148        }
149        
150100       return result;
151     }
152     
153     /**
154      * Filters all comments out of the input file and writes the filtered
155      * SQL to the output file.
156      * 
157      * @throws FileNotFoundException if the input file could not be opened
158      * @throws ParseException if the input file could not be parsed
159      */
160     public void filterComments () throws FileNotFoundException, ParseException
161     {
162        //System.out.println("SqlCommentFilter: transforming "
163        // + mInputFile + " to " + mOutputFile);
164100       PrintWriter p2w = null;
165100       final FileInputStream in = new FileInputStream(mInputFile);
166        try
167        {
168100           final ScannerInterface scanner = new SqlScanner(in);
169100           scanner.setReportWhitespace(true);
170100           p2w = new PrintWriter(new FileOutputStream(mOutputFile));
171      
172            Token token;
173100           final StringBuffer sbuf = new StringBuffer();
174100(1)          while ((token = scanner.nextToken()).getType() != TokenType.EOF)
175            {
176100              parserHook(token, sbuf);
177      
178100              final TokenType type = token.getType();
179      
180               // System.out.println("Token: " + token);
181100              if (type == TokenType.NEWLINE)
182               {
183100                 final String s = sbuf.toString();
184100(2)                if (! (s.trim().length() == 0))
185                  {
186                     // System.out.println("Writing : '" + s + "'");
187100                    p2w.println(s);
188                  }
189                  else
190                  {
191                     // System.out.println("Skipping: '" + s + "'");
192                  }
193100                 sbuf.setLength(0);
194100              }
195100              else if (type != TokenType.COMMENT)
196               {
197100                 sbuf.append(token.getValue());
198100                 if (type == TokenType.SEMICOLON)
199                  {
200                     // separate statements with an empty line
201100                    sbuf.append('\n');
202                  }
203               }
204100           }
205100           if (! (sbuf.toString().trim().length() == 0))
206            {
2070              p2w.println(sbuf.toString());
208            }
209        }
210        finally
211        {
21250           IoUtil.close(p2w);
21350           IoUtil.close(in);
214100       }
215100    }
216  
217 (3)   private void parserHook (Token token, StringBuffer out)
218     {
219100       final TokenType type = token.getType();
220100       if (type == TokenType.WHITESPACE || type == TokenType.NEWLINE)
221        {
222           // nop
223        }
224100       else if (type == TokenType.CREATE)
225        {
226100          if (mState != INITIAL)
227           {
2280(4)            throw new IllegalStateException("Expected state to be INITIAL");
229           }
230100          mState = IN_CREATE;
231        }
232100       else if (type == TokenType.TABLE
233              || type == TokenType.INDEX)
234        {
235100          if (mState == IN_CREATE)
236           {
237100             mObjectType = type;
238           }
239        }
240100       else if (mState == IN_CREATE && mObjectType != null
241              && mObjectName == null)
242        {
243100          if (type != TokenType.IDENTIFIER)
244           {
2450             throw new IllegalStateException(
246                    "Expected identifier but got " + token);
247           }
248100          mObjectName = token.getValue();
249        }
250100       else if (type == TokenType.SEMICOLON)
251        {
252100          if (mState == IN_CREATE && mObjectType != null && mObjectName != null)
253           {
254              // now we're at the end of a "CREATE TABLE"
255              // or "CREATE INDEX" clause
256100             printMetaInf(out);
257           }
258100          mState = INITIAL;
259100          mObjectType = null;
260100          mObjectName = null;
261        }
262100    }
263  
264     
265     /**
266      * @param out
267    */
268     private void printMetaInf (StringBuffer out)
269     {
270100       if (mMetainfFile != null)
271        {
272           final String metaInf;
273100          final Map metainfMap = getMetainfMap(mObjectType);
274           
275100          if (metainfMap.get(mObjectName.toUpperCase(
276                   Constants.SYSTEM_LOCALE)) == null)
277           {
278100             metaInf = (String) metainfMap.get(DEFAULT_KEY);
279           }
280           else
281           {
2820(5)(6)            metaInf = (String) metainfMap.get(mObjectName.toUpperCase());
283           }
284  
285100          out.append('\n');
286100          out.append(metaInf);
287        }
288100    }
289  
290     private Map getMetainfMap (TokenType t)
291     {
292        final Map result;
293100       if (t == TokenType.INDEX)
294        {
295100          result = mIndexMap;
296        }
297100       else if (t == TokenType.TABLE)
298        {
299100          result = mTableMap;
300        }
301        else
302        {
3030          throw new IllegalArgumentException("Illegal Token Type: " + t);
304        }
305100       return result;
306     }
307     
308     private void parseMetainfFile ()
309     {
310100       SqlMetainf metaInf = null;
311        try
312        {
313100          final JAXBContext ctx
314                 = JAXBContext.newInstance("org.jcoderz.phoenix.sqlparser.jaxb",
315                    this.getClass().getClassLoader());
316100          final Unmarshaller unmarsh = ctx.createUnmarshaller();
317100(7)         unmarsh.setValidating(true);
318100          metaInf = (SqlMetainf) unmarsh.unmarshal(mMetainfFile);
319        }
3200       catch (JAXBException e)
321        {
3220          e.printStackTrace();
3230(8)         System.exit(1);
324100       }
325100       mTableMap.put(DEFAULT_KEY, metaInf.getCreateTable().getDefault());
326100       for (final Iterator it = metaInf.getCreateTable().getTable().iterator();
327100          it.hasNext(); )
328        {
329100          final Table tab = (Table) it.next();
330100          if (mTableMap.containsKey(tab.getName()))
331           {
3320             throw new IllegalArgumentException(
333                    "Table " + tab.getName() + " exists twice in "
334                    + mMetainfFile.getName());
335           }
336100          mTableMap.put(tab.getName().toUpperCase(Constants.SYSTEM_LOCALE),
337                   tab.getValue());
338100       }
339        
340100       mIndexMap.put(DEFAULT_KEY, metaInf.getCreateIndex().getDefault());
341100       for (final Iterator it = metaInf.getCreateIndex().getIndex().iterator();
342100          it.hasNext(); )
343        {
344100          final Index ind = (Index) it.next();
345100          if (mIndexMap.containsKey(ind.getName()))
346           {
3470             throw new IllegalArgumentException(
348                    "Index " + ind.getName() + " exists twice in "
349                    + mMetainfFile.getName());
350           }
351100(9)         mIndexMap.put(ind.getName().toUpperCase(), ind.getValue());
352100       }
353100    }
354  
355     /**
356      * Main method.
357      * @param args command line args
358      */
359     public static void main (String[] args)
360     {
361100       final Options opts = parseCommandLine(args);
362100       checkOptions(opts);
363  
364100       if (opts.mUseFiles)
365        {
366100          final SqlTransformer filter = new SqlTransformer(
367                 opts.mInputFile, opts.mOutputFile, opts.mMetainfFile,
368                 opts.mForce);
369100          filter.execute();
370100       }
371        else
372        {
373100          final List files = checkAndListFiles(opts);
374100          for (final Iterator it = files.iterator(); it.hasNext(); )
375           {
376100             final File inFile = (File) it.next();
377100             final File outFile = new File(opts.mOutDir, inFile.getName());
378100             final SqlTransformer filter = new SqlTransformer(
379                    inFile.getAbsolutePath(), outFile.getAbsolutePath(),
380                    opts.mMetainfFile, opts.mForce);
381100             filter.execute();
382100          }
383        }
384100    }
385     
386     private static List checkAndListFiles (Options opts)
387     {
388100       final File inDir = new File(opts.mInDir);
389100       checkDir(inDir);
390100       final File outDir = new File(opts.mOutDir);
391100       checkDir(outDir);
392        
393100       final List list = new ArrayList();
394100       final FileFilter ff = new FileFilter() {
395           public boolean accept (File pathname)
396           {
397              final boolean result;
398100             if (pathname.getName().endsWith(".sql"))
399              {
400100                result = true;
401              }
402              else
403              {
404100                result = false;
405              }
406100             return result;
407           }
408        };
409100       final File[] inFiles = inDir.listFiles(ff);
410100       list.addAll(Arrays.asList(inFiles));
411100       return list;
412     }
413     
414     private static void checkDir (File dir)
415     {
416100       if (! dir.exists())
417        {
4180          System.err.println("Directory " + dir + " does not exist");
4190(10)         System.exit(1);
420        }
421100    }
422  
423     /**
424      * @param opts
425    */
426     private static void checkOptions (final Options opts)
427     {
428100       if (opts.mUseFiles && opts.mUseDirs)
429        {
4300          System.err.println("Specify either '-i' and '-o' options "
431                 + "or '-d' and '-t' options.");
4320          usage();
433        }
434        
435100       if (opts.mUseFiles)
436        {
437100          if (opts.mInputFile == null || opts.mOutputFile == null)
438           {
4390             usage();
440           }
441        }
442100       else if (opts.mUseDirs)
443        {
444100          if (opts.mInDir == null || opts.mOutDir == null)
445           {
4460             usage();
447           }
448        }
449        else
450        {
4510          usage();
452        }
453100    }
454  
455     private static Options parseCommandLine (String[] args)
456     {
457100       final Options opts = new Options();
458100       int i = 0;
459        try
460        {
461100          for (i = 0; i < args.length; i++)
462           {
463100(11)            if (args[i].equals("-i"))
464              {
465100                opts.mInputFile = args[++i];
466100                opts.mUseFiles = true;
467              }
468100(12)            else if (args[i].equals("-o"))
469              {
470100                opts.mOutputFile = args[++i];
471100                opts.mUseFiles = true;
472              }
473100(13)            else if (args[i].equals("-d"))
474              {
475100                opts.mInDir = args[++i];
476100                opts.mUseDirs = true;
477              }
478100(14)            else if (args[i].equals("-t"))
479              {
480100                opts.mOutDir = args[++i];
481100                opts.mUseDirs = true;
482              }
483100(15)            else if (args[i].equals("-f"))
484              {
485100                opts.mForce = true;
486              }
487100(16)            else if (args[i].equals("-m"))
488              {
489100                opts.mMetainfFile = args[++i];
490              }
491              else
492              {
4930                usage();
494              }
495           }
496        }
4970       catch (ArrayIndexOutOfBoundsException x)
498        {
4990          System.err.println("Error: argument "
500              + args[i - 1] + " requires an option");
5010          usage();
502100       }
503100       return opts;
504     }
505  
506     private static void usage ()
507     {
5080       System.err.println("Usage: SqlCommentFilter");
5090       System.err.println(" -i <input_file> ... input file to transform");
5100       System.err.println(" -o <output_file> ... output file to write to");
5110       System.err.println(" -d <input_dir> ... transform all files from"
512              + " directory");
5130       System.err.println(" -t <to_dir> ... write files to directory");
5140       System.err.println(" -m <metainf_file> ... use sql metainf file");
5150       System.err.println(" -f ... force transformation even"
516              + " if input file is newer");
5170       System.err.println("Note: you can either give '-i' and '-o' or ");
5180       System.err.println(" '-d' and '-t'");
5190(17)      System.exit(1);
5200    }
521     
522100(18)   private static class Options
523     {
524100(19)      private String mInputFile = null;
525100(20)      private String mOutputFile = null;
526100(21)      private boolean mUseFiles = false;
527        
528100(22)      private String mInDir = null;
529100(23)      private String mOutDir = null;
530100(24)      private boolean mUseDirs = false;
531        
532100(25)      private String mMetainfFile = null;
533100(26)      private boolean mForce = false;
534     }
535  }

Findings in this File

f (27) System.out.print is used main class
f (28) System.out.print is used main class
f (29) System.out.print is used main class
f (30) Avoid printStackTrace(); use a logger call instead. main class
f (31) System.out.print is used main class
f (32) System.out.print is used main class
f (33) System.out.print is used main class
f (34) System.out.print is used main class
f (35) System.out.print is used main class
f (36) System.out.print is used main class
f (37) System.out.print is used main class
f (38) System.out.print is used main class
f (39) System.out.print is used main class
f (40) System.out.print is used main class
f (41) System.out.print is used main class
f (42) System.out.print is used main class
c (1) 174 : 25 Inner assignments should be avoided.
i (2) 184 : 24 String.trim().length()==0 is an inefficient way to validate an empty String.
c (3) 217 : 4 Cyclomatic Complexity is 16 (max allowed is 12).
i (4) 228 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parserHook(Token, StringBuffer) throws exception with static message string
i (5) 282 : 0 Use of non-localized String.toUpperCase() or String.toLowerCase
c (6) 282 : 47 When doing a String.toLowerCase()/toUpperCase() call, use a Locale
d (7) 317 : 17 [deprecation] setValidating(boolean) in javax.xml.bind.Unmarshaller has been deprecated
w (8) 323 : 0 org.jcoderz.phoenix.sqlparser.SqlTransformer.parseMetainfFile() invokes System.exit(...), which shuts down the entire virtual machine
i (9) 351 : 0 Use of non-localized String.toUpperCase() or String.toLowerCase
i (10) 419 : 0 org.jcoderz.phoenix.sqlparser.SqlTransformer.checkDir(File) invokes System.exit(...), which shuts down the entire virtual machine
i (11) 463 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (12) 468 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (13) 473 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (14) 478 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (15) 483 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (16) 487 : 0 method org.jcoderz.phoenix.sqlparser.SqlTransformer.parseCommandLine(String[]) makes literal string comparisons passing the literal as an argument
i (17) 519 : 0 org.jcoderz.phoenix.sqlparser.SqlTransformer.usage() invokes System.exit(...), which shuts down the entire virtual machine
c (18) 522 : 4 Utility classes should not have a public or default constructor.
c (19) 524 : 22 Private field 'mInputFile' could be made final; it is only initialized in the declaration or constructor.
c (20) 525 : 22 Private field 'mOutputFile' could be made final; it is only initialized in the declaration or constructor.
c (21) 526 : 23 Private field 'mUseFiles' could be made final; it is only initialized in the declaration or constructor.
c (22) 528 : 22 Private field 'mInDir' could be made final; it is only initialized in the declaration or constructor.
c (23) 529 : 22 Private field 'mOutDir' could be made final; it is only initialized in the declaration or constructor.
c (24) 530 : 23 Private field 'mUseDirs' could be made final; it is only initialized in the declaration or constructor.
c (25) 532 : 22 Private field 'mMetainfFile' could be made final; it is only initialized in the declaration or constructor.
c (26) 533 : 23 Private field 'mForce' could be made final; it is only initialized in the declaration or constructor.