Project Report: fawkez

Packagesummary org.jcoderz.commons.taskdefs

org.jcoderz.commons.taskdefs.ApiDocTask

LineHitsNoteSource
1  /*
2   * $Id: ApiDocTask.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.commons.taskdefs;
34  
35  import java.io.File;
36  import java.io.FileInputStream;
37  import java.io.IOException;
38  import java.util.ArrayList;
39  import java.util.Collections;
40  import java.util.Iterator;
41  import java.util.List;
42  
43  import javax.xml.parsers.SAXParser;
44  import javax.xml.parsers.SAXParserFactory;
45  
46  import org.apache.tools.ant.BuildException;
47  import org.apache.tools.ant.Project;
48  import org.apache.tools.ant.Task;
49  import org.apache.tools.ant.taskdefs.Javadoc;
50  import org.apache.tools.ant.taskdefs.Javadoc.DocletInfo;
51  import org.apache.tools.ant.types.FileSet;
52  import org.apache.tools.ant.types.Path;
53  import org.apache.tools.ant.types.PatternSet.NameEntry;
54  import org.jcoderz.commons.util.IoUtil;
55  import org.xml.sax.Attributes;
56  import org.xml.sax.InputSource;
57  import org.xml.sax.helpers.DefaultHandler;
58  
59  
60  /**
61   * Generates API documentation (DocBook format).
62   *
63   * @author Michael Griffel
64   */
650 public class ApiDocTask
66          extends Task
67  {
68      /** Task name. */
69      public static final String NAME = "apidoc";
70  
71      /** File name extension of Java files. */
72      private static final String JAVA_EXTENSION = ".java";
73  
74      /** The output directory. */
75      private File mOutDir;
76  
77      /** The input file. */
78      private File mInFile;
79  
80      /** terminate ant build on error. */
81      private boolean mFailOnError;
82  
83      /** Doclet path. */
84      private Path mDocletPath;
85  
86      /** Source path - list of SourceDirectory. */
870     private final List mSources = new ArrayList();
88  
89      /**
90       * Sets the XML input file that contains the document.
91       *
92       * @param f the XML input file (log message info).
93       */
94      public void setIn (File f)
95      {
960         mInFile = f;
970     }
98  
99      /**
100       * Set the destination directory into which the result files should
101       * be copied to. This parameter is required.
102       *
103       * @param dir the name of the destination directory.
104       */
105      public void setOut (File dir)
106      {
1070         mOutDir = dir;
1080     }
109  
110      /**
111       * Set whether we should fail on an error.
112       *
113       * @param b Whether we should fail on an error.
114       */
115      public void setFailonerror (boolean b)
116      {
1170         mFailOnError = b;
1180     }
119  
120      /**
121       * Set the source path to be used for this task run.
122       *
123       * @param src an Ant FileSet object containing the compilation
124       *        source path.
125       */
126      public void addSrc (SourceDirectory src)
127      {
1280         mSources.add(src);
1290     }
130  
131      /**
132       * Set the doclet path to be used for this task run.
133       *
134       * @param path an Ant Path object containing the compilation source
135       *        path.
136       */
137      public void setDocletPath (Path path)
138      {
1390         if (mDocletPath == null)
140          {
1410             mDocletPath = path;
142          }
143          else
144          {
1450             mDocletPath.add(path);
146          }
1470     }
148  
149      /**
150       * Execute this task.
151       *
152       * @throws BuildException An building exception occurred.
153       */
154      public void execute ()
155              throws BuildException
156      {
157          try
158          {
1590             checkAttributes();
1600             final ApiDocSaxHandler handler = parse();
1610             log("APIs: " + handler.apiDocs().toString(), Project.MSG_DEBUG);
1620             final Iterator iterator = handler.apiDocs().iterator();
1630             while (iterator.hasNext())
164              {
1650                 final ApiDocType apiDoc = (ApiDocType) iterator.next();
1660                 final File xmlFile = runXmlDoclet(apiDoc);
1670                 log("Generated xmlFile " + xmlFile);
1680             }
169          }
1700         catch (BuildException e)
171          {
1720             if (mFailOnError)
173              {
1740                 throw e;
175              }
1760             log(e.getMessage(), Project.MSG_ERR);
1770         }
1780     }
179  
180      private File runXmlDoclet (final ApiDocType apiDoc)
181      {
1820         final Javadoc javadocTask = new Javadoc();
1830         javadocTask.setProject(getProject());
1840         javadocTask.setFailonerror(mFailOnError);
1850         javadocTask.setTaskName("xml-doclet");
1860         javadocTask.setPackage(true);
1870         javadocTask.setClasspath(mDocletPath);
1880         javadocTask.setClasspath(Path.systemClasspath);
1890         javadocTask.setDestdir(mOutDir);
1900         javadocTask.setAdditionalparam("-quiet");
1910         for (final Iterator i = mSources.iterator(); i.hasNext();)
192          {
1930             final SourceDirectory fs = (SourceDirectory) i.next();
1940             javadocTask.addFileset(addClasses(apiDoc, fs.getDir()));
1950         }
1960         final DocletInfo info = javadocTask.createDoclet();
1970         info.setProject(getProject());
1980         info.setName("org.jcoderz.commons.doclet.XmlDoclet");
1990         info.setPath(mDocletPath);
2000         final File tmpFile = new File(mOutDir, "/javadoc.xml");
2010         javadocTask.execute();
2020         final File outFile = new File(mOutDir, apiDoc.getName() + ".xml");
2030         if (!tmpFile.renameTo(outFile))
204          {
205              try
206              {
207                  // copy && delete
2080                 IoUtil.copy(tmpFile, outFile);
2090                 if (!tmpFile.delete())
210                  {
2110                     throw new BuildException("Cannot delete file " + tmpFile);
212                  }
213              }
2140             catch (IOException e)
215              {
2160                 throw new BuildException("Cannot move file " + tmpFile
217                          + " to " + outFile);
2180             }
219          }
220          try
221          {
2220             IoUtil.copy(outFile, new File(outFile.getParent(), outFile
223                      .getName()
224                      + ".in"));
225          }
2260         catch (IOException e)
227          {
2280             throw new BuildException("Failed to copy file: " + outFile, e);
2290         }
2300         return outFile;
231      }
232  
233      private FileSet addClasses (final ApiDocType diagram, File path)
234      {
2350         final FileSet filez = new FileSet();
2360         filez.setDir(path);
2370         filez.setProject(getProject());
2380         final Iterator i = diagram.classList().iterator();
2390         while (i.hasNext())
240          {
2410             final String name = (String) i.next();
2420             final NameEntry entry = filez.createInclude();
2430             final String pathName = name.replaceAll("\\.", "/")
244                      + JAVA_EXTENSION;
2450             log("Adding Source file " + pathName, Project.MSG_VERBOSE);
2460             entry.setName(pathName);
2470         }
2480         log("Source files: " + filez, Project.MSG_VERBOSE);
2490         return filez;
250      }
251  
252      private ApiDocSaxHandler parse ()
253      {
2540(1)        final ApiDocSaxHandler handler = new ApiDocSaxHandler();
255          try
256          {
257              // create a new XML parser
2580             final SAXParserFactory factory = SAXParserFactory.newInstance();
2590             factory.setNamespaceAware(true);
2600             factory.setValidating(true);
2610             final SAXParser parser = factory.newSAXParser();
262              /*
263               * parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
264               * parser.setProperty(JAXP_SCHEMA_SOURCE,
265               * AppInfoTask.class.getResource(APP_INFO_SCHEMA).toExternalForm());
266               */
2670             parser
268                      .parse(new InputSource(new FileInputStream(mInFile)),
269                              handler);
2700             log(mInFile + " parsed successfully.", Project.MSG_INFO);
271          }
2720         catch (Exception e)
273          {
2740             throw new BuildException(
275                      "Failed to parse " + mInFile + ": " + e, e);
2760         }
2770         return handler;
278      }
279  
280      /**
281       * Checks the attributes provided by this class.
282       *
283       * @throws BuildException
284    */
285      private void checkAttributes ()
286              throws BuildException
287      {
2880         checkAttributeInFile();
2890     }
290  
291      private void checkAttributeInFile ()
292      {
2930         if (mInFile == null)
294          {
2950             throw new BuildException("Missing mandatory attribute 'in'.",
296                      getLocation());
297          }
2980         if (!mInFile.exists())
299          {
3000             throw new BuildException("Input file '" + mInFile + "' not found.",
301                      getLocation());
302          }
3030     }
304  
3050     private static class ApiDocSaxHandler
306              extends DefaultHandler
307      {
3080         private final StringBuffer mBuffer = new StringBuffer();
309  
3100         private boolean mCaptureCharacters = false;
311  
3120         private final List mApiDocElementList = new ArrayList();
313  
3140         private ApiDocType mCurrentApiDocElement = null;
315  
316          /** {@inheritDoc} */
317          public void startElement (String uri, String localName, String qName,
318                  Attributes attributes)
319          {
3200             if ("apidoc".equals(localName))
321              {
3220                 mCurrentApiDocElement = new ApiDocType(attributes
323                          .getValue("name"));
3240                 mApiDocElementList.add(mCurrentApiDocElement);
325              }
3260             else if ("class".equals(localName) && mCurrentApiDocElement != null)
327              {
3280                 mCurrentApiDocElement.add(attributes.getValue("name"));
329              }
3300             else if ("description".equals(localName)
331                      && mCurrentApiDocElement != null)
332              {
3330                 captureCharacters();
334              }
3350         }
336  
337          /** {@inheritDoc} */
338          public void endElement (String uri, String localName, String qName)
339          {
3400             if ("apidoc".equals(localName))
341              {
3420                 mCurrentApiDocElement = null;
343              }
3440             else if ("description".equals(localName)
345                      && mCurrentApiDocElement != null)
346              {
3470                 mCurrentApiDocElement.setDescription(characters().trim());
348              }
3490         }
350  
351          /** {@inheritDoc} */
352          public void characters (char[] ch, int start, int length)
353          {
3540             if (mCaptureCharacters)
355              {
3560                 mBuffer.append(ch, start, length);
357              }
3580         }
359  
360          void captureCharacters ()
361          {
3620             mCaptureCharacters = true;
3630         }
364  
365          /**
366           * Returns the captured characters and <b>clears</b> the
367           * internal buffer.
368           *
369           * @return the captured characters.
370           */
371          String characters ()
372          {
3730             final String result = mBuffer.toString();
3740             mBuffer.setLength(0);
3750             mCaptureCharacters = false;
3760             return result;
377          }
378  
379          /**
380           * Returns a list of {@link ApiDocType}.
381           *
382           * @return a list of {@link ApiDocType}.
383           */
384          public List apiDocs ()
385          {
3860             return Collections.unmodifiableList(mApiDocElementList);
387          }
388      }
389  
3900     private static class ApiDocType
391      {
392          private final String mName;
393  
3940         private final List mClasses = new ArrayList();
395  
3960         private String mDescription = "";
397  
398          ApiDocType (String name)
3990         {
4000             mName = name;
4010         }
402  
403          void add (String clazz)
404          {
4050             mClasses.add(clazz);
4060         }
407  
408          List classList ()
409          {
4100             return Collections.unmodifiableList(mClasses);
411          }
412  
413          String getName ()
414          {
4150             return mName;
416          }
417  
418          /** {@inheritDoc} */
419          public String toString ()
420          {
4210(2)            final StringBuffer sb = new StringBuffer();
4220             sb.append("clazzes ");
4230             sb.append(mName);
4240             sb.append(" = ");
4250             sb.append(mClasses);
4260             sb.append(" description: '");
4270             sb.append(mDescription);
4280             sb.append('\'');
4290             return sb.toString();
430          }
431  
432          String getDescription ()
433          {
4340             return mDescription;
435          }
436  
437          void setDescription (String description)
438          {
4390             mDescription = description;
4400         }
441      }
442  }

Findings in this File

c (3) Got an exception - java.lang.RuntimeException: Unable to get class information for @throws tag 'BuildException'.
c (1) 254 : 0 Copied and pasted code. 150 equal tokens (49 lines) found in 2 locations. See also: org.jcoderz.commons.taskdefs.DiagramTask:373
i (2) 421 : 32 StringBuffer constructor is initialized with size 16, but has at least 28 characters appended.