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 &lt;strong&gt; 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