/* -*- Mode: JDE; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This file is part of the debugger and core tools for the AspectJ(tm)
* programming language; see http://aspectj.org
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is AspectJ.
*
* The Initial Developer of the Original Code is Xerox Corporation. Portions
* created by Xerox Corporation are Copyright (C) 1999-2002 Xerox Corporation.
* All Rights Reserved.
*/
package org.aspectj.tools.doclets.standard;
import org.aspectj.ajdoc.AdviceDoc;
import org.aspectj.ajdoc.AspectDoc;
import org.aspectj.ajdoc.IntroducedDoc;
import org.aspectj.ajdoc.IntroducedSuperDoc;
import org.aspectj.ajdoc.IntroductionDoc;
import org.aspectj.ajdoc.OfClauseDoc;
import org.aspectj.ajdoc.OfEachObjectDoc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.MemberDoc;
import com.sun.tools.doclets.ClassTree;
import com.sun.tools.doclets.DirectoryManager;
import com.sun.tools.doclets.DocletAbortException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
public class ClassWriter extends com.sun.tools.doclets.standard.ClassWriter {
/**
* The MethodSubWriter that prints out the methods
* of classdoc
.
*/
protected MethodSubWriter ourMethodSubWriter;
/**
* The ConstructorSubWriter that prints out the constructors
* of classdoc
.
*/
protected ConstructorSubWriter ourConstrSubWriter;
/**
* The FieldSubWriter that prints out the fields
* of classdoc
.
*/
protected FieldSubWriter ourFieldSubWriter;
/**
* The ClassSubWriter that prints out the classs
* of classdoc
.
*/
protected ClassSubWriter ourInnerSubWriter;
/**
* The PointcutSubWriter that prints out the pointcuts
* of classdoc
.
*/
protected PointcutSubWriter pointcutSubWriter = null;
/**
* The SuperIntroductionSubWriter that prints out the superintroductions
* of classdoc
.
*/
protected SuperIntroductionSubWriter superIntroductionSubWriter = null;
/**
* The FieldIntroductionSubWriter that prints out the fieldintroductions
* of classdoc
.
*/
protected FieldIntroductionSubWriter fieldIntroductionSubWriter = null;
/**
* The ConstructorIntroductionSubWriter that prints out the constructorintroductions
* of classdoc
.
*/
protected ConstructorIntroductionSubWriter constrIntroductionSubWriter = null;
/**
* The MethodIntroductionSubWriter that prints out the methodintroductions
* of classdoc
.
*/
protected MethodIntroductionSubWriter methodIntroductionSubWriter = null;
/**
* The AdviceSubWriter that prints out the advices
* of classdoc
.
*/
protected AdviceSubWriter adviceSubWriter = null;
/**
* Construct a ClassWriter from the passed in arguments. This
* will instantiate the subwriters to be used.
*
* @param path the path directory of the html file to generate.
* @param filename the html file to generate.
* @param classdoc the ClassDoc for which this file will
* be generated.
* @param prev the ClassDoc preceding classdoc
* in order of generation.
* @param next the ClassDoc following classdoc
* in order of generation.
* @param classtree the ClassTree to use.
* @param nopackage whether this classdoc
's package
* is specified to be documented.
*/
public ClassWriter(String path,
String filename,
ClassDoc classdoc,
ClassDoc prev,
ClassDoc next,
ClassTree classtree,
boolean nopackage)
throws IOException, DocletAbortException {
super(path, filename, classdoc, prev,
next, classtree, nopackage);
// Construct the subwriters just for ClassDocs
// We want our superclass to delegate to our subwriters delegate,
// but we want to call our subwriters. So we set our superclasses
// subwriters to our subwriters delegates.
ourMethodSubWriter = new MethodSubWriter(this, classdoc);
methodSubWriter = (com.sun.tools.doclets.standard.MethodSubWriter)
ourMethodSubWriter.del();
constrSubWriter = (com.sun.tools.doclets.standard.ConstructorSubWriter)
(ourConstrSubWriter = new ConstructorSubWriter(this, classdoc)).del();
fieldSubWriter = (com.sun.tools.doclets.standard.FieldSubWriter)
(ourFieldSubWriter = new FieldSubWriter(this, classdoc)).del();
innerSubWriter = (com.sun.tools.doclets.standard.ClassSubWriter)
(ourInnerSubWriter = new ClassSubWriter(this, classdoc)).del();
if (classdoc instanceof org.aspectj.ajdoc.ClassDoc) {
pointcutSubWriter =
new PointcutSubWriter(this, (org.aspectj.ajdoc.ClassDoc)classdoc);
}
// If we've been passed an AspectDoc, create the AspectJ-specfic
// subwriters
if (classdoc instanceof AspectDoc) {
AspectDoc ad = (AspectDoc)classdoc;
superIntroductionSubWriter = new SuperIntroductionSubWriter(this, ad);
fieldIntroductionSubWriter = new FieldIntroductionSubWriter(this, ad);
constrIntroductionSubWriter = new ConstructorIntroductionSubWriter(this, ad);
methodIntroductionSubWriter = new MethodIntroductionSubWriter(this, ad);
adviceSubWriter = new AdviceSubWriter(this, ad);
}
}
public static void generate(ClassDoc classdoc,
ClassDoc prev,
ClassDoc next,
ClassTree classtree,
boolean nopackage)
throws DocletAbortException {
ClassWriter cw = null;
String path = DirectoryManager.getDirectoryPath
(classdoc.containingPackage());
String filename = classdoc.name() + ".html";
try {
(cw = new ClassWriter(path, filename, classdoc,
prev, next, classtree, nopackage)).
generateClassFile();
} catch (IOException e) {
Standard.configuration().standardmessage.
error("doclet.exception_encountered", e+"", filename);
throw new DocletAbortException();
} finally {
if (cw != null) cw.close();
}
}
/**
* Prints the header of the class -- which is one
* of class
, interface
or
* aspect
with the name title
.
*
* @param title the name of the class.
*/
public void printHeader(String title) {
int ispace = title.indexOf(' ');
if (ispace != -1) {
title = Statics.type(classdoc) + title.substring(ispace);
}
super.printHeader(title);
}
/*
* This is set up to intercept calls to print out
* the correct type of classdoc before we automatically
* print 'class' or 'interface'.
*/
private boolean h2warn = false;
/**
* If we've started to print a h2 heading, we're
* printing the name of the class so get ready to
* to intercept the call.
*/
public void h2() {
h2warn = true;
super.h2();
}
/**
* After printing the class declaration with the h2 heading
* turn off the h2 warning.
*/
public void h2End() {
h2warn = false;
super.h2End();
}
/**
* This is where we intercept the call to print so
* we can print the correct type.
*/
public void print(String str) {
if (h2warn) {
int ispace = str.indexOf(' ');
if (ispace != -1 && str.charAt(0) == 'C') {
str = Statics.type(classdoc) + str.substring(ispace);
}
}
super.print(str);
}
/**
* Print the members summary for our AspectJ subwriters.
*/
protected void printAspectJSummary() {
printMembersSummary(superIntroductionSubWriter);
printMembersSummary(fieldIntroductionSubWriter);
printMembersSummary(constrIntroductionSubWriter);
printMembersSummary(methodIntroductionSubWriter);
printMembersSummary(pointcutSubWriter);
printMembersSummary(adviceSubWriter);
}
/**
* Formats the output correctly for a member summary.
*
* @param mw the AbstractSubWriter to use.
*/
protected final void printMembersSummary(AbstractSubWriter mw) {
if (mw != null) {
println();
println("");
println();
mw.printMembersSummary();
}
}
/**
* Print the members detail for our AspectJ subwriters.
*/
protected void printAspectJDetail() {
printMembersDetail(superIntroductionSubWriter);
printMembersDetail(fieldIntroductionSubWriter);
printMembersDetail(constrIntroductionSubWriter);
printMembersDetail(methodIntroductionSubWriter);
printMembersDetail(pointcutSubWriter);
printMembersDetail(adviceSubWriter);
}
/**
* Formats the output correctly for a member detail.
*
* @param mw the AbstractSubWriter to use.
*/
protected final void printMembersDetail(AbstractSubWriter mw) {
if (mw != null) {
println("");
println();
mw.printMembers();
println();
}
}
//TODO: Just need to make sure 'aspect; shows up and
//TODO not 'class'
protected void printClassDescription() {
boolean isInterface = classdoc.isInterface();
boolean isAspect = classdoc instanceof AspectDoc;
dl();
dt();
print(classdoc.modifiers() + " ");
if (!isInterface) {
print(isAspect ? "aspect " : "class ");
}
bold(classdoc.name());
if (!isInterface) {
ClassDoc superclass = classdoc.superclass();
if (superclass != null) {
dt();
print("extends ");
printClassLink(superclass);
printIntroducedSuper(superclass);
}
}
ClassDoc[] implIntfacs = classdoc.interfaces();
if (implIntfacs != null && implIntfacs.length > 0) {
dt();
print(isInterface? "extends " : "implements ");
for (int i = 0; i < implIntfacs.length; i++) {
if (i > 0) print(", ");
printClassLink(implIntfacs[i]);
printIntroducedSuper(implIntfacs[i]);
}
}
if (isAspect) {
AspectDoc ad = (AspectDoc)classdoc;
OfClauseDoc ofClause = ad.ofClause();
if (ofClause != null) {
dt();
if (ofClause.kind() == OfClauseDoc.Kind.EACH_CFLOW) {
print("percflow(..)");
} else if (ofClause.kind() == OfClauseDoc.Kind.EACH_JVM) {
print("issingleton()");
} else if (ofClause.kind() == OfClauseDoc.Kind.EACH_OBJECT) {
print("pertarget(");
printClassLinks(((OfEachObjectDoc)ofClause).instances());
print(")");
}
}
AspectDoc[] dominatees = ad.dominatees();
if (dominatees != null && dominatees.length > 0) {
dt();
print("dominates ");
printClassLinks(dominatees);
}
AspectDoc[] dominators = ad.dominators();
if (dominators != null && dominators.length > 0) {
dt();
print("dominated by ");
printClassLinks(dominators);
}
}
dlEnd();
}
/**
* Prints a list of class links separated by commas.
*
* @param cds array of ClassDoc to be printed.
*/
protected void printClassLinks(ClassDoc[] cds) {
if (cds == null || cds.length < 1) return;
for (int i = 0; i < cds.length; i++) {
if (i > 0) print(", ");
if (cds[i] != null) {
printClassLink(cds[i]);
}
}
}
/**
* Prints information about classdoc
's type introduction
* if cd
's type was introduced onto classdoc
.
*
* @param cd the ClassDoc being printed.
*/
protected void printIntroducedSuper(ClassDoc cd) {
IntroducedSuperDoc[] intros =
((org.aspectj.ajdoc.ClassDoc)classdoc).introducers();
if (null != intros) {
for (int i = 0; i < intros.length; i++) {
IntroducedSuperDoc intro = intros[i];
org.aspectj.ajdoc.Type[] types = intro.types();
for (int j = 0; j < types.length; j++) {
if (types[j].equals(cd)) {
print(' ');
printText("doclet.by_parens",
getClassLink
(intro.containingClass(),
superIntroductionSubWriter.link(intro),
"introduced"),
getClassLink(intro.containingClass()));
break;
}
}
}
}
}
/**
* Print the navSummaryLink for all the AspectJ subwriters.
*/
protected void navAspectJSummaryLinks() {
navSummaryLink(superIntroductionSubWriter);
navSummaryLink(fieldIntroductionSubWriter);
navSummaryLink(constrIntroductionSubWriter);
navSummaryLink(methodIntroductionSubWriter);
navSummaryLink(pointcutSubWriter);
navSummaryLink(adviceSubWriter);
}
/**
* Prints the navSummaryLink correctly.
*
* @param mw AbstractSubWriter to invoke.
*/
protected final void navSummaryLink(AbstractSubWriter mw) {
if (mw != null) {
mw.navSummaryLink();
_navGap();
}
}
/**
* Print the navDetailLink for all the AspectJ subwriters.
*/
protected void navAspectJDetailLinks() {
navDetailLink(superIntroductionSubWriter);
navDetailLink(fieldIntroductionSubWriter);
navDetailLink(constrIntroductionSubWriter);
navDetailLink(methodIntroductionSubWriter);
navDetailLink(pointcutSubWriter);
navDetailLink(adviceSubWriter);
}
/**
* Prints the navDetailLink correctly.
*
* @param mw AbstractSubWriter to invoke.
*/
protected final void navDetailLink(AbstractSubWriter mw) {
if (mw != null) {
mw.navDetailLink();
_navGap();
}
}
/*
* A hack... I'll explain later, if you need to change
* this mail jeffrey_palm@hotmail.com.
*/
protected final void _navGap() { super.navGap(); }
protected int navstate = 0;
protected void navGap() {
_navGap();
if (navstate == 1) {
navAspectJSummaryLinks();
navstate++;
} else if (navstate == 3) {
navAspectJDetailLinks();
navstate++;
}
}
protected void printEnclosingClassInfo() {
super.printEnclosingClassInfo();
printAdvisorInfo();
printAdviseeInfo();
}
protected void printAdviseeInfo() {
if (!(classdoc instanceof AspectDoc)) return;
AspectDoc ad = (AspectDoc)classdoc;
Set set = new TreeSet();
AdviceDoc[] as = ad.advice();
if (as != null) {
for (int i = 0; i < as.length; i++) {
ExecutableMemberDoc[] crosscuts = as[i].crosscuts();
if (null != crosscuts) {
for (int j = 0; j < crosscuts.length; j++) {
if (null != crosscuts[j]) {
set.add(crosscuts[j].containingClass());
}
}
}
}
}
IntroductionDoc[] is = ad.introductions();
if (null != is) {
for (int i = 0 ; i < is.length; i++) {
ClassDoc[] targets = is[i].targets();
for (int j = 0; j < targets.length; j++) {
set.add(targets[j]);
}
}
printInfo(set, "doclet.All_Advisees");
}
}
protected void printAdvisorInfo() {
Set set = new TreeSet();
set.addAll(advisors(classdoc.fields()));
set.addAll(advisors(classdoc.methods()));
set.addAll(advisors(classdoc.constructors()));
printInfo(set, "doclet.All_Advisors");
}
protected void printInfo(Collection classdocs, String str) {
if ((null != classdocs) && (classdocs.size() > 0)) {
printInfoHeader();
boldText(str);
dd();
for (Iterator i = classdocs.iterator(); i.hasNext();) {
printClassLink((ClassDoc)i.next());
if (i.hasNext()) print(", ");
}
ddEnd();
dlEnd();
}
}
protected final Collection advisors(final MemberDoc[] ms) {
List list = new ArrayList();
if (null != ms) {
for (int i = 0 ; i < ms.length; i++) {
IntroducedDoc id =
((org.aspectj.ajdoc.MemberDoc)ms[i]).introduced();
if (id != null) list.add(id.containingClass());
if (ms[i] instanceof org.aspectj.ajdoc.ExecutableMemberDoc) {
AdviceDoc[] as =
((org.aspectj.ajdoc.ExecutableMemberDoc)ms[i]).advice();
for (int j = 0; j < as.length; j++) {
list.add(as[j].containingClass());
}
}
}
}
return list;
}
}