Sun, 24 Feb 2013 11:36:58 -0800
7112427: The doclet needs to be able to generate JavaFX documentation.
Reviewed-by: jjg
Contributed-by: jan.valenta@oracle.com
1 /*
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.tools.doclets.internal.toolkit.taglets;
28 import java.io.*;
29 import java.lang.reflect.*;
30 import java.net.*;
31 import java.util.*;
33 import javax.tools.DocumentationTool;
34 import javax.tools.JavaFileManager;
36 import com.sun.javadoc.*;
37 import com.sun.tools.doclets.internal.toolkit.util.*;
39 /**
40 * Manages the<code>Taglet</code>s used by doclets.
41 *
42 * <p><b>This is NOT part of any supported API.
43 * If you write code that depends on this, you do so at your own risk.
44 * This code and its internal interfaces are subject to change or
45 * deletion without notice.</b>
46 *
47 * @author Jamie Ho
48 * @since 1.4
49 */
51 public class TagletManager {
53 /**
54 * The default separator for the simple tag option.
55 */
56 public static final char SIMPLE_TAGLET_OPT_SEPARATOR = ':';
58 /**
59 * The alternate separator for simple tag options. Use this
60 * when you want the default separator to be in the name of the
61 * custom tag.
62 */
63 public static final String ALT_SIMPLE_TAGLET_OPT_SEPARATOR = "-";
65 /**
66 * The map of custom tags.
67 */
68 private LinkedHashMap<String,Taglet> customTags;
70 /**
71 * The array of custom tags that can appear in packages.
72 */
73 private Taglet[] packageTags;
75 /**
76 * The array of custom tags that can appear in classes or interfaces.
77 */
78 private Taglet[] typeTags;
80 /**
81 * The array of custom tags that can appear in fields.
82 */
83 private Taglet[] fieldTags;
85 /**
86 * The array of custom tags that can appear in constructors.
87 */
88 private Taglet[] constructorTags;
90 /**
91 * The array of custom tags that can appear in methods.
92 */
93 private Taglet[] methodTags;
95 /**
96 * The array of custom tags that can appear in the overview.
97 */
98 private Taglet[] overviewTags;
100 /**
101 * The array of custom tags that can appear in comments.
102 */
103 private Taglet[] inlineTags;
105 /**
106 * The array of custom tags that can appear in the serialized form.
107 */
108 private Taglet[] serializedFormTags;
110 /**
111 * The message retriever that will be used to print error messages.
112 */
113 private MessageRetriever message;
115 /**
116 * Keep track of standard tags.
117 */
118 private Set<String> standardTags;
120 /**
121 * Keep track of standard tags in lowercase to compare for better
122 * error messages when a tag like @docRoot is mistakenly spelled
123 * lowercase @docroot.
124 */
125 private Set<String> standardTagsLowercase;
127 /**
128 * Keep track of overriden standard tags.
129 */
130 private Set<String> overridenStandardTags;
132 /**
133 * Keep track of the tags that may conflict
134 * with standard tags in the future (any custom tag without
135 * a period in its name).
136 */
137 private Set<String> potentiallyConflictingTags;
139 /**
140 * The set of unseen custom tags.
141 */
142 private Set<String> unseenCustomTags;
144 /**
145 * True if we do not want to use @since tags.
146 */
147 private boolean nosince;
149 /**
150 * True if we want to use @version tags.
151 */
152 private boolean showversion;
154 /**
155 * True if we want to use @author tags.
156 */
157 private boolean showauthor;
159 /**
160 * True if we want to use JavaFX-related tags (@propertyGetter,
161 * @propertySetter, @propertyDescription, @defaultValue, @treatAsPrivate,
162 * @expert).
163 */
164 private boolean javafx;
166 /**
167 * Construct a new <code>TagletManager</code>.
168 * @param nosince true if we do not want to use @since tags.
169 * @param showversion true if we want to use @version tags.
170 * @param showauthor true if we want to use @author tags.
171 * @param message the message retriever to print warnings.
172 */
173 public TagletManager(boolean nosince, boolean showversion,
174 boolean showauthor, boolean javafx,
175 MessageRetriever message) {
176 overridenStandardTags = new HashSet<String>();
177 potentiallyConflictingTags = new HashSet<String>();
178 standardTags = new HashSet<String>();
179 standardTagsLowercase = new HashSet<String>();
180 unseenCustomTags = new HashSet<String>();
181 customTags = new LinkedHashMap<String,Taglet>();
182 this.nosince = nosince;
183 this.showversion = showversion;
184 this.showauthor = showauthor;
185 this.javafx = javafx;
186 this.message = message;
187 initStandardTags();
188 initStandardTagsLowercase();
189 }
191 /**
192 * Add a new <code>CustomTag</code>. This is used to add a Taglet from within
193 * a Doclet. No message is printed to indicate that the Taglet is properly
194 * registered because these Taglets are typically added for every execution of the
195 * Doclet. We don't want to see this type of error message every time.
196 * @param customTag the new <code>CustomTag</code> to add.
197 */
198 public void addCustomTag(Taglet customTag) {
199 if (customTag != null) {
200 String name = customTag.getName();
201 if (customTags.containsKey(name)) {
202 customTags.remove(name);
203 }
204 customTags.put(name, customTag);
205 checkTagName(name);
206 }
207 }
209 /**
210 * Add a new <code>Taglet</code>. Print a message to indicate whether or not
211 * the Taglet was registered properly.
212 * @param classname the name of the class representing the custom tag.
213 * @param tagletPath the path to the class representing the custom tag.
214 */
215 public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) {
216 try {
217 Class<?> customTagClass = null;
218 // construct class loader
219 String cpString = null; // make sure env.class.path defaults to dot
221 ClassLoader tagClassLoader;
222 if (fileManager != null && fileManager.hasLocation(DocumentationTool.Location.TAGLET_PATH)) {
223 tagClassLoader = fileManager.getClassLoader(DocumentationTool.Location.TAGLET_PATH);
224 } else {
225 // do prepends to get correct ordering
226 cpString = appendPath(System.getProperty("env.class.path"), cpString);
227 cpString = appendPath(System.getProperty("java.class.path"), cpString);
228 cpString = appendPath(tagletPath, cpString);
229 tagClassLoader = new URLClassLoader(pathToURLs(cpString));
230 }
232 customTagClass = tagClassLoader.loadClass(classname);
233 Method meth = customTagClass.getMethod("register",
234 new Class<?>[] {java.util.Map.class});
235 Object[] list = customTags.values().toArray();
236 Taglet lastTag = (list != null && list.length > 0)
237 ? (Taglet) list[list.length-1] : null;
238 meth.invoke(null, new Object[] {customTags});
239 list = customTags.values().toArray();
240 Object newLastTag = (list != null&& list.length > 0)
241 ? list[list.length-1] : null;
242 if (lastTag != newLastTag) {
243 //New taglets must always be added to the end of the LinkedHashMap.
244 //If the current and previous last taglet are not equal, that
245 //means a new Taglet has been added.
246 message.notice("doclet.Notice_taglet_registered", classname);
247 if (newLastTag != null) {
248 checkTaglet(newLastTag);
249 }
250 }
251 } catch (Exception exc) {
252 message.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname);
253 }
255 }
257 private String appendPath(String path1, String path2) {
258 if (path1 == null || path1.length() == 0) {
259 return path2 == null ? "." : path2;
260 } else if (path2 == null || path2.length() == 0) {
261 return path1;
262 } else {
263 return path1 + File.pathSeparator + path2;
264 }
265 }
267 /**
268 * Utility method for converting a search path string to an array
269 * of directory and JAR file URLs.
270 *
271 * @param path the search path string
272 * @return the resulting array of directory and JAR file URLs
273 */
274 private URL[] pathToURLs(String path) {
275 Set<URL> urls = new LinkedHashSet<URL>();
276 for (String s: path.split(File.pathSeparator)) {
277 if (s.isEmpty()) continue;
278 try {
279 urls.add(new File(s).getAbsoluteFile().toURI().toURL());
280 } catch (MalformedURLException e) {
281 message.error("doclet.MalformedURL", s);
282 }
283 }
284 return urls.toArray(new URL[urls.size()]);
285 }
288 /**
289 * Add a new <code>SimpleTaglet</code>. If this tag already exists
290 * and the header passed as an argument is null, move tag to the back of the
291 * list. If this tag already exists and the header passed as an argument is
292 * not null, overwrite previous tag with new one. Otherwise, add new
293 * SimpleTaglet to list.
294 * @param tagName the name of this tag
295 * @param header the header to output.
296 * @param locations the possible locations that this tag
297 * can appear in.
298 */
299 public void addNewSimpleCustomTag(String tagName, String header, String locations) {
300 if (tagName == null || locations == null) {
301 return;
302 }
303 Taglet tag = customTags.get(tagName);
304 locations = locations.toLowerCase();
305 if (tag == null || header != null) {
306 customTags.remove(tagName);
307 customTags.put(tagName, new SimpleTaglet(tagName, header, locations));
308 if (locations != null && locations.indexOf('x') == -1) {
309 checkTagName(tagName);
310 }
311 } else {
312 //Move to back
313 customTags.remove(tagName);
314 customTags.put(tagName, tag);
315 }
316 }
318 /**
319 * Given a tag name, add it to the set of tags it belongs to.
320 */
321 private void checkTagName(String name) {
322 if (standardTags.contains(name)) {
323 overridenStandardTags.add(name);
324 } else {
325 if (name.indexOf('.') == -1) {
326 potentiallyConflictingTags.add(name);
327 }
328 unseenCustomTags.add(name);
329 }
330 }
332 /**
333 * Check the taglet to see if it is a legacy taglet. Also
334 * check its name for errors.
335 */
336 private void checkTaglet(Object taglet) {
337 if (taglet instanceof Taglet) {
338 checkTagName(((Taglet) taglet).getName());
339 } else if (taglet instanceof com.sun.tools.doclets.Taglet) {
340 com.sun.tools.doclets.Taglet legacyTaglet = (com.sun.tools.doclets.Taglet) taglet;
341 customTags.remove(legacyTaglet.getName());
342 customTags.put(legacyTaglet.getName(), new LegacyTaglet(legacyTaglet));
343 checkTagName(legacyTaglet.getName());
344 } else {
345 throw new IllegalArgumentException("Given object is not a taglet.");
346 }
347 }
349 /**
350 * Given a name of a seen custom tag, remove it from the set of unseen
351 * custom tags.
352 * @param name the name of the seen custom tag.
353 */
354 public void seenCustomTag(String name) {
355 unseenCustomTags.remove(name);
356 }
358 /**
359 * Given an array of <code>Tag</code>s, check for spelling mistakes.
360 * @param doc the Doc object that holds the tags.
361 * @param tags the list of <code>Tag</code>s to check.
362 * @param areInlineTags true if the array of tags are inline and false otherwise.
363 */
364 public void checkTags(Doc doc, Tag[] tags, boolean areInlineTags) {
365 if (tags == null) {
366 return;
367 }
368 Taglet taglet;
369 for (int i = 0; i < tags.length; i++) {
370 String name = tags[i].name();
371 if (name.length() > 0 && name.charAt(0) == '@') {
372 name = name.substring(1, name.length());
373 }
374 if (! (standardTags.contains(name) || customTags.containsKey(name))) {
375 if (standardTagsLowercase.contains(name.toLowerCase())) {
376 message.warning(tags[i].position(), "doclet.UnknownTagLowercase", tags[i].name());
377 continue;
378 } else {
379 message.warning(tags[i].position(), "doclet.UnknownTag", tags[i].name());
380 continue;
381 }
382 }
383 //Check if this tag is being used in the wrong location.
384 if ((taglet = customTags.get(name)) != null) {
385 if (areInlineTags && ! taglet.isInlineTag()) {
386 printTagMisuseWarn(taglet, tags[i], "inline");
387 }
388 if ((doc instanceof RootDoc) && ! taglet.inOverview()) {
389 printTagMisuseWarn(taglet, tags[i], "overview");
390 } else if ((doc instanceof PackageDoc) && ! taglet.inPackage()) {
391 printTagMisuseWarn(taglet, tags[i], "package");
392 } else if ((doc instanceof ClassDoc) && ! taglet.inType()) {
393 printTagMisuseWarn(taglet, tags[i], "class");
394 } else if ((doc instanceof ConstructorDoc) && ! taglet.inConstructor()) {
395 printTagMisuseWarn(taglet, tags[i], "constructor");
396 } else if ((doc instanceof FieldDoc) && ! taglet.inField()) {
397 printTagMisuseWarn(taglet, tags[i], "field");
398 } else if ((doc instanceof MethodDoc) && ! taglet.inMethod()) {
399 printTagMisuseWarn(taglet, tags[i], "method");
400 }
401 }
402 }
403 }
405 /**
406 * Given the taglet, the tag and the type of documentation that the tag
407 * was found in, print a tag misuse warning.
408 * @param taglet the taglet representing the misused tag.
409 * @param tag the misused tag.
410 * @param holderType the type of documentation that the misused tag was found in.
411 */
412 private void printTagMisuseWarn(Taglet taglet, Tag tag, String holderType) {
413 Set<String> locationsSet = new LinkedHashSet<String>();
414 if (taglet.inOverview()) {
415 locationsSet.add("overview");
416 }
417 if (taglet.inPackage()) {
418 locationsSet.add("package");
419 }
420 if (taglet.inType()) {
421 locationsSet.add("class/interface");
422 }
423 if (taglet.inConstructor()) {
424 locationsSet.add("constructor");
425 }
426 if (taglet.inField()) {
427 locationsSet.add("field");
428 }
429 if (taglet.inMethod()) {
430 locationsSet.add("method");
431 }
432 if (taglet.isInlineTag()) {
433 locationsSet.add("inline text");
434 }
435 String[] locations = locationsSet.toArray(new String[]{});
436 if (locations == null || locations.length == 0) {
437 //This known tag is excluded.
438 return;
439 }
440 StringBuilder combined_locations = new StringBuilder();
441 for (int i = 0; i < locations.length; i++) {
442 if (i > 0) {
443 combined_locations.append(", ");
444 }
445 combined_locations.append(locations[i]);
446 }
447 message.warning(tag.position(), "doclet.tag_misuse",
448 "@" + taglet.getName(), holderType, combined_locations.toString());
449 }
451 /**
452 * Return the array of <code>Taglet</code>s that can
453 * appear in packages.
454 * @return the array of <code>Taglet</code>s that can
455 * appear in packages.
456 */
457 public Taglet[] getPackageCustomTags() {
458 if (packageTags == null) {
459 initCustomTagArrays();
460 }
461 return packageTags;
462 }
464 /**
465 * Return the array of <code>Taglet</code>s that can
466 * appear in classes or interfaces.
467 * @return the array of <code>Taglet</code>s that can
468 * appear in classes or interfaces.
469 */
470 public Taglet[] getTypeCustomTags() {
471 if (typeTags == null) {
472 initCustomTagArrays();
473 }
474 return typeTags;
475 }
477 /**
478 * Return the array of inline <code>Taglet</code>s that can
479 * appear in comments.
480 * @return the array of <code>Taglet</code>s that can
481 * appear in comments.
482 */
483 public Taglet[] getInlineCustomTags() {
484 if (inlineTags == null) {
485 initCustomTagArrays();
486 }
487 return inlineTags;
488 }
490 /**
491 * Return the array of <code>Taglet</code>s that can
492 * appear in fields.
493 * @return the array of <code>Taglet</code>s that can
494 * appear in field.
495 */
496 public Taglet[] getFieldCustomTags() {
497 if (fieldTags == null) {
498 initCustomTagArrays();
499 }
500 return fieldTags;
501 }
503 /**
504 * Return the array of <code>Taglet</code>s that can
505 * appear in the serialized form.
506 * @return the array of <code>Taglet</code>s that can
507 * appear in the serialized form.
508 */
509 public Taglet[] getSerializedFormTags() {
510 if (serializedFormTags == null) {
511 initCustomTagArrays();
512 }
513 return serializedFormTags;
514 }
516 /**
517 * @return the array of <code>Taglet</code>s that can
518 * appear in the given Doc.
519 */
520 public Taglet[] getCustomTags(Doc doc) {
521 if (doc instanceof ConstructorDoc) {
522 return getConstructorCustomTags();
523 } else if (doc instanceof MethodDoc) {
524 return getMethodCustomTags();
525 } else if (doc instanceof FieldDoc) {
526 return getFieldCustomTags();
527 } else if (doc instanceof ClassDoc) {
528 return getTypeCustomTags();
529 } else if (doc instanceof PackageDoc) {
530 return getPackageCustomTags();
531 } else if (doc instanceof RootDoc) {
532 return getOverviewCustomTags();
533 }
534 return null;
535 }
537 /**
538 * Return the array of <code>Taglet</code>s that can
539 * appear in constructors.
540 * @return the array of <code>Taglet</code>s that can
541 * appear in constructors.
542 */
543 public Taglet[] getConstructorCustomTags() {
544 if (constructorTags == null) {
545 initCustomTagArrays();
546 }
547 return constructorTags;
548 }
550 /**
551 * Return the array of <code>Taglet</code>s that can
552 * appear in methods.
553 * @return the array of <code>Taglet</code>s that can
554 * appear in methods.
555 */
556 public Taglet[] getMethodCustomTags() {
557 if (methodTags == null) {
558 initCustomTagArrays();
559 }
560 return methodTags;
561 }
563 /**
564 * Return the array of <code>Taglet</code>s that can
565 * appear in an overview.
566 * @return the array of <code>Taglet</code>s that can
567 * appear in overview.
568 */
569 public Taglet[] getOverviewCustomTags() {
570 if (overviewTags == null) {
571 initCustomTagArrays();
572 }
573 return overviewTags;
574 }
576 /**
577 * Initialize the custom tag arrays.
578 */
579 private void initCustomTagArrays() {
580 Iterator<Taglet> it = customTags.values().iterator();
581 ArrayList<Taglet> pTags = new ArrayList<Taglet>(customTags.size());
582 ArrayList<Taglet> tTags = new ArrayList<Taglet>(customTags.size());
583 ArrayList<Taglet> fTags = new ArrayList<Taglet>(customTags.size());
584 ArrayList<Taglet> cTags = new ArrayList<Taglet>(customTags.size());
585 ArrayList<Taglet> mTags = new ArrayList<Taglet>(customTags.size());
586 ArrayList<Taglet> iTags = new ArrayList<Taglet>(customTags.size());
587 ArrayList<Taglet> oTags = new ArrayList<Taglet>(customTags.size());
588 ArrayList<Taglet> sTags = new ArrayList<Taglet>();
589 Taglet current;
590 while (it.hasNext()) {
591 current = it.next();
592 if (current.inPackage() && !current.isInlineTag()) {
593 pTags.add(current);
594 }
595 if (current.inType() && !current.isInlineTag()) {
596 tTags.add(current);
597 }
598 if (current.inField() && !current.isInlineTag()) {
599 fTags.add(current);
600 }
601 if (current.inConstructor() && !current.isInlineTag()) {
602 cTags.add(current);
603 }
604 if (current.inMethod() && !current.isInlineTag()) {
605 mTags.add(current);
606 }
607 if (current.isInlineTag()) {
608 iTags.add(current);
609 }
610 if (current.inOverview() && !current.isInlineTag()) {
611 oTags.add(current);
612 }
613 }
614 packageTags = pTags.toArray(new Taglet[] {});
615 typeTags = tTags.toArray(new Taglet[] {});
616 fieldTags = fTags.toArray(new Taglet[] {});
617 constructorTags = cTags.toArray(new Taglet[] {});
618 methodTags = mTags.toArray(new Taglet[] {});
619 overviewTags = oTags.toArray(new Taglet[] {});
620 inlineTags = iTags.toArray(new Taglet[] {});
622 //Init the serialized form tags
623 sTags.add(customTags.get("serialData"));
624 sTags.add(customTags.get("throws"));
625 if (!nosince)
626 sTags.add(customTags.get("since"));
627 sTags.add(customTags.get("see"));
628 serializedFormTags = sTags.toArray(new Taglet[] {});
629 }
631 /**
632 * Initialize standard Javadoc tags for ordering purposes.
633 */
634 private void initStandardTags() {
635 Taglet temp;
636 customTags.put((temp = new ParamTaglet()).getName(), temp);
637 customTags.put((temp = new ReturnTaglet()).getName(), temp);
638 customTags.put((temp = new ThrowsTaglet()).getName(), temp);
639 customTags.put((temp = new SimpleTaglet("exception",
640 null, SimpleTaglet.METHOD + SimpleTaglet.CONSTRUCTOR)).getName(), temp);
641 if (!nosince) {
642 customTags.put((temp = new SimpleTaglet("since", message.getText("doclet.Since"),
643 SimpleTaglet.ALL)).getName(), temp);
644 }
645 if (showversion) {
646 customTags.put((temp = new SimpleTaglet("version", message.getText("doclet.Version"),
647 SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)).getName(), temp);
648 }
649 if (showauthor) {
650 customTags.put((temp = new SimpleTaglet("author", message.getText("doclet.Author"),
651 SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)).getName(), temp);
652 }
653 customTags.put((temp = new SimpleTaglet("serialData", message.getText("doclet.SerialData"),
654 SimpleTaglet.EXCLUDED)).getName(), temp);
655 customTags.put((temp = new SimpleTaglet("factory", message.getText("doclet.Factory"),
656 SimpleTaglet.METHOD)).getName(), temp);
657 customTags.put((temp = new SeeTaglet()).getName(), temp);
658 //Standard inline tags
659 customTags.put((temp = new DocRootTaglet()).getName(), temp);
660 customTags.put((temp = new InheritDocTaglet()).getName(), temp);
661 customTags.put((temp = new ValueTaglet()).getName(), temp);
662 customTags.put((temp = new LegacyTaglet(new LiteralTaglet())).getName(),
663 temp);
664 customTags.put((temp = new LegacyTaglet(new CodeTaglet())).getName(),
665 temp);
667 //Keep track of the names of standard tags for error
668 //checking purposes.
669 standardTags.add("param");
670 standardTags.add("return");
671 standardTags.add("throws");
672 standardTags.add("exception");
673 standardTags.add("since");
674 standardTags.add("version");
675 standardTags.add("author");
676 standardTags.add("see");
677 standardTags.add("deprecated");
678 standardTags.add("link");
679 standardTags.add("linkplain");
680 standardTags.add("inheritDoc");
681 standardTags.add("docRoot");
682 standardTags.add("value");
683 standardTags.add("serial");
684 standardTags.add("serialData");
685 standardTags.add("serialField");
686 standardTags.add("Text");
687 standardTags.add("literal");
688 standardTags.add("code");
690 if (javafx) {
691 initJavaFXTags();
692 }
693 }
695 /**
696 * Initialize JavaFX-related tags.
697 */
698 private void initJavaFXTags() {
699 Taglet temp;
700 customTags.put((temp = new PropertyGetterTaglet()).getName(), temp);
701 customTags.put((temp = new PropertySetterTaglet()).getName(), temp);
702 customTags.put((temp = new SimpleTaglet("propertyDescription", message.getText("doclet.PropertyDescription"),
703 SimpleTaglet.FIELD + SimpleTaglet.METHOD)).getName(), temp);
704 customTags.put((temp = new SimpleTaglet("defaultValue", message.getText("doclet.DefaultValue"),
705 SimpleTaglet.FIELD + SimpleTaglet.METHOD)).getName(), temp);
706 customTags.put((temp = new SimpleTaglet("treatAsPrivate", null,
707 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)).getName(), temp);
708 customTags.put((temp = new LegacyTaglet(new ExpertTaglet())).getName(), temp);
710 standardTags.add("propertyGetter");
711 standardTags.add("propertySetter");
712 standardTags.add("propertyDescription");
713 standardTags.add("defaultValue");
714 standardTags.add("treatAsPrivate");
715 standardTags.add("expert");
716 }
718 /**
719 * Initialize lowercase version of standard Javadoc tags.
720 */
721 private void initStandardTagsLowercase() {
722 Iterator<String> it = standardTags.iterator();
723 while (it.hasNext()) {
724 standardTagsLowercase.add(it.next().toLowerCase());
725 }
726 }
728 public boolean isKnownCustomTag(String tagName) {
729 return customTags.containsKey(tagName);
730 }
732 /**
733 * Print a list of {@link Taglet}s that might conflict with
734 * standard tags in the future and a list of standard tags
735 * that have been overriden.
736 */
737 public void printReport() {
738 printReportHelper("doclet.Notice_taglet_conflict_warn", potentiallyConflictingTags);
739 printReportHelper("doclet.Notice_taglet_overriden", overridenStandardTags);
740 printReportHelper("doclet.Notice_taglet_unseen", unseenCustomTags);
741 }
743 private void printReportHelper(String noticeKey, Set<String> names) {
744 if (names.size() > 0) {
745 String[] namesArray = names.toArray(new String[] {});
746 String result = " ";
747 for (int i = 0; i < namesArray.length; i++) {
748 result += "@" + namesArray[i];
749 if (i + 1 < namesArray.length) {
750 result += ", ";
751 }
752 }
753 message.notice(noticeKey, result);
754 }
755 }
757 /**
758 * Given the name of a tag, return the corresponding taglet.
759 * Return null if the tag is unknown.
760 *
761 * @param name the name of the taglet to retrieve.
762 * @return return the corresponding taglet. Return null if the tag is
763 * unknown.
764 */
765 public Taglet getTaglet(String name) {
766 if (name.indexOf("@") == 0) {
767 return customTags.get(name.substring(1));
768 } else {
769 return customTags.get(name);
770 }
772 }
773 }