001: package org.testng.internal.annotations;
002:
003: import java.io.File;
004: import java.io.FileNotFoundException;
005: import java.io.FileReader;
006: import java.lang.reflect.Constructor;
007: import java.lang.reflect.Method;
008: import java.util.ArrayList;
009: import java.util.Collections;
010: import java.util.HashMap;
011: import java.util.Hashtable;
012: import java.util.List;
013: import java.util.Map;
014:
015: import org.testng.TestRunner;
016: import org.testng.internal.Utils;
017: import org.testng.log4testng.Logger;
018:
019: import com.thoughtworks.qdox.JavaDocBuilder;
020: import com.thoughtworks.qdox.directorywalker.DirectoryScanner;
021: import com.thoughtworks.qdox.directorywalker.FileVisitor;
022: import com.thoughtworks.qdox.directorywalker.SuffixFilter;
023: import com.thoughtworks.qdox.model.AbstractInheritableJavaEntity;
024: import com.thoughtworks.qdox.model.JavaClass;
025: import com.thoughtworks.qdox.model.JavaMethod;
026:
027: /**
028: * This class implements IAnnotationFinder with QDox for JDK 1.4
029: *
030: * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
031: * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
032: */
033: public class JDK14AnnotationFinder implements IAnnotationFinder {
034:
035: /** This class' loge4testng Logger. */
036: private static final Logger LOGGER = Logger
037: .getLogger(JDK14AnnotationFinder.class);
038:
039: private Map<String, List<File>> m_sourceFiles = new HashMap<String, List<File>>();
040:
041: private Map<String, String> m_parsedClasses = new HashMap<String, String>();
042: private Map<String, String> m_parsedFiles = new HashMap<String, String>();
043:
044: private JDK14TagFactory m_tagFactory = new JDK14TagFactory();
045: private JavaDocBuilder m_docBuilder;
046: private String[] m_dirPaths;
047: private IAnnotationTransformer m_transformer;
048:
049: public JDK14AnnotationFinder(IAnnotationTransformer transformer) {
050: m_docBuilder = new JavaDocBuilder();
051: m_transformer = transformer;
052: }
053:
054: public void addSourceDirs(String[] dirPaths) {
055: if (dirPaths == null) {
056: Utils
057: .log(getClass().getName(), 1,
058: "[WARNING] Array of source directory paths is null");
059: return;
060: }
061:
062: m_dirPaths = dirPaths;
063:
064: for (int i = 0; i < m_dirPaths.length; i++) {
065: File dir = new File(m_dirPaths[i]);
066: if (!dir.exists() || !dir.isDirectory()) {
067: Utils.log(getClass().getName(), 1,
068: "[WARNING] Invalid source directory "
069: + m_dirPaths[i] + " ignored");
070: continue;
071: }
072: DirectoryScanner scanner = new DirectoryScanner(dir);
073: scanner.addFilter(new SuffixFilter(".java"));
074: scanner.scan(new FileVisitor() {
075: public void visitFile(File currentFile) {
076: registerSourceFile(currentFile);
077: }
078: });
079: }
080: }
081:
082: /**
083: * Record in an internal map the existence of a source file.
084: * @param sourcefile the source file
085: */
086: private void registerSourceFile(File sourcefile) {
087: List<File> files = m_sourceFiles.get(sourcefile.getName());
088: if (null == files) {
089: files = new ArrayList<File>();
090: m_sourceFiles.put(sourcefile.getName(), files);
091: }
092: files.add(sourcefile);
093: }
094:
095: private boolean addSource(String filePath) {
096: if (m_parsedFiles.containsKey(filePath)) {
097: return true;
098: }
099:
100: try {
101: m_docBuilder.addSource(new FileReader(filePath));
102: m_parsedFiles.put(filePath, filePath);
103:
104: return true;
105: } catch (FileNotFoundException fnfe) {
106: Utils.log(getClass().getName(), 1,
107: "[WARNING] source file not found: " + filePath
108: + "\n " + fnfe.getMessage());
109: } catch (Throwable t) {
110: Utils.log(getClass().getName(), 1,
111: "[WARNING] cannot parse source: " + filePath
112: + "\n " + t.getMessage());
113: }
114:
115: return false;
116: }
117:
118: /**
119: * Must be synch to be assured that a file is not parsed twice
120: */
121: private synchronized JavaClass getClassByName(Class clazz) {
122: if (m_parsedClasses.containsKey(clazz.getName())) {
123: JavaClass jc = m_docBuilder.getClassByName(clazz.getName());
124: return jc;
125: } else {
126: parseSource(clazz);
127:
128: return getClassByName(clazz);
129: }
130: }
131:
132: /**
133: * Must be synch to be assured that a file is not parsed twice
134: */
135: private synchronized void parseSource(Class clazz) {
136: final String className = clazz.getName();
137: int innerSignPos = className.indexOf('$');
138: final String fileName = innerSignPos == -1 ? className
139: .substring(className.lastIndexOf('.') + 1) : clazz
140: .getName().substring(className.lastIndexOf('.') + 1,
141: innerSignPos);
142:
143: List<File> sourcefiles = m_sourceFiles.get(fileName + ".java");
144: if (null != sourcefiles) {
145: for (File f : sourcefiles) {
146: addSource(f.getAbsolutePath());
147: }
148: }
149:
150: m_parsedClasses.put(className, className);
151:
152: Class super Class = clazz.getSuperclass();
153: if (null != super Class && !Object.class.equals(super Class)) {
154: parseSource(super Class);
155: }
156: }
157:
158: public IAnnotation findAnnotation(Class cls, Class annotationClass) {
159: if (Object.class.equals(cls)) {
160: return null;
161: }
162:
163: IAnnotation result = m_tagFactory.createTag(annotationClass,
164: getClassByName(cls), m_transformer);
165:
166: transform(result, cls, null, null);
167:
168: return result;
169: }
170:
171: public IAnnotation findAnnotation(Method m, Class annotationClass) {
172: IAnnotation result = findMethodAnnotation(m.getName(), m
173: .getParameterTypes(), m.getDeclaringClass(),
174: annotationClass, m_transformer);
175:
176: transform(result, null, null, m);
177:
178: return result;
179: }
180:
181: public IAnnotation findAnnotation(Constructor m,
182: Class annotationClass) {
183: String name = stripPackage(m.getName());
184: IAnnotation result = findMethodAnnotation(name, m
185: .getParameterTypes(), m.getDeclaringClass(),
186: annotationClass, m_transformer);
187:
188: transform(result, null, m, null);
189:
190: return result;
191: }
192:
193: private void transform(IAnnotation a, Class testClass,
194: Constructor testConstructor, Method testMethod) {
195: if (a instanceof ITest) {
196: m_transformer.transform((ITest) a, testClass,
197: testConstructor, testMethod);
198: }
199: }
200:
201: private String stripPackage(String name) {
202: return name.substring(name.lastIndexOf('.') + 1);
203: // String result = name;
204: // int index = result.lastIndexOf(".");
205: // if (index > 0) {
206: // result = result.substring(index + 1);
207: // }
208: //
209: // return result;
210: }
211:
212: private IAnnotation findMethodAnnotation(String methodName,
213: Class[] parameterTypes, Class methodClass,
214: Class annotationClass, IAnnotationTransformer transformer) {
215: if (Object.class.equals(methodClass)) {
216: return null;
217: }
218:
219: IAnnotation result = null;
220: JavaClass jc = getClassByName(methodClass);
221: if (jc != null) {
222: List<JavaMethod> methods = new ArrayList<JavaMethod>();
223: JavaMethod[] allMethods = jc.getMethods();
224: for (int i = 0; i < allMethods.length; i++) {
225: JavaMethod jm = allMethods[i];
226: if (methodsAreEqual(jm, methodName, parameterTypes)) {
227: methods.add(jm);
228: }
229: }
230:
231: JavaMethod method = null;
232: // if (methods.size() > 1) {
233: // ppp("WARNING: method " + methodName + " is overloaded, only considering the first one");
234: // }
235:
236: if (methods.size() > 0) {
237: method = methods.get(0);
238: result = findTag(annotationClass, result, method,
239: transformer);
240: }
241:
242: } else {
243: Utils.log(getClass().getName(), 1,
244: "[WARNING] cannot resolve class: "
245: + methodClass.getName());
246: }
247:
248: return result;
249: }
250:
251: private boolean methodsAreEqual(JavaMethod jm, String methodName,
252: Class[] parameterTypes) {
253: boolean result = jm.getName().equals(methodName)
254: && jm.getParameters().length == parameterTypes.length;
255:
256: return result;
257: }
258:
259: private IAnnotation findTag(Class annotationClass,
260: IAnnotation result, AbstractInheritableJavaEntity entity,
261: IAnnotationTransformer transformer) {
262: return m_tagFactory.createTag(annotationClass, entity,
263: transformer);
264: }
265:
266: private static void ppp(String s) {
267: System.out.println("[JDK14AnnotationFinder] " + s);
268: }
269: }
|