1 // © 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /** 4 ******************************************************************************* 5 * Copyright (C) 2002-2016 International Business Machines Corporation * 6 * and others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 10 package com.ibm.icu.dev.tool.docs; 11 12 import java.text.BreakIterator; 13 import java.util.Locale; 14 import java.util.Map; 15 16 import com.sun.javadoc.Tag; 17 import com.sun.tools.doclets.internal.toolkit.taglets.Taglet; 18 19 public abstract class ICUTaglet extends ICUTagletAdapter implements Taglet { 20 protected final String name; 21 protected final int mask; 22 23 protected static final int MASK_FIELD = 1; 24 protected static final int MASK_CONSTRUCTOR = 2; 25 protected static final int MASK_METHOD = 4; 26 protected static final int MASK_OVERVIEW = 8; 27 protected static final int MASK_PACKAGE = 16; 28 protected static final int MASK_TYPE = 32; 29 protected static final int MASK_INLINE = 64; 30 31 protected static final int MASK_DEFAULT = 0x003f; // no inline 32 protected static final int MASK_DEFAULT_INLINE = 0x007f; // includes inline 33 protected static final int MASK_VALID = 0x007f; 34 register(Map taglets)35 public static void register(Map taglets) { 36 ICUInternalTaglet.register(taglets); 37 ICUDraftTaglet.register(taglets); 38 ICUStableTaglet.register(taglets); 39 ICUProvisionalTaglet.register(taglets); 40 ICUObsoleteTaglet.register(taglets); 41 ICUIgnoreTaglet.register(taglets); 42 ICUNewTaglet.register(taglets); 43 ICUNoteTaglet.register(taglets); 44 ICUEnhancedTaglet.register(taglets); 45 ICUDiscouragedTaglet.register(taglets); 46 } 47 ICUTaglet(String name, int mask)48 protected ICUTaglet(String name, int mask) { 49 this.name = name; 50 this.mask = mask & MASK_VALID; 51 } 52 inField()53 public boolean inField() { 54 return (mask & MASK_FIELD) != 0; 55 } 56 inConstructor()57 public boolean inConstructor() { 58 return (mask & MASK_CONSTRUCTOR) != 0; 59 } 60 inMethod()61 public boolean inMethod() { 62 return (mask & MASK_METHOD) != 0; 63 } 64 inOverview()65 public boolean inOverview() { 66 return (mask & MASK_OVERVIEW) != 0; 67 } 68 inPackage()69 public boolean inPackage() { 70 return (mask & MASK_PACKAGE) != 0; 71 } 72 inType()73 public boolean inType() { 74 return (mask & MASK_TYPE) != 0; 75 } 76 isInlineTag()77 public boolean isInlineTag() { 78 return (mask & MASK_INLINE) != 0; 79 } 80 getName()81 public String getName() { 82 return name; 83 } 84 toString(Tag tag)85 public String toString(Tag tag) { 86 return tag.text(); 87 } 88 toString(Tag[] tags)89 public String toString(Tag[] tags) { 90 91 if (!isInlineTag() && tags != null) { 92 if (tags.length > 1) { 93 String msg = "Should not have more than one ICU tag per element:\n"; 94 for (int i = 0; i < tags.length; ++i) { 95 msg += " [" + i + "] " + tags[i] + "\n"; 96 } 97 throw new IllegalStateException(msg); 98 } else if (tags.length > 0) { 99 return toString(tags[0]); 100 } 101 } 102 return null; 103 } 104 105 protected static final String STATUS = "<dt><b>Status:</b></dt>"; 106 107 public static class ICUDiscouragedTaglet extends ICUTaglet { 108 private static final String NAME = "discouraged"; 109 register(Map taglets)110 public static void register(Map taglets) { 111 taglets.put(NAME, new ICUDiscouragedTaglet()); 112 } 113 ICUDiscouragedTaglet()114 private ICUDiscouragedTaglet() { 115 super(NAME, MASK_DEFAULT); 116 } 117 toString(Tag tag)118 public String toString(Tag tag) { 119 String text = tag.text(); 120 if (text.length() == 0) { 121 System.err.println("Error: empty discouraged tag "); 122 } 123 return "<dt><b><font color=red>Discouraged:</font></b></dt><dd>" + text + "</dd>"; 124 } 125 } 126 127 public static class ICUInternalTaglet extends ICUTaglet { 128 private static final String NAME = "internal"; 129 register(Map taglets)130 public static void register(Map taglets) { 131 taglets.put(NAME, new ICUInternalTaglet()); 132 } 133 ICUInternalTaglet()134 private ICUInternalTaglet() { 135 super(NAME, MASK_DEFAULT); 136 } 137 toString(Tag tag)138 public String toString(Tag tag) { 139 if (tag.text().toLowerCase(Locale.US).indexOf("technology preview") >= 0) { 140 return STATUS + "<dd><em>Technology Preview</em>. <font color='red'>" + 141 "This API is still in the early stages of development. Use at your own risk.</font></dd>"; 142 } 143 return STATUS + "<dd><em>Internal</em>. <font color='red'>" + 144 "This API is <em>ICU internal only</em>.</font></dd>"; 145 } 146 } 147 148 public static class ICUDraftTaglet extends ICUTaglet { 149 private static final String NAME = "draft"; 150 register(Map taglets)151 public static void register(Map taglets) { 152 taglets.put(NAME, new ICUDraftTaglet()); 153 } 154 ICUDraftTaglet()155 private ICUDraftTaglet() { 156 super(NAME, MASK_DEFAULT); 157 } 158 toString(Tag tag)159 public String toString(Tag tag) { 160 String text = tag.text(); 161 if (text.length() == 0) { 162 System.err.println("Warning: empty draft tag"); 163 } 164 return STATUS + "<dd>Draft " + tag.text() + ".</dd>"; 165 } 166 } 167 168 public static class ICUStableTaglet extends ICUTaglet { 169 private static final String NAME = "stable"; 170 register(Map taglets)171 public static void register(Map taglets) { 172 taglets.put(NAME, new ICUStableTaglet()); 173 } 174 ICUStableTaglet()175 private ICUStableTaglet() { 176 super(NAME, MASK_DEFAULT); 177 } 178 toString(Tag tag)179 public String toString(Tag tag) { 180 String text = tag.text(); 181 if (text.length() > 0) { 182 return STATUS + "<dd>Stable " + text + ".</dd>"; 183 } else { 184 return STATUS + "<dd>Stable.</dd>"; 185 } 186 } 187 } 188 189 public static class ICUProvisionalTaglet extends ICUTaglet { 190 private static final String NAME = "provisional"; 191 register(Map taglets)192 public static void register(Map taglets) { 193 taglets.remove(NAME); // override standard deprecated taglet 194 taglets.put(NAME, new ICUProvisionalTaglet()); 195 } 196 ICUProvisionalTaglet()197 private ICUProvisionalTaglet() { 198 super(NAME, MASK_DEFAULT); 199 } 200 toString(Tag tag)201 public String toString(Tag tag) { 202 return null; 203 } 204 } 205 206 public static class ICUObsoleteTaglet extends ICUTaglet { 207 private static final String NAME = "obsolete"; 208 register(Map taglets)209 public static void register(Map taglets) { 210 taglets.put(NAME, new ICUObsoleteTaglet()); 211 } 212 ICUObsoleteTaglet()213 private ICUObsoleteTaglet() { 214 super(NAME, MASK_DEFAULT); 215 } 216 toString(Tag tag)217 public String toString(Tag tag) { 218 BreakIterator bi = BreakIterator.getSentenceInstance(Locale.US); 219 String text = tag.text(); 220 bi.setText(text); 221 int first = bi.first(); 222 int next = bi.next(); 223 if (text.length() == 0) { 224 first = next = 0; 225 } 226 return STATUS + "<dd><em>Obsolete.</em> <font color='red'>Will be removed in " + 227 text.substring(first, next) + "</font>. " + text.substring(next) + "</dd>"; 228 229 } 230 } 231 232 public static class ICUIgnoreTaglet extends ICUTaglet { 233 private static ICUTaglet singleton; 234 register(Map taglets)235 public static void register(Map taglets) { 236 if (singleton == null) { 237 singleton = new ICUIgnoreTaglet(); 238 } 239 taglets.put("bug", singleton); 240 taglets.put("test", singleton); 241 taglets.put("summary", singleton); 242 } 243 ICUIgnoreTaglet()244 private ICUIgnoreTaglet() { 245 super(".ignore", MASK_DEFAULT); 246 } 247 toString(Tag tag)248 public String toString(Tag tag) { 249 return null; 250 } 251 } 252 253 private static String ICU_LABEL = "<strong><font color=red>[icu]</font></strong>"; 254 255 /** 256 * This taglet should be used in the first line of the class description of classes 257 * that are enhancements of JDK classes that similar names and APIs. The text should 258 * provide the full package and name of the JDK class. A period should follow the 259 * tag. This puts an 'icu enhancement' message into the first line of the class docs, 260 * where it will also appear in the class summary. 261 * 262 * <p>Following this tag (and period), ideally in the first paragraph, the '@icu' tag 263 * should be used with the text '_label_' to generate the standard boilerplate about 264 * how that tag is used in the class docs. See {@link ICUNewTaglet}. 265 * 266 * <p>This cumbersome process is necessary because the javadoc code that handles 267 * taglets doesn't look at punctuation in the substitution text to determine when to 268 * end the first line, it looks in the original javadoc comment. So we need a tag to 269 * identify the related java class, then a period, then another tag. 270 */ 271 public static class ICUEnhancedTaglet extends ICUTaglet { 272 private static final String NAME = "icuenhanced"; 273 register(Map taglets)274 public static void register(Map taglets) { 275 taglets.put(NAME, new ICUEnhancedTaglet()); 276 } 277 ICUEnhancedTaglet()278 private ICUEnhancedTaglet() { 279 super(NAME, MASK_DEFAULT_INLINE); 280 } 281 toString(Tag tag)282 public String toString(Tag tag) { 283 String text = tag.text().trim(); 284 285 boolean isClassDoc = tag.holder().isClass() || tag.holder().isInterface(); 286 if (isClassDoc && text.length() > 0) { 287 StringBuilder sb = new StringBuilder(); 288 return sb.append("<strong><font color=red>[icu enhancement]</font></strong> ") 289 .append("ICU's replacement for <code>") 290 .append(text) 291 .append("</code>") 292 .toString(); 293 } 294 return ""; 295 } 296 } 297 298 /** 299 * This taglet should be used in the first line of any icu-specific members in a class 300 * that is an enhancement of a JDK class (see {@link ICUEnhancedTaglet}). It generates 301 * the '[icu]' marker followed by the <strong> text, if any. This does not 302 * start or end a paragraph or provide additional leading or trailing punctuation such 303 * as spaces or periods. 304 * 305 * <p>Note: if the text is '_usage_' (without quotes) this spits out a boilerplate 306 * message describing the meaning of the '[icu]' tag. This should be done in the 307 * first paragraph of the class docs of any class containing '@icu' tags. 308 */ 309 public static class ICUNewTaglet extends ICUTaglet { 310 private static final String NAME = "icu"; 311 register(Map taglets)312 public static void register(Map taglets) { 313 taglets.put(NAME, new ICUNewTaglet()); 314 } 315 ICUNewTaglet()316 private ICUNewTaglet() { 317 super(NAME, MASK_DEFAULT_INLINE); 318 } 319 toString(Tag tag)320 public String toString(Tag tag) { 321 String text = tag.text().trim(); 322 StringBuilder sb = new StringBuilder(); 323 if ("_usage_".equals(text)) { 324 return sb.append(" Methods, fields, and other functionality specific to ICU ") 325 .append("are labeled '" + ICU_LABEL + "'.</p>") 326 .toString(); 327 } 328 329 sb.append("<strong><font color=red>[icu]</font>"); 330 if (text.length() > 0) { 331 sb.append(" ").append(text); 332 } 333 sb.append("</strong>"); 334 return sb.toString(); 335 } 336 } 337 338 /** 339 * This taglet should be used in class or member documentation, after the first line, 340 * where the behavior of the ICU method or class has notable differences from its JDK 341 * counterpart. It starts a new paragraph and generates an '[icu] Note:' header. 342 */ 343 public static class ICUNoteTaglet extends ICUTaglet { 344 private static final String NAME = "icunote"; 345 register(Map taglets)346 public static void register(Map taglets) { 347 taglets.put(NAME, new ICUNoteTaglet()); 348 } 349 ICUNoteTaglet()350 private ICUNoteTaglet() { 351 super(NAME, MASK_DEFAULT_INLINE); 352 } 353 toString(Tag tag)354 public String toString(Tag tag) { 355 return "<p><strong><font color=red>[icu]</font> Note:</strong> "; 356 } 357 } 358 } 359