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