KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > tagshandler > PackageTagsHandler


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

5 package xdoclet.tagshandler;
6
7 import java.io.Serializable JavaDoc;
8 import java.util.*;
9
10 import xjavadoc.*;
11
12 import xdoclet.DocletContext;
13 import xdoclet.XDocletException;
14 import xdoclet.XDocletMessages;
15 import xdoclet.template.TemplateException;
16 import xdoclet.util.Translator;
17
18 /**
19  * Tags which manipulate package names and packages, including substitutions.
20  *
21  * @author Ara Abrahamian (ara_e@email.com)
22  * @created Oct 14, 2001
23  * @xdoclet.taghandler namespace="Package"
24  * @version $Revision: 1.16 $
25  */

26 public class PackageTagsHandler extends AbstractProgramElementTagsHandler
27 {
28     /**
29      * Gets the name of a package, optionally applying any substitutions.
30      *
31      * @param pak package
32      * @param withSubstitution whether to apply any substitutions
33      * @return package name
34      */

35     public static String JavaDoc getPackageNameFor(XPackage pak, boolean withSubstitution)
36     {
37         return getPackageNameFor(pak.getName(), withSubstitution);
38     }
39
40     /**
41      * Gets a package name with any subsitutions applied.
42      *
43      * @param packageName package name
44      * @return package name
45      */

46     public static String JavaDoc getPackageNameFor(String JavaDoc packageName)
47     {
48         return getPackageNameFor(packageName, true);
49     }
50
51     /**
52      * Apply package substitutions. If <tt>useFirst</tt> is <tt>true</tt> , the first occurrence of <tt>substituteWith
53      * </tt> will be replaced by <tt>packages</tt> , else the one of the direct container of the current class.
54      *
55      * @param packageName The (current) package name, on which substitution shall take place.
56      * @param withSubstitution true if package substitutions shall take place.
57      * @return The package name after substitutions.
58      */

59     public static String JavaDoc getPackageNameFor(String JavaDoc packageName, boolean withSubstitution)
60     {
61         ArrayList packageSubstitutions = getPackageSubstitutions(DocletContext.getInstance().getActiveSubTask().getSubTaskName());
62
63         if (packageSubstitutions == null || !withSubstitution) {
64             return packageName;
65         }
66
67         for (int i = 0; i < packageSubstitutions.size(); i++) {
68             PackageSubstitution ps = (PackageSubstitution) packageSubstitutions.get(i);
69             StringTokenizer st = new StringTokenizer(ps.getPackages(), ",", false);
70
71             if (ps.getUseFirst() == false) {
72                 while (st.hasMoreTokens()) {
73                     String JavaDoc packages = st.nextToken();
74                     String JavaDoc suffix = "." + packages;
75
76                     if (packageName.endsWith(suffix)) {
77                         if (ps.getSubstituteWith() == null || ps.getSubstituteWith().length() == 0) {
78                             packageName = packageName.substring(0, packageName.length() - suffix.length());
79                         }
80                         else {
81                             packageName = packageName.substring(0, packageName.length() -
82                                 suffix.length()) + '.' + ps.getSubstituteWith();
83                         }
84                         break;
85                     }
86                 }
87             }
88             else {
89                 packageName = replaceInline(packageName, ps.getPackages(), ps.getSubstituteWith());
90             }
91         }
92
93         return packageName;
94     }
95
96     /**
97      * Gets any PackageSubstitutions defined for a specified subtask.
98      *
99      * @param subtaskName subtask name
100      * @return ArrayList of substitutions
101      */

102     public static ArrayList getPackageSubstitutions(String JavaDoc subtaskName)
103     {
104         // SubTask's packageSubstitutions has precedence over
105
// the global packageSubstitutions defined in DocletTask
106
ArrayList packageSubstitutions = null;
107         boolean supportsPackageSubstitutionInheritance = true;
108
109         Boolean JavaDoc supports = ((Boolean JavaDoc) DocletContext.getInstance().getConfigParam(subtaskName + ".packageSubstitutionInheritanceSupported"));
110
111         if (supports != null) {
112             supportsPackageSubstitutionInheritance = supports.booleanValue();
113         }
114
115         packageSubstitutions = (ArrayList) DocletContext.getInstance().getConfigParam(subtaskName + ".packageSubstitutions");
116
117         // nothing specified for subtask, inherit the one from DocletTask
118
if (supportsPackageSubstitutionInheritance && (packageSubstitutions == null || packageSubstitutions.isEmpty())) {
119             packageSubstitutions = (ArrayList) DocletContext.getInstance().getConfigParam("packageSubstitutions");
120         }
121
122         return packageSubstitutions;
123     }
124
125     /**
126      * Returns a package name as a path, after applying any substitutions.
127      *
128      * @param pak package
129      * @return package name as path
130      * @doc.tag type="content"
131      */

132     public static String JavaDoc packageNameAsPathFor(XPackage pak)
133     {
134         return getPackageNameFor(pak, true).replace('.', '/');
135     }
136
137     /**
138      * Returns a package name as a path, without applying any substitutions.
139      *
140      * @param pak package
141      * @return package name as path
142      * @doc.tag type="content"
143      */

144     public static String JavaDoc packageNameAsPathWithoutSubstitutionFor(XPackage pak)
145     {
146         return getPackageNameFor(pak, false).replace('.', '/');
147     }
148
149     /**
150      * Returns a package name as a path, after applying any substitutions.
151      *
152      * @param qualifiedName package name
153      * @return package name as path
154      * @doc.tag type="content"
155      */

156     public static String JavaDoc packageNameAsPathFor(String JavaDoc qualifiedName)
157     {
158         String JavaDoc qName = qualifiedName;
159
160         ArrayList pss = getPackageSubstitutions(DocletContext.getInstance().getActiveSubTask().getSubTaskName());
161
162         PackageSubstitution ps;
163
164         for (int i = 0; i < pss.size(); i++) {
165             ps = (PackageSubstitution) pss.get(i);
166             if (ps.getUseFirst() == true) {
167                 qName = replaceInline(qName, ps.getPackages(), ps.getSubstituteWith());
168             }
169         }
170
171         return qName.replace('.', '/');
172     }
173
174     /**
175      * Replace the first occurrence of <code>oldOne</code> in <code>original</code> with <code>newOne</code>, or returns
176      * the original string if <code>oldOne</code> is not found.
177      *
178      * @param original String in which replacement should occour
179      * @param oldOne String to be replaced
180      * @param newOne String that replaces
181      * @return String original string with replacements
182      */

183     public static String JavaDoc replaceInline(String JavaDoc original, String JavaDoc oldOne, String JavaDoc newOne)
184     {
185         int index = original.indexOf(oldOne);
186
187         if (index > -1)
188             return original.substring(0, index) + newOne + original.substring(index + oldOne.length());
189         else
190             return original;
191     }
192
193     /**
194      * Returns the current package name. If we're in the context of a package iteration, this is the name of the current
195      * package. If we're in the context of a class iteration without a package iteration, return the name of the current
196      * class' package.
197      *
198      * @return current package name
199      * @exception XDocletException Description of Exception
200      * @doc.tag type="content"
201      */

202     public String JavaDoc packageName() throws XDocletException
203     {
204         if (getCurrentPackage() != null) {
205             // first try to get the name from current package. It exists if
206
return getCurrentPackage().getName();
207         }
208         else {
209             return getCurrentClass().getContainingPackage().getName();
210         }
211     }
212
213     /**
214      * Returns the not-full-qualified package name of the full-qualified class name specified in the body of this tag.
215      *
216      * @param template The body of the block tag
217      * @exception XDocletException Description of Exception
218      * @doc.tag type="block"
219      */

220     public void packageOf(String JavaDoc template) throws XDocletException
221     {
222         getEngine().print(getPackageNameFrom(template));
223     }
224
225     /**
226      * Writes the package declaration for the package name of the full-qualified class name specified in the body of
227      * this tag. No package declaration is written if the full-qualified class name has no package.
228      *
229      * @param template The body of the block tag
230      * @exception XDocletException Description of Exception
231      * @doc.tag type="block"
232      */

233     public void packageDeclarationOf(String JavaDoc template) throws XDocletException
234     {
235         String JavaDoc packageName = getPackageNameFrom(template);
236
237         if (packageName != null && packageName.length() > 0) {
238             getEngine().print("package " + packageName + ";");
239         }
240     }
241
242     /**
243      * Iterates over all packages loaded by XJavadoc. Subsequent calls to forAllClasses will only iterate over the
244      * classes in the current package.
245      *
246      * @param template The body of the block tag
247      * @param attributes The attributes of the template tag
248      * @exception XDocletException Description of Exception
249      * @doc.tag type="block"
250      * @doc.param name="abstract" optional="true" values="true,false" description="If true then accept
251      * abstract classes also; otherwise don't."
252      * @doc.param name="type" optional="true" description="For all classes by the type."
253      * @doc.param name="extent" optional="true" values="concrete-type,superclass,hierarchy"
254      * description="Specifies the extent of the type search. If concrete-type then only check the concrete type, if
255      * superclass then check also superclass, if hierarchy then search the whole hierarchy and find if the class is
256      * of the specified type. Default is hierarchy."
257      */

258     public void forAllPackages(String JavaDoc template, Properties attributes) throws XDocletException
259     {
260         Collection classes = getXJavaDoc().getSourceClasses();
261         SortedSet packages = new TreeSet();
262
263         for (Iterator i = classes.iterator(); i.hasNext(); ) {
264             XClass clazz = (XClass) i.next();
265
266             packages.add(clazz.getContainingPackage());
267         }
268
269         XPackage currentPackage = null;
270
271         for (Iterator packageIterator = packages.iterator(); packageIterator.hasNext(); ) {
272             currentPackage = (XPackage) packageIterator.next();
273             setCurrentPackage(currentPackage);
274             generate(template);
275         }
276         // restore current package to null, so subsequent class iterations can
277
// perform outside the context of a current package
278
setCurrentPackage(null);
279     }
280
281     /**
282      * Returns the current package name as a path.
283      *
284      * @return current package name as path
285      * @exception XDocletException Description of Exception
286      * @doc.tag type="content"
287      */

288     public String JavaDoc packageNameAsPath() throws XDocletException
289     {
290         return packageNameAsPathFor(packageName());
291     }
292
293     /**
294      * Returns the package name for the full-qualified class name specified in the body of the passed tag.
295      *
296      * @param template The body of the block tag
297      * @return the package name or an empty string if the full-qualified class name has no package
298      * @exception XDocletException Description of Exception
299      */

300     private String JavaDoc getPackageNameFrom(String JavaDoc template) throws XDocletException
301     {
302         try {
303             String JavaDoc fullClassName = getEngine().outputOf(template);
304             int pos = fullClassName.lastIndexOf('.');
305
306             if (pos < 0) {
307                 return "";
308             }
309             else {
310                 return getPackageNameFor(fullClassName.substring(0, pos), true);
311             }
312         }
313         catch (TemplateException ex) {
314             throw new XDocletException(ex, Translator.getString(XDocletMessages.class, XDocletMessages.METHOD_FAILED, new String JavaDoc[]{"packageOf"}));
315         }
316
317     }
318
319     /**
320      * It's good practice to put interfaces (such as remote/local interfaces, data objects and home interfaces) in a
321      * separate "interfaces" package rather than in the EJB bean implementation package. Previous versions of XDoclet
322      * dictated this behavior, so if package name of a bean ended with <code>.beans</code> or <code>.ejb</code>
323      * interfaces were put into .interfaces package. It's no more the case. You have full control over it. If you don't
324      * use a <code>packageSubstitution</code> element, then all interfaces are generated to the same package as the bean
325      * implementation class. But if you want to follow the pattern and put interfaces into a separate package you can,
326      * by providing the list of package name tails that interfaces of beans inside that packages should be placed into
327      * the package you define. For example interfaces of <code>test.ejb.CustomerBean</code> will be placed in <code>test.interfaces</code>
328      * by the following <code>packageSubstitution</code>:<p/>
329      *
330      * <pre><code>
331      *&lt;packageSubstitution packages="ejb,beans" substituteWith="interfaces" /&gt;
332      *</code></pre> <p/>
333      *
334      * By using the <code>useFirst</code> attribute, you can tell XDoclet to substitute the first occurrence and not the
335      * last. <br/>
336      * Now if you have a structure like<p/>
337      *
338      * com.acme.foo.bar.ejb <br/>
339      * com.acme.baz.lala.ejb<p/>
340      *
341      * you want to gather all interfaces under one root/subtree like e.g. <p/>
342      *
343      * com.acme.interfaces.bar.* <br/>
344      * com.acme.interfaces.lala.*<p/>
345      *
346      * now you can say:<br/>
347      * &lt;packagesubstitution packages="foo,baz" substituteWith="interfaces" useFirst="true"/&gt;
348      *
349      * @created 10. september 2002
350      */

351     public static class PackageSubstitution implements Serializable JavaDoc
352     {
353         private String JavaDoc packages = null;
354         private String JavaDoc substituteWith = null;
355         private boolean useFirst = false;
356
357         /**
358          * Get the comma-separated list of packages to be substituted.
359          *
360          * @return package list
361          */

362         public String JavaDoc getPackages()
363         {
364             return packages;
365         }
366
367         /**
368          * Get the substitute package name.
369          *
370          * @return package
371          */

372         public String JavaDoc getSubstituteWith()
373         {
374             return substituteWith;
375         }
376
377         /**
378          * Return the useFirst attribute. This attribute specifies if the substitution can only appear at the end of a
379          * package (useFirst=false) or also in the middle.
380          *
381          * @return boolean
382          */

383         public boolean getUseFirst()
384         {
385             return this.useFirst;
386         }
387
388         /**
389          * Set the comma-separated list of packages to be substituted.
390          *
391          * @param packages The new Packages value
392          */

393         public void setPackages(String JavaDoc packages)
394         {
395             this.packages = packages;
396         }
397
398         /**
399          * Set the substitute package name.
400          *
401          * @param substituteWith The new SubstituteWith value
402          */

403         public void setSubstituteWith(String JavaDoc substituteWith)
404         {
405             this.substituteWith = substituteWith;
406         }
407
408         /**
409          * Specify whether the first occurrence of a package from the list should be substituted, or the last.
410          *
411          * @param first should the first occurrence be used or not?
412          */

413         public void setUseFirst(boolean first)
414         {
415             this.useFirst = first;
416
417         }
418     }
419 }
420
Popular Tags