View Javadoc

1   
2   package net.sf.dtddoc.maven2;
3   
4   import java.io.File;
5   import java.io.IOException;
6   import java.util.ArrayList;
7   import java.util.Collections;
8   import java.util.HashSet;
9   import java.util.Iterator;
10  import java.util.List;
11  import java.util.Locale;
12  import java.util.Set;
13  
14  import DTDDoc.DTDCommenter;
15  
16  import org.apache.maven.doxia.sink.Sink;
17  import org.apache.maven.doxia.siterenderer.Renderer;
18  import org.apache.maven.project.MavenProject;
19  import org.apache.maven.reporting.AbstractMavenReport;
20  import org.apache.maven.reporting.MavenReportException;
21  import org.codehaus.plexus.util.FileUtils;
22  import org.codehaus.plexus.util.StringUtils;
23  
24  /**
25   * DTDDoc Maven2 plugin.
26   * @goal dtddoc
27   * @description Generates DTDDoc report
28   * @version $Id: DTDDocReport.java,v 1.12 2006/10/28 08:30:45 hboutemy Exp $
29   */
30  public class DTDDocReport extends AbstractMavenReport {
31    /**
32     * Specifies the destination directory where DTDDoc saves the generated HTML files.
33     *
34     * @parameter expression="${project.build.directory}/dtddoc/"
35     */
36    private File outputDirectory;
37  
38    /**
39     * Specifies the source directory where DTDDoc searches for DTDs.
40     *
41     * @parameter expression="src/main/resources"
42     */
43    private File sourceDirectory;
44  
45    /**
46     * List of patterns used to specify the files that should be included in DTD documentation.
47     * When not specified, the default includes will be <code>**&#47;*.dtd</code>.
48     *
49     * @parameter
50     */
51    private String[] includes;
52  
53   /**
54    * List of patterns used to specify the files that should be excluded in DTD documentation.
55     * When not specified, the default excludes will be empty.
56     *
57     * @parameter
58     */
59    private String[] excludes;
60  
61    /**
62     * Tells if the content of the <code>@hidden</code> tags must be part of the documentation
63     * @parameter expression="${dtddoc.hidden}" default-value="false"
64     */
65    private boolean showHiddenTags = false;
66  
67    /**
68     * Tells if the content of the <code>@fixme</code> tags must be part of the documentation
69     * @parameter expression="${dtddoc.fixme}" default-value="true"
70     */
71    private boolean showFixmeTags = true;
72  
73    /**
74     * In case you have comments that start with three hyphens, this option will tell DTDDoc
75     * to interpret them as regular double hyphens. This was introduced to support NetBeans comments.
76     * @parameter expression="${dtddoc.getAroundNetBeansComments}" default-value="true"
77     */
78    private boolean getAroundNetBeansComments = true;
79  
80    /**
81     * Name of the documentation: it will appear at the top of the index.
82     * @parameter expression="${dtddoc.title}" default-value=""
83     */
84    private String docTitle = "";
85  
86    /**
87     * The stylesheet to use to render the documentation. This stylesheet will be copied into the documentation.
88     * If not specified, DTDDoc's default stylesheet is used.
89     * @parameter expression="${dtddoc.styleSheet}"
90     */
91    private File styleSheet = null;
92  
93    /**
94     * Doxia Site Renderer.
95     *
96     * @component
97     */
98    protected Renderer siteRenderer;
99  
100   /**
101    * Maven project
102    * @parameter expression="${project}"
103    * @required
104    * @readonly
105    */
106   private MavenProject project;
107 
108   public String getName(Locale locale) {
109     return "DTDDoc";
110   }
111 
112   public String getDescription(Locale locale) {
113     return "DTD documentation";
114   }
115 
116   /**
117    * @see org.apache.maven.reporting.MavenReport#getOutputName()
118    */
119   public String getOutputName() {
120     return "dtddoc/index";
121   }
122 
123   /**
124    * @see org.apache.maven.reporting.AbstractMavenReport#getOutputDirectory()
125    */
126   protected String getOutputDirectory() {
127     return outputDirectory.getAbsoluteFile().toString();
128   }
129 
130   /**
131    * @see org.apache.maven.reporting.AbstractMavenReport#getProject()
132    */
133   protected MavenProject getProject() {
134     return project;
135   }
136 
137   /**
138    * @see org.apache.maven.reporting.AbstractMavenReport#getSiteRenderer()
139    */
140   protected Renderer getSiteRenderer() {
141     return siteRenderer;
142   }
143 
144   /**
145    * @see org.apache.maven.reporting.MavenReport#generate(org.codehaus.doxia.sink.Sink, java.util.Locale)
146    */
147   public void generate(Sink sink, Locale locale) throws MavenReportException {
148     executeReport(locale);
149   }
150 
151   private List getDtdFiles() {
152     if (! (sourceDirectory.exists() && sourceDirectory.isDirectory())) {
153       return new ArrayList();
154     }
155 
156     String includesAsString = "**/*.dtd";
157     if (includes != null) {
158       includesAsString = StringUtils.join(includes, "," );
159     }
160 
161     String excludesAsString = "";
162     if (excludes != null) {
163       excludesAsString = StringUtils.join(excludes, "," );
164     }
165 
166     try {
167       return FileUtils.getFiles(sourceDirectory, includesAsString, excludesAsString, true);
168     } catch (IOException ioe) {
169       getLog().warn("unable to determine which DTDs to process", ioe);
170     }
171     return new ArrayList();
172   }
173 
174   protected void executeReport(Locale locale) throws MavenReportException {
175     Set dtds = new HashSet(getDtdFiles());
176 
177     File dtddocDirectory = getReportOutputDirectory();
178     if (!dtddocDirectory.getAbsolutePath().equals(getOutputDirectory())) {
179       // we're in site-embedded report mode, so Doxia has set the
180       // reportOutputDirectory to the basedir of the site : append 'dtddoc'.
181       dtddocDirectory = new File(dtddocDirectory, "dtddoc");
182     }
183     dtddocDirectory.mkdirs();
184 
185     try {
186       getLog().info("documenting " + dtds.size() + " DTD(s), show @hidden tags: " + showHiddenTags + ", show @fixme tags: " + showFixmeTags);
187       File commonBase = getCommonBase(sourceDirectory, dtds);
188       if (! sourceDirectory.equals(commonBase)) {
189         getLog().info("sourceDirectory optimized as " + commonBase.getPath());
190       }
191       DTDCommenter commenter = new DTDCommenter(new MavenLogger(getLog()));
192       commenter
193           .commentDTDs(dtds, commonBase, dtddocDirectory, showHiddenTags, showFixmeTags, getAroundNetBeansComments, docTitle, styleSheet);
194     } catch (IOException ioe) {
195       throw new MavenReportException("error while generating DTDDoc reports : " + ioe.getMessage(), ioe);
196     } catch (Exception e) {
197       throw new MavenReportException("error while generating DTDDoc reports : " + e.getMessage(), e);
198     }
199   }
200 
201   public boolean isExternalReport() {
202     return true;
203   }
204 
205   /**
206    * @see org.apache.maven.reporting.MavenReport#canGenerateReport()
207    */
208   public boolean canGenerateReport() {
209     return getDtdFiles().size() > 0;
210   }
211 
212   protected static File[] getFileHierarchy(File from, File to) {
213     List hierarchy = new ArrayList();
214     hierarchy.add(to);
215     while (! to.equals(from)) {
216       to = to.getParentFile();
217       hierarchy.add(to);
218     }
219     Collections.reverse(hierarchy);
220     File[] files = new File[hierarchy.size()];
221     return (File[])hierarchy.toArray(files);
222   }
223 
224   protected File getCommonBase(File sourceDirectory, Set files) {
225     if (files.size() == 1) {
226       // if there is only one file, its directory is the "common" base
227       return ((File)files.iterator().next()).getParentFile();
228     }
229 
230     File[] base = null;
231     for (Iterator iter = files.iterator(); iter.hasNext(); ) {
232       File current = ((File)iter.next()).getParentFile();
233       File[] currentHierarchy = getFileHierarchy(sourceDirectory, current);
234       if (base == null) {
235         base = currentHierarchy;
236       } else {
237         // compute the common file hierarchy between base and currentHierarchy
238         int len = Math.min(base.length, currentHierarchy.length);
239         List newHierarchy = new ArrayList();
240         for (int i = 0; i < len; i++) {
241           File a = base[i];
242           File b = currentHierarchy[i];
243           if (a.equals(b)) {
244             // a directory is shared : great !
245             newHierarchy.add(a);
246           } else {
247             // it's the first directory that is not shared : the common file hierarchy is over
248             if (newHierarchy.size() == 1) {
249               // we're already to the source directory : don't need to search further, we can't get better
250               return sourceDirectory;
251             }
252             base = new File[newHierarchy.size()];
253             newHierarchy.toArray(base);
254             break;
255           }
256         }
257       }
258     }
259     // Yes, this work has lead to a common base different than sourceDirectory
260     return base[base.length - 1];
261   }
262 }