This project has retired. For details please refer to its Attic page.
QDoxTemplateSuiteFactory xref
View Javadoc

1   /*
2    * $Id: QDoxTemplateSuiteFactory.java 1349964 2012-06-13 17:18:51Z nlebas $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  package org.apache.tiles.autotag.core;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.net.URL;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.apache.tiles.autotag.core.runtime.ModelBody;
30  import org.apache.tiles.autotag.core.runtime.annotation.Parameter;
31  import org.apache.tiles.autotag.model.TemplateClass;
32  import org.apache.tiles.autotag.model.TemplateMethod;
33  import org.apache.tiles.autotag.model.TemplateParameter;
34  import org.apache.tiles.autotag.model.TemplateSuite;
35  import org.apache.tiles.autotag.model.TemplateSuiteFactory;
36  
37  import com.thoughtworks.qdox.JavaDocBuilder;
38  import com.thoughtworks.qdox.model.Annotation;
39  import com.thoughtworks.qdox.model.DocletTag;
40  import com.thoughtworks.qdox.model.JavaClass;
41  import com.thoughtworks.qdox.model.JavaMethod;
42  import com.thoughtworks.qdox.model.JavaParameter;
43  import com.thoughtworks.qdox.model.Type;
44  
45  /**
46   * Creates a template suite using QDox.
47   *
48   * @version $Rev: 1349964 $ $Date: 2012-06-13 19:18:51 +0200 (Wed, 13 Jun 2012) $
49   */
50  public class QDoxTemplateSuiteFactory implements TemplateSuiteFactory {
51  
52      /**
53       * The suffix of parsed classes.
54       */
55      private static final String TEMPLATE_SUFFIX = "Model";
56  
57      /**
58       * The Javadoc builder.
59       */
60      private JavaDocBuilder builder;
61  
62      /**
63       * The name of the suite.
64       */
65      private String suiteName;
66  
67      /**
68       * The documentation of the suite.
69       */
70      private String suiteDocumentation;
71  
72      /**
73       * The request class the suite.
74       */
75      private String requestClass;
76  
77      /**
78       * Constructor.
79       *
80       * @param sourceFiles All the source files to parse.
81       */
82      public QDoxTemplateSuiteFactory(File... sourceFiles) {
83          builder = new JavaDocBuilder();
84          try {
85              for (File file : sourceFiles) {
86                  builder.addSource(file);
87              }
88          } catch (IOException e) {
89              throw new ClassParseException(
90                      "I/O Exception when adding source files", e);
91          }
92      }
93  
94      /**
95       * Constructor.
96       *
97       * @param urls All the URLs of source files to parse.
98       */
99      public QDoxTemplateSuiteFactory(URL... urls) {
100         builder = new JavaDocBuilder();
101         try {
102             for (URL url : urls) {
103                 builder.addSource(url);
104             }
105         } catch (IOException e) {
106             throw new ClassParseException(
107                     "I/O Exception when adding source files", e);
108         }
109     }
110 
111     /**
112      * Sets the suite name to assign to the created suite.
113      *
114      * @param suiteName The suite name.
115      */
116     public void setSuiteName(String suiteName) {
117         this.suiteName = suiteName;
118     }
119 
120     /**
121      * Sets the suite documentation to assign to the suite.
122      *
123      * @param suiteDocumentation The suite documentation.
124      */
125     public void setSuiteDocumentation(String suiteDocumentation) {
126         this.suiteDocumentation = suiteDocumentation;
127     }
128 
129     /**
130      * Sets the request class used by the suite.
131      *
132      * @param requestClass The request class name.
133      */
134     public void setRequestClass(String requestClass) {
135         this.requestClass = requestClass;
136     }
137 
138     @Override
139     public TemplateSuite createTemplateSuite() {
140         List<TemplateClass> classes = new ArrayList<TemplateClass>();
141         for (JavaClass clazz : builder.getClasses()) {
142             String tagClassPrefix = getTagClassPrefix(clazz);
143             if (tagClassPrefix != null) {
144                 String tagName = tagClassPrefix.substring(0, 1).toLowerCase()
145                         + tagClassPrefix.substring(1);
146                 TemplateMethod executeMethod = null;
147                 for (JavaMethod method : clazz.getMethods()) {
148                     if (isFeasible(method)) {
149                         executeMethod = createMethod(method);
150                     }
151                 }
152                 if (executeMethod != null) {
153                     TemplateClass templateClass = new TemplateClass(clazz
154                             .getFullyQualifiedName(), tagName, tagClassPrefix,
155                             executeMethod);
156                     templateClass.setDocumentation(clazz.getComment());
157                     classes.add(templateClass);
158                 }
159             }
160         }
161         return new TemplateSuite(suiteName, suiteDocumentation, classes);
162     }
163 
164     /**
165      * Computes the tag class prefix.
166      *
167      * @param clazz The parsed class.
168      * @return The tag class prefix.
169      */
170     private String getTagClassPrefix(JavaClass clazz) {
171         String tagName;
172         String simpleClassName = clazz.getName();
173         if (simpleClassName.endsWith(TEMPLATE_SUFFIX)
174                 && simpleClassName.length() > TEMPLATE_SUFFIX.length()) {
175             tagName = simpleClassName.substring(0, 1).toUpperCase()
176                     + simpleClassName.substring(1, simpleClassName.length()
177                             - TEMPLATE_SUFFIX.length());
178         } else {
179             tagName = null;
180         }
181         return tagName;
182     }
183 
184     /**
185      * Creates a template method descriptor from a parsed method.
186      *
187      * @param method The parsed method.
188      * @return The template method descriptor.
189      */
190     private TemplateMethod createMethod(JavaMethod method) {
191         List<TemplateParameter> params = new ArrayList<TemplateParameter>();
192         for (JavaParameter parameter : method.getParameters()) {
193             String exportedName = parameter.getName();
194             boolean required = false;
195             String defaultValue = null;
196             Annotation[] annotations = parameter.getAnnotations();
197             if (annotations != null && annotations.length > 0) {
198                 boolean found = false;
199                 for (int i = 0; i < annotations.length && !found; i++) {
200                     if (Parameter.class.getName().equals(annotations[i].getType().getFullyQualifiedName())) {
201                         found = true;
202                         String candidateName = (String) annotations[i].getNamedParameter("name");
203                         if (candidateName != null && candidateName.length() > 2) {
204                             exportedName = candidateName.substring(1, candidateName.length() - 1);
205                         }
206                         required = "true".equals(annotations[i].getNamedParameter("required"));
207                         candidateName = (String) annotations[i].getNamedParameter("defaultValue");
208                         if (candidateName != null && candidateName.length() > 2) {
209                             defaultValue = candidateName.substring(1, candidateName.length() - 1);
210                         }
211                     }
212                 }
213             }
214             String parameterType = parameter.getType()
215                     .getFullyQualifiedName();
216             TemplateParameter templateParameter = new TemplateParameter(
217                     parameter.getName(), exportedName, parameterType, defaultValue, required,
218                     requestClass.equals(parameterType));
219             params.add(templateParameter);
220         }
221         TemplateMethod templateMethod = new TemplateMethod(method.getName(),
222                 params);
223         templateMethod.setDocumentation(method.getComment());
224         DocletTag[] tags = method.getTagsByName("param");
225         for (DocletTag tag : tags) {
226             String[] tagParams = tag.getParameters();
227             if (tagParams.length > 0) {
228                 TemplateParameter templateParameter = templateMethod
229                         .getParameterByName(tagParams[0]);
230                 if (templateParameter != null) {
231                     String tagValue = tag.getValue();
232                     int pos = tagValue.indexOf(" ");
233                     templateParameter.setDocumentation(tagValue.substring(pos)
234                             .trim());
235                 }
236             }
237         }
238         return templateMethod;
239     }
240 
241     /**
242      * Verifies if the method can be used as an "execute" method.
243      *
244      * @param method The parsed method.
245      * @return <code>true</code> if it is an execute method.
246      */
247     private boolean isFeasible(JavaMethod method) {
248         Type returns = method.getReturns();
249         if ("execute".equals(method.getName()) && returns != null
250                 && "void".equals(returns.getFullyQualifiedName())
251                 && method.isPublic() && !method.isStatic()
252                 && !method.isAbstract() && !method.isConstructor()) {
253             JavaParameter[] params = method.getParameters();
254             if (params.length > 0) {
255                 JavaParameter param = params[params.length - 1];
256                 if (requestClass.equals(
257                         param.getType().getFullyQualifiedName())) {
258                     return true;
259                 }
260             }
261             if (params.length >= 2) {
262                 JavaParameter param1 = params[params.length - 2];
263                 JavaParameter param2 = params[params.length - 1];
264                 if (requestClass.equals(
265                         param1.getType().getFullyQualifiedName())
266                         && ModelBody.class.getName().equals(
267                                 param2.getType().getFullyQualifiedName())) {
268                     return true;
269                 }
270             }
271         }
272         return false;
273     }
274 }