KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > DocletTask


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

5 package xdoclet;
6
7 import java.io.File JavaDoc;
8 import java.util.ArrayList JavaDoc;
9 import java.util.HashMap JavaDoc;
10 import java.util.Iterator JavaDoc;
11 import java.util.List JavaDoc;
12 import java.util.Map JavaDoc;
13
14 import org.apache.tools.ant.BuildException;
15 import org.apache.tools.ant.DynamicConfigurator;
16 import org.apache.tools.ant.Project;
17 import org.apache.tools.ant.types.FileSet;
18
19 import xjavadoc.ant.XJavadocTask;
20
21 import xdoclet.loader.ModuleFinder;
22 import xdoclet.loader.SubTaskDefinition;
23 import xdoclet.loader.XDocletModule;
24
25 import xdoclet.util.Translator;
26
27 /**
28  * A base class for all Tasks. It can also be used directly, useful for the case where you want to execute a template
29  * file but you don't want to bother writing a new task.
30  *
31  * @author Ara Abrahamian (ara_e@email.com)
32  * @author <a HREF="mailto:aslak.hellesoy@bekk.no">Aslak Helles�y</a>
33  * @created June 19, 2001
34  * @ant.element name="xdoclet" display-name="XDoclet Standard Task"
35  * @ant.attribute name="encoding" description="Specify the source file encoding name, such as Windows-31J, EUC-JP,
36  * UTF-8. In default, system default encoding is used."
37  * @ant.attribute name="docencoding" description="Specify encoding name for template engine. The generated file
38  * encoding may be this value. In default, system default encoding is used."
39  */

40 public class DocletTask extends XJavadocTask implements DynamicConfigurator
41 {
42     // ant will replace the tag with the version property specified in build.xml
43
public final static String JavaDoc XDOCLET_VERSION = "@VERSION@";
44
45     /**
46      * subtask class -> logical name (java.lang.String) Used to look up names. Lazily created.
47      */

48     private static Map JavaDoc subtaskNameMap;
49     /**
50      * logical name (java.lang.String) -> subtask (xdoclet.SubTask or a subclass of it). Lazily created.
51      */

52     private static Map JavaDoc subtaskMap;
53
54     private List JavaDoc packageSubstitutions = new ArrayList JavaDoc();
55
56     private boolean isModulesRegistered = false;
57
58     private File JavaDoc destDir;
59     private File JavaDoc mergeDir;
60     private String JavaDoc excludedTags = null;
61     private boolean force = false;
62     private boolean verbose = false;
63     private String JavaDoc addedTags;
64     private List JavaDoc subTasks = new ArrayList JavaDoc();
65     private List JavaDoc configParams = new ArrayList JavaDoc();
66
67     public DocletTask()
68     {
69         ModuleFinder.initClasspath(getClass());
70     }
71
72     public static String JavaDoc getSubTaskName(Class JavaDoc subTaskClass)
73     {
74         return (String JavaDoc) getSubtaskNameMap().get(subTaskClass);
75     }
76
77     static Map JavaDoc getConfigParamsAsMap(List JavaDoc configParams)
78     {
79         HashMap JavaDoc map = new HashMap JavaDoc();
80
81         for (Iterator JavaDoc i = configParams.iterator(); i.hasNext(); ) {
82             ConfigParameter cp = (ConfigParameter) i.next();
83
84             map.put(cp.getName(), cp.getValue());
85         }
86         return map;
87     }
88
89     static void registerSubTaskName(SubTask subTask, String JavaDoc name)
90     {
91         getSubtaskNameMap().put(subTask.getClass(), name);
92     }
93
94     private static Map JavaDoc getSubtaskMap()
95     {
96         if (subtaskMap == null)
97             subtaskMap = new HashMap JavaDoc();
98
99         return subtaskMap;
100     }
101
102     private static Map JavaDoc getSubtaskNameMap()
103     {
104         if (subtaskNameMap == null)
105             subtaskNameMap = new HashMap JavaDoc();
106
107         return subtaskNameMap;
108     }
109
110     /**
111      * Gets the PackageSubstitutions attribute of the EjbDocletTask object
112      *
113      * @return The PackageSubstitutions value
114      */

115     public List JavaDoc getPackageSubstitutions()
116     {
117         return packageSubstitutions;
118     }
119
120     /**
121      * Gets the ConfigParams attribute of the DocletTask object
122      *
123      * @return The ConfigParams value
124      */

125     public List JavaDoc getConfigParams()
126     {
127         return configParams;
128     }
129
130     public Map JavaDoc getConfigParamsAsMap()
131     {
132         return getConfigParamsAsMap(getConfigParams());
133     }
134
135     /**
136      * Gets the MergeDir attribute of the DocletTask object
137      *
138      * @return The MergeDir value
139      */

140     public File JavaDoc getMergeDir()
141     {
142         return mergeDir;
143     }
144
145     /**
146      * Gets the ExcludedTags attribute of the DocletTask object
147      *
148      * @return The ExcludedTags value
149      */

150     public String JavaDoc getExcludedTags()
151     {
152         return excludedTags;
153     }
154
155     /**
156      * Gets the DestDir attribute of the DocletTask object
157      *
158      * @return The DestDir value
159      */

160     public File JavaDoc getDestDir()
161     {
162         return destDir;
163     }
164
165     /**
166      * Gets the Force attribute of the DocletTask object.
167      *
168      * @return The Force value
169      */

170     public boolean isForce()
171     {
172         return force;
173     }
174
175     /**
176      * Gets the Verbose attribute of the DocletTask object.
177      *
178      * @return The Verbose value
179      */

180     public boolean isVerbose()
181     {
182         return verbose;
183     }
184
185     public String JavaDoc getAddedTags()
186     {
187         return addedTags;
188     }
189
190     /**
191      * Sets the PackageSubstitutions attribute of the EjbDocletTask object
192      *
193      * @param packageSubstitutions The new PackageSubstitutions value
194      * @ant.ignore
195      */

196     public void setPackageSubstitutions(List JavaDoc packageSubstitutions)
197     {
198         this.packageSubstitutions = packageSubstitutions;
199     }
200
201     /**
202      * @param name
203      * @param value
204      */

205     public void setDynamicAttribute(String JavaDoc name, String JavaDoc value)
206     {
207         throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.ATTRIBUTE_NOT_SUPPORTED, new String JavaDoc[]{getTaskName(), name}));
208     }
209
210     /**
211      * Sets the PackageNames attribute of the DocletTask object
212      *
213      * @param src The new PackageNames value
214      * @deprecated
215      * @ant.ignore
216      */

