Project Report: fawkez

Packagesummary org.jcoderz.commons.taskdefs

org.jcoderz.commons.taskdefs.XsltBasedTask

LineHitsNoteSource
1  /*
2   * $Id: XsltBasedTask.java 1633 2010-05-26 18:16:57Z 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.commons.taskdefs;
34  
35  
36  import java.io.File;
37  import java.io.FileInputStream;
38  import java.io.FileNotFoundException;
39  import java.io.IOException;
40  import java.io.InputStream;
41  import java.net.URISyntaxException;
42  import java.net.URL;
43  import java.util.Properties;
44  
45  import javax.xml.transform.ErrorListener;
46  import javax.xml.transform.Source;
47  import javax.xml.transform.Transformer;
48  import javax.xml.transform.TransformerException;
49  import javax.xml.transform.TransformerFactory;
50  import javax.xml.transform.sax.SAXSource;
51  import javax.xml.transform.stream.StreamResult;
52  import javax.xml.transform.stream.StreamSource;
53  
54  import org.apache.tools.ant.AntClassLoader;
55  import org.apache.tools.ant.BuildException;
56  import org.apache.tools.ant.Project;
57  import org.apache.tools.ant.Task;
58  import org.apache.xerces.util.XMLCatalogResolver;
59  import org.jcoderz.commons.util.IoUtil;
60  import org.jcoderz.commons.util.StringUtil;
61  import org.jcoderz.commons.util.XmlUtil;
62  import org.xml.sax.EntityResolver;
63  import org.xml.sax.InputSource;
64  import org.xml.sax.SAXException;
65  
66  
67  /**
68   * This class implements common functionality for XSLT based Ant tasks.
69   *
70   * @author Michael Griffel
71   */
72100 public abstract class XsltBasedTask
73      extends Task
74  {
75      /** System property for the XML Parser Configuration (Xalan2). */
76      private static final String XML_PARSER_CONFIGURATION_PROPERTY =
77          "org.apache.xerces.xni.parser.XMLParserConfiguration";
78  
79      /** Xalan2 XML Parser Configuration w/ XInclude support. */
80      private static final String XML_PARSER_CONFIG_WITH_XINCLUDE =
81          "org.apache.xerces.parsers.XIncludeParserConfiguration";
82  
83      /** The fawkeZ VERSION file. */
84      private static final String FAWKEZ_VERSION_FILE =
85          "/org/jcoderz/commons/VERSION";
86  
87      /** The destination directory. */
88100     private File mDestDir = null;
89  
90      /** The XSL stylesheet file. */
91100     private String mXslFile = null;
92  
93      /** The Input XML document (log message info file) to be used. */
94100     private File mInFile = null;
95  
96      /** The Output file. */
97100     private File mOutFile = null;
98  
99      /** force output of target files even if they already exist. */
100100     private boolean mForce = false;
101  
102      /** terminate ant build on error. */
103100     private boolean mFailOnError = false;
104  
105      /** Log level. */
106100     private int mLogLevel = Project.MSG_INFO;
107  
108100     private boolean mResolveExternalEntities = true;
109  
110      /**
111       * AntClassLoader for the nested <classpath> - if set.
112       * <p>
113       * We keep this here in order to reset the context classloader in
114       * execute. We can't use liaison.getClass().getClassLoader() since
115       * the actual liaison class may have been loaded by a loader higher
116       * up (system classloader, for example).
117       * </p>
118       *
119       * @since Ant 1.6.2
120       */
121100     private AntClassLoader mClassLoader = null;
122  
123      /**
124       * Set the destination directory into which the XSL result files
125       * should be copied to. This parameter is required.
126       *
127       * @param dir the name of the destination directory.
128       */
129      public void setDestdir (File dir)
130      {
131100         mDestDir = dir;
132100     }
133  
134      /**
135       * Sets the XSL file that is used to generate the log message info
136       * classes.
137       *
138       * @param s the XSL file to use.
139       */
140      public void setXsl (String s)
141      {
142100         mXslFile = s;
143100     }
144  
145      /**
146       * Sets the XML input file that contains the log message info
147       * document.
148       *
149       * @param f the XML input file (log message info).
150       */
151      public void setIn (File f)
152      {
153100         mInFile = f;
154100     }
155  
156      /**
157       * Sets the output file.
158       *
159       * @param f The output file.
160       */
161      public void setOut (File f)
162      {
163100         mOutFile = f;
164100     }
165  
166      /**
167       * Sets the force output of target files flag to the given value.
168       *
169       * @param b Whether we should force the generation of output files.
170       */
171      public void setForce (boolean b)
172      {
173100         mForce = b;
174100     }
175  
176      /**
177       * Set whether we should fail on an error.
178       *
179       * @param b Whether we should fail on an error.
180       */
181      public void setFailonerror (boolean b)
182      {
183100         mFailOnError = b;
184100     }
185  
186      /**
187       * Sets the log level.
188       *
189       * @param level the new log level
190       */
191      public void setLogLevel (int level)
192      {
1930         mLogLevel = level;
1940     }
195  
196      /**
197       * Execute this task.
198       *
199       * @throws BuildException An building exception occurred.
200       */
201      public void execute ()
202          throws BuildException
203      {
204          try
205          {
206100             checkAttributes();
20750             if (mForce || mInFile.lastModified() > mOutFile.lastModified())
208              {
209100                 if (mDestDir != null)
210                  {
211100                     log("Generating files to directory " + mDestDir,
212                          Project.MSG_VERBOSE);
213                  }
214100                 log("Processing " + mInFile + " to " + mOutFile
215                      + " using stylesheet " + mXslFile, mLogLevel);
216100                 transform();
217100                 postExecute();
218              }
219          }
220100         catch (BuildException e)
221          {
222100             if (mFailOnError)
223              {
224100                 throw e;
225              }
2260             log(e.getMessage(), Project.MSG_ERR);
227100         }
228100     }
229  
230      /**
231       * @return the fawkez version used for build.
232       */
233      public String getFawkezVersionAsString ()
234      {
2350(1)        final StringBuffer version = new StringBuffer();
236          try
237          {
2380             final Properties fawkezProps = getFawkezVersionProperties();
2390             version.append("fawkeZ ");
2400             version.append(fawkezProps.getProperty("version"));
2410             version.append(", [");
2420             version.append(fawkezProps.getProperty("cvs_name"));
2430(2)            version.append(']');
244          }
2450         catch (Exception x)
246          {
247              // sorry, we cannot read fawkeZ VERSION file
2480             version.append("unknown");
2490         }
2500         return version.toString();
251      }
252  
253      /**
254       * If set to <tt>false</tt>, external entities will not be
255       * resolved.
256       *
257       * @param b new value.
258       */
259      public void resolveExternalEntities (boolean b)
260      {
2610         mResolveExternalEntities = b;
2620     }
263  
264      static void checkXercesVersion (Task task)
265      {
266100         final String xercesVersion = org.apache.xerces.impl.Version
267              .getVersion();
268100(3)        if (StringUtil.contains(xercesVersion, ("2.6.2")))
269          {
2700             task.log("Found " + xercesVersion + " on classpath.",
271                  Project.MSG_WARN);
2720             task.log("This Version only supports the outdated 2003 "
273                  + "namespace for XInclude ", Project.MSG_WARN);
2740             task.log("please put a newer version of xerces on your classpath"
275                  + "or use", Project.MSG_WARN);
2760             task.log("at least ANT 1.7.0.", Project.MSG_WARN);
277          }
278100     }
279  
280      /**
281       * Returns the build-in default stylesheet file name that should be
282       * used by XSL transformer.
283       * <p>
284       * The stylesheet must be stored in the
285       * <tt>/org/jcoderz/commons/taskdefs</tt> directory.
286       *
287       * @return the default stylesheet file name.
288       */
289      abstract String getDefaultStyleSheet ();
290  
291      /**
292       * This method can be overwritten by subclasses to set additional
293       * transformer parameters.
294       *
295       * @param transformer the XSL transformer.
296       */
297      void setAdditionalTransformerParameters (Transformer transformer)
298      {
299          // NOP
300100(4)    }
301  
302      File getInFile ()
303      {
3040         return mInFile;
305      }
306  
307      File getOutFile ()
308      {
3090         return mOutFile;
310      }
311  
312      File getDestDir ()
313      {
3140         return mDestDir;
315      }
316  
317      boolean getFailOnError ()
318      {
3190         return mFailOnError;
320      }
321  
322      /**
323       * Checks the attributes provided by this class.
324       *
325       * @throws BuildException
326    */
327      void checkAttributes ()
328          throws BuildException
329      {
330100         checkAttributeInFile();
331100         checkAttributeOutFile();
332100         checkAttributeDestDir();
333100         checkAttributeXslFile();
334100         checkXercesVersion(this);
335100     }
336  
337      void checkAttributeXslFile ()
338      {
339100         if (mXslFile == null || !new File(mXslFile).exists())
340          {
341100             mXslFile = getDefaultStyleSheet();
342          }
343100     }
344  
345      void checkAttributeDestDir ()
346      {
347100         if (mDestDir == null)
348          {
349100             throw new BuildException("Missing mandatory attribute 'outdir'.",
350                  getLocation());
351          }
352100         AntTaskUtil.ensureDirectory(mDestDir);
353100     }
354  
355      void checkAttributeOutFile ()
356      {
357100         if (mOutFile == null)
358          {
359100             throw new BuildException("Missing mandatory attribute 'out'.",
360                  getLocation());
361          }
362100         AntTaskUtil.ensureDirectoryForFile(mOutFile);
363100     }
364  
365      void checkAttributeInFile ()
366      {
367100         if (mInFile == null)
368          {
369100             throw new BuildException("Missing mandatory attribute 'in'.",
370                  getLocation());
371          }
372100         if (!mInFile.exists())
373          {
374100             throw new BuildException("Input file '" + mInFile + "' not found.",
375                  getLocation());
376          }
377100     }
378  
379      /**
380       * This method is the last callback in the execute method. Can be
381       * overwritten by subclasses.
382       */
383      void postExecute ()
384      {
385          // NOP
386100(5)    }
387  
388      /**
389       * Execute the XSL transformation.
390       *
391       * @throws BuildException if an error during transformation occurs.
392       */
393      void transform ()
394          throws BuildException
395      {
396100         StreamResult out = null;
397          try
398          {
399100             final String xmlParserConfig
400                  = System.getProperty(XML_PARSER_CONFIGURATION_PROPERTY);
401100             if (!XML_PARSER_CONFIG_WITH_XINCLUDE.equals(xmlParserConfig))
402              {
403100                 System.setProperty(
404                      XML_PARSER_CONFIGURATION_PROPERTY,
405                      XML_PARSER_CONFIG_WITH_XINCLUDE);
406100                 log("Using XML Parser configuration "
407                      + XML_PARSER_CONFIG_WITH_XINCLUDE, Project.MSG_VERBOSE);
408              }
409              // Xalan2 transformer is required,
410              // that why we explicit use this factory
411100             final TransformerFactory factory
412                  = (TransformerFactory)
413                      (loadClass(
414                          "org.apache.xalan.processor.TransformerFactoryImpl")
415                              .newInstance());
416  
417100             factory.setURIResolver(new JarArchiveUriResolver(this));
418100             final StreamSource source = getXslFileAsSource();
419100             final Transformer transformer
420                  = factory.newTransformer(source);
421100             setAdditionalTransformerParameters(transformer);
42275             transformer.setParameter("outdir", mDestDir != null ? mDestDir
423                  .getAbsolutePath() : "");
424100             final Source xml = getInAsStreamSource();
425100             out = XmlUtil.createStreamResult(mOutFile);
426100             transformer.setErrorListener(new MyErrorListener());
427100             transformer.transform(xml, out);
428          }
429100         catch (Exception e)
430          {
431100             throw new BuildException("Error during transformation: " + e, e);
432          }
433          finally
434          {
435100             if (out != null)
436              {
437100                 IoUtil.close(out.getOutputStream());
438              }
439100             if (mClassLoader != null)
440              {
4410                 mClassLoader.resetThreadContextLoader();
4420                 mClassLoader.cleanup();
44333                 mClassLoader = null;
444              }
445          }
446100     }
447  
448      private Class loadClass (String classname)
449          throws ClassNotFoundException
450      {
451          final Class result;
452100         if (getClass().getClassLoader() instanceof AntClassLoader)
453          {
4540             mClassLoader = (AntClassLoader) getClass().getClassLoader();
4550             mClassLoader.setThreadContextLoader();
4560             result = Class.forName(classname, true, mClassLoader);
4570             log("Loading '" + classname + "' via " + mClassLoader,
458                  Project.MSG_VERBOSE);
459          }
460          else // if (mClassPath == null)
461          {
462100             result = Class.forName(classname);
463100             log("No ant-classloader found to load '" + classname + "',"
464                  + "using 'normal' Class.forName(classname).",
465                  Project.MSG_VERBOSE);
466          }
467100         return result;
468      }
469  
470      private StreamSource getXslFileAsSource ()
471      {
472          final StreamSource result;
473100         final InputStream xslStream
474              = XsltBasedTask.class.getResourceAsStream(mXslFile);
475100         if (xslStream == null)
476          {
477              try
478              {
4790                 final File file = new File(mXslFile);
4800                 final InputStream xslFile = new FileInputStream(file);
4810                 result = new StreamSource(xslFile);
4820                 result.setSystemId(file.toURI().toASCIIString());
483              }
4840             catch (FileNotFoundException e)
485              {
4860                 throw new BuildException("Cannot locate stylesheet "
487                      + mXslFile, e);
4880             }
489          }
490          else
491          {
492100             result = new StreamSource(xslStream);
49375             final URL url = XsltBasedTask.class.getResource(mXslFile);
494100             if (url != null)
495              {
496                  try
497                  {
498100                     result.setSystemId(url.toURI().toASCIIString());
499                  }
5000                 catch (URISyntaxException ex)
501                  {
5020                     log("Failed to set systemId. Got " + ex,
503                              Project.MSG_VERBOSE);
504100                 }
505              }
506          }
507100         return result;
508      }
509      
510      /**
511       * Instantiates xml resolver for xerces xml parser.
512       * 
513       * If xml-resolver.jar is available on the boot classpath of ant, the 
514       * implementation of an xml catalog resolver will be returned otherwise
515       * the dummy resolver implementation will be provided 
516       * 
517       * @return EntityResolver entity resolver
518       */
519      private EntityResolver getEntityResolver()
520      {
5210         EntityResolver resolver = new DummyEntityResolver(this);
522          try
523          {
5240(6)            String [] catalogs = {"src/xml/catalog.xml"};
5250             System.getProperties().put("xml.catalog.verbosity", "1000");
526              
5270             log("Instantiating xml catalog resolver .", Project.MSG_INFO);
528              // Create catalog resolver and set a catalog list.
5290             XMLCatalogResolver xmlResolver = new XMLCatalogResolver();
530              
5310             xmlResolver.setPreferPublic(false);
5320             xmlResolver.setCatalogList(catalogs);
5330             resolver = xmlResolver;
534          }
5350         catch (NoClassDefFoundError e)
536          {
537 (7)            // The most secure way to check for non-existence of the CatalogReader
538 (8)            // class is within ant class loaders is to catch the NoClassDefFoundError.
5390             log("Class CatalogReader (xml-resolver.jar) could not be found " +
540 (9)                            " within bootstrap classpath. No entity resolver is " +
541 (10)                            " available, setting dummy resolver.", Project.MSG_WARN);
5420         }
543          
5440         return resolver;
545      }
546  
547      /**
548       * @return a resource stream from in file.
549       * @throws FileNotFoundException
550    */
551      Source getInAsStreamSource ()
552      {
553          final Source result;
554100         if (!mResolveExternalEntities)
555          {
556              final org.xml.sax.XMLReader reader;
557              try
558              {
5590                 EntityResolver resolver = getEntityResolver();
560                  
561                  // reader = XMLReaderFactory.createXMLReader(
562                  // "org.apache.xerces.parsers.SAXParser");
5630                 reader = org.xml.sax.helpers.XMLReaderFactory.createXMLReader();
5640                 reader.setEntityResolver(resolver);
5650                 result = new SAXSource(reader, new InputSource(
566                      new FileInputStream(mInFile)));
567              }
5680             catch (SAXException e)
569              {
5700                 throw new BuildException("Cannot create SAX XML Reader: " + e,
571                      e);
572              }
5730             catch (FileNotFoundException e)
574              {
5750                 throw new BuildException("Ups, cannot open file: " + e, e);
5760             }
5770         }
578          else
579          {
580100             result = new StreamSource(mInFile);
581          }
582100         return result;
583      }
584  
585      /**
586       * Returns the VERSION file properties.
587       *
588       * @return the VERSION file properties.
589       * @throws IOException if the VERSION file cannot be found or read.
590       */
591      private Properties getFawkezVersionProperties ()
592          throws IOException
593      {
5940         final Properties props = new Properties();
5950         final InputStream in
596              = XsltBasedTask.class.getResourceAsStream(FAWKEZ_VERSION_FILE);
597          try
598          {
5990             props.load(in);
600          }
601          finally
602          {
6030             IoUtil.close(in);
6040         }
6050         return props;
606      }
607  
608100     private static class MyErrorListener
609          implements ErrorListener
610      {
611          /** {@inheritDoc} */
612          public void warning (TransformerException arg0)
613              throws TransformerException
614          {
615100             throw arg0;
616          }
617  
618          /** {@inheritDoc} */
619          public void error (TransformerException arg0)
620              throws TransformerException
621          {
6220             throw arg0;
623          }
624  
625          /** {@inheritDoc} */
626          public void fatalError (TransformerException arg0)
627              throws TransformerException
628          {
629100             throw arg0;
630          }
631      }
632  }

Findings in this File

c (11) Got an exception - java.lang.RuntimeException: Unable to get class information for @throws tag 'BuildException'.
i (1) 235 : 28 StringBuffer constructor is initialized with size 16, but has at least 18 characters appended.
i (2) 243 : 27 StringBuffer.append is called 2 consecutive times with literal Strings. Use a single append with a single String.
c (3) 268 : 49 This statement may have some unnecessary parentheses
w (4) 300 : 0 empty method org.jcoderz.commons.taskdefs.XsltBasedTask.setAdditionalTransformerParameters(Transformer) could be declared abstract
w (5) 386 : 0 empty method org.jcoderz.commons.taskdefs.XsltBasedTask.postExecute() could be declared abstract
i (6) 524 : 0 Method org.jcoderz.commons.taskdefs.XsltBasedTask.getEntityResolver() creates array using constants
c (7) 537 : 0 Line is longer than 80 characters.
c (8) 538 : 0 Line is longer than 80 characters.
c (9) 540 : 13 Line contains a tab character.
c (10) 541 : 13 Line contains a tab character.