View Javadoc

1   /*
2       Jameleon - An automation testing tool..
3       Copyright (C) 2003 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 02111-1307 USA
18  */
19  package net.sf.jameleon.ant;
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Properties;
27  
28  import net.sf.jameleon.bean.FunctionalPoint;
29  import net.sf.jameleon.bean.Javadoc2Bean;
30  import net.sf.jameleon.exception.JameleonException;
31  import net.sf.jameleon.util.InstanceSerializer;
32  
33  import org.apache.tools.ant.BuildException;
34  
35  import com.thoughtworks.qdox.ant.AbstractQdoxTask;
36  import com.thoughtworks.qdox.model.JavaClass;
37  
38  /***
39   * An Ant task that registers all functional points (defined in <code>isA</code>, which defaults to
40   * <code>FunctionTag</code>) so they can be recognized by the Jameleon engine.
41   */
42  public class JameleonXDoclet extends AbstractQdoxTask{
43  
44      protected File outputDir = null;
45      protected String outputFileName = new String("TestCaseTagDefs.properties");
46      protected String isA = "net.sf.jameleon.function.FunctionTag";
47      protected boolean quiet = false;
48      protected Javadoc2Bean j2b;
49  
50      /***
51       * Set the directory where TestCaseTagDefs.properties will be generated to
52       * @param outputDir - The directory where TestCaseTagDefs.properties will be generated to. 
53       */
54      public void setOutputDir(File outputDir){
55          this.outputDir = outputDir;
56      }
57  
58      /***
59       * Restricts the javadocs to be extracted to all classes that implement this class
60       * @param isA - The class to restrict by.
61       */
62      public void setIsA(String isA){
63          this.isA = isA;
64      }
65  
66      /***
67       * Sets the messages to be printed to stdout to true/false
68       * @param quiet - Set to true to be quite. Defaults to false
69       */
70      public void setQuiet(boolean quiet){
71          this.quiet = quiet;
72      }
73  
74      /***
75       * Set the file where the function points will be registered to. The default is TestCaseTagDefs.properties if this is not set
76       * @param fileName - The name of the file where the information will be sent to. This does not include the directory as that is set
77       * via the outputDir property.
78       */
79      public void setOutputFileName(String fileName){
80          outputFileName = fileName;
81      }
82  
83      /***
84       * Implement this method and play with _xJavaDoc
85       *
86       * @exception BuildException  Ant's way of reporting exception
87       */
88      public void execute() throws BuildException{
89          if (outputDir == null) {
90              throw new BuildException("outputDir must be set to the directory where TestCaseTagDefs.properties will be generated to.");
91          }else if (!outputDir.isDirectory()) {
92              throw new BuildException("outputDir is not a valid directory! Set outputDir to the directory where TestCaseTagDefs.properties will be generated to.");
93          }
94          try{
95  	        validateAttributes();
96  	        buildFileMap();
97  	        j2b = new Javadoc2Bean();
98  	        j2b.setIsA(isA);
99  	        mergeBuilderSources(j2b);
100 	        Properties props = new Properties();
101 	        JavaClass[] classes = j2b.getJavaDocBuilder().getClasses();
102 	        for (int i = 0; i < classes.length; i++) {
103 	            setClassAttributes(classes[i],props,j2b);
104 	        }
105 	    	saveTagDefs(props, getTagDefsFileName());
106         }catch(RuntimeException re){
107         	re.printStackTrace();
108         }
109     }
110     
111     protected void mergeBuilderSources(Javadoc2Bean j2b) {
112     	for (Iterator iterator = fileMap.keySet().iterator(); iterator.hasNext();) {
113     		String sourceFile = (String) iterator.next();
114     		j2b.getJavaDocBuilder().addSourceTree((File) fileMap.get(sourceFile));
115     	}
116     }
117 
118     /***
119      * Simply constructs a file from a String that represents the fully qualified class
120      * name. The path to the file will be prefixed by the <code>outputDir</code>.
121      * @param className - a String representing the name and partial (package) location of the file.
122      * @return A file that starts with <code>outputDir</code> and is followed by the directory 
123      *         structure (package) of the <code>className</code>
124      */
125     protected File constructFileFromClassName(String className){
126         String sourceName = new String(className);
127         if (sourceName.endsWith(".class")) {
128             sourceName = sourceName.substring(0,sourceName.indexOf(".class"));
129         }
130         sourceName = sourceName.replace('.',File.separatorChar);
131         sourceName += InstanceSerializer.SERIALIZED_EXT;
132         return new File(outputDir, sourceName);
133     }
134 
135     /***
136      * @return the complete path to the output file for the tag definitions of functional points
137      */
138     protected String getTagDefsFileName(){
139         String fileName = outputDir.getPath();
140         if (fileName.lastIndexOf(File.separator) < (fileName.length() -1) ) {
141             fileName += File.separator;
142         }
143         fileName += outputFileName;
144         return fileName;
145     }
146 
147     /***
148      * Saves the function point names and their corresponding class names to a file
149      * @param props - The properties to save to a file.
150      */
151     protected void saveTagDefs(Properties props, String fileName) throws BuildException{
152     	FileOutputStream fos = null;
153         try{
154         	fos = new FileOutputStream(fileName);
155             props.store(fos,"Function Tag Definitions generated by Jameleon."); 
156         }catch(IOException ioe){
157             throw new BuildException("Could not write to file "+fileName,ioe);
158         }finally{
159         	try{
160         		if (fos != null){
161         			fos.close();
162         		}
163         	}catch(IOException ioe){
164         		ioe.printStackTrace();
165         		//Couldn't close an output stream?
166         	}
167         }
168     }
169 
170     /***
171      * Set the class-specific attributes
172      */
173     protected void setClassAttributes(JavaClass clazz, Properties props, Javadoc2Bean j2b) throws BuildException{
174         String className = clazz.getFullyQualifiedName();
175         FunctionalPoint fp = null;
176         try{
177             fp = j2b.getFunctionalPoint(clazz);
178             if (fp != null){
179                 //validate that the type is correct
180                 fp.getType();
181             }
182         } catch (JameleonException iae){
183             throw new BuildException(className + ": "+iae.getMessage());
184         } 
185         String warningMsg = "WARNING: "+className+" is a valid function point, but it will NOT be automatically registered! "+
186                             "Please add a @jameleon.function name=\"functionName\" to the class javadocs of the function point";
187         if (fp != null) {
188             List tagNames = fp.getTagNames();
189             Iterator it = tagNames.iterator();
190             while (it.hasNext()) {
191                 String tagName = (String)it.next();
192                 if ( tagName != null && tagName.length() > 0 && props.getProperty(tagName) == null) {
193                     props.setProperty(tagName,className);
194                     serializeFunctionalPoint(fp, className);
195                 }else if(tagName != null && props.getProperty(tagName) != null){
196                     throw new BuildException(className +" and "+ props.getProperty(tagName) +" both have the same function point name registered! "+
197                                              "Change the @jameleon.function name=\"\" attribute of one of these classes to something unique and try again.");
198                 }else{
199                     if (!quiet) {
200                         System.out.println(warningMsg);
201                     }
202                 }
203             }
204             if (tagNames.size() == 0) {
205                 serializeFunctionalPoint(fp, className);
206                 if (!quiet) {
207                     System.out.println(warningMsg);
208                 }
209             }
210         }
211 
212     }
213 
214     protected void serializeFunctionalPoint(FunctionalPoint fp, String className) throws BuildException{
215         try{
216         	InstanceSerializer.serialize(fp,constructFileFromClassName(className));
217         }catch(IOException ioe){
218             throw new BuildException(ioe.toString());
219         }
220     }
221 
222 }