TagletManager.java revision 3337:cba09a2e6ae9
1/* 2 * Copyright (c) 2001, 2016, 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 */ 25 26package jdk.javadoc.internal.doclets.toolkit.taglets; 27 28import java.io.*; 29import java.lang.reflect.Method; 30import java.util.*; 31 32import javax.lang.model.element.Element; 33import javax.lang.model.element.ExecutableElement; 34import javax.lang.model.element.PackageElement; 35import javax.lang.model.element.TypeElement; 36import javax.lang.model.element.VariableElement; 37import javax.lang.model.util.SimpleElementVisitor9; 38import javax.tools.JavaFileManager; 39import javax.tools.StandardJavaFileManager; 40 41import com.sun.source.doctree.DocTree; 42import com.sun.tools.javac.util.DefinedBy; 43import com.sun.tools.javac.util.DefinedBy.Api; 44 45import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; 46import jdk.javadoc.internal.doclets.toolkit.util.MessageRetriever; 47import jdk.javadoc.internal.doclets.toolkit.util.Utils; 48 49import static javax.tools.DocumentationTool.Location.*; 50 51import static com.sun.source.doctree.DocTree.Kind.*; 52 53/** 54 * Manages the {@code Taglet}s used by doclets. 55 * 56 * <p><b>This is NOT part of any supported API. 57 * If you write code that depends on this, you do so at your own risk. 58 * This code and its internal interfaces are subject to change or 59 * deletion without notice.</b> 60 * 61 * @author Jamie Ho 62 */ 63 64public class TagletManager { 65 66 /** 67 * The default separator for the simple tag option. 68 */ 69 public static final char SIMPLE_TAGLET_OPT_SEPARATOR = ':'; 70 71 /** 72 * The alternate separator for simple tag options. Use this 73 * when you want the default separator to be in the name of the 74 * custom tag. 75 */ 76 public static final String ALT_SIMPLE_TAGLET_OPT_SEPARATOR = "-"; 77 78 /** 79 * The map of custom tags. 80 */ 81 private final LinkedHashMap<String,Taglet> customTags; 82 83 /** 84 * The array of custom tags that can appear in packages. 85 */ 86 private List<Taglet> packageTags; 87 88 /** 89 * The array of custom tags that can appear in classes or interfaces. 90 */ 91 private List<Taglet> typeTags; 92 93 /** 94 * The array of custom tags that can appear in fields. 95 */ 96 private List<Taglet> fieldTags; 97 98 /** 99 * The array of custom tags that can appear in constructors. 100 */ 101 private List<Taglet> constructorTags; 102 103 /** 104 * The array of custom tags that can appear in methods. 105 */ 106 private List<Taglet> methodTags; 107 108 /** 109 * The array of custom tags that can appear in the overview. 110 */ 111 private List<Taglet> overviewTags; 112 113 /** 114 * The array of custom tags that can appear in comments. 115 */ 116 private List<Taglet> inlineTags; 117 118 /** 119 * The array of custom tags that can appear in the serialized form. 120 */ 121 private List<Taglet> serializedFormTags; 122 123 /** 124 * The message retriever that will be used to print error messages. 125 */ 126 private final MessageRetriever message; 127 128 /** 129 * Keep track of standard tags. 130 */ 131 private final Set<String> standardTags; 132 133 /** 134 * Keep track of standard tags in lowercase to compare for better 135 * error messages when a tag like @docRoot is mistakenly spelled 136 * lowercase @docroot. 137 */ 138 private final Set<String> standardTagsLowercase; 139 140 /** 141 * Keep track of overriden standard tags. 142 */ 143 private final Set<String> overridenStandardTags; 144 145 /** 146 * Keep track of the tags that may conflict 147 * with standard tags in the future (any custom tag without 148 * a period in its name). 149 */ 150 private final Set<String> potentiallyConflictingTags; 151 152 /** 153 * The set of unseen custom tags. 154 */ 155 private final Set<String> unseenCustomTags; 156 157 /** 158 * True if we do not want to use @since tags. 159 */ 160 private final boolean nosince; 161 162 /** 163 * True if we want to use @version tags. 164 */ 165 private final boolean showversion; 166 167 /** 168 * True if we want to use @author tags. 169 */ 170 private final boolean showauthor; 171 172 /** 173 * True if we want to use JavaFX-related tags (@propertyGetter, 174 * @propertySetter, @propertyDescription, @defaultValue, @treatAsPrivate). 175 */ 176 private final boolean javafx; 177 178 /** 179 * Construct a new <code>TagletManager</code>. 180 * @param nosince true if we do not want to use @since tags. 181 * @param showversion true if we want to use @version tags. 182 * @param showauthor true if we want to use @author tags. 183 * @param javafx indicates whether javafx is active. 184 * @param message the message retriever to print warnings. 185 */ 186 public TagletManager(boolean nosince, boolean showversion, 187 boolean showauthor, boolean javafx, 188 MessageRetriever message) { 189 overridenStandardTags = new HashSet<>(); 190 potentiallyConflictingTags = new HashSet<>(); 191 standardTags = new HashSet<>(); 192 standardTagsLowercase = new HashSet<>(); 193 unseenCustomTags = new HashSet<>(); 194 customTags = new LinkedHashMap<>(); 195 this.nosince = nosince; 196 this.showversion = showversion; 197 this.showauthor = showauthor; 198 this.javafx = javafx; 199 this.message = message; 200 initStandardTaglets(); 201 initStandardTagsLowercase(); 202 } 203 204 /** 205 * Add a new <code>CustomTag</code>. This is used to add a Taglet from within 206 * a Doclet. No message is printed to indicate that the Taglet is properly 207 * registered because these Taglets are typically added for every execution of the 208 * Doclet. We don't want to see this type of error message every time. 209 * @param customTag the new <code>CustomTag</code> to add. 210 */ 211 public void addCustomTag(Taglet customTag) { 212 if (customTag != null) { 213 String name = customTag.getName(); 214 if (customTags.containsKey(name)) { 215 customTags.remove(name); 216 } 217 customTags.put(name, customTag); 218 checkTagName(name); 219 } 220 } 221 222 public Set<String> getCustomTagNames() { 223 return customTags.keySet(); 224 } 225 226 /** 227 * Add a new <code>Taglet</code>. Print a message to indicate whether or not 228 * the Taglet was registered properly. 229 * @param classname the name of the class representing the custom tag. 230 * @param fileManager the filemanager to load classes and resources. 231 * @param tagletPath the path to the class representing the custom tag. 232 */ 233 public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) { 234 try { 235 ClassLoader tagClassLoader = null; 236 if (!fileManager.hasLocation(TAGLET_PATH)) { 237 List<File> paths = new ArrayList<>(); 238 if (tagletPath != null) { 239 for (String pathname : tagletPath.split(File.pathSeparator)) { 240 paths.add(new File(pathname)); 241 } 242 } 243 if (fileManager instanceof StandardJavaFileManager) { 244 ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, paths); 245 } 246 } 247 tagClassLoader = fileManager.getClassLoader(TAGLET_PATH); 248 Class<?> customTagClass = tagClassLoader.loadClass(classname); 249 ensureReadable(customTagClass); 250 Object instance = customTagClass.newInstance(); 251 Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance); 252 String tname = newLegacy.getName(); 253 Taglet t = customTags.get(tname); 254 if (t != null) { 255 customTags.remove(tname); 256 } 257 customTags.put(tname, newLegacy); 258 message.notice("doclet.Notice_taglet_registered", classname); 259 } catch (Exception exc) { 260 message.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname); 261 } 262 } 263 264 /** 265 * Ensures that the module of the given class is readable to this 266 * module. 267 * @param targetClass class in module to be made readable 268 */ 269 private void ensureReadable(Class<?> targetClass) { 270 try { 271 Method getModuleMethod = Class.class.getMethod("getModule"); 272 Object thisModule = getModuleMethod.invoke(this.getClass()); 273 Object targetModule = getModuleMethod.invoke(targetClass); 274 275 Class<?> moduleClass = getModuleMethod.getReturnType(); 276 Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass); 277 addReadsMethod.invoke(thisModule, targetModule); 278 } catch (NoSuchMethodException e) { 279 // ignore 280 } catch (Exception e) { 281 throw new InternalError(e.toString()); 282 } 283 } 284 285 /** 286 * Add a new <code>SimpleTaglet</code>. If this tag already exists 287 * and the header passed as an argument is null, move tag to the back of the 288 * list. If this tag already exists and the header passed as an argument is 289 * not null, overwrite previous tag with new one. Otherwise, add new 290 * SimpleTaglet to list. 291 * @param tagName the name of this tag 292 * @param header the header to output. 293 * @param locations the possible locations that this tag 294 * can appear in. 295 */ 296 public void addNewSimpleCustomTag(String tagName, String header, String locations) { 297 if (tagName == null || locations == null) { 298 return; 299 } 300 Taglet tag = customTags.get(tagName); 301 locations = Utils.toLowerCase(locations); 302 if (tag == null || header != null) { 303 customTags.remove(tagName); 304 customTags.put(tagName, new SimpleTaglet(tagName, header, locations)); 305 if (locations != null && locations.indexOf('x') == -1) { 306 checkTagName(tagName); 307 } 308 } else { 309 //Move to back 310 customTags.remove(tagName); 311 customTags.put(tagName, tag); 312 } 313 } 314 315 /** 316 * Given a tag name, add it to the set of tags it belongs to. 317 */ 318 private void checkTagName(String name) { 319 if (standardTags.contains(name)) { 320 overridenStandardTags.add(name); 321 } else { 322 if (name.indexOf('.') == -1) { 323 potentiallyConflictingTags.add(name); 324 } 325 unseenCustomTags.add(name); 326 } 327 } 328 329 /** 330 * Check the taglet to see if it is a legacy taglet. Also 331 * check its name for errors. 332 */ 333 private void checkTaglet(Object taglet) { 334 if (taglet instanceof Taglet) { 335 checkTagName(((Taglet) taglet).getName()); 336 } else if (taglet instanceof jdk.javadoc.doclet.taglet.Taglet) { 337 jdk.javadoc.doclet.taglet.Taglet legacyTaglet = (jdk.javadoc.doclet.taglet.Taglet) taglet; 338 customTags.remove(legacyTaglet.getName()); 339 customTags.put(legacyTaglet.getName(), new UserTaglet(legacyTaglet)); 340 checkTagName(legacyTaglet.getName()); 341 } else { 342 throw new IllegalArgumentException("Given object is not a taglet."); 343 } 344 } 345 346 /** 347 * Given a name of a seen custom tag, remove it from the set of unseen 348 * custom tags. 349 * @param name the name of the seen custom tag. 350 */ 351 public void seenCustomTag(String name) { 352 unseenCustomTags.remove(name); 353 } 354 355 /** 356 * Given an array of <code>Tag</code>s, check for spelling mistakes. 357 * @param utils the utility class to use 358 * @param element the tags holder 359 * @param trees the trees containing the comments 360 * @param areInlineTags true if the array of tags are inline and false otherwise. 361 */ 362 public void checkTags(final Utils utils, Element element, 363 Iterable<? extends DocTree> trees, boolean areInlineTags) { 364 if (trees == null) { 365 return; 366 } 367 CommentHelper ch = utils.getCommentHelper(element); 368 for (DocTree tag : trees) { 369 String name = tag.getKind().tagName; 370 if (name == null) { 371 continue; 372 } 373 if (name.length() > 0 && name.charAt(0) == '@') { 374 name = name.substring(1, name.length()); 375 } 376 if (! (standardTags.contains(name) || customTags.containsKey(name))) { 377 if (standardTagsLowercase.contains(Utils.toLowerCase(name))) { 378 message.warning(ch.getDocTreePath(tag), "doclet.UnknownTagLowercase", ch.getTagName(tag)); 379 continue; 380 } else { 381 message.warning(ch.getDocTreePath(tag), "doclet.UnknownTag", ch.getTagName(tag)); 382 continue; 383 } 384 } 385 final Taglet taglet = customTags.get(name); 386 // Check and verify tag usage 387 if (taglet != null) { 388 if (areInlineTags && !taglet.isInlineTag()) { 389 printTagMisuseWarn(ch, taglet, tag, "inline"); 390 } 391 // nothing more to do 392 if (element == null) { 393 return; 394 } 395 new SimpleElementVisitor9<Void, Void>() { 396 @Override @DefinedBy(Api.LANGUAGE_MODEL) 397 public Void visitPackage(PackageElement e, Void p) { 398 if (!taglet.inPackage()) { 399 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "package"); 400 } 401 return null; 402 } 403 404 @Override @DefinedBy(Api.LANGUAGE_MODEL) 405 public Void visitType(TypeElement e, Void p) { 406 if (!taglet.inType()) { 407 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "class"); 408 } 409 return null; 410 } 411 412 @Override @DefinedBy(Api.LANGUAGE_MODEL) 413 public Void visitExecutable(ExecutableElement e, Void p) { 414 if (utils.isConstructor(e) && !taglet.inConstructor()) { 415 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "constructor"); 416 } else if (!taglet.inMethod()) { 417 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "method"); 418 } 419 return null; 420 } 421 422 @Override @DefinedBy(Api.LANGUAGE_MODEL) 423 public Void visitVariable(VariableElement e, Void p) { 424 if (utils.isField(e) && !taglet.inField()) { 425 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "field"); 426 } 427 return null; 428 } 429 430 @Override @DefinedBy(Api.LANGUAGE_MODEL) 431 public Void visitUnknown(Element e, Void p) { 432 if (utils.isOverviewElement(e) && !taglet.inOverview()) { 433 printTagMisuseWarn(utils.getCommentHelper(e), taglet, tag, "overview"); 434 } 435 return null; 436 } 437 438 @Override @DefinedBy(Api.LANGUAGE_MODEL) 439 protected Void defaultAction(Element e, Void p) { 440 return null; 441 } 442 }.visit(element); 443 } 444 } 445 } 446 447 /** 448 * Given the taglet, the tag and the type of documentation that the tag 449 * was found in, print a tag misuse warning. 450 * @param taglet the taglet representing the misused tag. 451 * @param tag the misused tag. 452 * @param holderType the type of documentation that the misused tag was found in. 453 */ 454 private void printTagMisuseWarn(CommentHelper ch, Taglet taglet, DocTree tag, String holderType) { 455 Set<String> locationsSet = new LinkedHashSet<>(); 456 if (taglet.inOverview()) { 457 locationsSet.add("overview"); 458 } 459 if (taglet.inPackage()) { 460 locationsSet.add("package"); 461 } 462 if (taglet.inType()) { 463 locationsSet.add("class/interface"); 464 } 465 if (taglet.inConstructor()) { 466 locationsSet.add("constructor"); 467 } 468 if (taglet.inField()) { 469 locationsSet.add("field"); 470 } 471 if (taglet.inMethod()) { 472 locationsSet.add("method"); 473 } 474 if (taglet.isInlineTag()) { 475 locationsSet.add("inline text"); 476 } 477 String[] locations = locationsSet.toArray(new String[]{}); 478 if (locations == null || locations.length == 0) { 479 //This known tag is excluded. 480 return; 481 } 482 StringBuilder combined_locations = new StringBuilder(); 483 for (int i = 0; i < locations.length; i++) { 484 if (i > 0) { 485 combined_locations.append(", "); 486 } 487 combined_locations.append(locations[i]); 488 } 489 message.warning(ch.getDocTreePath(tag), "doclet.tag_misuse", 490 "@" + taglet.getName(), holderType, combined_locations.toString()); 491 } 492 493 /** 494 * Return the array of <code>Taglet</code>s that can 495 * appear in packages. 496 * @return the array of <code>Taglet</code>s that can 497 * appear in packages. 498 */ 499 public List<Taglet> getPackageCustomTaglets() { 500 if (packageTags == null) { 501 initCustomTaglets(); 502 } 503 return packageTags; 504 } 505 506 /** 507 * Return the array of <code>Taglet</code>s that can 508 * appear in classes or interfaces. 509 * @return the array of <code>Taglet</code>s that can 510 * appear in classes or interfaces. 511 */ 512 public List<Taglet> getTypeCustomTaglets() { 513 if (typeTags == null) { 514 initCustomTaglets(); 515 } 516 return typeTags; 517 } 518 519 /** 520 * Return the array of inline <code>Taglet</code>s that can 521 * appear in comments. 522 * @return the array of <code>Taglet</code>s that can 523 * appear in comments. 524 */ 525 public List<Taglet> getInlineCustomTaglets() { 526 if (inlineTags == null) { 527 initCustomTaglets(); 528 } 529 return inlineTags; 530 } 531 532 /** 533 * Return the array of <code>Taglet</code>s that can 534 * appear in fields. 535 * @return the array of <code>Taglet</code>s that can 536 * appear in field. 537 */ 538 public List<Taglet> getFieldCustomTaglets() { 539 if (fieldTags == null) { 540 initCustomTaglets(); 541 } 542 return fieldTags; 543 } 544 545 /** 546 * Return the array of <code>Taglet</code>s that can 547 * appear in the serialized form. 548 * @return the array of <code>Taglet</code>s that can 549 * appear in the serialized form. 550 */ 551 public List<Taglet> getSerializedFormTaglets() { 552 if (serializedFormTags == null) { 553 initCustomTaglets(); 554 } 555 return serializedFormTags; 556 } 557 558 /** 559 * Returns the custom tags for a given element. 560 * 561 * @param e the element to get custom tags for 562 * @return the array of <code>Taglet</code>s that can 563 * appear in the given element. 564 */ 565 public List<Taglet> getCustomTaglets(Element e) { 566 switch (e.getKind()) { 567 case CONSTRUCTOR: 568 return getConstructorCustomTaglets(); 569 case METHOD: 570 return getMethodCustomTaglets(); 571 case ENUM_CONSTANT: 572 case FIELD: 573 return getFieldCustomTaglets(); 574 case ANNOTATION_TYPE: 575 case INTERFACE: 576 case CLASS: 577 case ENUM: 578 return getTypeCustomTaglets(); 579 case PACKAGE: 580 return getPackageCustomTaglets(); 581 case OTHER: 582 return getOverviewCustomTaglets(); 583 default: 584 throw new AssertionError("unknown element: " + e + " ,kind: " + e.getKind()); 585 } 586 } 587 588 /** 589 * Return a List of <code>Taglet</code>s that can 590 * appear in constructors. 591 * @return the array of <code>Taglet</code>s that can 592 * appear in constructors. 593 */ 594 public List<Taglet> getConstructorCustomTaglets() { 595 if (constructorTags == null) { 596 initCustomTaglets(); 597 } 598 return constructorTags; 599 } 600 601 /** 602 * Return a List of <code>Taglet</code>s that can 603 * appear in methods. 604 * @return the array of <code>Taglet</code>s that can 605 * appear in methods. 606 */ 607 public List<Taglet> getMethodCustomTaglets() { 608 if (methodTags == null) { 609 initCustomTaglets(); 610 } 611 return methodTags; 612 } 613 614 /** 615 * Return a List of <code>Taglet</code>s that can 616 * appear in an overview. 617 * @return the array of <code>Taglet</code>s that can 618 * appear in overview. 619 */ 620 public List<Taglet> getOverviewCustomTaglets() { 621 if (overviewTags == null) { 622 initCustomTaglets(); 623 } 624 return overviewTags; 625 } 626 627 /** 628 * Initialize the custom tag Lists. 629 */ 630 private void initCustomTaglets() { 631 632 packageTags = new ArrayList<>(); 633 typeTags = new ArrayList<>(); 634 fieldTags = new ArrayList<>(); 635 constructorTags = new ArrayList<>(); 636 methodTags = new ArrayList<>(); 637 inlineTags = new ArrayList<>(); 638 overviewTags = new ArrayList<>(); 639 640 for (Taglet current : customTags.values()) { 641 if (current.inPackage() && !current.isInlineTag()) { 642 packageTags.add(current); 643 } 644 if (current.inType() && !current.isInlineTag()) { 645 typeTags.add(current); 646 } 647 if (current.inField() && !current.isInlineTag()) { 648 fieldTags.add(current); 649 } 650 if (current.inConstructor() && !current.isInlineTag()) { 651 constructorTags.add(current); 652 } 653 if (current.inMethod() && !current.isInlineTag()) { 654 methodTags.add(current); 655 } 656 if (current.isInlineTag()) { 657 inlineTags.add(current); 658 } 659 if (current.inOverview() && !current.isInlineTag()) { 660 overviewTags.add(current); 661 } 662 } 663 664 //Init the serialized form tags 665 serializedFormTags = new ArrayList<>(); 666 serializedFormTags.add(customTags.get(SERIAL_DATA.tagName)); 667 serializedFormTags.add(customTags.get(THROWS.tagName)); 668 if (!nosince) 669 serializedFormTags.add(customTags.get(SINCE.tagName)); 670 serializedFormTags.add(customTags.get(SEE.tagName)); 671 } 672 673 /** 674 * Initialize standard Javadoc tags for ordering purposes. 675 */ 676 private void initStandardTaglets() { 677 if (javafx) { 678 initJavaFXTaglets(); 679 } 680 681 Taglet temp; 682 addStandardTaglet(new ParamTaglet()); 683 addStandardTaglet(new ReturnTaglet()); 684 addStandardTaglet(new ThrowsTaglet()); 685 addStandardTaglet(new SimpleTaglet(EXCEPTION.tagName, null, 686 SimpleTaglet.METHOD + SimpleTaglet.CONSTRUCTOR)); 687 addStandardTaglet(!nosince, new SimpleTaglet(SINCE.tagName, message.getText("doclet.Since"), 688 SimpleTaglet.ALL)); 689 addStandardTaglet(showversion, new SimpleTaglet(VERSION.tagName, message.getText("doclet.Version"), 690 SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 691 addStandardTaglet(showauthor, new SimpleTaglet(AUTHOR.tagName, message.getText("doclet.Author"), 692 SimpleTaglet.PACKAGE + SimpleTaglet.TYPE + SimpleTaglet.OVERVIEW)); 693 addStandardTaglet(new SimpleTaglet(SERIAL_DATA.tagName, message.getText("doclet.SerialData"), 694 SimpleTaglet.EXCLUDED)); 695 addStandardTaglet(new SimpleTaglet(HIDDEN.tagName, message.getText("doclet.Hidden"), 696 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 697 customTags.put((temp = new SimpleTaglet("factory", message.getText("doclet.Factory"), 698 SimpleTaglet.METHOD)).getName(), temp); 699 addStandardTaglet(new SeeTaglet()); 700 //Standard inline tags 701 addStandardTaglet(new DocRootTaglet()); 702 addStandardTaglet(new InheritDocTaglet()); 703 addStandardTaglet(new ValueTaglet()); 704 addStandardTaglet(new LiteralTaglet()); 705 addStandardTaglet(new CodeTaglet()); 706 addStandardTaglet(new IndexTaglet()); 707 708 // Keep track of the names of standard tags for error 709 // checking purposes. The following are not handled above. 710 standardTags.add(DEPRECATED.tagName); 711 standardTags.add(LINK.tagName); 712 standardTags.add(LINK_PLAIN.tagName); 713 standardTags.add(SERIAL.tagName); 714 standardTags.add(SERIAL_FIELD.tagName); 715 } 716 717 /** 718 * Initialize JavaFX-related tags. 719 */ 720 private void initJavaFXTaglets() { 721 addStandardTaglet(new PropertyGetterTaglet()); 722 addStandardTaglet(new PropertySetterTaglet()); 723 addStandardTaglet(new SimpleTaglet("propertyDescription", 724 message.getText("doclet.PropertyDescription"), 725 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 726 addStandardTaglet(new SimpleTaglet("defaultValue", message.getText("doclet.DefaultValue"), 727 SimpleTaglet.FIELD + SimpleTaglet.METHOD)); 728 addStandardTaglet(new SimpleTaglet("treatAsPrivate", null, 729 SimpleTaglet.FIELD + SimpleTaglet.METHOD + SimpleTaglet.TYPE)); 730 } 731 732 void addStandardTaglet(Taglet taglet) { 733 String name = taglet.getName(); 734 customTags.put(name, taglet); 735 standardTags.add(name); 736 } 737 738 void addStandardTaglet(boolean enable, Taglet taglet) { 739 String name = taglet.getName(); 740 if (enable) 741 customTags.put(name, taglet); 742 standardTags.add(name); 743 } 744 745 /** 746 * Initialize lowercase version of standard Javadoc tags. 747 */ 748 private void initStandardTagsLowercase() { 749 for (String standardTag : standardTags) { 750 standardTagsLowercase.add(Utils.toLowerCase(standardTag)); 751 } 752 } 753 754 public boolean isKnownCustomTag(String tagName) { 755 return customTags.containsKey(tagName); 756 } 757 758 /** 759 * Print a list of {@link Taglet}s that might conflict with 760 * standard tags in the future and a list of standard tags 761 * that have been overriden. 762 */ 763 public void printReport() { 764 printReportHelper("doclet.Notice_taglet_conflict_warn", potentiallyConflictingTags); 765 printReportHelper("doclet.Notice_taglet_overriden", overridenStandardTags); 766 printReportHelper("doclet.Notice_taglet_unseen", unseenCustomTags); 767 } 768 769 private void printReportHelper(String noticeKey, Set<String> names) { 770 if (names.size() > 0) { 771 String[] namesArray = names.toArray(new String[] {}); 772 String result = " "; 773 for (int i = 0; i < namesArray.length; i++) { 774 result += "@" + namesArray[i]; 775 if (i + 1 < namesArray.length) { 776 result += ", "; 777 } 778 } 779 message.notice(noticeKey, result); 780 } 781 } 782 783 /** 784 * Given the name of a tag, return the corresponding taglet. 785 * Return null if the tag is unknown. 786 * 787 * @param name the name of the taglet to retrieve. 788 * @return return the corresponding taglet. Return null if the tag is 789 * unknown. 790 */ 791 public Taglet getTaglet(String name) { 792 if (name.indexOf("@") == 0) { 793 return customTags.get(name.substring(1)); 794 } else { 795 return customTags.get(name); 796 } 797 798 } 799} 800