217     public void setPackageNames(String JavaDoc src)
218     {
219         throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.OBSOLETE_TASK_ATTRIBUTE, new String JavaDoc[]{"packageNames"}));
220     }
221
222     /**
223      * Sets the ExcludePackageNames attribute of the DocletTask object
224      *
225      * @param src The new ExcludePackageNames value
226      * @deprecated
227      * @ant.ignore
228      */

229     public void setExcludePackageNames(String JavaDoc src)
230     {
231         throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.OBSOLETE_TASK_ATTRIBUTE, new String JavaDoc[]{"excludePackageNames"}));
232     }
233
234     /**
235      * Specify tags that should not be automatically written to output files. The normal behaviour is to include all @
236      * tags from the source file to the output files. This may cause trouble if you use cvs-like tag like $Revision: 1.5
237      * $ that will be overwritten at each build and causes a difference for CVS even if the code himself is not changed.
238      * Example: excludedtags="@ version" For excluded tags, ejbdoclet will generate an hardcoded tag. Example: @ version
239      * XDOCLET 1.0
240      *
241      * @param tags The new ExcludedTags value
242      * @deprecated
243      */

244     public void setExcludedTags(String JavaDoc tags)
245     {
246         excludedTags = tags;
247     }
248
249     /**
250      * Destination directory for output files
251      *
252      * @param dir The new DestDir value
253      * @ant.not-required Only if it's not specified for a subtask.
254      */

255     public void setDestDir(File JavaDoc dir)
256     {
257         destDir = dir;
258     }
259
260     /**
261      * Directory where subtasks will look for files to be merged with generated files.
262      *
263      * @param dir The new MergeDir value
264      * @ant.not-required No, but should be set if you want to use the merge feature.
265      */

266     public void setMergeDir(File JavaDoc dir)
267     {
268         mergeDir = dir;
269     }
270
271     /**
272      * Specify if the generation of files should be forced. In normal cases, the timestamp of generated file is checked
273      * against the timestamps of the class (and its super classes) we generate from. When this timestamp checking should
274      * be bypassed (for example after the installtion of a new xdoclet version) then the user should force the
275      * regeneration. The easiest way is to run the Ant build file with a parameter "-Dxdoclet.force=true" and add the
276      * option "force=${xdoclet.force}" to the doclet call.
277      *
278      * @param force The new Force value
279      */

