0001: /*
0002: * Project: BeautyJ - Customizable Java Source Code Transformer
0003: * Class: de.gulden.util.javasource.sourclet.standard.StandardSourclet
0004: * Version: 1.1
0005: *
0006: * Date: 2004-09-29
0007: *
0008: * Note: Contains auto-generated Javadoc comments created by BeautyJ.
0009: *
0010: * This is licensed under the GNU General Public License (GPL)
0011: * and comes with NO WARRANTY. See file license.txt for details.
0012: *
0013: * Author: Jens Gulden
0014: * Email: beautyj@jensgulden.de
0015: */
0016:
0017: package de.gulden.util.javasource.sourclet.standard;
0018:
0019: import de.gulden.util.javasource.sourclet.*;
0020: import de.gulden.util.javasource.Package;
0021: import de.gulden.util.javasource.Class;
0022: import de.gulden.util.javasource.Exception;
0023: import de.gulden.util.javasource.*;
0024: import de.gulden.util.Toolbox;
0025: import java.io.*;
0026: import java.util.*;
0027: import java.text.*;
0028: import java.lang.reflect.Modifier;
0029:
0030: /**
0031: * The StandardSourclet used by BeautyJ.
0032: * See documentation of Beauty and the Java Sourclet API.
0033: *
0034: * @author Jens Gulden
0035: * @version 1.1
0036: */
0037: public class StandardSourclet extends AbstractSourclet {
0038:
0039: // ------------------------------------------------------------------------
0040: // --- static fields ---
0041: // ------------------------------------------------------------------------
0042:
0043: /**
0044: *
0045: * @see #getSpecialPrefix
0046: * @see #hasSpecialPrefix
0047: */
0048: protected static String[] specialPrefixes = { "get", "set", "add",
0049: "remove", "is", "init", "parse", "create", "build" };
0050:
0051: /**
0052: * These defaults are also named for option doc.exception.texts in the configuration XML File.
0053: * But if they are overwritten by the user, they still get used, so keep here as constant and always add to user's texts.
0054: */
0055: protected static String defaultExceptionTexts = "IOException=if an i/o error occurs,SQLException=if a database error occurs,SAXException=if an XML parser error occurs,NumberFormatException=if the string cannot be parsed as a number";
0056:
0057: // ------------------------------------------------------------------------
0058: // --- fields ---
0059: // ------------------------------------------------------------------------
0060:
0061: /**
0062: * The exception texts.
0063: */
0064: protected Properties exceptionTexts = null;
0065:
0066: /**
0067: * The headerfile text.
0068: */
0069: protected String headerfileText = null;
0070:
0071: // ------------------------------------------------------------------------
0072: // --- constructor ---
0073: // ------------------------------------------------------------------------
0074:
0075: /**
0076: * Creates a new instance of StandardSourclet.
0077: */
0078: public StandardSourclet() {
0079:
0080: }
0081:
0082: // ------------------------------------------------------------------------
0083: // --- methods ---
0084: // ------------------------------------------------------------------------
0085:
0086: /**
0087: * Outputs the start part of a source object.
0088: * This is the part which comes before the 'normal' head
0089: * (e.g. before a method's signature), so usually this is
0090: * the place where to output Javadoc comments.
0091: *
0092: * @throws IOException if an i/o error occurs
0093: */
0094: public void buildStartSource(OutputStream out,
0095: SourceObjectDeclared o) throws IOException {
0096: if (o instanceof Class) {
0097: Class clazz = (Class) o;
0098: if (!(clazz instanceof ClassInner)) {
0099: String headerfile = getHeaderfile();
0100: if (headerfile != null) {
0101: write(out, headerfile);
0102: } else {
0103: String opt;
0104: write(out, "/*" + nl);
0105: opt = getOption("project.name");
0106: if (opt != null) {
0107: write(out, " * Project: " + opt + nl);
0108: }
0109: write(out, " * Class: " + clazz.getName() + nl);
0110: opt = getOption("project.version");
0111: if (opt != null) {
0112: write(out, " * Version: " + opt + nl);
0113: }
0114: opt = getOption("project.date");
0115: if (opt != null) {
0116: String op = opt.trim();
0117: if (op.equalsIgnoreCase("now")
0118: || op.equalsIgnoreCase("today")) {
0119: opt = isodate();
0120: }
0121: write(out, " *" + nl);
0122: write(out, " * Date: " + opt + nl);
0123: }
0124: opt = getOption("project.description");
0125: if (opt != null) {
0126: opt = replace(opt, "\\n", "\n"); // allow line breaks expressed as "\n"
0127: write(out, " *" + nl);
0128: write(out, startWithStars(opt, ""));
0129: }
0130: write(out, " *" + nl);
0131: opt = getOption("author.name");
0132: if (opt != null) {
0133: write(out, " * Author: " + opt + nl);
0134: }
0135: opt = getOption("author.email");
0136: if (opt != null) {
0137: write(out, " * Email: " + opt + nl);
0138: }
0139: write(out, " */" + nl + nl);
0140: }
0141: // package
0142: if (!clazz.getPackage().isBasePackage()) {
0143: write(out, "package "
0144: + clazz.getPackage().getName() + ";" + nl);
0145: }
0146:
0147: // imports
0148: NamedIterator it = clazz.getImports();
0149: if (it.hasMore()) {
0150: write(out, nl);
0151: while (it.hasMore()) {
0152: Import im = (Import) it.next();
0153: write(out, "import " + im.getName() + ";" + nl);
0154: }
0155: }
0156: write(out, nl);
0157: }
0158: }
0159:
0160: // fields, methods, constructors, classes
0161: if ((o instanceof Member) || (o instanceof Class)) {
0162: String type = getTypeCode(o);
0163:
0164: String spaces;
0165: if (o instanceof Class) {
0166: spaces = "";
0167: } else {
0168: spaces = indent(1);
0169: }
0170:
0171: DocumentationDeclared doc = (DocumentationDeclared) o
0172: .getDocumentation();
0173: String text = null;
0174: DocumentationDeclared supDoc = tryGetDocumentationFromSuperclass(o); // inheriting documentation doesn't work properly yet is still undocumented
0175: if ((doc != null) // documentation exists
0176: && (doc instanceof DocumentationDeclared)) {
0177: if (!hasOption(type + ".remove.text", "description")) {
0178: text = doc.getText();
0179: if (text == null || text.equals("")) {
0180: if (supDoc != null) {
0181: text = supDoc.getText();
0182: }
0183: }
0184: }
0185: } else { // documentation doesn't exist yet, try to find in a superclass
0186: if ((supDoc != null)
0187: && (!hasOption(type + ".remove.text",
0188: "description"))) {
0189: text = supDoc.getText();
0190: }
0191: }
0192: // if it's a dummy, remove if option is set to do so
0193: if ((text != null)
0194: && isDummy(text)
0195: && (hasOption(type + ".remove.dummy", "description"))) {
0196: text = null;
0197: }
0198:
0199: // if no documentation found by now (or has been removed by option), maybe auto-generate
0200: if (text == null) {
0201: String unqualifiedName = o.getUnqualifiedName();
0202: String specialPrefix = getSpecialPrefix(unqualifiedName);
0203: if (hasOption(type + ".create.text", "description")) {
0204: if ((o instanceof Constructor)
0205: && hasOption("method.create.text",
0206: "description")) {
0207: text = "Creates a new instance of "
0208: + unqualifiedName + ".";
0209: } else if ((o instanceof Method)
0210: && (specialPrefix != null)
0211: && hasOption("method.create.text",
0212: "description")) {
0213: if (specialPrefix.equals("get")) {
0214: text = "Returns the "
0215: + toWords(unqualifiedName
0216: .substring(specialPrefix
0217: .length())) + ".";
0218: } else if (specialPrefix.equals("set")) {
0219: text = "Sets the "
0220: + toWords(unqualifiedName
0221: .substring(specialPrefix
0222: .length())) + ".";
0223: } else if (specialPrefix.equals("add")) {
0224: text = "Adds a "
0225: + toWords(unqualifiedName
0226: .substring(specialPrefix
0227: .length())) + ".";
0228: } else if (specialPrefix.equals("remove")) {
0229: text = "Removes a "
0230: + toWords(unqualifiedName
0231: .substring(specialPrefix
0232: .length())) + ".";
0233: } else if (specialPrefix.equals("init")) {
0234: text = "Inits the "
0235: + toWords(unqualifiedName
0236: .substring(specialPrefix
0237: .length())) + ".";
0238: } else if (specialPrefix.equals("parse")) {
0239: text = "Parses the "
0240: + toWords(unqualifiedName
0241: .substring(specialPrefix
0242: .length())) + ".";
0243: } else if (specialPrefix.equals("create")) {
0244: text = "Creates the "
0245: + toWords(unqualifiedName
0246: .substring(specialPrefix
0247: .length())) + ".";
0248: } else if (specialPrefix.equals("build")) {
0249: text = "Builds the "
0250: + toWords(unqualifiedName
0251: .substring(specialPrefix
0252: .length())) + ".";
0253: }
0254: } else if ((o instanceof Field)
0255: && hasOption("field.create.text",
0256: "description")) {
0257: if (Modifier.isFinal(o.getModifier())) {
0258: text = "Constant "
0259: + o.getUnqualifiedName()
0260: + SourceParser.repeat("[]",
0261: (((Field) o).getType()
0262: .getDimension()))
0263: + ".";
0264: } else {
0265: text = "The "
0266: + toWords(o.getUnqualifiedName())
0267: + (((Field) o).getType()
0268: .getDimension() > 0 ? " array"
0269: : "") + ".";
0270: }
0271: } else if ((o instanceof Class)
0272: && hasOption("class.create.text",
0273: "description")) {
0274: text = "Class " + o.getUnqualifiedName() + ".";
0275: }
0276: }
0277: // if no text found or generated, maybe generate a dummy
0278: if ((text == null)
0279: && hasOption(type + ".create.dummy",
0280: "description")) {
0281: if (specialPrefix != null) {
0282: if (specialPrefix.equals("is")) {
0283: text = "Tests if ...";
0284: }
0285: }
0286: if (text == null) {
0287: text = "...";
0288: }
0289: }
0290: }
0291:
0292: boolean headDone = false;
0293:
0294: if (text != null) {
0295: write(out, spaces + "/**" + nl);
0296: headDone = true;
0297: write(out, startWithStars(text, spaces));
0298: }
0299:
0300: ByteArrayOutputStream buf = new ByteArrayOutputStream();
0301: buildTagDocumentation(buf, o, doc, supDoc);
0302: if (buf.size() > 0) {
0303: if (!headDone) {
0304: write(out, spaces + "/**" + nl);
0305: headDone = true;
0306: }
0307: write(out, startWithStars(" ", spaces));
0308: buf.writeTo(out);
0309: }
0310: if (headDone) {
0311: write(out, spaces + " */" + nl);
0312: }
0313: }
0314: }
0315:
0316: /**
0317: * Outputs the head part of a source object.
0318: * This is the actual Java code that declares the source object,
0319: * for example a method's signature.
0320: *
0321: * @throws IOException if an i/o error occurs
0322: */
0323: public void buildHeadSource(OutputStream out, SourceObjectDeclared o)
0324: throws IOException {
0325: boolean fullQualify = isOption("code.qualify");
0326:
0327: if (o instanceof Member) {
0328: write(out, indent(1));
0329: }
0330:
0331: String mod = Modifier.toString(o.getModifier());
0332: if (mod.length() > 0) {
0333: write(out, mod + " ");
0334: }
0335:
0336: if (o instanceof Typed) { // Method, Field or Parameter
0337: Typed typed = (Typed) o;
0338: String t;
0339: if (fullQualify) {
0340: t = typed.getType().getFullTypeName();
0341: } else {
0342: t = typed.getType().getFullUnqualifiedTypeName();
0343: String unqualifiedType = typed.getType()
0344: .getUnqualifiedTypeName();
0345: String qualifiedType = typed.getType().getTypeName();
0346: Class declaringClass;
0347: if (!(typed instanceof Parameter)) {
0348: declaringClass = ((SourceObjectDeclared) typed)
0349: .getDeclaringClass();
0350: } else {
0351: declaringClass = ((Parameter) typed)
0352: .getMemberExecutable().getDeclaringClass();
0353: }
0354: if (makeSureIsQualifyable(declaringClass,
0355: unqualifiedType, qualifiedType).equals(
0356: qualifiedType)) {
0357: t = typed.getType().getFullTypeName(); // 'fallback' to fully qualified
0358: }
0359: if (t.indexOf('.') != -1) {
0360: // Although unqualified, inner classes will be lead by classname-prefix.
0361: // Remove this prefix if it is the current class.
0362: if (declaringClass != null) {
0363: String this Classname = declaringClass
0364: .getUnqualifiedName();
0365: if (t.startsWith(this Classname + ".")) {
0366: t = t.substring(this Classname.length() + 1);
0367: }
0368: }
0369: }
0370: }
0371: write(out, t + " ");
0372: }
0373:
0374: if (o instanceof Class) {
0375: Class clazz = (Class) o;
0376: write(out, clazz.isInterface() ? "interface " : "class ");
0377: }
0378:
0379: // name
0380: write(out, o.getUnqualifiedName());
0381:
0382: if (o instanceof Class) {
0383: Class clazz = (Class) o;
0384: String sup = clazz.getSuperclassName();
0385: if (!sup.equals("java.lang.Object")) {
0386: String s = sup;
0387: if (!fullQualify) {
0388: s = unqualifyClassname(clazz, s);
0389: }
0390: write(out, " extends " + s);
0391: }
0392:
0393: // implemented interfaces
0394: Enumeration en = clazz.getInterfaceNames();
0395: if (en.hasMoreElements()) {
0396: if (!clazz.isInterface()) {
0397: write(out, " implements ");
0398: } else {
0399: write(out, " extends ");
0400: }
0401: while (en.hasMoreElements()) {
0402: String in = (String) en.nextElement();
0403: if (!fullQualify) {
0404: in = unqualifyClassname(clazz, in);
0405: }
0406: write(out, in
0407: + (en.hasMoreElements() ? (", ") : ""));
0408: }
0409: }
0410: }
0411:
0412: else if (o instanceof MemberExecutable) {
0413: MemberExecutable mex = (MemberExecutable) o;
0414: // parameters
0415: write(out, "(");
0416: for (NamedIterator it = mex.getParameters(); it.hasMore();) {
0417: Parameter pa = (Parameter) it.next();
0418: buildSource(out, pa);
0419: if (it.hasMore()) {
0420: write(out, ", ");
0421: }
0422: }
0423: write(out, ")");
0424:
0425: // exceptions
0426: NamedIterator it = mex.getExceptions();
0427: if (it.hasMore()) {
0428: write(out, " throws ");
0429: while (it.hasMore()) {
0430: Exception ex = (Exception) it.next();
0431: String exx;
0432: if (!fullQualify) {
0433: exx = ex.getUnqualifiedName();
0434: exx = makeSureIsQualifyable(mex
0435: .getDeclaringClass(), exx, ex.getName());
0436: } else {
0437: exx = ex.getName();
0438: }
0439:
0440: write(out, exx + (it.hasMore() ? ", " : ""));
0441: }
0442: }
0443: }
0444: }
0445:
0446: /**
0447: * Outputs the body content of the source object. For example,
0448: * in case of methods this is Java code, in case of classes this recursively
0449: * contains other SourceObjects' code.
0450: *
0451: * @throws IOException if an i/o error occurs
0452: */
0453: public void buildBodySource(OutputStream out, SourceObjectDeclared o)
0454: throws IOException {
0455:
0456: boolean bracesLinebreak = isOption("code.braces.linebreak");
0457:
0458: // --- class
0459:
0460: if (o instanceof Class) {
0461: Class clazz = (Class) o;
0462: NamedIterator it = clazz.getAllMembers();
0463: if (bracesLinebreak) { // start with curly brace on individual line
0464: write(out, nl + "{");
0465: if (!isOption("code.separators")) {
0466: write(out, nl);
0467: }
0468: } else { // output curly brace at the end of the method's declaration
0469: write(out, " {" + nl);
0470: }
0471:
0472: Vector todo = new Vector();
0473:
0474: if (isOption("code.preserve.fields.order")) {
0475:
0476: it.reset();
0477: boolean firstField = true;
0478: while (it.hasMore()) {
0479: Member m = (Member) it.next();
0480: if (m instanceof Field) {
0481: todo.addElement(m);
0482: //buildSourceAll(out,todo,(Modifier.isFinal(m.getModifier()) ? "final ":"") + "static field"); // will generate a header for each field, but that doesn't do any harm (called individually for each element to preserve order)
0483: }
0484: }
0485:
0486: buildHeader(out, '-', "field", "fields", todo.size());
0487:
0488: Vector singleTodo = new Vector();
0489: for (Enumeration e = todo.elements(); e
0490: .hasMoreElements();) {
0491: singleTodo.removeAllElements();
0492: singleTodo.addElement(e.nextElement());
0493: buildSourceAll(out, singleTodo, null); // build single elements
0494: }
0495:
0496: } else { // normal beautification: order by final-static / static / non-static and public / protected / friendly / private
0497:
0498: it.reset();
0499: while (it.hasMore()) {
0500: Member m = (Member) it.next();
0501: if ((m instanceof Field)
0502: && Modifier.isStatic(m.getModifier())
0503: && Modifier.isFinal(m.getModifier())) {
0504: todo.addElement(m);
0505: }
0506: }
0507: buildSourceAll(out, todo, "final static field");
0508:
0509: it.reset();
0510: todo.removeAllElements();
0511: while (it.hasMore()) {
0512: Member m = (Member) it.next();
0513: if ((m instanceof Field)
0514: && Modifier.isStatic(m.getModifier())
0515: && (!Modifier.isFinal(m.getModifier()))) {
0516: todo.addElement(m);
0517: }
0518: }
0519: buildSourceAll(out, todo, "static field");
0520:
0521: it.reset();
0522: todo.removeAllElements();
0523: while (it.hasMore()) {
0524: Member m = (Member) it.next();
0525: if ((m instanceof Field)
0526: && (!Modifier.isStatic(m.getModifier()))) {
0527: todo.addElement(m);
0528: }
0529: }
0530: buildSourceAll(out, todo, "field");
0531:
0532: }
0533:
0534: // initializers (must appear after field declarations to avoid forward references)
0535:
0536: Code[] initializers = clazz.getStaticInitializers();
0537: if (initializers.length > 0) {
0538: buildHeader(out, '-', "static initializer",
0539: initializers.length);
0540: for (int i = 0; i < initializers.length; i++) {
0541: String code = initializers[i].getRaw();
0542: code = applyCodeFormatting(code);
0543: write(out, indent("static {", 1));
0544: write(out, nl);
0545: write(out, code);
0546: write(out, nl);
0547: write(out, indent("}", 1));
0548: write(out, nl);
0549: }
0550: }
0551:
0552: initializers = clazz.getInstanceInitializers();
0553: if (initializers.length > 0) {
0554: buildHeader(out, '-', "instance initializer",
0555: initializers.length);
0556: for (int i = 0; i < initializers.length; i++) {
0557: String code = initializers[i].getRaw();
0558: code = applyCodeFormatting(code);
0559: write(out, indent("{", 1));
0560: write(out, nl);
0561: write(out, code);
0562: write(out, nl);
0563: write(out, indent("}", 1));
0564: write(out, nl);
0565: }
0566: }
0567:
0568: it.reset();
0569: todo.removeAllElements();
0570: while (it.hasMore()) {
0571: Member m = (Member) it.next();
0572: if (m instanceof Constructor) {
0573: todo.addElement(m);
0574: }
0575: }
0576: buildSourceAll(out, todo, "constructor");
0577:
0578: it.reset();
0579: todo.removeAllElements();
0580: while (it.hasMore()) {
0581: Member m = (Member) it.next();
0582: if ((m instanceof Method)
0583: && (!Modifier.isStatic(m.getModifier()))) {
0584: todo.addElement(m);
0585: }
0586: }
0587: buildSourceAll(out, todo, "method");
0588:
0589: it.reset();
0590: todo.removeAllElements();
0591: while (it.hasMore()) {
0592: Member m = (Member) it.next();
0593: if ((m instanceof Method)
0594: && (Modifier.isStatic(m.getModifier()))) {
0595: todo.addElement(m);
0596: }
0597: }
0598: buildSourceAll(out, todo, "static method");
0599:
0600: // inner classes and interfaces
0601:
0602: it = clazz.getInnerClasses();
0603: if (it.size() > 0) {
0604: buildHeader(out, '*', (it.size() == 1) ? "inner class"
0605: : "inner classes");
0606: while (it.hasMore()) {
0607: Class c = (Class) it.next();
0608: ByteArrayOutputStream outInner = new ByteArrayOutputStream();
0609: buildSource(outInner, c);
0610: String shifted = indent(new String(outInner
0611: .toByteArray()), 1);
0612: write(out, shifted + nl);
0613: }
0614: }
0615:
0616: write(out, "} // end " + clazz.getUnqualifiedName() + nl);
0617: }
0618:
0619: // --- method / field
0620:
0621: else if ((o instanceof MemberExecutable)
0622: || (o instanceof Field)) {
0623: Code code;
0624: if (o instanceof MemberExecutable) {
0625: code = ((MemberExecutable) o).getCode();
0626: } else {
0627: code = ((Field) o).getCode();
0628: }
0629:
0630: if (code != null) {
0631: String c = code.getRaw();
0632: if (o instanceof MemberExecutable) {
0633: if (isOption("code.braces.linebreak")) { // start with curly brace on individual line
0634: write(out, nl);
0635: write(out, indent("{", 1) + nl);
0636: } else { // output curly brace at the end of the method's declaration
0637: write(out, " {" + nl);
0638: }
0639: c = applyCodeFormatting(c);
0640: write(out, c + nl);
0641: write(out, indent("}", 1) + nl);
0642: } else { // Field
0643: write(out, " = " + c + ";" + nl);
0644: }
0645: } else {
0646: write(out, ";" + nl);
0647: }
0648: write(out, nl);
0649: }
0650: }
0651:
0652: /**
0653: * Outputs everything that occurs after the SourceObject.
0654: *
0655: * @throws IOException if an i/o error occurs
0656: */
0657: public void buildEndSource(OutputStream out, SourceObjectDeclared o)
0658: throws IOException {
0659: //nop
0660: }
0661:
0662: /**
0663: * Returns the associated description for the exception class name specified by <code>exc</code>.
0664: */
0665: protected String getExceptionText(String exc) {
0666: if (exceptionTexts == null) { // auto-init on first call
0667: exceptionTexts = new Properties();
0668: String t = defaultExceptionTexts
0669: + getOption("exception.texts"); // repeat defaultExceptionTexts to make sure that defaults are contained if the user sets own value, append in front to make user settings able to overwrite defaults
0670: StringTokenizer st = new StringTokenizer(t, ",", false);
0671: while (st.hasMoreTokens()) {
0672: String s = st.nextToken();
0673: StringTokenizer st2 = new StringTokenizer(s, "=", false);
0674: String exception = st2.nextToken();
0675: String text = st2.nextToken();
0676: if (!(exception == null || text == null || st2
0677: .hasMoreTokens())) {
0678: exceptionTexts.setProperty(exception.trim(), text
0679: .trim());
0680: } else {
0681: // illegal option format, ignore
0682: }
0683: }
0684: }
0685: return exceptionTexts.getProperty(exc);
0686: }
0687:
0688: /**
0689: * If a headerfile is specified, get the content as string.
0690: */
0691: protected String getHeaderfile() {
0692: if (headerfileText == null) {
0693: // auto-init from project.headerfile
0694: String filename = getOption("project.headerfile");
0695: if (filename != null) {
0696: File file = new File(filename);
0697: if (file.isFile()) {
0698: try {
0699: char[] c = new char[(int) file.length()];
0700: FileReader f = new FileReader(file);
0701: f.read(c);
0702: f.close();
0703: headerfileText = new String(c);
0704: } catch (IOException e) {
0705: headerfileText = "/* ERROR READING HEADERFILE '"
0706: + filename + "' */";
0707: }
0708: }
0709: }
0710: }
0711: return headerfileText; // null if no headerfile
0712: }
0713:
0714: /**
0715: * Builds the tag documentation.
0716: *
0717: * @throws IOException if an i/o error occurs
0718: */
0719: protected void buildTagDocumentation(OutputStream out,
0720: SourceObjectDeclared o, DocumentationDeclared doc,
0721: DocumentationDeclared supDoc) throws IOException {
0722: // parameters doc, supDoc may be null
0723: if (o instanceof Class) {
0724: Class clazz = (Class) o;
0725: // @author
0726: String opt;
0727: opt = getOption("author.name");
0728: if (opt != null) {
0729: buildTagDocumentationSynthesize(out, "class", "author",
0730: null, opt, doc, supDoc, "", true);
0731: }
0732: // @version
0733: opt = getOption("project.version");
0734: if (opt != null) {
0735: buildTagDocumentationSynthesize(out, "class",
0736: "version", null, opt, doc, supDoc, "", true);
0737: }
0738: } else if (o instanceof MemberExecutable) {
0739: MemberExecutable mex = (MemberExecutable) o;
0740: String unqualifiedName = o.getUnqualifiedName();
0741: String specialPrefix = getSpecialPrefix(unqualifiedName);
0742:
0743: // @param
0744: boolean createText = hasOption("method.create.text",
0745: "param");
0746: boolean createDummy = hasOption("method.create.dummy",
0747: "param");
0748: String type = getTypeCode(o);
0749: for (NamedIterator it = mex.getParameters(); it.hasMore();) {
0750: Parameter pa = (Parameter) it.next();
0751: String def = null;
0752: if (createText && (specialPrefix != null)
0753: && (specialPrefix.equals("set"))) {
0754: def = "The "
0755: + toWords(unqualifiedName
0756: .substring(specialPrefix.length()))
0757: + (pa.getType().getDimension() > 0 ? " array"
0758: : "") + ".";
0759: } else if (createText) {
0760: String n = pa.getName();
0761: if (n.length() < 3) { // use type name if too short identifier
0762: n = pa.getType().getUnqualifiedTypeName();
0763: }
0764: def = "The "
0765: + toWords(n)
0766: + (pa.getType().getDimension() > 0 ? " array"
0767: : "") + ".";
0768: } else if (createDummy) {
0769: def = "The ...";
0770: }
0771: buildTagDocumentationSynthesize(out, type, "param", pa
0772: .getName(), def, doc, supDoc, indent(1), true);
0773: }
0774:
0775: // @throws
0776: createText = hasOption("method.create.text", "throws");
0777: createDummy = hasOption("method.create.dummy", "throws");
0778: for (NamedIterator it = mex.getExceptions(); it.hasMore();) {
0779: Exception ex = (Exception) it.next();
0780: String exc = ex.getUnqualifiedName();
0781: // is there a text given for that particular exception?
0782: String def = getExceptionText(exc);
0783: // if no text given, synthesize dummy (if dummy option enabled)
0784: if (createDummy && (def == null)) {
0785: def = "if ...";
0786: }
0787: buildTagDocumentationSynthesize(out, type, "throws",
0788: exc, def, doc, supDoc, indent(1), true);
0789: }
0790:
0791: // @return
0792: if (o instanceof Method) {
0793: Method met = (Method) o;
0794: createText = hasOption("method.create.text", "return");
0795: createDummy = hasOption("method.create.text", "return");
0796: if (!(met.getType().getFullTypeName().equals("void"))) {
0797: // get default text
0798: String def = null;
0799: if (createText && (specialPrefix != null)
0800: && specialPrefix.equals("get")) {
0801: def = "The "
0802: + toWords(unqualifiedName
0803: .substring(specialPrefix
0804: .length()))
0805: + (met.getType().getDimension() > 0 ? " array"
0806: : "") + ".";
0807: } else if (createText) {
0808: def = "The "
0809: + toWords(met.getType()
0810: .getUnqualifiedTypeName())
0811: + (met.getType().getDimension() > 0 ? " array"
0812: : "") + ".";
0813: } else if (createDummy) {
0814: def = "The ...";
0815: }
0816: buildTagDocumentationSynthesize(out, "method",
0817: "return", null, def, doc, supDoc,
0818: indent(1), true);
0819: }
0820: }
0821: // @see - not useful
0822: }
0823: // copy all other tags
0824: if (doc != null) {
0825: for (Enumeration e = doc.getTags(); e.hasMoreElements();) {
0826: DocumentationTagged dt = (DocumentationTagged) e
0827: .nextElement();
0828: if ((!dt.getTag().equals("@param"))
0829: && (!dt.getTag().equals("@throws"))
0830: && (!dt.getTag().equals("@return"))
0831: && (!((o instanceof Class) && (dt.getTag()
0832: .equals("@author"))))
0833: && (!((o instanceof Class) && (dt.getTag()
0834: .equals("@version"))))) {
0835: buildDocumentationTagged(out, dt,
0836: (o instanceof Class) ? "" : indent(1));
0837: }
0838: }
0839: } else if (supDoc != null) {
0840: for (Enumeration e = supDoc.getTags(); e.hasMoreElements();) {
0841: DocumentationTagged dt = (DocumentationTagged) e
0842: .nextElement();
0843: if ((!dt.getTag().equals("@param"))
0844: && (!dt.getTag().equals("@throws"))
0845: && (!dt.getTag().equals("@return"))
0846: && (!((o instanceof Class) && (dt.getTag()
0847: .equals("@author"))))
0848: && (!((o instanceof Class) && (dt.getTag()
0849: .equals("@version"))))) {
0850: buildDocumentationTagged(out, dt,
0851: (o instanceof Class) ? "" : indent(1));
0852: }
0853: }
0854: }
0855: }
0856:
0857: /**
0858: * Builds the tag documentation synthesize.
0859: *
0860: * @throws IOException if an i/o error occurs
0861: */
0862: protected void buildTagDocumentationSynthesize(OutputStream out,
0863: String typeName, String tagName, String tagItem,
0864: String defaultValue, DocumentationDeclared doc,
0865: DocumentationDeclared supDoc, String spaces,
0866: boolean synthesize) throws IOException {
0867: // parameters defaultValue, doc, supDoc may be null
0868: DocumentationTagged tag = null;
0869: // tag already there?
0870: if (doc != null) {
0871: if (!hasOption(typeName + ".remove.text", tagName)) {
0872: tag = doc.findTag("@" + tagName, tagItem);
0873: }
0874: String text = null;
0875: if (tag != null) {
0876: text = tag.getText();
0877: }
0878: if ((text == null) || (text.trim().length() == 0)) {
0879: tag = null;
0880: }
0881: // remove dummy if activated
0882: if ((tag != null) && isDummy(text)
0883: && hasOption(typeName + ".remove.dummy", tagName)) {
0884: tag = null;
0885: }
0886: }
0887: // is there a matching documentation tag in superclass documentation?
0888: if (tag == null) {
0889: if (supDoc != null) {
0890: tag = supDoc.findTag("@" + tagName, tagItem);
0891: }
0892: String text = null;
0893: if (tag != null) {
0894: text = tag.getText();
0895: }
0896: if ((text == null) || (text.trim().length() == 0)) {
0897: tag = null;
0898: }
0899: // remove dummy if activated
0900: if ((tag != null)
0901: && (isDummy(text) && (hasOption(typeName
0902: + ".remove.dummy", tagName)))) {
0903: tag = null;
0904: }
0905: }
0906: // auto-generate
0907: if ((tag == null) && synthesize && (defaultValue != null)) {
0908: tag = new DocumentationTagged();
0909: tag.setTag("@" + tagName);
0910: tag.setItem(tagItem);
0911: tag.setText(defaultValue);
0912: }
0913: // output if something found or generated
0914: if (tag != null) {
0915: buildDocumentationTagged(out, tag, spaces);
0916: }
0917: }
0918:
0919: /**
0920: * Builds all source objects in Vector <code>v</code>, sorted by
0921: * <ul>
0922: * <li><b>public</b></li>
0923: * <li><b>protected</b></li>
0924: * <li><b>package-private</b></li>
0925: * <li><b>private</b></li>
0926: * </ul>
0927: * modifiers.<br>
0928: * In front of the generated code, a header is attached which names the type
0929: * of the source objects, distinguishing between singular (if v.size()==1) and plural (f v.size()>1) form.<br>
0930: * Here, the plural form is derived from simply adding an 's', which works for
0931: * most english words.
0932: *
0933: * @throws IOException if an i/o error occurs
0934: */
0935: protected void buildSourceAll(OutputStream out, Vector v,
0936: String header) throws IOException {
0937: //, InvalidOptionException
0938: String headerPlural;
0939: if (header != null) {
0940: headerPlural = header + "s";
0941: } else {
0942: headerPlural = null;
0943: }
0944:
0945: buildSourceAll(out, v, header, headerPlural);
0946: }
0947:
0948: /**
0949: * Builds all source objects in Vector <code>v</code>, sorted by
0950: * <ul>
0951: * <li><b>public</b></li>
0952: * <li><b>protected</b></li>
0953: * <li><b>package-private</b></li>
0954: * <li><b>private</b></li>
0955: * </ul>
0956: * modifiers.<br>
0957: * In front of the generated code, a header is attached which names the type
0958: * of the source objects, distinguishing between singular (if v.size()==1) and plural (f v.size()>1) form.
0959: *
0960: * @throws IOException if an i/o error occurs
0961: */
0962: protected void buildSourceAll(OutputStream out, Vector v,
0963: String header, String headerPlural) throws IOException {
0964: if (!v.isEmpty()) {
0965: if ((header != null) && (headerPlural != null)) {
0966: buildHeader(out, '-', header, headerPlural, v.size());
0967: }
0968: // public
0969: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0970: SourceObjectDeclared o = (SourceObjectDeclared) e
0971: .nextElement();
0972: if (Modifier.isPublic(o.getModifier())) {
0973: buildSource(out, o);
0974: }
0975: }
0976: // protected
0977: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0978: SourceObjectDeclared o = (SourceObjectDeclared) e
0979: .nextElement();
0980: if (Modifier.isProtected(o.getModifier())) {
0981: buildSource(out, o);
0982: }
0983: }
0984: // friendly
0985: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0986: SourceObjectDeclared o = (SourceObjectDeclared) e
0987: .nextElement();
0988: if ((!Modifier.isPublic(o.getModifier()))
0989: && (!Modifier.isProtected(o.getModifier()))
0990: && (!Modifier.isPrivate(o.getModifier()))) {
0991: buildSource(out, o);
0992: }
0993: }
0994: // private
0995: for (Enumeration e = v.elements(); e.hasMoreElements();) {
0996: SourceObjectDeclared o = (SourceObjectDeclared) e
0997: .nextElement();
0998: if (Modifier.isPrivate(o.getModifier())) {
0999: buildSource(out, o);
1000: }
1001: }
1002: }
1003: }
1004:
1005: /**
1006: * Outputs a seperating header, if the corresponding option is set.
1007: *
1008: * @throws IOException if an i/o error occurs
1009: */
1010: protected void buildHeader(OutputStream out, char mark,
1011: String header) throws IOException {
1012: if (isOption("code.separators")) {
1013: write(out, nl
1014: + indent("// " + chars(mark, 72) + nl + "// "
1015: + chars(mark, 3) + " " + header
1016: + spaces(65 - header.length())
1017: + chars(mark, 3) + nl + "// "
1018: + chars(mark, 72) + nl, 1) + nl);
1019: }
1020: }
1021:
1022: /**
1023: * Outputs a seperating header, if the corresponding option is set. Depending on <code>num</code>,
1024: * the plural or singular form is used (or nothing, if num==0).
1025: *
1026: * @throws IOException if an i/o error occurs
1027: */
1028: protected void buildHeader(OutputStream out, char mark,
1029: String header, String headerPlural, int num)
1030: throws IOException {
1031: if (num > 0) {
1032: buildHeader(out, mark, (num != 1 ? headerPlural : header));
1033: }
1034: }
1035:
1036: /**
1037: * Outputs a seperating header, if the corresponding option is set. Depending on <code>num</code>,
1038: * a plural or singular form is used (or nothing, if num==0). The plural is auto-generated by adding an 's'.
1039: *
1040: * @throws IOException if an i/o error occurs
1041: */
1042: protected void buildHeader(OutputStream out, char mark,
1043: String header, int num) throws IOException {
1044: buildHeader(out, mark, header, header + "s", num);
1045: }
1046:
1047: /**
1048: * Indents a given block of text by the given number of steps.
1049: * The size of each step in 'number of spaces' is set by option
1050: * code.indent.spaces.
1051: *
1052: * @return Indented text.
1053: */
1054: protected String indent(String text, int steps) {
1055: StringTokenizer st = new StringTokenizer(text, "\n\r", true);
1056: StringBuffer sb = new StringBuffer();
1057: int spaces = getIntOption("code.indent.spaces"); // TODO: optimize
1058: char lastBreak = (char) 0;
1059:
1060: while (st.hasMoreTokens()) {
1061: String line = st.nextToken();
1062: char first = line.charAt(0);
1063: if (first == '\n' || first == '\r') { // delimiter token
1064: if ((lastBreak == (char) 0) || lastBreak == first) {
1065: sb.append(nl); // etxtra blank line
1066: lastBreak = first;
1067: }
1068: } else { // full line token
1069: sb.append(spaces(steps * spaces));
1070: sb.append(line);
1071: lastBreak = (char) 0;
1072: }
1073: }
1074: return sb.toString();
1075: }
1076:
1077: /**
1078: * Returns a string with spaces. The number is determined by steps*option('code.indent.spaces').
1079: */
1080: protected String indent(int steps) {
1081: int spaces = getIntOption("code.indent.spaces"); // TODO: optimize
1082: return spaces(steps * spaces);
1083: }
1084:
1085: /**
1086: * Apply code transformations according to options set by the user.
1087: */
1088: protected String applyCodeFormatting(String code) {
1089: if (isOption("code.clean")) {
1090: code = cleanCode(code);
1091: }
1092: if (isOption("code.format")) {
1093: code = format(code);
1094: }
1095: code = indent(code, 2);
1096: return code;
1097: }
1098:
1099: /**
1100: * Format a code block according to standard auto-indentation rules.
1101: * This is a quick solution and could be done much more sophisticated.
1102: * (The current version of the StandardSourclet puts focus in the overall
1103: * organization of .java files, not primarily on the code blocks.)
1104: * Maybe later versions should incorporate mature code from other OpenSource
1105: * beautifier projects here - volunteers welcome!
1106: */
1107: protected String format(String code) {
1108: int codeLength = code.length();
1109: if (codeLength > 0) {
1110: StringBuffer sb = new StringBuffer();
1111: StringBuffer line = new StringBuffer();
1112: char quoted = (char) 0;
1113: char comment = (char) 0;
1114: boolean escape = false;
1115: int indentLevel = 0;
1116: int indentLevelDiff = 0;
1117: boolean newline = false;
1118: boolean previousNewline = false;
1119: int i = 0;
1120: char c = (char) 0;
1121: char prevC;
1122: char nextC = code.charAt(0);
1123:
1124: while (i < codeLength) {
1125: prevC = c;
1126: c = nextC;
1127: if (i < codeLength - 1) {
1128: nextC = code.charAt(i + 1);
1129: } else {
1130: nextC = (char) 0;
1131: }
1132:
1133: if (escape) { // escaped char
1134: line.append(c);
1135: escape = false;
1136:
1137: } else if (comment == '/') { // line comment
1138: if (c == '\n') {
1139: newline = true;
1140: previousNewline = true;
1141: comment = (char) 0;
1142: }
1143: line.append(c);
1144:
1145: } else if (comment == '*') { // block comment
1146: if (c == '/' && prevC == '*') {
1147: comment = (char) 0;
1148: }
1149: line.append(c);
1150:
1151: } else if (quoted != (char) 0) { // quoted text, either ".." or '..'
1152:
1153: if (c == '\\') {
1154: escape = true;
1155: } else if (quoted == c) { // quote char again: end quoting
1156: quoted = (char) 0;
1157: }
1158: line.append(c);
1159:
1160: } else { // normal code
1161:
1162: switch (c) {
1163: case '\\':
1164: escape = true;
1165: break;
1166: case '/':
1167: if (nextC == '/' || nextC == '*') {
1168: comment = nextC;
1169: }
1170: break;
1171: case '\"':
1172: case '\'':
1173: quoted = c;
1174: break;
1175: case '\n':
1176: newline = previousNewline; // explicit newline only if no other (auto-generated) newline since last explicit newline
1177: previousNewline = true;
1178: break;
1179: case ';':
1180: String l = line.toString().trim();
1181: if (!l.startsWith("for")) { // special: no line break after ; in for-loop declaration
1182: newline = true;
1183: }
1184: break;
1185: case '{':
1186: newline = true;
1187: indentLevelDiff = +1;
1188: break;
1189: case '}':
1190: l = line.toString().trim();
1191: if (l.length() > 0) { // already something there in current line: write as own line
1192: sb.append(indent(l, indentLevel) + nl);
1193: line = new StringBuffer();
1194: }
1195: indentLevel -= 1;
1196: newline = (nextC == '\n'); // cheap trick to make sure we don't loose blank lines after } (will fail if e.g. "} \n" )
1197: break;
1198: }
1199: line.append(c);
1200:
1201: }
1202:
1203: i++; // next char
1204: if (i >= codeLength) { // always output last line if end reached
1205: newline = true;
1206: }
1207: if (newline) {
1208: sb.append(indent(line.toString().trim(),
1209: indentLevel));
1210: if (i < codeLength) { // prepare for next line if end not reached,also output nl only in that case
1211: sb.append(nl);
1212: indentLevel += indentLevelDiff;
1213: indentLevelDiff = 0;
1214: line = new StringBuffer();
1215: newline = false;
1216: previousNewline = false;
1217: }
1218: }
1219:
1220: }
1221: return sb.toString();
1222: } else {
1223: return "";
1224: }
1225: }
1226:
1227: protected String unqualifyClassname(Class inClass, String name) {
1228: String result;
1229: if (name.indexOf('.') != -1) { // not unqualified already
1230: String u = unqualify(name);
1231: String rest = name.substring(0, name.length() - u.length()
1232: - 1);
1233: // is parent-identifier a class? (not package) - then it is an inner class
1234: if (Package.isSourcePackage(inClass.getPackage()
1235: .getBasePackage(), rest)) { // optimization, but will not find a package if from classpath
1236: result = u;
1237: } else {
1238: String outer;
1239: try {
1240: outer = inClass.qualify(rest);
1241: result = unqualifyClassname(inClass, outer) + "."
1242: + u;
1243: } catch (NoClassDefFoundError ncdfe) {
1244: result = u;
1245: }
1246: }
1247: } else {
1248: result = name;
1249: }
1250: return makeSureIsQualifyable(inClass, result, name);
1251: }
1252:
1253: /**
1254: * Tests if an unqulified class name can be fully qualified inside a class declaration.
1255: * If this is not the case, depending on the user-option '-code.auto.import' an import statement
1256: * is generated, or just a warning message is output.
1257: */
1258: protected String makeSureIsQualifyable(Class inClass,
1259: String unqualified, String qualified) {
1260: try {
1261: inClass.qualify(unqualified);
1262: return unqualified;
1263: } catch (NoClassDefFoundError ncdfe) {
1264: if (isOption("code.qualify.auto")) {
1265: // auto-generate import statement
1266: return qualified;
1267: } else {
1268: System.err
1269: .println("warning: in class "
1270: + inClass.getName()
1271: + ": outputting unqualified classname '"
1272: + unqualified
1273: + "', although it seems to be not fully qualifyable. If this leads to problems when compiling, try option -code.qualify.auto, or use -code.qualify to always use fully qualified classnames.");
1274: return unqualified;
1275: }
1276: }
1277: }
1278:
1279: // ------------------------------------------------------------------------
1280: // --- static methods ---
1281: // ------------------------------------------------------------------------
1282:
1283: /**
1284: * Appends a vertical line of star characters in front of <code>s</code>.
1285: * <code>s</code> may contain multiple lines, seperated by either \n or \r,
1286: * in that case a multi-line result is returned.
1287: */
1288: public static String startWithStars(String s, String spaces) {
1289: StringTokenizer st = new StringTokenizer(s, "\r\n");
1290: StringBuffer sb = new StringBuffer();
1291: while (st.hasMoreTokens()) {
1292: sb.append(spaces + " * " + st.nextToken() + nl);
1293: }
1294: return sb.toString();
1295: }
1296:
1297: /**
1298: * Return the name part of an identifier behind the last '.' occurrence.
1299: *
1300: * @param n The qualified (or already unqualified) identifier name.
1301: * @return The unqualified identifier name.
1302: */
1303: public static String unqualify(String n) {
1304: int pos = n.lastIndexOf('.');
1305: if (pos != -1) {
1306: return n.substring(pos + 1);
1307: } else {
1308: return n;
1309: }
1310: }
1311:
1312: /**
1313: * Returns a string repeating the character <code>mark</code>
1314: * for <code>count</code> times.
1315: */
1316: public static String chars(char mark, int count) {
1317: StringBuffer sb = new StringBuffer();
1318: for (int i = 0; i < count; i++) {
1319: sb.append(mark);
1320: }
1321: return sb.toString();
1322: }
1323:
1324: /**
1325: * Returns a string repeating the space character
1326: * for <code>count</code> times.
1327: */
1328: public static String spaces(int count) {
1329: return chars(' ', count);
1330: }
1331:
1332: /**
1333: * Replaces all occurrences of string <code>find</code> in <code>s</code> by <code>repl</code>.
1334: */
1335: public static String replace(String s, String find, String repl) {
1336: int pos = s.indexOf(find);
1337: if (pos != -1) {
1338: return s.substring(0, pos)
1339: + repl
1340: + replace(s.substring(pos + find.length()), find,
1341: repl);
1342: } else {
1343: return s;
1344: }
1345: }
1346:
1347: /**
1348: * Returns the current date in ISO date format yyyy-MM-dd.
1349: */
1350: public static String isodate() {
1351: SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
1352: return formatter.format(new Date());
1353: }
1354:
1355: /**
1356: * Returns the special prefix of the identifer, if there is any.
1357: * Otherwise <code>null</code> is returned.
1358: *
1359: * @see #specialPrefixes
1360: */
1361: public static String getSpecialPrefix(String id) {
1362: for (int i = 0; i < specialPrefixes.length; i++) {
1363: int l = specialPrefixes[i].length();
1364: if ((id.length() > l) && id.startsWith(specialPrefixes[i])
1365: && Character.isUpperCase(id.charAt(l)) // next char after prefix must be upper case
1366: ) {
1367: return specialPrefixes[i];
1368: }
1369: }
1370: return null;
1371: }
1372:
1373: /**
1374: * Tests whether the identifier has a special prefix.
1375: *
1376: * @see #specialPrefixes
1377: */
1378: public static boolean hasSpecialPrefix(String id) {
1379: return getSpecialPrefix(id) != null;
1380: }
1381:
1382: /**
1383: * Convert a string of format "xxxYyyyZzzz" to "xxx yyyy zzzz".
1384: * This is a simple mechanism to retrieve english language
1385: * for auto-generating Javadoc comments from semantically rich identifier names.
1386: *
1387: * @param s The identifier name.
1388: * @return English language fragment retrieved from identifier name.
1389: */
1390: public static String toWords(String s) {
1391: if (s.length() > 0) {
1392: int end = 1;
1393: while ((end < s.length())
1394: && (!Character.isUpperCase(s.charAt(end)))) {
1395: end++;
1396: }
1397: if (end == s.length()) {
1398: return s.toLowerCase();
1399: } else {
1400: return s.substring(0, end).toLowerCase() + " "
1401: + toWords(s.substring(end)); // recursion
1402: }
1403: } else {
1404: return "";
1405: }
1406: }
1407:
1408: public static boolean isDummy(String text) {
1409: return text.indexOf("...") != -1; // Strings like "The result is..." are also dummies.
1410: }
1411:
1412: /**
1413: * Removes out-commented dead lines of from a block of Java code.
1414: *
1415: * @see #isDeadCodeLine
1416: */
1417: public static String cleanCode(String c) {
1418: BufferedReader b = new BufferedReader(new StringReader(c));
1419: StringBuffer r = new StringBuffer();
1420: try {
1421: String l = b.readLine();
1422: while (l != null) {
1423: String nextL = b.readLine();
1424: if (!isDeadCodeLine(l)) {
1425: r.append(l);
1426: if (nextL != null) {
1427: r.append(nl);
1428: }
1429: }
1430: l = nextL;
1431: }
1432: } catch (IOException io) {
1433: r.append("// *** ERROR: IOException while cleaning code");
1434: }
1435: return r.toString();
1436: }
1437:
1438: /**
1439: * Tests whether a line of Java code is an out-commented dead line of code.
1440: * This is the case when it starts with "//" and end with either ';', '{' or '}'.
1441: */
1442: public static boolean isDeadCodeLine(String l) {
1443: l = l.trim();
1444: return l.startsWith("//")
1445: && (l.endsWith(";") || l.endsWith("{") || l
1446: .endsWith("}"));
1447: }
1448:
1449: /**
1450: * Returns the canonical string representation of a SourceObject's type.
1451: */
1452: public static String getTypeCode(SourceObject o) {
1453: String c = unqualify(o.getClass().getName()).toLowerCase();
1454: if (c.equals("constructor")) {
1455: c = "method"; // use same parameters for constructors and methods
1456: } else if (c.equals("classinner")) {
1457: c = "class";
1458: }
1459: return c;
1460: }
1461:
1462: /**
1463: * Returns the parent part of a fully qualified identifier name.
1464: */
1465: protected static String getParentQualifier(String name) {
1466: int pos = name.lastIndexOf('.');
1467: if (pos != -1) {
1468: name = name.substring(0, pos);
1469: } else {
1470: name = null;
1471: }
1472: return name;
1473: }
1474:
1475: protected static DocumentationDeclared tryGetDocumentationFromSuperclass(
1476: SourceObjectDeclared o) {
1477: if (o instanceof MemberExecutable) {
1478: MemberExecutable mex = (MemberExecutable) o;
1479: Class c = mex.getDeclaringClass();
1480: String supName = c.getSuperclassName();
1481: Class sup = c.getPackage().getBasePackage().findClass(
1482: supName);
1483: while (sup != null) {
1484: for (NamedIterator it = sup.getAllMembers(); it
1485: .hasMore();) {
1486: Member m = (Member) it.next();
1487: if (m instanceof MemberExecutable) {
1488: if (m.equals(mex)) {
1489: Documentation d = m.getDocumentation();
1490: if ((d != null)
1491: && (d instanceof DocumentationDeclared)) {
1492: return (DocumentationDeclared) d;
1493: }
1494: }
1495: }
1496: }
1497: if (!sup.getName().equals("java.lang.Object")) {
1498: supName = sup.getSuperclassName();
1499: sup = c.getPackage().getBasePackage().findClass(
1500: supName);
1501: } else {
1502: sup = null;
1503: }
1504: }
1505: }
1506: return null;
1507: }
1508:
1509: /**
1510: * Builds the documentation tagged.
1511: *
1512: * @throws IOException if an i/o error occurs
1513: */
1514: protected static void buildDocumentationTagged(OutputStream out,
1515: DocumentationTagged tag, String spaces) throws IOException {
1516: write(out, startWithStars(
1517: tag.getTag()
1518: + " "
1519: + (((tag.getItem() != null) ? tag.getItem()
1520: : "")
1521: + " " + tag.getText()), spaces));
1522: }
1523:
1524: } // end StandardSourclet
|