KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > modules > doc > AntdocSubTask


1 /*
2  * Copyright (c) 2001, 2002 The XDoclet team
3  * All rights reserved.
4  */

5 package xdoclet.modules.doc;
6
7 import java.beans.Introspector JavaDoc;
8
9 import java.util.*;
10
11 import xjavadoc.*;
12
13 import xdoclet.TemplateSubTask;
14 import xdoclet.XDocletException;
15 import xdoclet.template.TemplateEngine;
16 import xdoclet.template.TemplateException;
17
18 /**
19  * Generates ant docs. Introspects classes and looks for nested elements. Generates one single file for each element.
20  * All generated element docs also links nested elements' docs.
21  *
22  * @author Aslak Hellesøy
23  * @created 21. juli 2002
24  * @ant.element display-name="Ant documentation" name="antdocs" parent="xdoclet.DocletTask"
25  * @todo use DocletTask as parent instead. should be enough.
26  * @version $Revision: 1.17 $
27  */

28 public class AntdocSubTask extends TemplateSubTask
29 {
30     private static String JavaDoc ANTDOC_TEMPLATE_FILE = "resources/antdoc-xdoc.xdt";
31
32     /**
33      * Usually, one class corresponds to only one XML element, but in some rare cases it might correspond to more. This
34      * is if the same class is used in e.g. several create methods: <code>Gee createFoo()</code>, <code>Gee createBar()</code>
35      * <p>
36      *
37      * The Gee class corresponds to &lt;foo&gt; AND &lt;bar&gt;. This map's values are Sets containing AntElements.</p>
38      */

39     protected final Map classToAntElementMap = new HashMap();
40
41     private final Set alreadyRecursed = new HashSet();
42
43     public String JavaDoc getDestinationFile()
44     {
45         return "{0}.xml";
46     }
47
48     public void init(XJavaDoc xJavaDoc) throws XDocletException
49     {
50         super.init(xJavaDoc);
51
52         if (getTemplateURL() == null) {
53             setTemplateURL(getClass().getResource(ANTDOC_TEMPLATE_FILE));
54         }
55
56         // Discover the top elements
57
discoverTasks();
58
59         // Link from bottom and up. Dynamic elements know who their parents are
60
discoverDynamicElements();
61
62         // Link from top and down. Look for addBlaBla(), addConfiguredBlaBla() and createBlaBla()
63
discoverChildElements();
64     }
65
66     public void validateOptions() throws XDocletException
67     {
68         // super.validateOptions();
69
}
70
71     protected boolean processInnerClasses()
72     {
73         return true;
74     }
75
76     protected void generateForClass(XClass clazz) throws XDocletException
77     {
78         Element element = (Element) classToAntElementMap.get(clazz);
79         AntdocTagsHandler antdocTagsHandler = null;
80
81         try {
82             antdocTagsHandler = (AntdocTagsHandler) TemplateEngine.getEngineInstance().getTagHandlerFor("Antdoc");
83         }
84         catch (TemplateException e) {
85             throw new XDocletException(e.getMessage());
86         }
87         antdocTagsHandler.setDocElement(element);
88         super.generateForClass(clazz);
89     }
90
91     protected boolean matchesGenerationRules(XClass clazz) throws XDocletException
92     {
93         // We only want to generate for classes that correspond to AntElements
94
boolean result = classToAntElementMap.containsKey(clazz);
95
96         return result;
97     }
98
99     /**
100      * Gets an AntElement. If the element doesn't exist, it is created.
101      *
102      * @param clazz the class to use for the element
103      * @return
104      */

105     private Element getElement(XClass clazz)
106     {
107         Element element = (Element) classToAntElementMap.get(clazz);
108
109         if (element == null) {
110             element = new Element(clazz);
111
112             classToAntElementMap.put(clazz, element);
113         }
114         return element;
115     }
116
117     /**
118      * Scans all sources to discover what classes can be interfaced by Ant. Starts by looking at all classes passed to
119      * XDoclet (Should be Ant tasks only), then by introspecting the addBlaBla, addConfiguredBlaBla and createBlaBla
120      * methods to discover additonal classes that represent nested elements.
121      */

122     private void discoverTasks()
123     {
124         // Register the "top" elements, that is, regular Ant tasks
125
Collection classes = getXJavaDoc().getSourceClasses();
126
127         for (Iterator i = classes.iterator(); i.hasNext(); ) {
128             XClass clazz = (XClass) i.next();
129
130             if ((clazz.isA("org.apache.tools.ant.Task") || clazz.isA("org.apache.tools.ant.types.DataType")) && !clazz.isAbstract() && clazz.isPublic()) {
131                 getElement(clazz);
132                 // This will register the element in the global map
133
}
134         }
135     }
136
137     /**
138      * Discovers dynamic elements.
139      */

140     private void discoverDynamicElements()
141     {
142         Collection classes = getXJavaDoc().getSourceClasses();
143
144         for (Iterator i = classes.iterator(); i.hasNext(); ) {
145             XClass child = (XClass) i.next();
146             XDoc doc = child.getDoc();
147
148             String JavaDoc parentClassName = doc.getTagAttributeValue("ant.element", "parent");
149             String JavaDoc elementName = doc.getTagAttributeValue("ant.element", "name");
150
151             if (parentClassName != null) {
152                 XClass parent = getXJavaDoc().getXClass(parentClassName);
153
154                 if (parent.isA("org.apache.tools.ant.DynamicConfigurator")) {
155                     // Both clazz and parentClazz are Ant elements
156
Element childElement = getElement(child);
157                     Element parentElement = getElement(parent);
158                     SubElement subElement = new SubElement(childElement, null, elementName);
159
160                     parentElement.addSubElement(subElement);
161                 }
162             }
163         }
164     }
165
166     private void discoverChildElements()
167     {
168         // Iterate over the elements we've discovered so far.
169
// Can't use an iterator because antElements will be modified
170
List soFar = Arrays.asList(classToAntElementMap.values().toArray());
171
172         for (Iterator i = soFar.iterator(); i.hasNext(); ) {
173             Element element = (Element) i.next();
174
175             addChidrenRecursive(element);
176         }
177     }
178
179     private void addChidrenRecursive(Element element)
180     {
181         Collection methods = element.getXClass().getMethods(true);
182
183         for (Iterator i = methods.iterator(); i.hasNext(); ) {
184             XMethod method = (XMethod) i.next();
185
186             addChildElementMaybe(element, method);
187         }
188     }
189
190     private void addChildElementMaybe(Element parentElement, XMethod method)
191     {
192         XClass clazz = null;
193         String JavaDoc name = null;
194
195         if (method.isPublic()) {
196             if (method.getName().startsWith("create") && method.getParameters().size() == 0 && method.getReturnType().getDimension() == 0) {
197                 // public AntElementClass createFoo()
198
clazz = method.getReturnType().getType();
199                 name = Introspector.decapitalize(method.getName().substring(6));
200             }
201             else if (method.getName().startsWith("addConfigured") && method.getParameters().size() == 1 && method.getReturnType().getType().getQualifiedName().equals("void")) {
202                 // public void addFoo(AntElementClass ne)
203
clazz = ((XParameter) method.getParameters().iterator().next()).getType();
204                 name = Introspector.decapitalize(method.getName().substring(13));
205             }
206             else if (method.getName().startsWith("add") && method.getParameters().size() == 1 && method.getReturnType().getType().getQualifiedName().equals("void")) {
207                 // public void addFoo(AntElementClass ne)
208
clazz = ((XParameter) method.getParameters().iterator().next()).getType();
209                 name = Introspector.decapitalize(method.getName().substring(3));
210             }
211         }
212         if (clazz != null) {
213
214             Element element = getElement(clazz);
215             SubElement subElement = new SubElement(element, method, name);
216
217             parentElement.addSubElement(subElement);
218
219             // Avoid infinite cycles if an element can contain itself, like PatternSet
220
if (!alreadyRecursed.contains(clazz)) {
221                 alreadyRecursed.add(clazz);
222                 addChidrenRecursive(element);
223             }
224         }
225     }
226
227     /**
228      * This class corresponds to an XML element in an Ant build file. This can be a task, or a nested element at any
229      * level.
230      *
231      * @created 21. juli 2002
232      */

233     public class Element
234     {
235         private final String JavaDoc TASK = "task";
236         private final String JavaDoc SUBTASK = "subtask";
237         private final SortedSet subElements = new TreeSet();
238
239         private XClass clazz;
240
241         /**
242          * @param clazz the bean class "implementing" the element
243          */

244         public Element(XClass clazz)
245         {
246             this.clazz = clazz;
247         }
248
249         public Collection getSubElements()
250         {
251             return subElements;
252         }
253
254         public XClass getXClass()
255         {
256             return clazz;
257         }
258
259         public String JavaDoc getName()
260         {
261             String JavaDoc elementName = getXClass().getDoc().getTagAttributeValue("ant.element", "name");
262
263             if (elementName == null) {
264                 String JavaDoc classNameDecapitalized = clazz.getName().toLowerCase();
265
266                 if (classNameDecapitalized.endsWith(SUBTASK)) {
267                     elementName = classNameDecapitalized.substring(0, classNameDecapitalized.length() - SUBTASK.length());
268                 }
269                 else if (classNameDecapitalized.endsWith(TASK)) {
270                     elementName = classNameDecapitalized.substring(0, classNameDecapitalized.length() - TASK.length());
271                 }
272                 else {
273                     elementName = classNameDecapitalized;
274                 }
275             }
276             return elementName;
277         }
278
279         public void addSubElement(SubElement subElement)
280         {
281             subElements.add(subElement);
282         }
283
284         public String JavaDoc toString()
285         {
286             return clazz.getQualifiedName() + "(" + clazz.getClass().getName() + ")";
287         }
288
289         public boolean equals(Object JavaDoc o)
290         {
291
292             return o == this;
293         }
294
295         public int hashCode()
296         {
297             return toString().hashCode();
298         }
299     }
300
301     /**
302      * @created 29. august 2002
303      */

304     public class SubElement implements Comparable JavaDoc
305     {
306         private final Element subject;
307         private final String JavaDoc name;
308         private final XMethod method;
309
310         public SubElement(Element subject, XMethod method, String JavaDoc name)
311         {
312             this.subject = subject;
313             this.name = name;
314             this.method = method;
315         }
316
317         public Element getSubject()
318         {
319             return subject;
320         }
321
322         public String JavaDoc getName()
323         {
324             return name;
325         }
326
327         public boolean isDynamicSubElement()
328         {
329             return method == null;
330         }
331
332         public XClass getXClass()
333         {
334             return getSubject().getXClass();
335         }
336
337         public String JavaDoc getDescription()
338         {
339             if (isDynamicSubElement() == false) {
340                 // hard sub element
341
return method.getDoc().getCommentText();
342             }
343             else {
344                 // dynamic sub element
345
return getXClass().getDoc().getFirstSentence();
346             }
347         }
348
349         public int compareTo(Object JavaDoc o)
350         {
351             SubElement other = (SubElement) o;
352
353             return getName().compareTo(other.getName());
354         }
355     }
356 }
357
Popular Tags