280     public void setForce(boolean force)
281     {
282         this.force = force;
283     }
284
285     /**
286      * Sets the Verbose attribute of the DocletTask object.
287      *
288      * @param verbose The new Verbose value
289      */

290     public void setVerbose(boolean verbose)
291     {
292         this.verbose = verbose;
293     }
294
295     /**
296      * Add some JavaDoc tags (or comments) to the generated classes. A special case @ xdoclet-generated. If this is
297      * included, ejbdoclet will not consider the file if it is by error in the fileset of the ejbdoclet task.
298      *
299      * @param addedTags
300      */

301     public void setAddedTags(String JavaDoc addedTags)
302     {
303         this.addedTags = addedTags;
304     }
305
306     /**
307      * Substitutes the package of the generated files.
308      *
309      * @param ps The feature to be added to the Fileset attribute
310      */

311     public void addPackageSubstitution(xdoclet.tagshandler.PackageTagsHandler.PackageSubstitution ps)
312     {
313         packageSubstitutions.add(ps);
314     }
315
316     /**
317      * Ant's &lt;fileset&gt; definition. To define the files to parse.
318      *
319      * @param set a fileset to add
320      */

321     public void addFileset(FileSet set)
322     {
323         // does nothing apart from calling super - it's only here for the
324
// javadocs, for the generated documentation.
325
super.addFileset(set);
326     }
327
328     /**
329      * @param name
330      * @return
331      * @exception BuildException
332      */

333     public Object JavaDoc createDynamicElement(String JavaDoc name) throws BuildException
334     {
335         if (!isModulesRegistered) {
336             registerModules();
337             isModulesRegistered = true;
338         }
339
340         SubTask subTask = (SubTask) getSubtaskMap().get(name);
341
342         if (subTask == null) {
343             throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.CREATE_TASK_ERROR, new String JavaDoc[]{name, getTaskName()}));
344         }
345         subTasks.add(subTask);
346         return subTask;
347     }
348
349     /**
350      * Generic subtask.
351      *
352      * @param subtask The subtask to be added
353      * @ant.ignore
354      */

355     public void addSubTask(SubTask subtask)
356     {
357         subTasks.add(subtask);
358     }
359
360     /**
361      * Generic subtask for processing a user-supplied template.
362      *
363      * @param subtask Describe the method parameter
364      * @exception BuildException
365      * @ant.ignore
366      */

367     public void addTemplate(TemplateSubTask subtask) throws BuildException
368     {
369         if (subtask.getSubTaskClassName() == null) {
370             addSubTask(subtask);
371         }
372         else {
373             try {
374                 Class JavaDoc subtaskClass = Class.forName(subtask.getSubTaskClassName());
375                 TemplateSubTask alias = (TemplateSubTask) subtaskClass.newInstance();
376
377                 // now copy from subtask to real alias
378
alias.copyAttributesFrom(subtask);
379
380                 addSubTask(alias);
381             }
382             catch (ClassNotFoundException JavaDoc e) {
383                 throw new BuildException(Translator.getString(XDocletMessages.class,
384                     XDocletMessages.CLASS_NOT_FOUND_EXCEPTION,
385                     new String JavaDoc[]{subtask.getSubTaskClassName(), e.getMessage()}), e, location);
386             }
387             catch (InstantiationException JavaDoc e) {
388                 throw new BuildException(Translator.getString(XDocletMessages.class,
389                     XDocletMessages.INSTANTIATION_EXCEPTION,
390                     new String JavaDoc[]{subtask.getSubTaskClassName(), e.getMessage()}), e, location);
391             }
392             catch (IllegalAccessException JavaDoc e) {
393                 throw new BuildException(Translator.getString(XDocletMessages.class,
394                     XDocletMessages.ILLEGAL_ACCESS_EXCEPTION,
395                     new String JavaDoc[]{subtask.getSubTaskClassName(), e.getMessage()}), e, location);
396             }
397         }
398     }
399
400     /**
401      * Generic subtask for processing a user-supplied template, to generate an XML document.
402      *
403      * @param subtask Describe the method parameter
404      * @ant.ignore
405      */

406     public void addXmlTemplate(XmlSubTask subtask)
407     {
408         addTemplate(subtask);
409     }
410
411     /**
412      * Allows to set configuration parameters that will be included in the element as attribute value pair.
413      *
414      * @param configParam Describe the method parameter
415      */

416     public void addConfigParam(ConfigParameter configParam)
417     {
418         configParams.add(configParam);
419     }
420
421     /**
422      * Gets the SubTasks attribute of the DocletTask object
423      *
424      * @return The SubTasks value
425      */

