1 package xdoclet.sdk.ant;
2
3 import org.apache.tools.ant.IntrospectionHelper;
4 import org.apache.tools.ant.types.EnumeratedAttribute;
5
6 import xdoclet.XDocletException;
7
8 import xjavadoc.XClass;
9 import xjavadoc.XCollections;
10 import xjavadoc.XMethod;
11 import xjavadoc.XParameter;
12 import xjavadoc.XTag;
13
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.Enumeration;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Properties;
24
25 /***
26 *
27 * @author <a href="mailto:aslak.hellesoy at bekk.no">Aslak Hellesøy</a>
28 * @author Erik Hatcher
29 * @version $Revision: 1.9 $
30 */
31 public class AntUtil {
32 /***
33 * Default category for tasks without a category attribute.
34 */
35 public final static String DEFAULT_CATEGORY = "other";
36 private static Map attributeDisplayMap = new HashMap();
37 private static Map elementDisplayMap = new HashMap();
38 private static String[] fluffPrefixes = { "set a", "set the", "sets a", "sets the" };
39
40 static {
41 attributeDisplayMap.put("java.lang.String", "String");
42 attributeDisplayMap.put("boolean", "boolean");
43 attributeDisplayMap.put("org.apache.tools.ant.types.Path", "Path");
44 attributeDisplayMap.put("org.apache.tools.ant.types.Reference", "Reference");
45 attributeDisplayMap.put("java.io.File", "File");
46 attributeDisplayMap.put("java.util.Date", "Date");
47 attributeDisplayMap.put("java.net.URL", "URL");
48 attributeDisplayMap.put("java.lang.Long", "long");
49 attributeDisplayMap.put("java.lang.Integer", "int");
50 attributeDisplayMap.put("java.lang.Float", "float");
51 attributeDisplayMap.put("java.lang.Double", "double");
52
53 elementDisplayMap.put("org.apache.tools.ant.types.Path", "Path");
54 elementDisplayMap.put("org.apache.tools.ant.types.FileSet", "Fileset");
55 elementDisplayMap.put("org.apache.tools.ant.taskdefs.Property", "see <property>");
56 elementDisplayMap.put("org.apache.tools.ant.types.Mapper", "Mapper");
57 elementDisplayMap.put("org.apache.tools.ant.types.PatternSet", "Patternset");
58 elementDisplayMap.put("org.apache.tools.ant.types.FileList", "Filelist");
59 elementDisplayMap.put("org.apache.tools.ant.types.FilterChain", "FilterChain");
60 elementDisplayMap.put("org.apache.tools.ant.types.FilterSet", "Filterset");
61 elementDisplayMap.put("org.apache.tools.ant.types.ZipFileSet", "ZipFileset");
62 elementDisplayMap.put("org.apache.tools.ant.types.DirSet", "Dirset");
63 elementDisplayMap.put("org.apache.tools.ant.types.XMLCatalog", "XMLCatalog");
64 }
65
66 /***
67 * Provides the Ant task name. Order of rules:
68 * <ol>
69 * <li> Value of @ant.task name="..."</li>
70 * <li> Lowercased classname with "Task" suffix removed</li>
71 * </ol>
72 *
73 * @param clazz the class to for which we're getting the task name.
74 * @return the task name
75 */
76 public final static String getTaskName(XClass clazz) {
77 String tagValue = clazz.getDoc().getTagAttributeValue("ant.task", "name");
78
79 if (tagValue == null) {
80 // use classname, but strip "Task" suffix if there
81 tagValue = clazz.getName();
82
83 if (tagValue.endsWith("Task")) {
84 tagValue = tagValue.substring(0, tagValue.indexOf("Task"));
85 }
86
87 tagValue = tagValue.toLowerCase();
88 }
89
90 return tagValue;
91 }
92
93 /***
94 * Provides the Ant category name as the Value of the category attribute.
95 *
96 * @param clazz the class to for which we're getting the category name.
97 * @return the task category name
98 */
99 public final static String getCategoryName(XClass clazz) {
100 String tagValue = clazz.getDoc().getTagAttributeValue("ant.task", "category");
101
102 if (tagValue != null) {
103 tagValue = tagValue.toLowerCase();
104 } else {
105 tagValue = DEFAULT_CATEGORY;
106 }
107
108 return tagValue;
109 }
110
111 /***
112 * Provides the element name for the current method
113 *
114 * @return the element name
115 * @exception XDocletException
116 */
117 public String elementName(XMethod method)
118 throws XDocletException {
119 String methodName = method.getName();
120 String elementName = "<not a valid element>";
121
122 if (methodName.startsWith("addConfigured")) {
123 elementName = methodName.substring(13, methodName.length());
124 } else if (methodName.startsWith("add")) {
125 elementName = methodName.substring(3, methodName.length());
126 } else if (methodName.startsWith("create")) {
127 elementName = methodName.substring(6, methodName.length());
128 }
129
130 return elementName.toLowerCase();
131 }
132
133 public String displayAttributeType(XMethod method)
134 throws XDocletException {
135 Collection parameters = method.getParameters();
136 XParameter param = XCollections.parameterIterator(parameters).next();
137
138 String methodType = param.getType().getQualifiedName();
139 String display = (String) attributeDisplayMap.get(methodType);
140
141 if (display == null) {
142 Class clazz = getAttributeClass(methodType);
143
144 if (clazz == null) {
145 return methodType;
146 }
147
148 Object instance = null;
149
150 try {
151 instance = clazz.newInstance();
152 } catch (InstantiationException e) {
153 } catch (IllegalAccessException e) {
154 }
155
156 if ((instance != null) && instance instanceof EnumeratedAttribute) {
157 EnumeratedAttribute enum = (EnumeratedAttribute) instance;
158 String[] values = enum.getValues();
159
160 display = "";
161
162 for (int i = 0; i < values.length; i++) {
163 display += (""" + values[i] + """);
164
165 if (i != (values.length - 1)) {
166 display += ", ";
167 }
168 }
169
170 return display;
171 }
172
173 display = "";
174 }
175
176 return display;
177 }
178
179 public String displayElementType()
180 throws XDocletException {
181 String elementType = elementType();
182 String display = (String) elementDisplayMap.get(elementType);
183
184 if (display == null) {
185 display = "";
186 }
187
188 return display;
189 }
190
191 /***
192 * Provides the element type for the current method
193 *
194 * @return the element type (qualified class name).
195 * @exception XDocletException
196 */
197 public String elementType()
198 throws XDocletException {
199 XClass clazz = elementClassDoc();
200
201 if (clazz == null) {
202 throw new XDocletException("Method is not an Ant element!");
203 }
204
205 return clazz.getQualifiedName();
206 }
207
208 public String shortMethodDescription(XMethod method)
209 throws XDocletException {
210 String desc = method.getDoc().getFirstSentence();
211
212 if ((desc == null) || (desc.length() == 0)) {
213 desc = "no description";
214 }
215
216 desc = desc.trim();
217
218 String descLower = desc.toLowerCase();
219
220 for (int i = 0; i < fluffPrefixes.length; i++) {
221 String prefix = fluffPrefixes[i].toLowerCase() + " ";
222
223 if (descLower.startsWith(prefix)) {
224 desc = desc.substring(prefix.length());
225
226 break;
227 }
228 }
229
230 desc = desc.substring(0, 1).toUpperCase() + desc.substring(1);
231
232 if (!desc.endsWith(".")) {
233 desc += ".";
234 }
235
236 return desc;
237 }
238
239 private Class getAttributeClass(String type)
240 throws XDocletException {
241 // System.out.println("type = " + type);
242 Class clazz = null;
243
244 try {
245 clazz = Class.forName(type);
246 } catch (ClassNotFoundException e) {
247 int lastDotPosition = type.lastIndexOf('.');
248
249 if (lastDotPosition < 0) {
250 // probably a primitive
251 return null;
252 }
253
254 type = type.substring(0, lastDotPosition) + "$" + type.substring(lastDotPosition + 1);
255
256 try {
257 clazz = Class.forName(type);
258 } catch (ClassNotFoundException e1) {
259 throw new XDocletException(e1.getMessage());
260 }
261 }
262
263 return clazz;
264 }
265
266 /***
267 * @param cur_class
268 * @return
269 * @exception XDocletException
270 * @todo refactor to cache methods per class, and save some time
271 */
272 private XMethod[] getAttributeMethods(XClass cur_class)
273 throws XDocletException {
274 // Use Ant's own introspection mechanism to gather the
275 // attributes this class supports
276 IntrospectionHelper is = null;
277
278 try {
279 is = IntrospectionHelper.getHelper(Class.forName(cur_class.getQualifiedName()));
280 } catch (ClassNotFoundException e) {
281 throw new XDocletException(e);
282 }
283
284 // Regroup the attributes, since IntrospectionHelper
285 // doesn't give us the whole data structure directly
286 Enumeration enum = is.getAttributes();
287 Properties attributeTypeMap = new Properties();
288
289 while (enum.hasMoreElements()) {
290 String name = (String) enum.nextElement();
291 Class type = is.getAttributeType(name);
292
293 attributeTypeMap.setProperty(name, type.getName());
294
295 // System.out.println(name + " = " + type.getName());
296 }
297
298 // We need to return XMethod[] from this method
299 // so get all methods from the current class
300 XMethod[] allMethods = getMethods(cur_class);
301
302 // System.out.println("allMethods = " + allMethods.length);
303 // And now filter the methods based
304 // on what IntrospectionHelper says
305 List attributeMethods = new ArrayList();
306
307 for (int i = 0; i < allMethods.length; i++) {
308 XMethod method = allMethods[i];
309 String methodName = method.getName();
310
311 // System.out.println("methodName = " + methodName);
312 if (!methodName.startsWith("set")) {
313 continue;
314 }
315
316 String attributeName = methodName.substring(3).toLowerCase();
317
318 // System.out.println("attributeName = " + attributeName);
319 if ((method.getParameters().size() != 1) || (!method.isPublic())) {
320 continue;
321 }
322
323 String attributeType = XCollections.parameterIterator(method.getParameters()).next().getType()
324 .getQualifiedName();
325
326 // System.out.println("attributeType = " + attributeType);
327 String mapAttribute = attributeTypeMap.getProperty(attributeName);
328
329 if (mapAttribute == null) {
330 continue;
331 }
332
333 // inner classes are noted with $ in our map, but not
334 // n the parameter type name.
335 if (!attributeType.equals(mapAttribute.replace('$', '.'))) {
336 continue;
337 }
338
339 // System.out.println(methodName + " : " + attributeName + " : " + attributeType);
340 attributeMethods.add(method);
341 }
342
343 return (XMethod[]) attributeMethods.toArray(new XMethod[0]);
344 }
345
346 /***
347 * @param cur_class
348 * @return methods corresponding to elements
349 * @throws XDocletException if something goes wrong.
350 * @todo add checks for number parameters and appropriate return value
351 * check for proper exception too? method prefixes: add, create,
352 * addConfigured (but not addText)
353 * @todo add DynamicConfigurator (this should be noted in the template,
354 * not dealt with here)
355 */
356 private XMethod[] getElementMethods(XClass cur_class)
357 throws XDocletException {
358 // Use Ant's own introspection mechanism to gather the
359 // elements this class supports
360 IntrospectionHelper is = null;
361
362 try {
363 is = IntrospectionHelper.getHelper(Class.forName(cur_class.getQualifiedName()));
364 } catch (ClassNotFoundException e) {
365 throw new XDocletException(e.getMessage());
366 }
367
368 // Regroup the elements, since IntrospectionHelper
369 // doesn't give us the whole data structure directly
370 Enumeration enum = is.getNestedElements();
371 Properties elementTypeMap = new Properties();
372
373 while (enum.hasMoreElements()) {
374 String name = (String) enum.nextElement();
375 Class type = is.getElementType(name);
376
377 elementTypeMap.setProperty(name, type.getName());
378
379 // System.out.println(name + " = " + type.getName());
380 }
381
382 // We need to return MethodDoc[] from this method
383 // so get all methods from the current class
384 XMethod[] allMethods = getMethods(cur_class);
385
386 // And now filter the MethodDoc's based
387 // on what IntrospectionHelper says
388 List elementMethods = new ArrayList();
389
390 for (int i = 0; i < allMethods.length; i++) {
391 XMethod method = allMethods[i];
392 String methodName = method.getName();
393
394 // Object create(), void add(Object), void addConfigured(Object)
395 String elementName = null;
396
397 // true if addXXX or addConfiguredXXX
398 boolean adder = false;
399
400 if (methodName.startsWith("create")) {
401 elementName = methodName.substring(6).toLowerCase();
402 }
403
404 if (methodName.startsWith("add")) {
405 int length = 3;
406
407 if (methodName.startsWith("addConfigured")) {
408 length = 13;
409 }
410
411 elementName = methodName.substring(length).toLowerCase();
412 adder = true;
413 }
414
415 if (elementName == null) {
416 continue;
417 }
418
419 // System.out.println("elementName = " + elementName);
420 String elementType = null;
421
422 if (adder) {
423 if (method.getParameters().size() != 1) {
424 continue;
425 }
426
427 elementType = XCollections.parameterIterator(method.getParameters()).next().getType().getQualifiedName();
428 } else {
429 elementType = method.getReturnType().getType().getQualifiedName();
430 }
431
432 if (!method.isPublic()) {
433 continue;
434 }
435
436 String mapElementType = elementTypeMap.getProperty(elementName);
437
438 // System.out.println("elementType = " + elementType + " mapElementType = " + mapElementType);
439 if (mapElementType == null) {
440 continue;
441 }
442
443 // inner classes are noted with $ in our map, but not
444 // the parameter type name.
445 if (!elementType.equals(mapElementType.replace('$', '.'))) {
446 continue;
447 }
448
449 elementMethods.add(method);
450 }
451
452 return (XMethod[]) elementMethods.toArray(new XMethod[elementMethods.size()]);
453 }
454
455 /***
456 * This is a slightly refactored (thank you IntelliJ) version of some
457 * cut-and-paste from XDoclet code. It sorts all
458 * methods together rather than in batches of superclasses like XDoclet stuff does.
459 *
460 * @param cur_class
461 * @return
462 */
463 private XMethod[] getMethods(XClass cur_class) {
464 Map already = new HashMap();
465
466 List methods = new ArrayList();
467
468 while (cur_class != null) {
469 // hardcoded to stop when it hits Task, nothing there
470 // or above that needs to be processed
471 if (cur_class.getQualifiedName().equals("org.apache.tools.ant.Task")
472 || cur_class.getQualifiedName().equals("org.apache.tools.ant.taskdefs.MatchingTask")) {
473 break;
474 }
475
476 Collection curMethods = cur_class.getMethods();
477
478 Iterator iter = curMethods.iterator();
479
480 while (iter.hasNext()) {
481 XMethod method = (XMethod) iter.next();
482
483 if (isDeprecated(method)) {
484 continue;
485 }
486
487 if (shouldIgnore(method)) {
488 continue;
489 }
490
491 String methodName = method.getName();
492
493 // System.out.println("method = " + method + ":" + methodName);
494 if (method.getContainingClass() == cur_class) {
495 if (already.containsKey(methodName) == false) {
496 already.put(methodName, method);
497 methods.add(method);
498 }
499 }
500 }
501
502 cur_class = cur_class.getSuperclass();
503 }
504
505 return sortMethods(methods);
506 }
507
508 private boolean isDeprecated(XMethod method) {
509 Collection tags = method.getDoc().getTags();
510 Iterator iter = tags.iterator();
511
512 while (iter.hasNext()) {
513 XTag tag = (XTag) iter.next();
514
515 if (tag.getName().equals("@deprecated")) {
516 return true;
517 }
518 }
519
520 return false;
521 }
522
523 /***
524 * Provides the element type for the current method. If the return type is
525 * null, the first parameter is used.
526 *
527 * @return ??
528 */
529 private XClass elementClassDoc() {
530 XClass clazz = null;
531
532 /*
533 String methodName = getCurrentMethod().getName();
534
535 if (methodName.startsWith("addConfigured") ||
536 methodName.startsWith("add") ||
537 methodName.startsWith("create")) {
538 clazz = getCurrentMethod().getReturnType();
539 if ("void".equals(clazz.getName())) {
540 Collection params = getCurrentMethod().getParameters();
541
542 if (params.size() == 1) {
543 clazz = XCollections.parameterIterator(params).next().getType();
544 }
545 }
546 }
547 // System.out.println(methodName + ": clazz = " + clazz.getQualifiedName());
548 */
549 return clazz;
550 }
551
552 /***
553 * For now, lump attributes and elements together since we won't have those
554 * tags on the same method.
555 *
556 * @param method
557 * @return true if the method should be ignored.
558 */
559 private boolean shouldIgnore(XMethod method) {
560 String value = method.getDoc().getTagAttributeValue("ant.attribute", "ignore");
561
562 if ("true".equalsIgnoreCase(value)) {
563 return true;
564 }
565
566 value = method.getDoc().getTagAttributeValue("ant.element", "ignore");
567
568 if ("true".equalsIgnoreCase(value)) {
569 return true;
570 }
571
572 return false;
573 }
574
575 private XMethod[] sortMethods(List methods) {
576 //sort methods
577 Collections.sort(methods,
578 new Comparator() {
579 public int compare(Object o1, Object o2) {
580 XMethod m1 = (XMethod) o1;
581 XMethod m2 = (XMethod) o2;
582
583 return m1.getName().compareTo(m2.getName());
584 }
585
586 public boolean equals(Object obj) {
587 //dumb
588 return obj == this;
589 }
590 });
591
592 return (XMethod[]) methods.toArray(new XMethod[0]);
593 }
594 }
This page was automatically generated by Maven