View Javadoc

1   /*
2       Jameleon - An automation testing tool..
3       Copyright (C) 2003-2006 Christian W. Hargraves (engrean@hotmail.com)
4       
5       This library is free software; you can redistribute it and/or
6       modify it under the terms of the GNU Lesser General Public
7       License as published by the Free Software Foundation; either
8       version 2.1 of the License, or (at your option) any later version.
9   
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13      Lesser General Public License for more details.
14  
15      You should have received a copy of the GNU Lesser General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111AssertLevel.NO_FUNCTION07 USA
18  */
19  package net.sf.jameleon.bean;
20  
21  import com.thoughtworks.qdox.JavaDocBuilder;
22  import com.thoughtworks.qdox.model.*;
23  import net.sf.jameleon.exception.JameleonException;
24  import net.sf.jameleon.util.InstanceSerializer;
25  
26  import java.io.File;
27  import java.io.FileNotFoundException;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.util.*;
31  
32  public class Javadoc2Bean {
33  
34      protected File sourceDir;
35      protected String isA = "net.sf.jameleon.function.FunctionTag";
36      protected JavaDocBuilder docBuilder;
37      protected Map serializedFiles = new HashMap();
38  
39      /***
40       * Default constructor only used to initialize variables
41       */
42      public Javadoc2Bean() {
43      	docBuilder = new JavaDocBuilder();
44      	docBuilder.getClassLibrary().addClassLoader(getClass().getClassLoader());
45      }
46      
47      public String getClassNameFromSource(String sourceFileName) throws MissingResourceException{
48          if (sourceFileName.startsWith(sourceDir.getPath())) {
49              sourceFileName = sourceFileName.substring(sourceDir.getPath().length() + 1);
50          }
51          String className = sourceFileName.substring(0, sourceFileName.lastIndexOf(".java"));
52          className = className.replace(File.separatorChar, '.');
53          return className;
54      }
55  
56      public File getSourceFile(String className){
57          String sourceName = convertClassNameToSourceName(className,true);
58          sourceName = sourceDir.getPath() + File.separator + sourceName;
59          return new File(sourceName);
60      }
61  
62      public String convertClassNameToSourceName(String className, boolean appendJava){
63          int index = className.indexOf(".class");
64          String sourceName = className;
65          if (index > -1) {
66              sourceName = sourceName.substring(0,index);
67          }
68          sourceName = sourceName.replace('.',File.separatorChar);
69          if (appendJava) {
70              sourceName += ".java";
71          }
72          return sourceName;
73      }
74  
75      public File getSourceDir(){
76          return this.sourceDir;
77      }
78  
79      public void setSourceDir(File sourceDir){
80          this.sourceDir = sourceDir;
81      }
82  
83      public String getIsA(){
84          return isA;
85      }
86  
87      public void setIsA(String isA){
88          this.isA = isA;
89      }
90      
91      public FunctionalPoint getFunctionalPointWithClass(String className) throws FileNotFoundException{
92          return getFunctionalPoint(getJavaClassWithClass(className));
93      }
94  
95      public FunctionalPoint getFunctionalPointWithSource(File sourceFile) throws FileNotFoundException{
96          return getFunctionalPoint(getJavaClassWithSource(sourceFile));
97      }
98  
99      public FunctionalPoint getFunctionalPoint(JavaClass clss){
100         FunctionalPoint fp = null;
101         if ( clss != null && clss.isA(isA)) {
102             fp  = new FunctionalPoint();
103             fp.setClassName(clss.getFullyQualifiedName());
104             addClassDocs(fp, clss);
105             addApplications(fp, clss);
106             addSteps(fp, clss);
107             addFields(fp, clss);
108             addMethods(fp, clss);
109             addDocsFromSerializedFP(fp,clss);
110         }
111         return fp;
112     }
113 
114     protected FunctionalPoint getFunctionalPointFromSerializedFile(JavaClass clss){
115         String qName = clss.getFullyQualifiedName();
116         FunctionalPoint fp = null;
117         if (serializedFiles.containsKey(qName)) {
118             fp = (FunctionalPoint)serializedFiles.get(qName);
119         } else {
120             String fileName = qName.replace('.', '/')+".dat";
121             InputStream in = getClass().getClassLoader().getResourceAsStream(fileName);
122             if (in != null) {
123                 try {
124                     fp = (FunctionalPoint) InstanceSerializer.deserialize(in);
125                     serializedFiles.put(qName,fp);
126                 } catch (IOException ioe) {
127                     //This simply means no accompanying .dat file was found
128                 } catch (ClassNotFoundException cnfe) {
129                     throw new JameleonException("Can not find FunctionalPoint! "+cnfe);
130                 }
131             }
132         }
133         return fp;
134     }
135 
136     protected void addDocsFromSerializedFP(FunctionalPoint fp, JavaClass clss){
137         FunctionalPoint serFp;
138         for (JavaClass superClass = clss; superClass != null && superClass.isA(isA); superClass = superClass.getSuperJavaClass()) {
139             serFp = getFunctionalPointFromSerializedFile(superClass);
140             if (serFp != null) {
141                 String key;
142                 for (Iterator it = serFp.getAttributes().keySet().iterator(); it.hasNext();) {
143                     key = (String)it.next();
144                     if ( !fp.getAttributes().containsKey(key) ) {
145                         fp.addAttribute((Attribute)serFp.getAttributes().get(key));
146                     }
147                 }
148             }
149         }
150     }
151 
152     protected void addClassDocs(FunctionalPoint fp, JavaClass clss) {
153     	String comment = clss.getComment();
154         fp.setDescription(comment);
155         fp.setShortDescription(getShortDescription(comment));
156         DocletTag[] tagNames = clss.getTagsByName("jameleon.function");
157         for (int i = 0; i < tagNames.length; i++) {
158             fp.addTagName(convertNullToString(tagNames[i].getNamedParameter("name")));
159             fp.setType(convertNullToString(tagNames[i].getNamedParameter("type")));
160         }
161         DocletTag tag = clss.getTagByName("author");
162         if (tag != null) {
163             fp.setAuthor(convertNullToString(tag.getValue()));
164         }
165     }
166     
167     protected String getShortDescription(String description){
168     	String desc = description;
169     	if (desc != null && desc.trim().length() > 0){
170     		desc = description.replaceAll("(?s)^(.+?)[.//n//r]+.*", "$1")+".";
171     	}
172         return desc;
173     }
174 
175     protected void addApplications(FunctionalPoint fp, JavaClass clss) {
176         DocletTag[] applicationTags = clss.getTagsByName("jameleon.application");
177         for (int i = 0; i < applicationTags.length; i++) {
178             fp.addApplication(convertNullToString(applicationTags[i].getValue()));
179         }
180     }
181 
182     protected void addSteps(FunctionalPoint fp, JavaClass clss) {
183         DocletTag[] tags = clss.getTagsByName("jameleon.step");
184         for (int i = 0; i < tags.length; i++) {
185             fp.addStep(convertNullToString(tags[i].getValue()));
186         }
187     }
188 
189     protected void addMethods(FunctionalPoint fp, JavaClass clss) {
190         String name, type;
191         JavaMethod[] methods = clss.getMethods(true);
192         Attribute attr;
193         for (int i = 0; i < methods.length; i++) {
194             if (methods[i].isPropertyMutator() && methods[i].getTagByName("jameleon.attribute") != null) {
195                 type =  getFirstParameterTypeFromJavaMethod(methods[i]);
196                 name = methods[i].getPropertyName();
197                 if (fp.getAttributes().containsKey(name)) {
198                     attr = (Attribute)fp.getAttributes().get(name);
199                     fp.addAttribute(createAttributeFromTag(methods[i], name, attr.getType(), attr.getContextName(), false));
200                 } else {
201                     fp.addAttribute(createAttributeFromTag(methods[i], name, type, "",false));
202                 }
203             }
204         }
205     }
206 
207     protected void addFields(FunctionalPoint fp, JavaClass clss) {
208         JavaField[] fields = getFields(clss);        
209         processAttributes(fields, fp);
210     }
211 
212     protected JavaField[] getFields(JavaClass clss) {
213         Set signatures = new HashSet();
214     	List fields = new ArrayList();
215         addFieldsFromSuperclassAndInterfaces(signatures, fields, clss);
216         return (JavaField[]) fields.toArray(new JavaField[fields.size()]);
217     }
218 
219     protected void addFieldsFromSuperclassAndInterfaces(Set signatures, List fieldList, JavaClass clazz) {
220     	JavaField[] fields = clazz.getFields();
221     	
222     	addNewFields(signatures, fieldList, fields);
223     	
224     	JavaClass superclass = clazz.getSuperJavaClass();
225     	
226     	// workaround for a bug in getSuperJavaClass
227     	if ((superclass != null) && (superclass != clazz)) {
228     	    addFieldsFromSuperclassAndInterfaces(signatures, fieldList, superclass);
229     	}
230     	
231     	JavaClass[] implementz = clazz.getImplementedInterfaces();
232     	
233     	for (int i = 0; i < implementz.length; i++) {
234     	    if (implementz[i] != null) {
235     	        addFieldsFromSuperclassAndInterfaces(signatures, fieldList, implementz[i]);
236     	    }
237     	}
238     }
239     
240     private void addNewFields(Set signatures, List fieldList, JavaField[] fields) {
241     	for (int i = 0; i < fields.length; i++) {
242 	        String signature = fields[i].getName();
243 	        if (!signatures.contains(signature)) {
244 	            fieldList.add(fields[i]);
245 	            signatures.add(signature);
246 	        }
247     	}
248     }
249     
250     private void processAttributes(JavaField[] attributes, FunctionalPoint fp){
251         String name, contextName, type;
252         for (int i = 0; i < attributes.length; i++){
253             if (attributes[i].getTagByName("jameleon.attribute") != null) {
254                 contextName = attributes[i].getNamedParameter("jameleon.attribute","contextName");
255                 type =  attributes[i].getType().getValue();
256                 name = attributes[i].getName();
257                 fp.addAttribute(createAttributeFromTag(attributes[i], name, type, contextName,true));
258             }
259         }
260     }
261 
262     protected Attribute createAttributeFromTag(AbstractJavaEntity aje, String name, String type, String contextName, boolean instanceVariable) {
263         Attribute attr = new Attribute();
264         attr.setName(convertNullToString(name));
265         attr.setContextName(contextName);
266         attr.setType(convertNullToString(type));
267         attr.setDescription(convertNullToString(aje.getComment()));
268         attr.setRequired(Boolean.valueOf(aje.getNamedParameter("jameleon.attribute", "required")).booleanValue());
269         //This needs to default to null
270         attr.setDefaultValue(aje.getNamedParameter("jameleon.attribute","default"));
271         attr.setInstanceVariable(instanceVariable);
272         return attr;
273     }
274 
275     public JavaDocBuilder getJavaDocBuilder(){
276     	return setUpSourceSet();
277     }
278     
279     protected JavaDocBuilder setUpSourceSet(){
280         if (docBuilder == null) {
281         	docBuilder = new JavaDocBuilder();
282             docBuilder.getClassLibrary().addClassLoader(getClass().getClassLoader());
283             docBuilder.addSourceTree(sourceDir);
284         }
285         return docBuilder;
286     }
287     
288     protected JavaClass getJavaClassWithClass(String className) throws FileNotFoundException{
289     	return getJavaClass(className, className);
290     }
291     
292     private JavaClass getJavaClass(String className, String resource) throws FileNotFoundException{
293         try {
294             getSourceFile(className);
295         } catch (MissingResourceException mre) {
296             throw new FileNotFoundException("File corresponding to "+resource +" not found");
297         }
298         return getJavaDocBuilder().getClassByName(className);
299     }
300 
301     protected JavaClass getJavaClassWithSource(File sourceFile) throws FileNotFoundException{
302         if (!sourceFile.exists()) {
303             throw new FileNotFoundException("File \""+sourceFile.getPath() +"\" not found");
304         }
305         return getJavaDocBuilder().getClassByName(getClassNameFromSource(sourceFile.getPath()));
306     }
307 
308     protected String convertNullToString(String str){
309         String rtrStr = ""; 
310         if (str != null && str.length() > 0) {
311             rtrStr = str;
312         }
313         return rtrStr;
314     }
315 
316     /***
317      * XJavadoc only gets the unqualified type of the instance variable, e.g. String not java.lang.String
318      * But on method params, XJavadoc gets the fully qualified name
319      * Since we use both, we want to make it consistent
320      * @param method - the method that represents the attribute
321      * @return the first parameter type as a String, fully qualified.
322      */
323     protected String getFirstParameterTypeFromJavaMethod(JavaMethod method) {
324         String type = "";
325         JavaParameter[] params = method.getParameters();
326         if (params.length > 0) {
327             JavaParameter param = params[0];
328             type = param.getType().getValue();
329             int index = type.indexOf(" ");
330             if (index > -1) {
331                 type = type.substring(0, index);
332             }
333         }
334         return type;
335     }
336 
337 }
338 
339 
340