426     protected final List JavaDoc getSubTasks()
427     {
428         return subTasks;
429     }
430
431     /**
432      * Gets the ConfigParams attribute of the DocletTask object
433      *
434      * @param subtasks Describe what the parameter does
435      * @return The ConfigParams value
436      */

437     protected HashMap JavaDoc getConfigParams(List JavaDoc subtasks)
438     {
439         HashMap JavaDoc configs = new HashMap JavaDoc();
440
441         // config params of task
442
ConfigParamIntrospector.fillConfigParamsFor(this, configs);
443
444         // config params of substask
445
for (int i = 0; i < subtasks.size(); i++) {
446             SubTask subtask = (SubTask) subtasks.get(i);
447
448             if (subtask != null) {
449                 ConfigParamIntrospector.fillConfigParamsFor(subtask, configs);
450
451                 // user defined params of SubTask
452
fillWithUserDefinedConfigParams(configs, subtask.getConfigParams(), subtask.getSubTaskName() + '.');
453             }
454         }
455
456         // user defined params of DocletTask
457
fillWithUserDefinedConfigParams(configs, getConfigParams(), "");
458
459         return configs;
460     }
461
462     /**
463      * @exception BuildException
464      */

465     protected void start() throws BuildException
466     {
467         try {
468             new XDocletMain().start(getXJavaDoc());
469         }
470         catch (XDocletException e) {
471             throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.XDOCLET_FAILED), e, location);
472         }
473         finally {
474             DocletContext.setSingleInstance(null);
475             // Fix for http://opensource.atlassian.com/projects/xdoclet/browse/XDT-879
476
//subtaskNameMap = null;
477
//subtaskMap = null;
478
//destDir = null;
479
//mergeDir = null;
480
//subTasks = null;
481
//configParams = null;
482

483             ModuleFinder.resetFoundModules();
484         }
485     }
486
487     /**
488      * Called by superclass before start() is called
489      *
490      * @exception BuildException Describe the exception
491      */

492     protected void validateOptions() throws BuildException
493     {
494         super.validateOptions();
495         if (destDir == null) {
496             throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.ATTRIBUTE_NOT_PRESENT_ERROR, new String JavaDoc[]{"destDir"}), location);
497         }
498         validateSubTasks();
499     }
500
501     /**
502      * Throws BuildException if a specific class is not on the CP. Should be called from subclasses' validateOptions()
503      * to verify that classpath is OK.
504      *
505      * @param className
506      */

507     protected void checkClass(String JavaDoc className)
508     {
509         try {
510             Class.forName(className);
511         }
512         catch (Exception JavaDoc e) {
513             throw new BuildException(Translator.getString(XDocletMessages.class, XDocletMessages.CHECK_CLASS_FAILED, new String JavaDoc[]{className, getTaskName()}));
514         }
515     }
516
517     /**
518      * Describe what the method does
519      *
520      * @exception BuildException Describe the exception
521      */

