001/*license*\
002   Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com)
003
004   This software is dual-licensed under the:
005   - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version;
006   - Apache Software License (ASL) version 2.0.
007
008   Either license may be applied at your discretion. More information may be found at
009   - http://en.wikipedia.org/wiki/Multi-licensing.
010
011   The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at:
012   - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
013   - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
014\*license*/
015package  com.github.aliteralmind.codelet.taglet;
016   import  com.sun.tools.doclets.Taglet;
017   import  java.util.Map;
018   import  com.github.xbn.lang.CrashIfObject;
019   import  com.github.aliteralmind.codelet.util.JavaDocUtil;
020   import  com.github.xbn.util.JavaRegexes;
021   import  com.sun.javadoc.ClassDoc;
022   import  com.sun.javadoc.Doc;
023   import  com.sun.javadoc.PackageDoc;
024   import  com.sun.javadoc.ProgramElementDoc;
025   import  com.sun.javadoc.Tag;
026   import  java.util.regex.Matcher;
027   import  java.util.regex.Pattern;
028/**
029   <p>Generically-useful utilities related to {@code com.sun.javadoc}.</p>
030
031 * @since  0.1.0
032 * @author  Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <a href="http://codelet.aliteralmind.com">{@code http://codelet.aliteralmind.com}</a>, <a href="https://github.com/aliteralmind/codelet">{@code https://github.com/aliteralmind/codelet}</a>
033 **/
034public class ComSunJavaDocUtil  {
035   /**
036      <p>Register a Taglet as required by JavaDoc.</p>
037
038      <h3><i>(Why is the map parameter type-erased? What generics does it need?)</i></h3>
039
040      <p>Steps<ol>
041         <li>If a taglet with the name equal to <code>taglet.<!-- No package-list for Taglet --><a href="http://docs.oracle.com/javase/7/docs/jdk/api/javadoc/taglet/com/sun/tools/doclets/Taglet.html#getName()">getName</a>()</code> already exists in the map, remove it.</li>
042         <li>{@code taglet} is <a href="http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#put(K, V)">added</a> to the map, with its name as the key.</li>
043      </ol></p>
044
045    * @param  taglet  The taglet to register. May not be {@code null}.
046    * @param map  The map to register this tag to. May not be {@code null}.
047    * @since  0.1.1
048    */
049   @SuppressWarnings({"unchecked", "rawtypes"})
050   public static void registerNewTagletInstance(Taglet taglet, Map map)  {
051      try  {
052         final String name = taglet.getName();
053         final Taglet alreadyRegisteredTaglet = (Taglet)map.get(name);
054         if (alreadyRegisteredTaglet != null) {
055            map.remove(name);
056         }
057         map.put(name, taglet);
058      }  catch(RuntimeException rx)  {
059         CrashIfObject.nnull(taglet, "taglet", null);
060         throw  CrashIfObject.nullOrReturnCause(map, "map", null, rx);
061      }
062/*
063      FileTextletTaglet tag = new FileTextletTaglet();
064      Taglet t = (Taglet) map.get(tag.getName());
065      if (t != null) {
066         map.remove(tag.getName());
067      }
068      map.put(tag.getName(), tag);
069 */
070   }
071
072   /**
073      <p>Get the relative url whose value is equivalent to {@code {@docRoot}}.</p>
074
075    * @return  <code>{@link com.github.aliteralmind.codelet.util.JavaDocUtil JavaDocUtil}.{@link com.github.aliteralmind.codelet.util.JavaDocUtil#getRelativeUrlToDocRoot(String) getRelativeUrlToDocRoot}({@link #getEnclosingPackageName(Tag) getEnclosingPackageName}(tag))</code>
076    */
077   public static final String getRelativeUrlToDocRoot(Tag tag)  {
078      return  JavaDocUtil.getRelativeUrlToDocRoot(getEnclosingPackageName(tag));
079   }
080   /*
081   private static final Matcher packageElementMtchr = Pattern.compile("[\\p{L}_\\p{Sc}][\\p{L}\\p{N}_\\p{Sc}]*\\.?").matcher("");
082      <p>Get the relative url whose value is equivalent to {@code {@docRoot}}. This is a generic (self-contained) version of {@link #getRelativeUrlToDocRoot(Tag) getRelativeUrlToDocRoot}--they both do the same thing.</p>
083
084    * @return  <code>packageElementMtchr.reset({@link #getEnclosingPackageName(Tag) getEnclosingPackageName}(tag)).{@link java.util.regex.Matcher#replaceAll(String) replaceAll}(&quot;../&quot;)</code>
085      <br/>Where {@code packageElementMtchr} is initialized to
086      <br/> &nbsp; &nbsp; <code>Pattern.{@link java.util.regex.Pattern#compile(String) compile}(&quot;[\\p{L}_\\p{Sc}][\\p{L}\\p{N}_\\p{Sc}]*\\.?&quot;).{@link java.util.regex.Pattern#matcher(CharSequence) matcher}(&quot;&quot;)</code>
087    * @see  <code><a href="http://stackoverflow.com/questions/4079268/custom-taglet-with-reference-to-docroot">http://stackoverflow.com/questions/4079268/custom-taglet-with-reference-to-docroot</a></code>
088   public static final String getRelativeUrlToDocRootGeneric(Tag tag)  {
089      return  packageElementMtchr.reset(getEnclosingPackageName(tag)).replaceAll("../");
090   }
091    */
092   /**
093      <p>Get the package of the tag-containing JavaDoc page.</p>
094
095    * @return  If {@link #getPackageDoc(Tag) getPackageDoc}{@code (tag)} is<ul>
096         <li>{@code null}: {@code ""}</li>
097         <li>non-{@code null}: Its {@linkplain com.sun.javadoc.PackageDoc#name() name}.</li>
098      </ul>
099    */
100   public static final String getEnclosingPackageName(Tag tag)  {
101      PackageDoc pkgDoc = getPackageDoc(tag);
102      return  ((pkgDoc == null) ? "" : pkgDoc.name());
103   }
104   /**
105      <p>Get the tag-containing JavaDoc page's post-package name.</p>
106
107    * @param  tag  May not be {@code null}.
108    * @param  include_postClassName  If the taglet is in the class JavaDoc-block, The classes generics, if any, are included in its simple name. If the taglet is in a function's JavaDoc-block, its name and parameters are included. If this parameter is {@link IncludePostClassName#YES YES}, the generics or function name, if any, are included in the returned value. If {@link IncludePostClassName#NO NO}, they are excluded. This parameter may not be {@code null}.
109    * @return  If the tag's {@linkplain #getEnclosingPackageName(Tag) enclosing package name}<ul>
110         <li>Has no characters: {@code "OVERVIEW_SUMMARY"}</li>
111         <li>Non empty and its name<ul>
112            <li>Has no characters: {@code "PACKAGE_SUMMARY"}</li>
113            <li>Non-empty: The name</li>
114         </ul></li>
115      </ul>
116    */
117   public static final String getEnclosingSimpleName(Tag tag, IncludePostClassName include_postClassName)  {
118      String pkg = getEnclosingPackageName(tag);
119      if(pkg.length() == 0)  {
120//System.out.println("getEnclosingSimpleName.1 OVERVIEW_SUMMARY");
121         return  "OVERVIEW_SUMMARY";
122      }
123
124      String name = tag.holder().toString().substring(pkg.length());
125//System.out.println("getEnclosingSimpleName.1a tag.holder()=\"" + tag.holder() + "\"\n   - without package=\"" + name+ "\"");
126
127
128      if(name.length() == 0)  {
129//System.out.println("getEnclosingSimpleName.2 PACKAGE_SUMMARY");
130         return  "PACKAGE_SUMMARY";
131      }
132
133      if(name.charAt(0) == '.')  {
134         name = name.substring(1);
135      }
136
137      try  {
138         if(include_postClassName.isYes())  {
139//System.out.println("getEnclosingSimpleName.2a " + name);
140            return  name;
141         }
142      }  catch(RuntimeException rx)  {
143         throw  CrashIfObject.nullOrReturnCause(include_postClassName, "include_postClassName", null, rx);
144      }
145
146      //include_postClassName.NO
147
148      name = oneOrMoreWordCharsAtInputStartMtchr.reset(name).replaceFirst("$1");
149
150//System.out.println("getEnclosingSimpleName.3 " + name);
151      return  name;
152
153/*
154      try  {
155         if(include_postClassName.isYes())  {
156System.out.println("getEnclosingSimpleName.3 " + name);
157            return  name;
158         }
159      }  catch(RuntimeException rx)  {
160         throw  CrashIfObject.nullOrReturnCause(include_postClassName, "include_postClassName", null, rx);
161      }
162
163      int idxGreaterThan = name.indexOf('<');
164      int idxOpenParen = name.indexOf('(');
165
166      //Must check for parens first, because it is possible for generics to be
167      //inside parameters!
168      if(idxOpenParen == -1)  {
169         if(idxGreaterThan == -1)  {
170System.out.println("getEnclosingSimpleName.4 " + name);
171            return  name;
172         }
173         name = name.substring(0, idxGreaterThan);
174System.out.println("getEnclosingSimpleName.5 " + name);
175         return  name;
176
177      }
178      //Return name up-through-but-not-including the dot-func-signature
179
180      name = name.substring(0, name.lastIndexOf('.', idxOpenParen));
181System.out.println("getEnclosingSimpleName.6 " + name);
182      return  name;
183 */
184
185   }
186      private static final Matcher oneOrMoreWordCharsAtInputStartMtchr = Pattern.compile("^(\\w+).*$").matcher("");
187   /**
188      <p>Get the object containing the &quot;package&quot; of the tag-containing JavaDoc page.</p>
189
190      <p>This function was written by <a href="http://stackoverflow.com">Stack Overflow</a> user <a href="http://stackoverflow.com/users/547546/chad-retz">Chad Retz</a>.</p>-
191
192    * @return  If the tag's {@linkplain com.sun.javadoc.Tag#holder() holder }<ul>
193         <li>is a {@link com.sun.javadoc.ProgramElementDoc}: Its {@linkplain com.sun.javadoc.ProgramElementDoc#containingPackage() containing package}.</li>
194         <li>is a {@link com.sun.javadoc.PackageDoc}: {@code tag}.</li>
195         <li>Otherwise: {@code null}</li>
196      </ul>
197    * @see  <code><a href="https://chadretz.wordpress.com/2010/12/19/mathml-inside-javadoc-using-mathjax-and-a-custom-taglet/">https://chadretz.wordpress.com/2010/12/19/mathml-inside-javadoc-using-mathjax-and-a-custom-taglet/</a></code>
198    */
199   public static final PackageDoc getPackageDoc(Tag tag) {
200      Doc holder = tag.holder();
201      if (holder instanceof ProgramElementDoc) {
202         return ((ProgramElementDoc) holder).containingPackage();
203      } else if (holder instanceof PackageDoc) {
204         return (PackageDoc) holder;
205      } else {
206         return  null;
207      }
208   }
209}