001: /*
002: * This program is free software; you can redistribute it and/or modify
003: * it under the terms of the GNU General Public License as published by
004: * the Free Software Foundation; either version 2 of the License, or
005: * (at your option) any later version.
006: *
007: * This program is distributed in the hope that it will be useful,
008: * but WITHOUT ANY WARRANTY; without even the implied warranty of
009: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
010: * GNU General Public License for more details.
011: *
012: * You should have received a copy of the GNU General Public License
013: * along with this program; if not, write to the Free Software
014: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
015: */
016:
017: /*
018: * Javadoc.java
019: * Copyright (C) 2006 University of Waikato, Hamilton, New Zealand
020: */
021:
022: package weka.core;
023:
024: import java.io.BufferedReader;
025: import java.io.File;
026: import java.io.FileReader;
027: import java.util.Enumeration;
028: import java.util.StringTokenizer;
029: import java.util.Vector;
030:
031: /**
032: * Abstract superclass for classes that generate Javadoc comments and replace
033: * the content between certain comment tags.
034: *
035: * @author fracpete (fracpete at waikato dot ac dot nz)
036: * @version $Revision: 1.5 $
037: */
038: public abstract class Javadoc implements OptionHandler {
039:
040: /** the start tag */
041: protected String[] m_StartTag = null;
042:
043: /** the end tag */
044: protected String[] m_EndTag = null;
045:
046: /** the classname */
047: protected String m_Classname = Javadoc.class.getName();
048:
049: /** whether to include the stars in the Javadoc */
050: protected boolean m_UseStars = true;
051:
052: /** the directory above the class to update */
053: protected String m_Dir = "";
054:
055: /** whether to suppress error messages (no printout in the console) */
056: protected boolean m_Silent = false;
057:
058: /**
059: * Returns an enumeration describing the available options.
060: *
061: * @return an enumeration of all the available options.
062: */
063: public Enumeration listOptions() {
064: Vector result = new Vector();
065:
066: result.addElement(new Option("\tThe class to load.", "W", 1,
067: "-W <classname>"));
068:
069: result.addElement(new Option(
070: "\tSuppresses the '*' in the Javadoc.", "nostars", 0,
071: "-nostars"));
072:
073: result
074: .addElement(new Option(
075: "\tThe directory above the package hierarchy of the class.",
076: "dir", 1, "-dir <dir>"));
077:
078: result.addElement(new Option(
079: "\tSuppresses printing in the console.", "silent", 0,
080: "-silent"));
081:
082: return result.elements();
083: }
084:
085: /**
086: * Parses a given list of options.
087: *
088: * @param options the list of options as an array of strings
089: * @throws Exception if an option is not supported
090: */
091: public void setOptions(String[] options) throws Exception {
092: String tmpStr;
093:
094: tmpStr = Utils.getOption('W', options);
095: if (tmpStr.length() > 0)
096: setClassname(tmpStr);
097: else
098: setClassname(this .getClass().getName());
099:
100: setUseStars(!Utils.getFlag("nostars", options));
101:
102: setDir(Utils.getOption("dir", options));
103:
104: setSilent(Utils.getFlag("silent", options));
105: }
106:
107: /**
108: * Gets the current settings of this object.
109: *
110: * @return an array of strings suitable for passing to setOptions
111: */
112: public String[] getOptions() {
113: Vector result;
114:
115: result = new Vector();
116:
117: result.add("-W");
118: result.add(getClassname());
119:
120: if (!getUseStars())
121: result.add("-nostars");
122:
123: if (getDir().length() != 0) {
124: result.add("-dir");
125: result.add(getDir());
126: }
127:
128: if (getSilent())
129: result.add("-silent");
130:
131: return (String[]) result.toArray(new String[result.size()]);
132: }
133:
134: /**
135: * sets the classname of the class to generate the Javadoc for
136: *
137: * @param value the new classname
138: */
139: public void setClassname(String value) {
140: m_Classname = value;
141: }
142:
143: /**
144: * returns the current classname
145: *
146: * @return the current classname
147: */
148: public String getClassname() {
149: return m_Classname;
150: }
151:
152: /**
153: * sets whether to prefix the Javadoc with "*"
154: *
155: * @param value true if stars are used
156: */
157: public void setUseStars(boolean value) {
158: m_UseStars = value;
159: }
160:
161: /**
162: * whether the Javadoc is prefixed with "*"
163: *
164: * @return whether stars are used
165: */
166: public boolean getUseStars() {
167: return m_UseStars;
168: }
169:
170: /**
171: * sets the dir containing the file that is to be updated. It is the dir
172: * above the package hierarchy of the class.
173: *
174: * @param value the directory containing the classes
175: */
176: public void setDir(String value) {
177: m_Dir = value;
178: }
179:
180: /**
181: * returns the current dir containing the class to update. It is the dir
182: * above the package name of the class.
183: *
184: * @return the current directory
185: */
186: public String getDir() {
187: return m_Dir;
188: }
189:
190: /**
191: * sets whether to suppress output in the console
192: *
193: * @param value true if output is to be suppressed
194: */
195: public void setSilent(boolean value) {
196: m_Silent = value;
197: }
198:
199: /**
200: * whether output in the console is suppressed
201: *
202: * @return true if output is suppressed
203: */
204: public boolean getSilent() {
205: return m_Silent;
206: }
207:
208: /**
209: * prints the given object to System.err
210: *
211: * @param o the object to print
212: */
213: protected void println(Object o) {
214: if (!getSilent())
215: System.err.println(o.toString());
216: }
217:
218: /**
219: * returns true if the class can be instantiated, i.e., has a default
220: * constructor.
221: *
222: * @return true if the class can be instantiated
223: */
224: protected boolean canInstantiateClass() {
225: boolean result;
226: Class cls;
227:
228: result = true;
229: cls = null;
230:
231: try {
232: cls = Class.forName(getClassname());
233: } catch (Exception e) {
234: result = false;
235: println("Cannot instantiate '" + getClassname()
236: + "'! Class in CLASSPATH?");
237: }
238:
239: if (result) {
240: try {
241: cls.newInstance();
242: } catch (Exception e) {
243: result = false;
244: println("Cannot instantiate '" + getClassname()
245: + "'! Missing default constructor?");
246: }
247: }
248:
249: return result;
250: }
251:
252: /**
253: * Returns a new instance of the class
254: *
255: * @return a new instance of the class
256: */
257: protected Object getInstance() {
258: Object result;
259: Class cls;
260:
261: result = null;
262:
263: try {
264: cls = Class.forName(getClassname());
265: result = cls.newInstance();
266: } catch (Exception e) {
267: result = null;
268: }
269:
270: return result;
271: }
272:
273: /**
274: * converts the given String into HTML, i.e., replacing some char entities
275: * with HTML entities.
276: *
277: * @param s the string to convert
278: * @return the HTML conform string
279: */
280: protected String toHTML(String s) {
281: String result;
282:
283: result = s;
284:
285: result = result.replaceAll("&", "&");
286: result = result.replaceAll("<", "<");
287: result = result.replaceAll(">", ">");
288: result = result.replaceAll("@", "@");
289: result = result.replaceAll("\n", "<br/>\n");
290:
291: return result;
292: }
293:
294: /**
295: * indents the given string by a given number of indention strings
296: *
297: * @param content the string to indent
298: * @param count the number of times to indent one line
299: * @param indentStr the indention string
300: * @return the indented content
301: */
302: protected String indent(String content, int count, String indentStr) {
303: String result;
304: StringTokenizer tok;
305: int i;
306:
307: tok = new StringTokenizer(content, "\n", true);
308: result = "";
309: while (tok.hasMoreTokens()) {
310: if (result.endsWith("\n") || (result.length() == 0)) {
311: for (i = 0; i < count; i++)
312: result += indentStr;
313: }
314: result += tok.nextToken();
315: }
316:
317: return result;
318: }
319:
320: /**
321: * generates and returns the Javadoc for the specified start/end tag pair.
322: *
323: * @param index the index in the start/end tag array
324: * @return the generated Javadoc
325: * @throws Exception in case the generation fails
326: */
327: protected abstract String generateJavadoc(int index)
328: throws Exception;
329:
330: /**
331: * generates and returns the Javadoc
332: *
333: * @return the generated Javadoc
334: * @throws Exception in case the generation fails
335: */
336: protected String generateJavadoc() throws Exception {
337: String result;
338: int i;
339:
340: result = "";
341:
342: for (i = 0; i < m_StartTag.length; i++) {
343: if (i > 0)
344: result += "\n\n";
345: result += generateJavadoc(i).trim();
346: }
347:
348: return result;
349: }
350:
351: /**
352: * determines the base string of the given indention string, whether it's
353: * either only spaces (one space will be retured) or mixed mode (tabs and
354: * spaces, in that case the same string will be returned)
355: *
356: * @param str the string to analyze
357: * @return the indention string
358: */
359: protected String getIndentionString(String str) {
360: String result;
361:
362: // only spaces?
363: if (str.replaceAll(" ", "").length() == 0)
364: result = " ";
365: // only tabs?
366: else if (str.replaceAll("\t", "").length() == 0)
367: result = "\t";
368: else
369: result = str;
370:
371: return result;
372: }
373:
374: /**
375: * determines the number of indention strings that have to be inserted to
376: * generated the given indention string.
377: *
378: * @param str the string to analyze
379: * @return the number of base indention strings to insert
380: */
381: protected int getIndentionLength(String str) {
382: int result;
383:
384: // only spaces?
385: if (str.replaceAll(" ", "").length() == 0)
386: result = str.length();
387: // only tabs?
388: else if (str.replaceAll("\t", "").length() == 0)
389: result = str.length();
390: else
391: result = 1;
392:
393: return result;
394: }
395:
396: /**
397: * generates and returns the Javadoc for the specified start/end tag pair
398: *
399: * @param content the current source code
400: * @param index the index in the start/end tag array
401: * @return the generated Javadoc
402: * @throws Exception in case the generation fails
403: */
404: protected String updateJavadoc(String content, int index)
405: throws Exception {
406: StringBuffer resultBuf;
407: int indentionLen;
408: String indentionStr;
409: String part;
410: String tmpStr;
411:
412: // start and end tag?
413: if ((content.indexOf(m_StartTag[index]) == -1)
414: || (content.indexOf(m_EndTag[index]) == -1)) {
415: println("No start and/or end tags found: "
416: + m_StartTag[index] + "/" + m_EndTag[index]);
417: return content;
418: }
419:
420: // replace option-tags
421: resultBuf = new StringBuffer();
422: while (content.length() > 0) {
423: if (content.indexOf(m_StartTag[index]) > -1) {
424: part = content.substring(0, content
425: .indexOf(m_StartTag[index]));
426: // is it a Java constant? -> skip
427: if (part.endsWith("\"")) {
428: resultBuf.append(part);
429: resultBuf.append(m_StartTag[index]);
430: content = content.substring(part.length()
431: + m_StartTag[index].length());
432: } else {
433: tmpStr = part.substring(part.lastIndexOf("\n") + 1);
434: indentionLen = getIndentionLength(tmpStr);
435: indentionStr = getIndentionString(tmpStr);
436: part = part
437: .substring(0, part.lastIndexOf("\n") + 1);
438: resultBuf.append(part);
439: resultBuf.append(indent(m_StartTag[index],
440: indentionLen, indentionStr)
441: + "\n");
442: resultBuf.append(indent(generateJavadoc(index),
443: indentionLen, indentionStr));
444: resultBuf.append(indent(m_EndTag[index],
445: indentionLen, indentionStr));
446: content = content.substring(content
447: .indexOf(m_EndTag[index]));
448: content = content.substring(m_EndTag[index]
449: .length());
450: }
451: } else {
452: resultBuf.append(content);
453: content = "";
454: }
455: }
456:
457: return resultBuf.toString().trim();
458: }
459:
460: /**
461: * updates the Javadoc in the given source code.
462: *
463: * @param content the source code
464: * @return the updated source code
465: * @throws Exception in case the generation fails
466: */
467: protected String updateJavadoc(String content) throws Exception {
468: String result;
469: int i;
470:
471: result = content;
472:
473: for (i = 0; i < m_StartTag.length; i++) {
474: result = updateJavadoc(result, i);
475: }
476:
477: return result;
478: }
479:
480: /**
481: * generates the Javadoc and returns it applied to the source file if one
482: * was provided, otherwise an empty string.
483: *
484: * @return the generated Javadoc
485: * @throws Exception in case the generation fails
486: */
487: public String updateJavadoc() throws Exception {
488: StringBuffer contentBuf;
489: BufferedReader reader;
490: String line;
491: String result;
492: File file;
493:
494: result = "";
495:
496: // non-existing?
497: file = new File(getDir() + "/"
498: + getClassname().replaceAll("\\.", "/") + ".java");
499: if (!file.exists()) {
500: println("File '" + file.getAbsolutePath()
501: + "' doesn't exist!");
502: return result;
503: }
504:
505: try {
506: // load file
507: reader = new BufferedReader(new FileReader(file));
508: contentBuf = new StringBuffer();
509: while ((line = reader.readLine()) != null) {
510: contentBuf.append(line + "\n");
511: }
512: reader.close();
513: result = updateJavadoc(contentBuf.toString());
514: } catch (Exception e) {
515: e.printStackTrace();
516: }
517:
518: return result.trim();
519: }
520:
521: /**
522: * generates either the plain Javadoc (if no filename specified) or the
523: * updated file (if a filename is specified). The start and end tag for
524: * the global info have to be specified in the file in the latter case.
525: *
526: * @return either the plain Javadoc or the modified file
527: * @throws Exception in case the generation fails
528: */
529: public String generate() throws Exception {
530: if (getDir().length() == 0)
531: return generateJavadoc();
532: else
533: return updateJavadoc();
534: }
535:
536: /**
537: * generates a string to print as help on the console
538: *
539: * @return the generated help
540: */
541: public String generateHelp() {
542: String result;
543: Enumeration enm;
544: Option option;
545:
546: result = getClass().getName().replaceAll(".*\\.", "")
547: + " Options:\n\n";
548: enm = listOptions();
549: while (enm.hasMoreElements()) {
550: option = (Option) enm.nextElement();
551: result += option.synopsis() + "\n" + option.description()
552: + "\n";
553: }
554:
555: return result;
556: }
557:
558: /**
559: * runs the javadoc producer with the given commandline options
560: *
561: * @param javadoc the javadoc producer to execute
562: * @param options the commandline options
563: */
564: protected static void runJavadoc(Javadoc javadoc, String[] options) {
565: try {
566: try {
567: if (Utils.getFlag('h', options))
568: throw new Exception("Help requested");
569:
570: javadoc.setOptions(options);
571: Utils.checkForRemainingOptions(options);
572:
573: // directory is necessary!
574: if (javadoc.getDir().length() == 0)
575: throw new Exception("No directory provided!");
576: } catch (Exception ex) {
577: String result = "\n" + ex.getMessage() + "\n\n"
578: + javadoc.generateHelp();
579: throw new Exception(result);
580: }
581:
582: System.out.println(javadoc.generate() + "\n");
583: } catch (Exception ex) {
584: System.err.println(ex.getMessage());
585: }
586: }
587: }
|