/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* * Javadoc.java * Copyright (C) 2006-2012 University of Waikato, Hamilton, New Zealand */ package weka.core; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; /** * Abstract superclass for classes that generate Javadoc comments and replace * the content between certain comment tags. * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision: 8034 $ */ public abstract class Javadoc implements OptionHandler, RevisionHandler { /** the start tag */ protected String[] m_StartTag = null; /** the end tag */ protected String[] m_EndTag = null; /** the classname */ protected String m_Classname = Javadoc.class.getName(); /** whether to include the stars in the Javadoc */ protected boolean m_UseStars = true; /** the directory above the class to update */ protected String m_Dir = ""; /** whether to suppress error messages (no printout in the console) */ protected boolean m_Silent = false; /** * Returns an enumeration describing the available options. * * @return an enumeration of all the available options. */ public Enumeration listOptions() { Vector<Option> result = new Vector<Option>(); result.addElement(new Option( "\tThe class to load.", "W", 1, "-W <classname>")); result.addElement(new Option( "\tSuppresses the '*' in the Javadoc.", "nostars", 0, "-nostars")); result.addElement(new Option( "\tThe directory above the package hierarchy of the class.", "dir", 1, "-dir <dir>")); result.addElement(new Option( "\tSuppresses printing in the console.", "silent", 0, "-silent")); return result.elements(); } /** * Parses a given list of options. * * @param options the list of options as an array of strings * @throws Exception if an option is not supported */ public void setOptions(String[] options) throws Exception { String tmpStr; tmpStr = Utils.getOption('W', options); if (tmpStr.length() > 0) setClassname(tmpStr); else setClassname(this.getClass().getName()); setUseStars(!Utils.getFlag("nostars", options)); setDir(Utils.getOption("dir", options)); setSilent(Utils.getFlag("silent", options)); } /** * Gets the current settings of this object. * * @return an array of strings suitable for passing to setOptions */ public String[] getOptions() { Vector<String> result; result = new Vector<String>(); result.add("-W"); result.add(getClassname()); if (!getUseStars()) result.add("-nostars"); if (getDir().length() != 0) { result.add("-dir"); result.add(getDir()); } if (getSilent()) result.add("-silent"); return (String[]) result.toArray(new String[result.size()]); } /** * sets the classname of the class to generate the Javadoc for * * @param value the new classname */ public void setClassname(String value) { m_Classname = value; } /** * returns the current classname * * @return the current classname */ public String getClassname() { return m_Classname; } /** * sets whether to prefix the Javadoc with "*" * * @param value true if stars are used */ public void setUseStars(boolean value) { m_UseStars = value; } /** * whether the Javadoc is prefixed with "*" * * @return whether stars are used */ public boolean getUseStars() { return m_UseStars; } /** * sets the dir containing the file that is to be updated. It is the dir * above the package hierarchy of the class. * * @param value the directory containing the classes */ public void setDir(String value) { m_Dir = value; } /** * returns the current dir containing the class to update. It is the dir * above the package name of the class. * * @return the current directory */ public String getDir() { return m_Dir; } /** * sets whether to suppress output in the console * * @param value true if output is to be suppressed */ public void setSilent(boolean value) { m_Silent = value; } /** * whether output in the console is suppressed * * @return true if output is suppressed */ public boolean getSilent() { return m_Silent; } /** * prints the given object to System.err * * @param o the object to print */ protected void println(Object o) { if (!getSilent()) System.err.println(o.toString()); } /** * returns true if the class can be instantiated, i.e., has a default * constructor. * * @return true if the class can be instantiated */ protected boolean canInstantiateClass() { boolean result; Class cls; result = true; cls = null; try { cls = Class.forName(getClassname()); } catch (Exception e) { result = false; println("Cannot instantiate '" + getClassname() + "'! Class in CLASSPATH?"); } if (result) { try { cls.newInstance(); } catch (Exception e) { result = false; println("Cannot instantiate '" + getClassname() + "'! Missing default constructor?"); } } return result; } /** * Returns a new instance of the class * * @return a new instance of the class */ protected Object getInstance() { Object result; Class cls; result = null; try { cls = Class.forName(getClassname()); result = cls.newInstance(); } catch (Exception e) { result = null; } return result; } /** * converts the given String into HTML, i.e., replacing some char entities * with HTML entities. * * @param s the string to convert * @return the HTML conform string */ protected String toHTML(String s) { String result; result = s; result = result.replaceAll("&", "&"); result = result.replaceAll("<", "<"); result = result.replaceAll(">", ">"); result = result.replaceAll("@", "@"); result = result.replaceAll("\n", "<br/>\n"); return result; } /** * indents the given string by a given number of indention strings * * @param content the string to indent * @param count the number of times to indent one line * @param indentStr the indention string * @return the indented content */ protected String indent(String content, int count, String indentStr) { String result; StringTokenizer tok; int i; tok = new StringTokenizer(content, "\n", true); result = ""; while (tok.hasMoreTokens()) { if (result.endsWith("\n") || (result.length() == 0)) { for (i = 0; i < count; i++) result += indentStr; } result += tok.nextToken(); } return result; } /** * generates and returns the Javadoc for the specified start/end tag pair. * * @param index the index in the start/end tag array * @return the generated Javadoc * @throws Exception in case the generation fails */ protected abstract String generateJavadoc(int index) throws Exception; /** * generates and returns the Javadoc * * @return the generated Javadoc * @throws Exception in case the generation fails */ protected String generateJavadoc() throws Exception { String result; int i; result = ""; for (i = 0; i < m_StartTag.length; i++) { if (i > 0) result += "\n\n"; result += generateJavadoc(i).trim(); } return result; } /** * determines the base string of the given indention string, whether it's * either only spaces (one space will be retured) or mixed mode (tabs and * spaces, in that case the same string will be returned) * * @param str the string to analyze * @return the indention string */ protected String getIndentionString(String str) { String result; // only spaces? if (str.replaceAll(" ", "").length() == 0) result = " "; // only tabs? else if (str.replaceAll("\t", "").length() == 0) result = "\t"; else result = str; return result; } /** * determines the number of indention strings that have to be inserted to * generated the given indention string. * * @param str the string to analyze * @return the number of base indention strings to insert */ protected int getIndentionLength(String str) { int result; // only spaces? if (str.replaceAll(" ", "").length() == 0) result = str.length(); // only tabs? else if (str.replaceAll("\t", "").length() == 0) result = str.length(); else result = 1; return result; } /** * generates and returns the Javadoc for the specified start/end tag pair * * @param content the current source code * @param index the index in the start/end tag array * @return the generated Javadoc * @throws Exception in case the generation fails */ protected String updateJavadoc(String content, int index) throws Exception { StringBuffer resultBuf; int indentionLen; String indentionStr; String part; String tmpStr; // start and end tag? if ( (content.indexOf(m_StartTag[index]) == -1) || (content.indexOf(m_EndTag[index]) == -1) ) { println( "No start and/or end tags found: " + m_StartTag[index] + "/" + m_EndTag[index]); return content; } // replace option-tags resultBuf = new StringBuffer(); while (content.length() > 0) { if (content.indexOf(m_StartTag[index]) > -1) { part = content.substring(0, content.indexOf(m_StartTag[index])); // is it a Java constant? -> skip if (part.endsWith("\"")) { resultBuf.append(part); resultBuf.append(m_StartTag[index]); content = content.substring(part.length() + m_StartTag[index].length()); } else { tmpStr = part.substring(part.lastIndexOf("\n") + 1); indentionLen = getIndentionLength(tmpStr); indentionStr = getIndentionString(tmpStr); part = part.substring(0, part.lastIndexOf("\n") + 1); resultBuf.append(part); resultBuf.append(indent(m_StartTag[index], indentionLen, indentionStr) + "\n"); resultBuf.append(indent(generateJavadoc(index), indentionLen, indentionStr)); resultBuf.append(indent(m_EndTag[index], indentionLen, indentionStr)); content = content.substring(content.indexOf(m_EndTag[index])); content = content.substring(m_EndTag[index].length()); } } else { resultBuf.append(content); content = ""; } } return resultBuf.toString().trim(); } /** * updates the Javadoc in the given source code. * * @param content the source code * @return the updated source code * @throws Exception in case the generation fails */ protected String updateJavadoc(String content) throws Exception { String result; int i; result = content; for (i = 0; i < m_StartTag.length; i++) { result = updateJavadoc(result, i); } return result; } /** * generates the Javadoc and returns it applied to the source file if one * was provided, otherwise an empty string. * * @return the generated Javadoc * @throws Exception in case the generation fails */ public String updateJavadoc() throws Exception { StringBuffer contentBuf; BufferedReader reader; String line; String result; File file; result = ""; // non-existing? file = new File(getDir() + "/" + getClassname().replaceAll("\\.", "/") + ".java"); if (!file.exists()) { println("File '" + file.getAbsolutePath() + "' doesn't exist!"); return result; } try { // load file reader = new BufferedReader(new FileReader(file)); contentBuf = new StringBuffer(); while ((line = reader.readLine()) != null) { contentBuf.append(line + "\n"); } reader.close(); result = updateJavadoc(contentBuf.toString()); } catch (Exception e) { e.printStackTrace(); } return result.trim(); } /** * generates either the plain Javadoc (if no filename specified) or the * updated file (if a filename is specified). The start and end tag for * the global info have to be specified in the file in the latter case. * * @return either the plain Javadoc or the modified file * @throws Exception in case the generation fails */ public String generate() throws Exception { if (getDir().length() == 0) return generateJavadoc(); else return updateJavadoc(); } /** * generates a string to print as help on the console * * @return the generated help */ public String generateHelp() { String result; Enumeration enm; Option option; result = getClass().getName().replaceAll(".*\\.", "") + " Options:\n\n"; enm = listOptions(); while (enm.hasMoreElements()) { option = (Option) enm.nextElement(); result += option.synopsis() + "\n" + option.description() + "\n"; } return result; } /** * runs the javadoc producer with the given commandline options * * @param javadoc the javadoc producer to execute * @param options the commandline options */ protected static void runJavadoc(Javadoc javadoc, String[] options) { try { try { if (Utils.getFlag('h', options)) throw new Exception("Help requested"); javadoc.setOptions(options); Utils.checkForRemainingOptions(options); // directory is necessary! if (javadoc.getDir().length() == 0) throw new Exception("No directory provided!"); } catch (Exception ex) { String result = "\n" + ex.getMessage() + "\n\n" + javadoc.generateHelp(); throw new Exception(result); } System.out.println(javadoc.generate() + "\n"); } catch (Exception ex) { System.err.println(ex.getMessage()); } } }