View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.doclet;
17  
18  import com.sun.javadoc.AnnotationDesc;
19  import com.sun.javadoc.ClassDoc;
20  import com.sun.javadoc.MethodDoc;
21  import com.sun.javadoc.ProgramElementDoc;
22  import com.sun.javadoc.RootDoc;
23  import com.sun.tools.javadoc.Main;
24  
25  import java.io.FileOutputStream;
26  import java.io.IOException;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.Enumeration;
30  import java.util.Properties;
31  import java.util.Vector;
32  
33  /**
34   * A JavaDoc tools doclet class that generates a properties file containing information about
35   * any @BeanTag classes @BeanTagAttribute properties
36   *
37   * @author Kuali Rice Team (rice.collab@kuali.org)
38   */
39  public class KRADLibraryPropertiesDoclet {
40  
41      // TODO : remove hard coded arguments
42      public static void main(String[] args) {
43          Main.execute(new String[]{"-doclet", "org.kuali.rice.krad.demo.uif.library.tools.KRADLibraryPropertiesDoclet",
44                  "-sourcepath", "C:/Java/Projects/Rice/Trunk/krad/krad-web-framework/src/main/java", "-subpackages",
45                  "org.kuali.rice.krad.uif:org.kuali.rice.krad.datadictionary.validation.constraint"});
46      }
47  
48      /*
49       * The method that will be called by the JavaDoc tool when executing this doclet
50       *
51       * @param root - the RootDoc containing all the class information as specified by the javadoc call arguments
52       * @return boolean
53       */
54      public static boolean start(RootDoc root) {
55          storeToPropertyFile(root);
56          return true;
57      }
58  
59      /*
60       * Writes all BeanTag properties to a propties file with their getter javadoc description
61       *
62       * @param root- the RootDoc containing all the class information as specified by the javadoc call arguments
63       */
64      private static void storeToPropertyFile(RootDoc root) {
65          ClassDoc[] classes = root.classes();
66          SortedProperties prop = new SortedProperties();
67  
68          for (ClassDoc classDoc : classes) {
69  
70              // Check only BeanTag classes
71              if (isAnnotatedWith(classDoc, "org.kuali.rice.krad.datadictionary.parse.BeanTag",
72                      "org.kuali.rice.krad.datadictionary.parse.BeanTags")) {
73  
74                  String className = classDoc.qualifiedName();
75                  String classDescription = classDoc.commentText();
76                  prop.setProperty(className, classDescription);
77  
78                  MethodDoc[] methods = classDoc.methods();
79  
80                  for (MethodDoc methodDoc : methods) {
81  
82                      // Check only getters that i BeanTagAttribute annotated
83                      if (methodDoc.parameters().length == 0 &&
84                              (methodDoc.name().startsWith("get") || methodDoc.name().startsWith("is")) &&
85                              !(methodDoc.name().equals("get") || methodDoc.name().equals("is")) &&
86                              isAnnotatedWith(methodDoc, "org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute")) {
87                          String methodName;
88  
89                          if (methodDoc.name().startsWith("get")) {
90                              methodName = methodDoc.name().replaceFirst("get", "");
91                          } else {
92                              methodName = methodDoc.name().replaceFirst("is", "");
93                          }
94                          String propertyName = Character.toLowerCase(methodName.charAt(0)) + (methodName.length() > 1 ?
95                                  methodName.substring(1) : "");
96                          String propertyType = methodDoc.returnType().typeName();
97                          String propertyDescription = getDocText(methodDoc, root);
98  
99                          prop.setProperty(className + "|" + propertyName + "|" + propertyType, propertyDescription);
100                     }
101                 }
102             }
103         }
104 
105         // TODO : remove hard coding of filepath
106         try {
107             prop.store(new FileOutputStream("C:/Java/Projects/Rice/Trunk/sampleapp/src/main/resources/"
108                     + "org/kuali/rice/devtools/krad/documentation/PropertiesDescription.properties"), null);
109         } catch (IOException e) {
110             e.printStackTrace();
111         }
112     }
113 
114     /*
115      * Returns the javadoc text for a method, when it is a @see comment the referenced methods documentation will
116      * be returned
117      *
118      * @param method
119      * @return String
120      */
121     private static String getDocText(MethodDoc method, RootDoc root) {
122 
123         if (method.commentText() != null && !method.commentText().equals("")) {
124             return method.commentText();
125         }
126 
127         String docText = method.getRawCommentText();
128 
129         if (docText != null && docText.contains("@see")) {
130             String classMethodName = docText.replace("@see", "").replace("\n", "").replace(" ", "");
131             String className = classMethodName.substring(0, classMethodName.indexOf("#"));
132             String methodName = classMethodName.substring(classMethodName.indexOf("#") + 1).replace("()", "");
133             ClassDoc classDoc = root.classNamed(className);
134 
135             if (classDoc == null) {
136                 System.err.println("warning - Comment on "
137                         + method.toString()
138                         + " does not have valid fully qualified "
139                         + "method in @see annotation.\n"
140                         + docText);
141                 return "";
142             }
143             MethodDoc methodDoc = getNoParamMethodFromClassDocByName(classDoc, methodName);
144             return methodDoc.commentText();
145         }
146 
147         return "";
148     }
149 
150     /*
151      * Finds the no arguments method's MethodDoc on a class with a specified name
152      *
153      * @param classDoc
154      * @param methodName
155      * @return MethodDoc
156      */
157     private static MethodDoc getNoParamMethodFromClassDocByName(ClassDoc classDoc, String methodName) {
158         MethodDoc[] methods = classDoc.methods();
159 
160         for (MethodDoc methodDoc : methods) {
161 
162             if (methodDoc.name().equals(methodName) && methodDoc.parameters().length == 0) {
163                 return methodDoc;
164             }
165         }
166         return null;
167     }
168 
169     /*
170      * Checks if a specific ClassDoc or MethodDoc is annotated with the specified annotations
171      *
172      * @param elementDoc
173      * @param tagString
174      * @return
175      */
176     private static boolean isAnnotatedWith(ProgramElementDoc elementDoc, String... tagString) {
177         AnnotationDesc[] annotations = elementDoc.annotations();
178 
179         for (AnnotationDesc annotation : annotations) {
180 
181             if (Arrays.asList(tagString).contains(annotation.annotationType().toString())) {
182                 return true;
183             }
184         }
185 
186         return false;
187     }
188 
189     /*
190      * This class keeps properties sorted in order to make the file easier to read
191      */
192     static class SortedProperties extends Properties {
193 
194         public Enumeration keys() {
195             Enumeration keysEnum = super.keys();
196             Vector<String> keyList = new Vector<String>();
197 
198             while (keysEnum.hasMoreElements()) {
199                 keyList.add((String) keysEnum.nextElement());
200             }
201             Collections.sort(keyList);
202             return keyList.elements();
203         }
204     }
205 
206 }