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}("../")</CODE> 085 <BR>Where {@code packageElementMtchr} is initialized to 086 <BR> <CODE>Pattern.{@link java.util.regex.Pattern#compile(String) compile}("[\\p{L}_\\p{Sc}][\\p{L}\\p{N}_\\p{Sc}]*\\.?").{@link java.util.regex.Pattern#matcher(CharSequence) matcher}("")</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 "package" 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}