001 package de.java2html.anttasks;
002 
003 import java.io.File;
004 import java.io.FileWriter;
005 import java.io.IOException;
006 import java.io.Writer;
007 
008 import de.java2html.converter.IJavaSourceConverter;
009 import de.java2html.converter.JavaSourceConverterProvider;
010 import de.java2html.javasource.TypedSource;
011 import de.java2html.javasource.JavaSourceParser;
012 import de.java2html.options.ConversionOptionsUtilities;
013 import de.java2html.options.HorizontalAlignment;
014 import de.java2html.options.JavaSourceConversionOptions;
015 import de.java2html.options.JavaSourceStyleTable;
016 import de.java2html.util.IoUtilities;
017 
018 import org.apache.tools.ant.BuildException;
019 import org.apache.tools.ant.DirectoryScanner;
020 import org.apache.tools.ant.Project;
021 import org.apache.tools.ant.taskdefs.MatchingTask;
022 import org.apache.tools.ant.util.FileNameMapper;
023 import org.apache.tools.ant.util.GlobPatternMapper;
024 import org.apache.tools.ant.util.SourceFileScanner;
025 
026 /**
027  * Runs the java2html converter as a task inside the well known build tool
028  * "ant" (see ant.apache.org).
029  
030  * Thanks to <a href="mailto:markus@jave.de">Markus Gebhard</a>, the author
031  * of java2html itself. I contribute this code to the project under the same
032  * license as java2html.
033  
034  * For an example for a <code>build.xml</code> containing this task have a
035  * look at the docs/anttask/ folder.
036  
037  @author <a href="mailto:mbohlen@mbohlen.de">Matthias Bohlen</a>
038  @author <a href="mailto:markus@jave.de">Markus Gebhard</a>
039  */
040 public class Java2HtmlTask extends MatchingTask {
041   private String style = JavaSourceConversionOptions.getDefault().getStyleTable().getName();
042   private File srcDir;
043   private File destDir;
044   private boolean overwrite = false;
045   private String outputFormat = JavaSourceConverterProvider.getDefaultConverterName();
046   private int tabs = JavaSourceConversionOptions.getDefault().getTabSize();
047   private boolean showLineNumbers = JavaSourceConversionOptions.getDefault().isShowLineNumbers();
048   private boolean showDefaultTitle = false;
049   private boolean addLineAnchors = false;
050   private String lineAnchorPrefix = "";
051   private boolean showTableBorder = false;
052   private boolean showFileName = false;
053   private boolean includeDocumentHeader = true;
054   private boolean includeDocumentFooter = true;
055   private boolean useShortFileName = false;
056   private String horizontalAlignment = JavaSourceConversionOptions
057       .getDefault().getHorizontalAlignment().getName();
058   private String charset = JavaSourceConversionOptions.DEFAULT_CHARSET;
059 
060   /**
061    * Sets the charset of output file.
062    
063    @param charset
064    */
065   public void setCharset(String charset) {
066     this.charset = charset;
067   }
068 
069   /**
070    * Sets the directory where the Java sources are stored.
071    
072    @param srcDir
073    *          directory name
074    */
075   public void setSrcDir(File srcDir) {
076     this.srcDir = srcDir;
077   }
078 
079   /**
080    * Sets the directory where the output is written.
081    
082    @param destDir
083    *          directory name
084    */
085   public void setDestDir(File destDir) {
086     this.destDir = destDir;
087   }
088 
089   /**
090    * Sets the output format.
091    
092    @param outputFormat
093    *          the output format identifier ("html", "xhtml", "latex")
094    */
095   public void setOutputFormat(String outputFormat) {
096     this.outputFormat = outputFormat;
097   }
098 
099   /**
100    @see org.apache.tools.ant.Task#execute()
101    */
102   @Override
103   public void execute() throws BuildException {
104     if (srcDir == null) {
105       // We directly change the user variable, because it
106       // shouldn't lead to problems
107       srcDir = project.resolveFile(".");
108     }
109 
110     // find the files/directories
111     final DirectoryScanner dirScanner = getDirectoryScanner(srcDir);
112 
113     // get a list of files to work on
114     final String[] allSourceFiles = dirScanner.getIncludedFiles();
115 
116     final IJavaSourceConverter converter = getConverter();
117     final JavaSourceConversionOptions options = getConversionOptions();
118     final SourceFileScanner sourceScanner = new SourceFileScanner(this);
119 
120     String[] sourceFilesToProcess;
121     if (isOverwrite()) {
122       sourceFilesToProcess = allSourceFiles;
123     }
124     else {
125       final FileNameMapper sourceToOutMapper = new GlobPatternMapper();
126       sourceToOutMapper.setFrom("*");
127       sourceToOutMapper.setTo("*." + converter.getMetaData().getDefaultFileExtension());
128       sourceFilesToProcess = sourceScanner.restrict(allSourceFiles, srcDir, destDir, sourceToOutMapper);
129     }
130 
131     if (sourceFilesToProcess.length > 0) {
132       final String files = (sourceFilesToProcess.length == " file" " files");
133       log("Converting " + sourceFilesToProcess.length + files, Project.MSG_INFO);
134     }
135 
136     for (int i = 0; i < sourceFilesToProcess.length; ++i) {
137       process(sourceFilesToProcess[i], options, converter);
138     }
139   }
140 
141   /**
142    * Returns a new conversions options object filled in from the Ant task.
143    
144    @return a new conversions options object
145    */
146   private JavaSourceConversionOptions getConversionOptions() {
147     final JavaSourceConversionOptions options = JavaSourceConversionOptions.getDefault();
148     options.setTabSize(tabs);
149     options.setShowFileName(isShowFileName());
150     options.setShowTableBorder(isShowTableBorder());
151     options.setShowLineNumbers(isShowLineNumbers());
152     options.setAddLineAnchors(isAddLineAnchors());
153     options.setLineAnchorPrefix(lineAnchorPrefix);
154 
155     options.setCharset(charset);
156 
157     final JavaSourceStyleTable table = JavaSourceStyleTable.getPredefinedTable(style);
158     if (table == null) {
159       throw new BuildException("Specified style table '"
160           + style
161           "' does not exist "
162           " - valid values are: "
163           + ConversionOptionsUtilities.getPredefinedStyleTableNameString());
164     }
165     options.setStyleTable(table);
166 
167     final HorizontalAlignment alignment = HorizontalAlignment.getByName(horizontalAlignment);
168     if (alignment == null) {
169       throw new BuildException("Specified alignment '" //$NON-NLS-1$
170           + horizontalAlignment
171           "'does not exist - valid values are: " //$NON-NLS-1$
172           + ConversionOptionsUtilities.getAvailableHorizontalAlignmentNames());
173     }
174     options.setHorizontalAlignment(alignment);
175 
176     return options;
177   }
178 
179   private IJavaSourceConverter getConverter() throws BuildException {
180     final IJavaSourceConverter converter = JavaSourceConverterProvider.getJavaSourceConverterByName(outputFormat);
181     if (converter == null) {
182       throw new BuildException("unknown output file format: " + outputFormat)//$NON-NLS-1$
183     }
184     return converter;
185   }
186 
187   /**
188    * Convert a Java source to HTML, XHTML or LaTex.
189    
190    @param sourcefileName
191    *          the name of the file to convert
192    @param options
193    *          conversion options
194    @param converter
195    *          the converter to use
196    */
197   private void process(String sourcefileName, JavaSourceConversionOptions options, IJavaSourceConverter converter)
198       throws BuildException {
199     log("Converting '" + sourcefileName + "'", Project.MSG_VERBOSE)//$NON-NLS-1$ //$NON-NLS-2$
200     final JavaSourceParser parser = new JavaSourceParser(options);
201     TypedSource source;
202     final File inFile = new File(srcDir, sourcefileName);
203     try {
204       source = parser.parse(inFile);
205     }
206     catch (final IOException e1) {
207       throw new BuildException("Unable to parse file " + inFile.getName(), e1)//$NON-NLS-1$
208     }
209 
210     final File outFile = createOutputFile(sourcefileName, converter);
211     ensureDirectoryFor(outFile);
212     Writer writer = null;
213     try {
214       writer = new FileWriter(outFile);
215     }
216     catch (final Exception e) {
217       throw new BuildException("Error opening output file " + outFile.getName(), e)//$NON-NLS-1$
218     }
219 
220     String title = ""//$NON-NLS-1$
221     if (isShowDefaultTitle()) {
222       title = sourcefileName.replace('\\''/');
223     }
224     try {
225       if (isIncludeDocumentHeader()) {
226         converter.writeDocumentHeader(writer, options, title);
227       }
228       converter.convert(source, options, writer);
229       if (isIncludeDocumentFooter()) {
230         converter.writeDocumentFooter(writer, options);
231       }
232     }
233     catch (final Exception e) {
234       throw new BuildException("Error writing output to " + outFile.getName(), e)//$NON-NLS-1$
235     }
236     finally {
237       IoUtilities.close(writer);
238     }
239 
240     log("Output: " + outFile, Project.MSG_VERBOSE)//$NON-NLS-1$
241   }
242 
243   private File createOutputFile(String sourcefileName, IJavaSourceConverter converter) {
244     String fileNamePrefix = sourcefileName;
245     if (isUseShortFileName()) {
246       final int index = sourcefileName.lastIndexOf('.');
247       if (index != -1) {
248         fileNamePrefix = sourcefileName.substring(0, index);
249       }
250     }
251     return new File(destDir, fileNamePrefix + "." + converter.getMetaData().getDefaultFileExtension());
252   }
253 
254   /**
255    * Sets the number of spaces per tab.
256    
257    @param tabs
258    */
259   public void setTabs(int tabs) {
260     this.tabs = tabs;
261   }
262 
263   /**
264    * Sets the table name for the output style, e.g. "kawa" or "eclipse".
265    
266    @see JavaSourceStyleTable
267    */
268   public void setStyle(String style) {
269     this.style = style;
270   }
271 
272   /**
273    * Creates directories as needed.
274    
275    @param targetFile
276    *          a <code>File</code> whose parent directories need to exist
277    @exception BuildException
278    *              if the parent directories couldn't be created
279    */
280   private void ensureDirectoryFor(File targetFilethrows BuildException {
281     final File directory = new File(targetFile.getParent());
282     if (!directory.exists()) {
283       if (!directory.mkdirs()) {
284         throw new BuildException("Unable to create directory: " + directory.getAbsolutePath());
285       }
286     }
287   }
288 
289   private boolean isShowFileName() {
290     return showFileName;
291   }
292 
293   private boolean isShowLineNumbers() {
294     return showLineNumbers;
295   }
296 
297   private boolean isShowDefaultTitle() {
298     return showDefaultTitle;
299   }
300 
301   private boolean isShowTableBorder() {
302     return showTableBorder;
303   }
304 
305   public void setShowFileName(boolean showFileName) {
306     this.showFileName = showFileName;
307   }
308 
309   public void setShowLineNumbers(boolean showLineNumbers) {
310     this.showLineNumbers = showLineNumbers;
311   }
312 
313   public void setShowDefaultTitle(boolean showDefaultTitle) {
314     this.showDefaultTitle = showDefaultTitle;
315   }
316 
317   public void setShowTableBorder(boolean showTableBorder) {
318     this.showTableBorder = showTableBorder;
319   }
320 
321   private boolean isIncludeDocumentFooter() {
322     return includeDocumentFooter;
323   }
324 
325   private boolean isIncludeDocumentHeader() {
326     return includeDocumentHeader;
327   }
328 
329   public void setIncludeDocumentFooter(boolean includeDocumentFooter) {
330     this.includeDocumentFooter = includeDocumentFooter;
331   }
332 
333   public void setIncludeDocumentHeader(boolean includeDocumentHeader) {
334     this.includeDocumentHeader = includeDocumentHeader;
335   }
336 
337   private boolean isAddLineAnchors() {
338     return addLineAnchors;
339   }
340 
341   public void setAddLineAnchors(boolean addLineAnchors) {
342     this.addLineAnchors = addLineAnchors;
343   }
344 
345   public void setLineAnchorPrefix(String string) {
346     lineAnchorPrefix = string;
347   }
348 
349   public void setHorizontalAlignment(String horizontalAlignment) {
350     this.horizontalAlignment = horizontalAlignment;
351   }
352 
353   private boolean isUseShortFileName() {
354     return useShortFileName;
355   }
356 
357   public void setUseShortFileName(boolean useShortFileName) {
358     this.useShortFileName = useShortFileName;
359   }
360 
361   private boolean isOverwrite() {
362     return overwrite;
363   }
364 
365   public void setOverwrite(boolean overwrite) {
366     this.overwrite = overwrite;
367   }
368 }