Source Code Cross Referenced for ClassGraph.java in  » UML » UMLGraph » org » umlgraph » doclet » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » UML » UMLGraph » org.umlgraph.doclet 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Create a graphviz graph based on the classes in the specified java
0003:         * source files.
0004:         *
0005:         * (C) Copyright 2002-2005 Diomidis Spinellis
0006:         *
0007:         * Permission to use, copy, and distribute this software and its
0008:         * documentation for any purpose and without fee is hereby granted,
0009:         * provided that the above copyright notice appear in all copies and that
0010:         * both that copyright notice and this permission notice appear in
0011:         * supporting documentation.
0012:         *
0013:         * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
0014:         * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
0015:         * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
0016:         *
0017:         * $Id: ClassGraph.java,v 1.95 2007/12/06 07:11:49 dds Exp $
0018:         *
0019:         */
0020:
0021:        package org.umlgraph.doclet;
0022:
0023:        import java.io.BufferedOutputStream;
0024:        import java.io.File;
0025:        import java.io.FileOutputStream;
0026:        import java.io.OutputStream;
0027:        import java.io.IOException;
0028:        import java.io.OutputStreamWriter;
0029:        import java.io.PrintWriter;
0030:        import java.util.ArrayList;
0031:        import java.util.Arrays;
0032:        import java.util.HashMap;
0033:        import java.util.HashSet;
0034:        import java.util.List;
0035:        import java.util.Map;
0036:        import java.util.Set;
0037:        import java.util.regex.Pattern;
0038:
0039:        import com.sun.javadoc.ClassDoc;
0040:        import com.sun.javadoc.ConstructorDoc;
0041:        import com.sun.javadoc.Doc;
0042:        import com.sun.javadoc.FieldDoc;
0043:        import com.sun.javadoc.MethodDoc;
0044:        import com.sun.javadoc.PackageDoc;
0045:        import com.sun.javadoc.Parameter;
0046:        import com.sun.javadoc.ParameterizedType;
0047:        import com.sun.javadoc.ProgramElementDoc;
0048:        import com.sun.javadoc.RootDoc;
0049:        import com.sun.javadoc.Tag;
0050:        import com.sun.javadoc.Type;
0051:        import com.sun.javadoc.TypeVariable;
0052:        import com.sun.javadoc.WildcardType;
0053:
0054:        /**
0055:         * Class graph generation engine
0056:         * @depend - - - StringUtil
0057:         * @depend - - - Options
0058:         * @composed - - * ClassInfo
0059:         * @has - - - OptionProvider
0060:         *
0061:         * @version $Revision: 1.95 $
0062:         * @author <a href="http://www.spinellis.gr">Diomidis Spinellis</a>
0063:         */
0064:        class ClassGraph {
0065:            protected static final char FILE_SEPARATOR = '/';
0066:
0067:            enum Font {
0068:                NORMAL, ABSTRACT, CLASS, CLASS_ABSTRACT, TAG, PACKAGE
0069:            }
0070:
0071:            enum Align {
0072:                LEFT, CENTER, RIGHT
0073:            };
0074:
0075:            public static Map<RelationType, String> associationMap = new HashMap<RelationType, String>();
0076:            static {
0077:                associationMap.put(RelationType.ASSOC, "arrowhead=none");
0078:                associationMap.put(RelationType.NAVASSOC, "arrowhead=open");
0079:                associationMap.put(RelationType.HAS,
0080:                        "arrowhead=none, arrowtail=ediamond");
0081:                associationMap.put(RelationType.COMPOSED,
0082:                        "arrowhead=none, arrowtail=diamond");
0083:                associationMap.put(RelationType.DEPEND,
0084:                        "arrowhead=open, style=dashed");
0085:            }
0086:            protected Map<String, ClassInfo> classnames = new HashMap<String, ClassInfo>();
0087:            protected Set<String> rootClasses;
0088:            protected Map<String, ClassDoc> rootClassdocs = new HashMap<String, ClassDoc>();
0089:            protected OptionProvider optionProvider;
0090:            protected PrintWriter w;
0091:            protected ClassDoc collectionClassDoc;
0092:            protected ClassDoc mapClassDoc;
0093:            protected String linePostfix;
0094:            protected String linePrefix;
0095:
0096:            // used only when generating context class diagrams in UMLDoc, to generate the proper
0097:            // relative links to other classes in the image map
0098:            protected Doc contextDoc;
0099:
0100:            /**
0101:             * Create a new ClassGraph.  <p>The packages passed as an
0102:             * argument are the ones specified on the command line.</p>
0103:             * <p>Local URLs will be generated for these packages.</p>
0104:             * @param root The root of docs as provided by the javadoc API
0105:             * @param optionProvider The main option provider
0106:             * @param contextDoc The current context for generating relative links, may be a ClassDoc 
0107:             * 	or a PackageDoc (used by UMLDoc)
0108:             */
0109:            public ClassGraph(RootDoc root, OptionProvider optionProvider,
0110:                    Doc contextDoc) {
0111:                this .optionProvider = optionProvider;
0112:                this .collectionClassDoc = root
0113:                        .classNamed("java.util.Collection");
0114:                this .mapClassDoc = root.classNamed("java.util.Map");
0115:                this .contextDoc = contextDoc;
0116:
0117:                // to gather the packages containing specified classes, loop thru them and gather
0118:                // package definitions. User root.specifiedPackages is not safe, since the user
0119:                // may specify just a list of classes (human users usually don't, but automated tools do)
0120:                rootClasses = new HashSet<String>();
0121:                for (ClassDoc classDoc : root.classes()) {
0122:                    rootClasses.add(classDoc.qualifiedName());
0123:                    rootClassdocs.put(classDoc.qualifiedName(), classDoc);
0124:                }
0125:
0126:                Options opt = optionProvider.getGlobalOptions();
0127:                if (opt.compact) {
0128:                    linePrefix = "";
0129:                    linePostfix = "";
0130:                } else {
0131:                    linePrefix = "\t";
0132:                    linePostfix = "\n";
0133:                }
0134:            }
0135:
0136:            /** Return the class's name, possibly by stripping the leading path */
0137:            private String qualifiedName(Options opt, String r) {
0138:                if (!opt.showQualified) {
0139:                    // Create readable string by stripping leading path
0140:                    for (;;) {
0141:                        int dotpos = r.lastIndexOf('.');
0142:                        if (dotpos == -1)
0143:                            break; // Work done!
0144:                        /*
0145:                         * Change all occurences of
0146:                         * "p1.p2.myClass<S extends dummy.Otherclass>" into
0147:                         * "myClass<S extends Otherclass>"
0148:                         */
0149:                        int start = dotpos;
0150:                        while (start > 0
0151:                                && Character.isJavaIdentifierPart(r
0152:                                        .charAt(start - 1)))
0153:                            start--;
0154:                        r = r.substring(0, start) + r.substring(dotpos + 1);
0155:                    }
0156:                }
0157:                return r;
0158:            }
0159:
0160:            /**
0161:             * Escape &lt;, &gt;, and &amp; characters in the string with
0162:             * the corresponding HTML entity code.
0163:             */
0164:            private String escape(String s) {
0165:                final Pattern toEscape = Pattern.compile("[&<>]");
0166:
0167:                if (toEscape.matcher(s).find()) {
0168:                    StringBuffer sb = new StringBuffer(s);
0169:                    for (int i = 0; i < sb.length();) {
0170:                        switch (sb.charAt(i)) {
0171:                        case '&':
0172:                            sb.replace(i, i + 1, "&amp;");
0173:                            i += "&amp;".length();
0174:                            break;
0175:                        case '<':
0176:                            sb.replace(i, i + 1, "&lt;");
0177:                            i += "&lt;".length();
0178:                            break;
0179:                        case '>':
0180:                            sb.replace(i, i + 1, "&gt;");
0181:                            i += "&gt;".length();
0182:                            break;
0183:                        default:
0184:                            i++;
0185:                        }
0186:                    }
0187:                    return sb.toString();
0188:                } else
0189:                    return s;
0190:            }
0191:
0192:            /**
0193:             * Convert embedded newlines into HTML line breaks
0194:             */
0195:            private String htmlNewline(String s) {
0196:                if (s.indexOf('\n') == -1)
0197:                    return (s);
0198:
0199:                StringBuffer sb = new StringBuffer(s);
0200:                for (int i = 0; i < sb.length();) {
0201:                    if (sb.charAt(i) == '\n') {
0202:                        sb.replace(i, i + 1, "<br/>");
0203:                        i += "<br/>".length();
0204:                    } else
0205:                        i++;
0206:                }
0207:                return sb.toString();
0208:            }
0209:
0210:            /**
0211:             * Convert &lt; and &gt; characters in the string to the respective guillemot characters.
0212:             */
0213:            private String guillemize(Options opt, String s) {
0214:                StringBuffer r = new StringBuffer(s);
0215:                for (int i = 0; i < r.length();)
0216:                    switch (r.charAt(i)) {
0217:                    case '<':
0218:                        r.replace(i, i + 1, opt.guilOpen);
0219:                        i += opt.guilOpen.length();
0220:                        break;
0221:                    case '>':
0222:                        r.replace(i, i + 1, opt.guilClose);
0223:                        i += opt.guilClose.length();
0224:                        break;
0225:                    default:
0226:                        i++;
0227:                        break;
0228:                    }
0229:                return r.toString();
0230:            }
0231:
0232:            /**
0233:             * Wraps a string in Guillemot (or an ASCII substitute) characters.
0234:             *
0235:             * @param str the <code>String</code> to be wrapped.
0236:             * @return the wrapped <code>String</code>.
0237:             */
0238:            private String guilWrap(Options opt, String str) {
0239:                return opt.guilOpen + str + opt.guilClose;
0240:            }
0241:
0242:            /**
0243:             * Print the visibility adornment of element e prefixed by
0244:             * any stereotypes
0245:             */
0246:            private String visibility(Options opt, ProgramElementDoc e) {
0247:                if (!opt.showVisibility)
0248:                    return " ";
0249:                if (e.isPrivate())
0250:                    return "- ";
0251:                else if (e.isPublic())
0252:                    return "+ ";
0253:                else if (e.isProtected())
0254:                    return "# ";
0255:                else if (e.isPackagePrivate())
0256:                    return "~ ";
0257:                else
0258:                    return " ";
0259:            }
0260:
0261:            /** Print the method parameter p */
0262:            private String parameter(Options opt, Parameter p[]) {
0263:                String par = "";
0264:                for (int i = 0; i < p.length; i++) {
0265:                    par += p[i].name() + typeAnnotation(opt, p[i].type());
0266:                    if (i + 1 < p.length)
0267:                        par += ", ";
0268:                }
0269:                return par;
0270:            }
0271:
0272:            /** Print a a basic type t */
0273:            private String type(Options opt, Type t) {
0274:                String type = "";
0275:                if (opt.showQualified)
0276:                    type = t.qualifiedTypeName();
0277:                else
0278:                    type = t.typeName();
0279:                type += typeParameters(opt, t.asParameterizedType());
0280:                return type;
0281:            }
0282:
0283:            /** Print the parameters of the parameterized type t */
0284:            private String typeParameters(Options opt, ParameterizedType t) {
0285:                String tp = "";
0286:                if (t == null)
0287:                    return tp;
0288:                Type args[] = t.typeArguments();
0289:                tp += "&lt;";
0290:                for (int i = 0; i < args.length; i++) {
0291:                    tp += type(opt, args[i]);
0292:                    if (i != args.length - 1)
0293:                        tp += ", ";
0294:                }
0295:                tp += "&gt;";
0296:                return tp;
0297:            }
0298:
0299:            /** Annotate an field/argument with its type t */
0300:            private String typeAnnotation(Options opt, Type t) {
0301:                String ta = "";
0302:                if (t.typeName().equals("void"))
0303:                    return ta;
0304:                ta += " : ";
0305:                ta += type(opt, t);
0306:                ta += t.dimension();
0307:                return ta;
0308:            }
0309:
0310:            /** Print the class's attributes fd */
0311:            private void attributes(Options opt, FieldDoc fd[]) {
0312:                for (FieldDoc f : fd) {
0313:                    if (hidden(f))
0314:                        continue;
0315:                    String att = "";
0316:                    stereotype(opt, f, Align.LEFT);
0317:                    att = visibility(opt, f) + f.name();
0318:                    if (opt.showType)
0319:                        att += typeAnnotation(opt, f.type());
0320:                    tableLine(Align.LEFT, att);
0321:                    tagvalue(opt, f);
0322:                }
0323:            }
0324:
0325:            /*
0326:             * The following two methods look similar, but can't
0327:             * be refactored into one, because their common interface,
0328:             * ExecutableMemberDoc, doesn't support returnType for ctors.
0329:             */
0330:
0331:            /** Print the class's constructors m */
0332:            private boolean operations(Options opt, ConstructorDoc m[]) {
0333:                boolean printed = false;
0334:                for (ConstructorDoc cd : m) {
0335:                    if (hidden(cd))
0336:                        continue;
0337:                    stereotype(opt, cd, Align.LEFT);
0338:                    String cs = visibility(opt, cd) + cd.name();
0339:                    if (opt.showType) {
0340:                        cs += "(" + parameter(opt, cd.parameters()) + ")";
0341:                    } else {
0342:                        cs += "()";
0343:                    }
0344:                    tableLine(Align.LEFT, cs);
0345:                    printed = true;
0346:                    tagvalue(opt, cd);
0347:                }
0348:                return printed;
0349:            }
0350:
0351:            /** Print the class's operations m */
0352:            private boolean operations(Options opt, MethodDoc m[]) {
0353:                boolean printed = false;
0354:                for (MethodDoc md : m) {
0355:                    if (hidden(md))
0356:                        continue;
0357:                    // Filter-out static initializer method
0358:                    if (md.name().equals("<clinit>") && md.isStatic()
0359:                            && md.isPackagePrivate())
0360:                        continue;
0361:                    stereotype(opt, md, Align.LEFT);
0362:                    String op = visibility(opt, md) + md.name();
0363:                    if (opt.showType) {
0364:                        op += "(" + parameter(opt, md.parameters()) + ")"
0365:                                + typeAnnotation(opt, md.returnType());
0366:                    } else {
0367:                        op += "()";
0368:                    }
0369:                    tableLine(Align.LEFT, op, opt,
0370:                            md.isAbstract() ? Font.ABSTRACT : Font.NORMAL);
0371:                    printed = true;
0372:
0373:                    tagvalue(opt, md);
0374:                }
0375:                return printed;
0376:            }
0377:
0378:            /** Print the common class node's properties */
0379:            private void nodeProperties(Options opt) {
0380:                w.print(", fontname=\"" + opt.nodeFontName + "\"");
0381:                w.print(", fontcolor=\"" + opt.nodeFontColor + "\"");
0382:                w.print(", fontsize=" + opt.nodeFontSize);
0383:                w.print(opt.shape.graphvizAttribute());
0384:                w.println("];");
0385:            }
0386:
0387:            /**
0388:             * Return as a string the tagged values associated with c
0389:             * @param opt the Options used to guess font names
0390:             * @param c the Doc entry to look for @tagvalue
0391:             * @param prevterm the termination string for the previous element
0392:             * @param term the termination character for each tagged value
0393:             */
0394:            private void tagvalue(Options opt, Doc c) {
0395:                Tag tags[] = c.tags("tagvalue");
0396:                if (tags.length == 0)
0397:                    return;
0398:
0399:                for (Tag tag : tags) {
0400:                    String t[] = StringUtil.tokenize(tag.text());
0401:                    if (t.length != 2) {
0402:                        System.err.println("@tagvalue expects two fields: "
0403:                                + tag.text());
0404:                        continue;
0405:                    }
0406:                    tableLine(Align.RIGHT, "{" + t[0] + " = " + t[1] + "}",
0407:                            opt, Font.TAG);
0408:                }
0409:            }
0410:
0411:            /**
0412:             * Return as a string the stereotypes associated with c
0413:             * terminated by the escape character term
0414:             */
0415:            private void stereotype(Options opt, Doc c, Align align) {
0416:                for (Tag tag : c.tags("stereotype")) {
0417:                    String t[] = StringUtil.tokenize(tag.text());
0418:                    if (t.length != 1) {
0419:                        System.err.println("@stereotype expects one field: "
0420:                                + tag.text());
0421:                        continue;
0422:                    }
0423:                    tableLine(align, guilWrap(opt, t[0]));
0424:                }
0425:            }
0426:
0427:            /** Return true if c has a @hidden tag associated with it */
0428:            private boolean hidden(ProgramElementDoc c) {
0429:                Tag tags[] = c.tags("hidden");
0430:                if (tags.length > 0)
0431:                    return true;
0432:                tags = c.tags("view");
0433:                if (tags.length > 0)
0434:                    return true;
0435:                Options opt;
0436:                if (c instanceof  ClassDoc)
0437:                    opt = optionProvider.getOptionsFor((ClassDoc) c);
0438:                else
0439:                    opt = optionProvider.getOptionsFor(c.containingClass());
0440:                return opt.matchesHideExpression(c.toString());
0441:            }
0442:
0443:            protected ClassInfo getClassInfo(String className) {
0444:                return classnames.get(removeTemplate(className));
0445:            }
0446:
0447:            private ClassInfo newClassInfo(String className, boolean printed,
0448:                    boolean hidden) {
0449:                ClassInfo ci = new ClassInfo(printed, hidden);
0450:                classnames.put(removeTemplate(className), ci);
0451:                return ci;
0452:            }
0453:
0454:            /** Return true if the class name is associated to an hidden class or matches a hide expression */
0455:            private boolean hidden(String s) {
0456:                ClassInfo ci = getClassInfo(s);
0457:                Options opt = optionProvider.getOptionsFor(s);
0458:                if (ci != null)
0459:                    return ci.hidden || opt.matchesHideExpression(s);
0460:                else
0461:                    return opt.matchesHideExpression(s);
0462:            }
0463:
0464:            /**
0465:             * Prints the class if needed.
0466:             * <p>
0467:             * A class is a rootClass if it's included among the classes returned by
0468:             * RootDoc.classes(), this information is used to properly compute
0469:             * relative links in diagrams for UMLDoc
0470:             */
0471:            public String printClass(ClassDoc c, boolean rootClass) {
0472:                ClassInfo ci;
0473:                boolean toPrint;
0474:                Options opt = optionProvider.getOptionsFor(c);
0475:
0476:                String className = c.toString();
0477:                if ((ci = getClassInfo(className)) != null)
0478:                    toPrint = !ci.nodePrinted;
0479:                else {
0480:                    toPrint = true;
0481:                    ci = newClassInfo(className, true, hidden(c));
0482:                }
0483:                if (toPrint && !hidden(c)
0484:                        && (!c.isEnum() || opt.showEnumerations)) {
0485:                    // Associate classname's alias
0486:                    String r = className;
0487:                    w.println("\t// " + r);
0488:                    // Create label
0489:                    w.print("\t" + ci.name + " [label=");
0490:
0491:                    boolean showMembers = (opt.showAttributes && c.fields().length > 0)
0492:                            || (c.isEnum() && opt.showEnumConstants && c
0493:                                    .enumConstants().length > 0)
0494:                            || (opt.showOperations && c.methods().length > 0)
0495:                            || (opt.showConstructors && c.constructors().length > 0);
0496:
0497:                    externalTableStart(opt, c.qualifiedName(), classToUrl(c,
0498:                            rootClass));
0499:
0500:                    // Calculate the number of innerTable rows we will emmit
0501:                    int nRows = 1;
0502:                    if (showMembers) {
0503:                        if (opt.showAttributes)
0504:                            nRows++;
0505:                        else if (!c.isEnum()
0506:                                && (opt.showConstructors || opt.showOperations))
0507:                            nRows++;
0508:                        if (c.isEnum() && opt.showEnumConstants)
0509:                            nRows++;
0510:                        if (!c.isEnum()
0511:                                && (opt.showConstructors || opt.showOperations))
0512:                            nRows++;
0513:                    }
0514:
0515:                    firstInnerTableStart(opt, nRows);
0516:                    if (c.isInterface())
0517:                        tableLine(Align.CENTER, guilWrap(opt, "interface"));
0518:                    if (c.isEnum())
0519:                        tableLine(Align.CENTER, guilWrap(opt, "enumeration"));
0520:                    stereotype(opt, c, Align.CENTER);
0521:                    Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT
0522:                            : Font.CLASS;
0523:                    String qualifiedName = qualifiedName(opt, r);
0524:                    int startTemplate = qualifiedName.indexOf('<');
0525:                    int idx = 0;
0526:                    if (startTemplate < 0)
0527:                        idx = qualifiedName.lastIndexOf('.');
0528:                    else
0529:                        idx = qualifiedName.lastIndexOf('.', startTemplate);
0530:                    if (opt.showComment)
0531:                        tableLine(Align.LEFT, htmlNewline(escape(c
0532:                                .commentText())), opt, Font.CLASS);
0533:                    else if (opt.postfixPackage && idx > 0
0534:                            && idx < (qualifiedName.length() - 1)) {
0535:                        String packageName = qualifiedName.substring(0, idx);
0536:                        String cn = className.substring(idx + 1);
0537:                        tableLine(Align.CENTER, escape(cn), opt, font);
0538:                        tableLine(Align.CENTER, packageName, opt, Font.PACKAGE);
0539:                    } else {
0540:                        tableLine(Align.CENTER, escape(qualifiedName), opt,
0541:                                font);
0542:                    }
0543:                    tagvalue(opt, c);
0544:                    firstInnerTableEnd(opt, nRows);
0545:
0546:                    /*
0547:                     * Warning: The boolean expressions guarding innerTableStart()
0548:                     * in this block, should match those in the code block above
0549:                     * marked: "Calculate the number of innerTable rows we will emmit"
0550:                     */
0551:                    if (showMembers) {
0552:                        if (opt.showAttributes) {
0553:                            innerTableStart();
0554:                            FieldDoc[] fields = c.fields();
0555:                            // if there are no fields, print an empty line to generate proper HTML
0556:                            if (fields.length == 0)
0557:                                tableLine(Align.LEFT, "");
0558:                            else
0559:                                attributes(opt, c.fields());
0560:                            innerTableEnd();
0561:                        } else if (!c.isEnum()
0562:                                && (opt.showConstructors || opt.showOperations)) {
0563:                            // show an emtpy box if we don't show attributes but
0564:                            // we show operations
0565:                            innerTableStart();
0566:                            tableLine(Align.LEFT, "");
0567:                            innerTableEnd();
0568:                        }
0569:                        if (c.isEnum() && opt.showEnumConstants) {
0570:                            innerTableStart();
0571:                            FieldDoc[] ecs = c.enumConstants();
0572:                            // if there are no constants, print an empty line to generate proper HTML		    
0573:                            if (ecs.length == 0) {
0574:                                tableLine(Align.LEFT, "");
0575:                            } else {
0576:                                for (FieldDoc fd : c.enumConstants()) {
0577:                                    tableLine(Align.LEFT, fd.name());
0578:                                }
0579:                            }
0580:                            innerTableEnd();
0581:                        }
0582:                        if (!c.isEnum()
0583:                                && (opt.showConstructors || opt.showOperations)) {
0584:                            innerTableStart();
0585:                            boolean printedLines = false;
0586:                            if (opt.showConstructors)
0587:                                printedLines |= operations(opt, c
0588:                                        .constructors());
0589:                            if (opt.showOperations)
0590:                                printedLines |= operations(opt, c.methods());
0591:
0592:                            if (!printedLines)
0593:                                // if there are no operations nor constructors,
0594:                                // print an empty line to generate proper HTML
0595:                                tableLine(Align.LEFT, "");
0596:
0597:                            innerTableEnd();
0598:                        }
0599:                    }
0600:                    externalTableEnd();
0601:                    nodeProperties(opt);
0602:
0603:                    // If needed, add a note for this node
0604:                    int ni = 0;
0605:                    for (Tag t : c.tags("note")) {
0606:                        String noteName = "n" + ni + "c" + ci.name;
0607:                        w.print("\t// Note annotation\n");
0608:                        w.print("\t" + noteName + " [label=");
0609:                        externalTableStart(UmlGraph.getCommentOptions(), c
0610:                                .qualifiedName(), classToUrl(c, rootClass));
0611:                        innerTableStart();
0612:                        tableLine(Align.LEFT, htmlNewline(escape(t.text())),
0613:                                UmlGraph.getCommentOptions(), Font.CLASS);
0614:                        innerTableEnd();
0615:                        externalTableEnd();
0616:                        nodeProperties(UmlGraph.getCommentOptions());
0617:                        w.print("\t" + noteName + " -> " + relationNode(c)
0618:                                + "[arrowhead=none];\n");
0619:                        ni++;
0620:                    }
0621:                    ci.nodePrinted = true;
0622:                }
0623:                return ci.name;
0624:            }
0625:
0626:            private String getNodeName(ClassDoc c) {
0627:                String className = c.toString();
0628:                ClassInfo ci = getClassInfo(className);
0629:                if (ci == null)
0630:                    ci = newClassInfo(className, false, hidden(c));
0631:                return ci.name;
0632:            }
0633:
0634:            /** Return a class's internal name */
0635:            private String getNodeName(String c) {
0636:                ClassInfo ci = getClassInfo(c);
0637:
0638:                if (ci == null)
0639:                    ci = newClassInfo(c, false, false);
0640:                return ci.name;
0641:            }
0642:
0643:            /**
0644:             * Print all relations for a given's class's tag
0645:             * @param tagname the tag containing the given relation
0646:             * @param from the source class
0647:             * @param edgetype the dot edge specification
0648:             */
0649:            private void allRelation(Options opt, RelationType rt, ClassDoc from) {
0650:                String tagname = rt.toString().toLowerCase();
0651:                for (Tag tag : from.tags(tagname)) {
0652:                    String t[] = StringUtil.tokenize(tag.text()); // l-src label l-dst target
0653:                    if (t.length != 4) {
0654:                        System.err
0655:                                .println("Error in "
0656:                                        + from
0657:                                        + "\n"
0658:                                        + tagname
0659:                                        + " expects four fields (l-src label l-dst target): "
0660:                                        + tag.text());
0661:                        return;
0662:                    }
0663:                    ClassDoc to = from.findClass(t[3]);
0664:
0665:                    if (to != null) {
0666:                        if (hidden(to))
0667:                            continue;
0668:                        relation(opt, rt, from, to, t[0], t[1], t[2]);
0669:                    } else {
0670:                        if (hidden(t[3]))
0671:                            continue;
0672:                        relation(opt, rt, from, from.toString(), to, t[3],
0673:                                t[0], t[1], t[2]);
0674:                    }
0675:                }
0676:            }
0677:
0678:            /**
0679:             * Print the specified relation
0680:             * @param from the source class (may be null)
0681:             * @param fromName the source class's name
0682:             * @param to the destination class (may be null)
0683:             * @param toName the destination class's name
0684:             */
0685:            private void relation(Options opt, RelationType rt, ClassDoc from,
0686:                    String fromName, ClassDoc to, String toName,
0687:                    String tailLabel, String label, String headLabel) {
0688:
0689:                // print relation
0690:                String edgetype = associationMap.get(rt);
0691:                w.println("\t// " + fromName + " " + rt.toString() + " "
0692:                        + toName);
0693:                w.println("\t" + relationNode(from, fromName) + " -> "
0694:                        + relationNode(to, toName) + " [" + "taillabel=\""
0695:                        + tailLabel + "\", " + "label=\""
0696:                        + guillemize(opt, label) + "\", " + "headlabel=\""
0697:                        + headLabel + "\", " + "fontname=\"" + opt.edgeFontName
0698:                        + "\", " + "fontcolor=\"" + opt.edgeFontColor + "\", "
0699:                        + "fontsize=" + opt.edgeFontSize + ", " + "color=\""
0700:                        + opt.edgeColor + "\", " + edgetype + "];");
0701:
0702:                // update relation info
0703:                RelationDirection d = RelationDirection.BOTH;
0704:                if (rt == RelationType.NAVASSOC || rt == RelationType.DEPEND)
0705:                    d = RelationDirection.OUT;
0706:                getClassInfo(fromName).addRelation(toName, rt, d);
0707:                getClassInfo(toName).addRelation(fromName, rt, d.inverse());
0708:            }
0709:
0710:            /**
0711:             * Print the specified relation
0712:             * @param from the source class
0713:             * @param to the destination class
0714:             */
0715:            private void relation(Options opt, RelationType rt, ClassDoc from,
0716:                    ClassDoc to, String tailLabel, String label,
0717:                    String headLabel) {
0718:                relation(opt, rt, from, from.toString(), to, to.toString(),
0719:                        tailLabel, label, headLabel);
0720:            }
0721:
0722:            /** Return the full name of a relation's node.
0723:             * This may involve appending the port :p for the standard nodes
0724:             * whose outline is rendered through an inner table.
0725:             */
0726:            private String relationNode(ClassDoc c) {
0727:                Options opt = optionProvider.getOptionsFor(c);
0728:                String name = getNodeName(c);
0729:                return name + opt.shape.landingPort();
0730:            }
0731:
0732:            /** Return the full name of a relation's node c.
0733:             * This may involve appending the port :p for the standard nodes
0734:             * whose outline is rendered through an inner table.
0735:             * @param c the node's class (may be null)
0736:             * @param cName the node's class name
0737:             */
0738:            private String relationNode(ClassDoc c, String cName) {
0739:                Options opt;
0740:                if (c == null)
0741:                    opt = optionProvider.getOptionsFor(cName);
0742:                else
0743:                    opt = optionProvider.getOptionsFor(c);
0744:                String name = getNodeName(cName);
0745:                return name + opt.shape.landingPort();
0746:            }
0747:
0748:            /** Print a class's relations */
0749:            public void printRelations(ClassDoc c) {
0750:                Options opt = optionProvider.getOptionsFor(c);
0751:                if (hidden(c) || c.name().equals("")) // avoid phantom classes, they may pop up when the source uses annotations
0752:                    return;
0753:                String className = c.toString();
0754:
0755:                // Print generalization (through the Java superclass)
0756:                Type s = c.super classType();
0757:                if (s != null && !s.toString().equals("java.lang.Object")
0758:                        && !c.isEnum() && !hidden(s.asClassDoc())) {
0759:                    ClassDoc sc = s.asClassDoc();
0760:                    w.println("\t//" + c + " extends " + s + "\n" + "\t"
0761:                            + relationNode(sc) + " -> " + relationNode(c)
0762:                            + " [dir=back,arrowtail=empty];");
0763:                    getClassInfo(className).addRelation(sc.toString(),
0764:                            RelationType.EXTENDS, RelationDirection.OUT);
0765:                    getClassInfo(sc.toString()).addRelation(className,
0766:                            RelationType.EXTENDS, RelationDirection.IN);
0767:                }
0768:
0769:                // Print generalizations (through @extends tags)
0770:                for (Tag tag : c.tags("extends"))
0771:                    if (!hidden(tag.text())) {
0772:                        ClassDoc from = c.findClass(tag.text());
0773:                        w.println("\t//" + c + " extends " + tag.text() + "\n"
0774:                                + "\t" + relationNode(from, tag.text())
0775:                                + " -> " + relationNode(c)
0776:                                + " [dir=back,arrowtail=empty];");
0777:                        getClassInfo(className).addRelation(tag.text(),
0778:                                RelationType.EXTENDS, RelationDirection.OUT);
0779:                        getClassInfo(tag.text()).addRelation(className,
0780:                                RelationType.EXTENDS, RelationDirection.IN);
0781:                    }
0782:                // Print realizations (Java interfaces)
0783:                for (Type iface : c.interfaceTypes()) {
0784:                    ClassDoc ic = iface.asClassDoc();
0785:                    if (!hidden(ic)) {
0786:                        w.println("\t//" + c + " implements " + ic + "\n\t"
0787:                                + relationNode(ic) + " -> " + relationNode(c)
0788:                                + " [dir=back,arrowtail=empty,style=dashed];");
0789:                        getClassInfo(className).addRelation(ic.toString(),
0790:                                RelationType.IMPLEMENTS, RelationDirection.OUT);
0791:                        getClassInfo(ic.toString()).addRelation(className,
0792:                                RelationType.IMPLEMENTS, RelationDirection.IN);
0793:                    }
0794:                }
0795:                // Print other associations
0796:                allRelation(opt, RelationType.ASSOC, c);
0797:                allRelation(opt, RelationType.NAVASSOC, c);
0798:                allRelation(opt, RelationType.HAS, c);
0799:                allRelation(opt, RelationType.COMPOSED, c);
0800:                allRelation(opt, RelationType.DEPEND, c);
0801:            }
0802:
0803:            /** Print classes that were parts of relationships, but not parsed by javadoc */
0804:            public void printExtraClasses(RootDoc root) {
0805:                Set<String> names = new HashSet<String>(classnames.keySet());
0806:                for (String className : names) {
0807:                    ClassInfo info = getClassInfo(className);
0808:                    if (!info.nodePrinted) {
0809:                        ClassDoc c = root.classNamed(className);
0810:                        if (c != null) {
0811:                            printClass(c, false);
0812:                        } else {
0813:                            Options opt = optionProvider
0814:                                    .getOptionsFor(className);
0815:                            if (opt.matchesHideExpression(className))
0816:                                continue;
0817:                            w.println("\t// " + className);
0818:                            w.print("\t" + info.name + "[label=");
0819:                            externalTableStart(opt, className,
0820:                                    classToUrl(className));
0821:                            innerTableStart();
0822:                            int idx = className.lastIndexOf(".");
0823:                            if (opt.postfixPackage && idx > 0
0824:                                    && idx < (className.length() - 1)) {
0825:                                String packageName = className
0826:                                        .substring(0, idx);
0827:                                String cn = className.substring(idx + 1);
0828:                                tableLine(Align.CENTER, escape(cn), opt,
0829:                                        Font.CLASS);
0830:                                tableLine(Align.CENTER, packageName, opt,
0831:                                        Font.PACKAGE);
0832:                            } else {
0833:                                tableLine(Align.CENTER, escape(className), opt,
0834:                                        Font.CLASS);
0835:                            }
0836:                            innerTableEnd();
0837:                            externalTableEnd();
0838:                            nodeProperties(opt);
0839:                        }
0840:                    }
0841:                }
0842:            }
0843:
0844:            /**
0845:             * Prints associations recovered from the fields of a class. An association is inferred only
0846:             * if another relation between the two classes is not already in the graph.
0847:             * @param classes
0848:             */
0849:            public void printInferredRelations(ClassDoc[] classes) {
0850:                for (ClassDoc c : classes) {
0851:                    printInferredRelations(c);
0852:                }
0853:            }
0854:
0855:            /**
0856:             * Prints associations recovered from the fields of a class. An association is inferred only
0857:             * if another relation between the two classes is not already in the graph.
0858:             * @param classes
0859:             */
0860:            public void printInferredRelations(ClassDoc c) {
0861:                Options opt = optionProvider.getOptionsFor(c);
0862:
0863:                // check if the source is excluded from inference
0864:                if (hidden(c))
0865:                    return;
0866:
0867:                for (FieldDoc field : c.fields(false)) {
0868:                    // skip statics
0869:                    if (field.isStatic())
0870:                        continue;
0871:
0872:                    // skip primitives
0873:                    FieldRelationInfo fri = getFieldRelationInfo(field);
0874:                    if (fri == null)
0875:                        continue;
0876:
0877:                    // check if the destination is excluded from inference
0878:                    if (hidden(fri.cd))
0879:                        continue;
0880:
0881:                    String destAdornment = fri.multiple ? "*" : "";
0882:                    relation(opt, opt.inferRelationshipType, c, fri.cd, "", "",
0883:                            destAdornment);
0884:                }
0885:            }
0886:
0887:            /**
0888:             * Prints dependencies recovered from the methods of a class. A
0889:             * dependency is inferred only if another relation between the two
0890:             * classes is not already in the graph.
0891:             * @param classes
0892:             */
0893:            public void printInferredDependencies(ClassDoc[] classes) {
0894:                for (ClassDoc c : classes) {
0895:                    printInferredDependencies(c);
0896:                }
0897:            }
0898:
0899:            /**
0900:             * Prints dependencies recovered from the methods of a class. A
0901:             * dependency is inferred only if another relation between the two
0902:             * classes is not already in the graph.
0903:             * @param classes
0904:             */
0905:            public void printInferredDependencies(ClassDoc c) {
0906:                Options opt = optionProvider.getOptionsFor(c);
0907:
0908:                String sourceName = c.toString();
0909:                if (hidden(c))
0910:                    return;
0911:
0912:                Set<Type> types = new HashSet<Type>();
0913:                // harvest method return and parameter types
0914:                for (MethodDoc method : filterByVisibility(c.methods(false),
0915:                        opt.inferDependencyVisibility)) {
0916:                    types.add(method.returnType());
0917:                    for (Parameter parameter : method.parameters()) {
0918:                        types.add(parameter.type());
0919:                    }
0920:                }
0921:                // and the field types
0922:                if (!opt.inferRelationships) {
0923:                    for (FieldDoc field : filterByVisibility(c.fields(false),
0924:                            opt.inferDependencyVisibility)) {
0925:                        types.add(field.type());
0926:                    }
0927:                }
0928:                // see if there are some type parameters
0929:                if (c.asParameterizedType() != null) {
0930:                    ParameterizedType pt = c.asParameterizedType();
0931:                    types.addAll(Arrays.asList(pt.typeArguments()));
0932:                }
0933:                // see if type parameters extend something
0934:                for (TypeVariable tv : c.typeParameters()) {
0935:                    if (tv.bounds().length > 0)
0936:                        types.addAll(Arrays.asList(tv.bounds()));
0937:                }
0938:
0939:                // and finally check for explicitly imported classes (this
0940:                // assumes there are no unused imports...)
0941:                if (opt.useImports)
0942:                    types.addAll(Arrays.asList(c.importedClasses()));
0943:
0944:                // compute dependencies
0945:                for (Type type : types) {
0946:                    // skip primitives and type variables, as well as dependencies
0947:                    // on the source class
0948:                    if (type.isPrimitive()
0949:                            || type instanceof  WildcardType
0950:                            || type instanceof  TypeVariable
0951:                            || c.toString()
0952:                                    .equals(type.asClassDoc().toString()))
0953:                        continue;
0954:
0955:                    // check if the destination is excluded from inference
0956:                    ClassDoc fc = type.asClassDoc();
0957:                    if (hidden(fc))
0958:                        continue;
0959:
0960:                    // check if source and destination are in the same package and if we are allowed
0961:                    // to infer dependencies between classes in the same package
0962:                    if (!opt.inferDepInPackage
0963:                            && c.containingPackage().equals(
0964:                                    fc.containingPackage()))
0965:                        continue;
0966:
0967:                    // if source and dest are not already linked, add a dependency
0968:                    RelationPattern rp = getClassInfo(sourceName).getRelation(
0969:                            fc.toString());
0970:                    if (rp == null
0971:                            || rp.matchesOne(new RelationPattern(
0972:                                    RelationDirection.OUT))) {
0973:                        relation(opt, RelationType.DEPEND, c, fc, "", "", "");
0974:                    }
0975:
0976:                }
0977:            }
0978:
0979:            /**
0980:             * Returns all program element docs that have a visibility greater or
0981:             * equal than the specified level
0982:             */
0983:            private <T extends ProgramElementDoc> List<T> filterByVisibility(
0984:                    T[] docs, Visibility visibility) {
0985:                if (visibility == Visibility.PRIVATE)
0986:                    return Arrays.asList(docs);
0987:
0988:                List<T> filtered = new ArrayList<T>();
0989:                for (T doc : docs) {
0990:                    if (Visibility.get(doc).compareTo(visibility) > 0)
0991:                        filtered.add(doc);
0992:                }
0993:                return filtered;
0994:            }
0995:
0996:            private FieldRelationInfo getFieldRelationInfo(FieldDoc field) {
0997:                Type type = field.type();
0998:                if (type.isPrimitive() || type instanceof  WildcardType
0999:                        || type instanceof  TypeVariable)
1000:                    return null;
1001:
1002:                if (type.dimension().endsWith("[]")) {
1003:                    return new FieldRelationInfo(type.asClassDoc(), true);
1004:                }
1005:
1006:                Options opt = optionProvider.getOptionsFor(type.asClassDoc());
1007:                if (opt.matchesCollPackageExpression(type.qualifiedTypeName())) {
1008:                    Type[] argTypes = getInterfaceTypeArguments(
1009:                            collectionClassDoc, type);
1010:                    if (argTypes != null && argTypes.length == 1
1011:                            && !argTypes[0].isPrimitive())
1012:                        return new FieldRelationInfo(argTypes[0].asClassDoc(),
1013:                                true);
1014:
1015:                    argTypes = getInterfaceTypeArguments(mapClassDoc, type);
1016:                    if (argTypes != null && argTypes.length == 2
1017:                            && !argTypes[1].isPrimitive())
1018:                        return new FieldRelationInfo(argTypes[1].asClassDoc(),
1019:                                true);
1020:                }
1021:
1022:                return new FieldRelationInfo(type.asClassDoc(), false);
1023:            }
1024:
1025:            private Type[] getInterfaceTypeArguments(ClassDoc iface, Type t) {
1026:                if (t instanceof  ParameterizedType) {
1027:                    ParameterizedType pt = (ParameterizedType) t;
1028:                    if (iface.equals(t.asClassDoc())) {
1029:                        return pt.typeArguments();
1030:                    } else {
1031:                        for (Type pti : pt.interfaceTypes()) {
1032:                            Type[] result = getInterfaceTypeArguments(iface,
1033:                                    pti);
1034:                            if (result != null)
1035:                                return result;
1036:                        }
1037:                        if (pt.super classType() != null)
1038:                            return getInterfaceTypeArguments(iface, pt
1039:                                    .super classType());
1040:                    }
1041:                } else if (t instanceof  ClassDoc) {
1042:                    ClassDoc cd = (ClassDoc) t;
1043:                    for (Type pti : cd.interfaceTypes()) {
1044:                        Type[] result = getInterfaceTypeArguments(iface, pti);
1045:                        if (result != null)
1046:                            return result;
1047:                    }
1048:                    if (cd.super classType() != null)
1049:                        return getInterfaceTypeArguments(iface, cd
1050:                                .super classType());
1051:                }
1052:                return null;
1053:            }
1054:
1055:            /** Removes the template specs from a class name. */
1056:            private String removeTemplate(String name) {
1057:                int openIdx = name.indexOf('<');
1058:                if (openIdx == -1)
1059:                    return name;
1060:                else
1061:                    return name.substring(0, openIdx);
1062:            }
1063:
1064:            /** Convert the class name into a corresponding URL */
1065:            public String classToUrl(ClassDoc cd, boolean rootClass) {
1066:                // building relative path for context and package diagrams
1067:                if (contextDoc != null && rootClass) {
1068:                    // determine the context path, relative to the root
1069:                    String packageName = null;
1070:                    if (contextDoc instanceof  ClassDoc) {
1071:                        packageName = ((ClassDoc) contextDoc)
1072:                                .containingPackage().name();
1073:                    } else if (contextDoc instanceof  PackageDoc) {
1074:                        packageName = ((PackageDoc) contextDoc).name();
1075:                    } else {
1076:                        return classToUrl(cd.qualifiedName());
1077:                    }
1078:                    return buildRelativePath(packageName, cd
1079:                            .containingPackage().name())
1080:                            + cd.name() + ".html";
1081:                } else {
1082:                    return classToUrl(cd.qualifiedName());
1083:                }
1084:            }
1085:
1086:            protected static String buildRelativePath(
1087:                    String contextPackageName, String classPackageName) {
1088:                // path, relative to the root, of the destination class
1089:                String[] contextClassPath = contextPackageName.split("\\.");
1090:                String[] currClassPath = classPackageName.split("\\.");
1091:
1092:                // compute relative path between the context and the destination
1093:                // ... first, compute common part
1094:                int i = 0;
1095:                while (i < contextClassPath.length && i < currClassPath.length
1096:                        && contextClassPath[i].equals(currClassPath[i]))
1097:                    i++;
1098:                // ... go up with ".." to reach the common root
1099:                StringBuffer buf = new StringBuffer();
1100:                if (i == contextClassPath.length) {
1101:                    buf.append(".").append(FILE_SEPARATOR);
1102:                } else {
1103:                    for (int j = i; j < contextClassPath.length; j++) {
1104:                        buf.append("..").append(FILE_SEPARATOR);
1105:                    }
1106:                }
1107:                // ... go down from the common root to the destination
1108:                for (int j = i; j < currClassPath.length; j++) {
1109:                    buf.append(currClassPath[j]).append(FILE_SEPARATOR);
1110:                }
1111:                return buf.toString();
1112:            }
1113:
1114:            private String getPackageName(String className) {
1115:                if (this .rootClassdocs.get(className) == null) {
1116:                    return className.substring(0, className.lastIndexOf('.'));
1117:                } else {
1118:                    return this .rootClassdocs.get(className)
1119:                            .containingPackage().name();
1120:                }
1121:            }
1122:
1123:            private String getUnqualifiedName(String className) {
1124:                if (this .rootClassdocs.get(className) == null) {
1125:                    return className.substring(className.lastIndexOf('.') + 1);
1126:                } else {
1127:                    return this .rootClassdocs.get(className).name();
1128:                }
1129:            }
1130:
1131:            /** Convert the class name into a corresponding URL */
1132:            public String classToUrl(String className) {
1133:                String docRoot = mapApiDocRoot(className);
1134:                if (docRoot != null) {
1135:                    StringBuffer buf = new StringBuffer(docRoot);
1136:                    buf.append(getPackageName(className).replace('.',
1137:                            FILE_SEPARATOR)
1138:                            + FILE_SEPARATOR);
1139:                    buf.append(getUnqualifiedName(className));
1140:                    buf.append(".html");
1141:                    return buf.toString();
1142:                } else {
1143:                    return null;
1144:                }
1145:            }
1146:
1147:            /**
1148:             * Returns the appropriate URL "root" for a given class name.
1149:             * The root will be used as the prefix of the URL used to link the class in
1150:             * the final diagram to the associated JavaDoc page.
1151:             */
1152:            private String mapApiDocRoot(String className) {
1153:                String root = null;
1154:                /* If no packages are specified, we use apiDocRoot for all of them. */
1155:                if (rootClasses.contains(className)) {
1156:                    root = optionProvider.getGlobalOptions().apiDocRoot;
1157:                } else {
1158:                    Options globalOptions = optionProvider.getGlobalOptions();
1159:                    root = globalOptions.getApiDocRoot(className);
1160:                }
1161:                return root;
1162:            }
1163:
1164:            /** Dot prologue 
1165:             * @throws IOException */
1166:            public void prologue() throws IOException {
1167:                Options opt = optionProvider.getGlobalOptions();
1168:                OutputStream os = null;
1169:
1170:                if (opt.outputFileName.equals("-"))
1171:                    os = System.out;
1172:                else {
1173:                    // prepare output file. Use the output file name as a full path unless the output
1174:                    // directory is specified
1175:                    File file = null;
1176:                    if (opt.outputDirectory != null)
1177:                        file = new File(opt.outputDirectory, opt.outputFileName);
1178:                    else
1179:                        file = new File(opt.outputFileName);
1180:                    // make sure the output directory are there, otherwise create them
1181:                    if (file.getParentFile() != null
1182:                            && !file.getParentFile().exists())
1183:                        file.getParentFile().mkdirs();
1184:                    os = new FileOutputStream(file);
1185:                }
1186:
1187:                // print plologue
1188:                w = new PrintWriter(new OutputStreamWriter(
1189:                        new BufferedOutputStream(os), opt.outputEncoding));
1190:                w.println("#!/usr/local/bin/dot\n" + "#\n"
1191:                        + "# Class diagram \n"
1192:                        + "# Generated by UmlGraph version " + Version.VERSION
1193:                        + " (http://www.spinellis.gr/sw/umlgraph)\n" + "#\n\n"
1194:                        + "digraph G {\n" + "\tedge [fontname=\""
1195:                        + opt.edgeFontName + "\",fontsize=10,labelfontname=\""
1196:                        + opt.edgeFontName + "\",labelfontsize=10];\n"
1197:                        + "\tnode [fontname=\"" + opt.nodeFontName
1198:                        + "\",fontsize=10,shape=plaintext];");
1199:                if (opt.horizontal)
1200:                    w.println("\trankdir=LR;\n\tranksep=1;");
1201:                if (opt.bgColor != null)
1202:                    w.println("\tbgcolor=\"" + opt.bgColor + "\";\n");
1203:            }
1204:
1205:            /** Dot epilogue */
1206:            public void epilogue() {
1207:                w.println("}\n");
1208:                w.flush();
1209:                w.close();
1210:            }
1211:
1212:            private void externalTableStart(Options opt, String name, String url) {
1213:                String bgcolor = "";
1214:                if (opt.nodeFillColor != null)
1215:                    bgcolor = " bgcolor=\"" + opt.nodeFillColor + "\"";
1216:                String href = "";
1217:                if (url != null)
1218:                    href = " href=\"" + url + "\"";
1219:
1220:                w.print("<<table border=\"0\" cellborder=\""
1221:                        + opt.shape.cellBorder() + "\" cellspacing=\"0\" "
1222:                        + "cellpadding=\"2\" port=\"p\"" + bgcolor + href + ">"
1223:                        + linePostfix);
1224:            }
1225:
1226:            private void externalTableEnd() {
1227:                w.print(linePrefix + linePrefix + "</table>>");
1228:            }
1229:
1230:            private void innerTableStart() {
1231:                w.print(linePrefix + linePrefix
1232:                        + "<tr><td><table border=\"0\" cellspacing=\"0\" "
1233:                        + "cellpadding=\"1\">" + linePostfix);
1234:            }
1235:
1236:            /**
1237:             * Start the first inner table of a class.
1238:             * @param nRows the total number of rows in this table.
1239:             */
1240:            private void firstInnerTableStart(Options opt, int nRows) {
1241:                w.print(linePrefix + linePrefix + "<tr>"
1242:                        + opt.shape.extraColumn(nRows)
1243:                        + "<td><table border=\"0\" cellspacing=\"0\" "
1244:                        + "cellpadding=\"1\">" + linePostfix);
1245:            }
1246:
1247:            private void innerTableEnd() {
1248:                w.print(linePrefix + linePrefix + "</table></td></tr>"
1249:                        + linePostfix);
1250:            }
1251:
1252:            /**
1253:             * End the first inner table of a class.
1254:             * @param nRows the total number of rows in this table.
1255:             */
1256:            private void firstInnerTableEnd(Options opt, int nRows) {
1257:                w.print(linePrefix + linePrefix + "</table></td>"
1258:                        + opt.shape.extraColumn(nRows) + "</tr>" + linePostfix);
1259:            }
1260:
1261:            private void tableLine(Align align, String text) {
1262:                tableLine(align, text, null, Font.NORMAL);
1263:            }
1264:
1265:            private void tableLine(Align align, String text, Options opt,
1266:                    Font font) {
1267:                String open;
1268:                String close = "</td></tr>";
1269:                String prefix = linePrefix + linePrefix + linePrefix;
1270:                String alignText;
1271:
1272:                if (align == Align.CENTER)
1273:                    alignText = "center";
1274:                else if (align == Align.LEFT)
1275:                    alignText = "left";
1276:                else if (align == Align.RIGHT)
1277:                    alignText = "right";
1278:                else
1279:                    throw new RuntimeException("Unknown alignement type "
1280:                            + align);
1281:
1282:                text = fontWrap(" " + text + " ", opt, font);
1283:                open = "<tr><td align=\"" + alignText + "\" balign=\""
1284:                        + alignText + "\">";
1285:                w.print(open + text + close + linePostfix);
1286:            }
1287:
1288:            /**
1289:             * Wraps the text with the appropriate font according to the specified font type
1290:             * @param opt
1291:             * @param text
1292:             * @param font
1293:             * @return
1294:             */
1295:            private String fontWrap(String text, Options opt, Font font) {
1296:                if (font == Font.ABSTRACT) {
1297:                    return fontWrap(text, opt.nodeFontAbstractName,
1298:                            opt.nodeFontSize);
1299:                } else if (font == Font.CLASS) {
1300:                    return fontWrap(text, opt.nodeFontClassName,
1301:                            opt.nodeFontClassSize);
1302:                } else if (font == Font.CLASS_ABSTRACT) {
1303:                    String name;
1304:                    if (opt.nodeFontClassAbstractName == null)
1305:                        name = opt.nodeFontAbstractName;
1306:                    else
1307:                        name = opt.nodeFontClassAbstractName;
1308:                    return fontWrap(text, name, opt.nodeFontClassSize);
1309:                } else if (font == Font.PACKAGE) {
1310:                    return fontWrap(text, opt.nodeFontPackageName,
1311:                            opt.nodeFontPackageSize);
1312:                } else if (font == Font.TAG) {
1313:                    return fontWrap(text, opt.nodeFontTagName,
1314:                            opt.nodeFontTagSize);
1315:                } else {
1316:                    return text;
1317:                }
1318:            }
1319:
1320:            /**
1321:             * Wraps the text with the appropriate font tags when the font name
1322:             * and size are not void
1323:             * @param text the text to be wrapped
1324:             * @param fontName considered void when it's null 
1325:             * @param fontSize considered void when it's <= 0
1326:             */
1327:            private String fontWrap(String text, String fontName,
1328:                    double fontSize) {
1329:                if (fontName == null && fontSize == -1)
1330:                    return text;
1331:                else if (fontName == null)
1332:                    return "<font point-size=\"" + fontSize + "\">" + text
1333:                            + "</font>";
1334:                else if (fontSize <= 0)
1335:                    return "<font face=\"" + fontName + "\">" + text
1336:                            + "</font>";
1337:                else
1338:                    return "<font face=\"" + fontName + "\" point-size=\""
1339:                            + fontSize + "\">" + text + "</font>";
1340:            }
1341:
1342:            private static class FieldRelationInfo {
1343:                ClassDoc cd;
1344:                boolean multiple;
1345:
1346:                public FieldRelationInfo(ClassDoc cd, boolean multiple) {
1347:                    this.cd = cd;
1348:                    this.multiple = multiple;
1349:                }
1350:            }
1351:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.