522     protected void validateSubTasks() throws BuildException
523     {
524         DocletContext context = createContext();
525         SubTask[] subtasks = context.getSubTasks();
526
527         for (int i = 0; i < subtasks.length; i++) {
528             SubTask subtask = subtasks[i];
529
530             if (subtask != null) {
531                 log("validating subTask: " + subtask.getSubTaskName() + " class: " + subtask.getClass(), Project.MSG_DEBUG);
532                 try {
533                     subtask.validateOptions();
534                 }
535                 catch (XDocletException ex) {
536                     throw new BuildException(subtask.getSubTaskName() + ": " + ex.getMessage(), location);
537                 }
538             }
539         }
540     }
541
542     private void registerModules()
543     {
544         // Register subtasks that apply to us (they do if they in xdoclet.xml have declared us as parent)
545
List JavaDoc modules = ModuleFinder.findModules();
546         Iterator JavaDoc i = modules.iterator();
547
548         while (i.hasNext()) {
549             XDocletModule module = (XDocletModule) i.next();
550             List JavaDoc subTaskDefinitions = module.getSubTaskDefinitions();
551             Iterator JavaDoc j = subTaskDefinitions.iterator();
552
553             while (j.hasNext()) {
554                 SubTaskDefinition subTaskDefinition = (SubTaskDefinition) j.next();
555
556                 try {
557                     Class JavaDoc parentTaskClass = Class.forName(subTaskDefinition.parentTaskClass);
558
559                     if (parentTaskClass.isAssignableFrom(getClass())) {
560                         if (getSubtaskMap().containsKey(subTaskDefinition.name)) {
561                             String JavaDoc conflictingSubTaskClassName = getSubtaskMap().get(subTaskDefinition.name).getClass().getName();
562
563                             if (!subTaskDefinition.implementationClass.equals(conflictingSubTaskClassName)) {
564                                 // duplicate subtask definition, and it's not the same classname (which occurs
565
// if a module is twice or more on classpath - which is OK)
566
throw new BuildException(Translator.getString(XDocletMessages.class,
567                                     XDocletMessages.AMBIGUOUS_SUBTASK_DEFINITION,
568                                     new String JavaDoc[]{subTaskDefinition.name, conflictingSubTaskClassName,
569                                     subTaskDefinition.implementationClass}));
570                             }
571
572                             //make sure a new subtask is not created when we can use an already created one. This happens
573
//when you run the task several times.
574
continue;
575                         }
576
577                         Class JavaDoc subTaskClass = Class.forName(subTaskDefinition.implementationClass);
578                         SubTask subTask = (SubTask) subTaskClass.newInstance();
579
580                         log("Registering SubTask " + subTaskDefinition.name + " (" + subTaskDefinition.implementationClass + ") to DocletTask " + getClass().getName(), Project.MSG_DEBUG);
581                         getSubtaskMap().put(subTaskDefinition.name, subTask);
582                         registerSubTaskName(subTask, subTaskDefinition.name);
583                     }
584                 }
585                 catch (ClassNotFoundException JavaDoc e) {
586                     throw new BuildException(Translator.getString(XDocletMessages.class,
587                         XDocletMessages.DEPENDENT_CLASS_FOR_SUBTASK_NOT_FOUND,
588                         new String JavaDoc[]{subTaskDefinition.parentTaskClass, ModuleFinder.getClasspath()}), e);
589                 }
590                 catch (InstantiationException JavaDoc e) {
591                     throw new BuildException(Translator.getString(XDocletMessages.class,
592                         XDocletMessages.INSTANTIATION_EXCEPTION,
593                         new String JavaDoc[]{subTaskDefinition.implementationClass, e.getMessage()}), e);
594                 }
595                 catch (IllegalAccessException JavaDoc e) {
596                     throw new BuildException(Translator.getString(XDocletMessages.class,
597                         XDocletMessages.ILLEGAL_ACCESS_EXCEPTION,
598                         new String JavaDoc[]{subTaskDefinition.implementationClass, e.getMessage()}), e);
599                 }
600                 catch (ClassCastException JavaDoc e) {
601                     throw new BuildException(Translator.getString(XDocletMessages.class,
602                         XDocletMessages.CLASS_CAST_EXCEPTION,
603                         new String JavaDoc[]{subTaskDefinition.implementationClass, SubTask.class.getName()}), e);
604                 }
605             }
606         }
607     }
608
609     /**
610      * Returns the singleton context object and creates it if not already created and registers it as the single
611      * instance.
612      *
613      * @return the singleton context object
614      */

615     private DocletContext createContext()
616     {
617         if (DocletContext.getInstance() != null) {
618             return DocletContext.getInstance();
619         }
620
621         List JavaDoc subtasks = getSubTasks();
622         HashMap JavaDoc configs = getConfigParams(subtasks);
623
624         DocletContext context = new DocletContext(
625             this.destDir.toString(),
626             this.mergeDir != null ? this.mergeDir.toString() : null,
627             this.excludedTags,
628             (SubTask[]) subtasks.toArray(new SubTask[0]),
629             project.getProperties(),
630             configs,
631             force,
632             verbose,
633             addedTags
634             );
635
636         // now register this single instance
637
DocletContext.setSingleInstance(context);
638
639         return context;
640     }
641
642     /**
643      * Describe what the method does
644      *
645      * @param configs Describe what the parameter does
646      * @param configParams Describe what the parameter does
647      * @param prefix Describe what the parameter does
648      */

649     private void fillWithUserDefinedConfigParams(HashMap JavaDoc configs, List JavaDoc configParams, String JavaDoc prefix)
650     {
651         // config params declared with <configParam name="nnn" value="val"/>
652
for (int i = 0; i < configParams.size(); i++) {
653             ConfigParameter configParam = (ConfigParameter) configParams.get(i);
654
655             configs.put((prefix + configParam.getName()).toLowerCase(), configParam.getValue());
656         }
657     }
658
659 }
660
Popular Tags