
com.github.markusbernhardt.xmldoclet.XmlDoclet Maven / Gradle / Ivy
package com.github.markusbernhardt.xmldoclet;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.markusbernhardt.xmldoclet.xjc.Root;
import com.sun.javadoc.DocErrorReporter;
import com.sun.javadoc.LanguageVersion;
import com.sun.javadoc.RootDoc;
/**
* Doclet class.
*
* @author markus
*/
public class XmlDoclet {
private final static Logger log = LoggerFactory.getLogger(Parser.class);
/**
* The parsed object model. Used in unit tests.
*/
public static Root root;
/**
* The Options instance to parse command line strings.
*/
public final static Options options;
static {
options = new Options();
OptionBuilder.withArgName("directory");
OptionBuilder.isRequired(false);
OptionBuilder.hasArg();
OptionBuilder.withDescription("Destination directory for output file.\nDefault: .");
options.addOption(OptionBuilder.create("d"));
OptionBuilder.withArgName("encoding");
OptionBuilder.isRequired(false);
OptionBuilder.hasArg();
OptionBuilder.withDescription("Encoding of the output file.\nDefault: UTF8");
options.addOption(OptionBuilder.create("docencoding"));
OptionBuilder.withArgName("dryrun");
OptionBuilder.isRequired(false);
OptionBuilder.hasArgs(0);
OptionBuilder.withDescription("Parse javadoc, but don't write output file.\nDefault: false");
options.addOption(OptionBuilder.create("dryrun"));
OptionBuilder.withArgName("filename");
OptionBuilder.isRequired(false);
OptionBuilder.hasArg();
OptionBuilder.withDescription("Name of the output file.\nDefault: javadoc.xml");
options.addOption(OptionBuilder.create("filename"));
}
/**
* Check for doclet-added options. Returns the number of arguments you must
* specify on the command line for the given option. For example, "-d docs"
* would return 2.
*
* This method is required if the doclet contains any options. If this
* method is missing, Javadoc will print an invalid flag error for every
* option.
*
* @see com.sun.javadoc.Doclet#optionLength(String)
*
* @param optionName
* The name of the option.
* @return number of arguments on the command line for an option including
* the option name itself. Zero return means option not known.
* Negative value means error occurred.
*/
public static int optionLength(String optionName) {
Option option = options.getOption(optionName);
if (option == null) {
return 0;
}
return option.getArgs() + 1;
}
/**
* Check that options have the correct arguments.
*
* This method is not required, but is recommended, as every option will be
* considered valid if this method is not present. It will default
* gracefully (to true) if absent.
*
* Printing option related error messages (using the provided
* DocErrorReporter) is the responsibility of this method.
*
* @see com.sun.javadoc.Doclet#validOptions(String[][], DocErrorReporter)
*
* @param optionsArrayArray
* The two dimensional array of options.
* @param reporter
* The error reporter.
*
* @return true
if the options are valid.
*/
public static boolean validOptions(String optionsArrayArray[][], DocErrorReporter reporter) {
return null != parseCommandLine(optionsArrayArray);
}
/**
* Processes the JavaDoc documentation.
*
* This method is required for all doclets.
*
* @see com.sun.javadoc.Doclet#start(RootDoc)
*
* @param rootDoc
* The root of the documentation tree.
*
* @return true
if processing was successful.
*/
public static boolean start(RootDoc rootDoc) {
CommandLine commandLine = parseCommandLine(rootDoc.options());
Parser parser = new Parser();
root = parser.parseRootDoc(rootDoc);
save(commandLine, root);
return true;
}
/**
* Save XML object model to a file via JAXB.
*
* @param commandLine
* the parsed command line arguments
* @param root
* the document root
*/
public static void save(CommandLine commandLine, Root root) {
if (commandLine.hasOption("dryrun")) {
return;
}
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
JAXBContext contextObj = JAXBContext.newInstance(Root.class);
Marshaller marshaller = contextObj.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
if (commandLine.hasOption("docencoding")) {
marshaller.setProperty(Marshaller.JAXB_ENCODING, commandLine.getOptionValue("docencoding"));
}
String filename = "javadoc.xml";
if (commandLine.hasOption("filename")) {
filename = commandLine.getOptionValue("filename");
}
if (commandLine.hasOption("d")) {
filename = commandLine.getOptionValue("d") + File.separator + filename;
}
fileOutputStream = new FileOutputStream(filename);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream, 1024 * 1024);
marshaller.marshal(root, bufferedOutputStream);
bufferedOutputStream.flush();
fileOutputStream.flush();
} catch (JAXBException e) {
log.error(e.getMessage(), e);
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
try {
if (bufferedOutputStream != null) {
bufferedOutputStream.close();
}
if (fileOutputStream != null) {
fileOutputStream.close();
}
} catch (IOException e) {
log.error(e.getMessage(), e);
}
}
}
/**
* Return the version of the Java Programming Language supported by this
* doclet.
*
* This method is required by any doclet supporting a language version newer
* than 1.1.
*
* This Doclet supports Java 5.
*
* @see com.sun.javadoc.Doclet#languageVersion()
*
* @return LanguageVersion#JAVA_1_5
*/
public static LanguageVersion languageVersion() {
return LanguageVersion.JAVA_1_5;
}
/**
* Parse the given options.
*
* @param optionsArrayArray
* The two dimensional array of options.
* @return the parsed command line arguments.
*/
public static CommandLine parseCommandLine(String[][] optionsArrayArray) {
try {
List argumentList = new ArrayList();
for (String[] optionsArray : optionsArrayArray) {
argumentList.addAll(Arrays.asList(optionsArray));
}
CommandLineParser commandLineParser = new BasicParser() {
@Override
protected void processOption(final String arg, @SuppressWarnings("rawtypes") final ListIterator iter)
throws ParseException {
boolean hasOption = getOptions().hasOption(arg);
if (hasOption) {
super.processOption(arg, iter);
}
}
};
CommandLine commandLine = commandLineParser.parse(options, argumentList.toArray(new String[] {}));
return commandLine;
} catch (ParseException e) {
LoggingOutputStream loggingOutputStream = new LoggingOutputStream(log, LoggingLevelEnum.INFO);
PrintWriter printWriter = new PrintWriter(loggingOutputStream);
HelpFormatter helpFormatter = new HelpFormatter();
helpFormatter.printHelp(printWriter, 74, "javadoc -doclet " + XmlDoclet.class.getName() + " [options]",
null, options, 1, 3, null, false);
return null;
}
}
}