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.{@link com.sun.javadoc.Taglet#getName() getName}()</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#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="http://chadretz.wordpress.com/2010/12/19/mathml-inside-javadoc-using-mathjax-and-a-custom-taglet/">http://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}