KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jacorb > test > common > TestAnnotationsParser


1 package org.jacorb.test.common;
2
3 /*
4  * JacORB - a free Java ORB
5  *
6  * Copyright (C) 2005 Gerald Brose.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
21  * MA 02110-1301, USA.
22  */

23
24 import java.util.*;
25 import java.util.regex.*;
26 import java.io.*;
27 import java.nio.*;
28 import java.nio.channels.*;
29 import java.nio.charset.*;
30
31 /**
32  * Parses test annotations from javadoc comments in JUnit tests. A single
33  * instance of this class is created for each source file to be parsed.
34  * After the parsing is done, the instance is still kept around because it
35  * stores the annotations that were found in the file for access by other
36  * parts of the program.
37  *
38  * @author Andre Spiegel spiegel@gnu.org
39  * @version $Id: TestAnnotationsParser.java,v 1.1 2005/05/13 13:16:57 andre.spiegel Exp $
40  */

41 public class TestAnnotationsParser
42 {
43     /**
44      * Maps qualified class names to the corresponding instances
45      * of this class (String -> TestAnnotationsParser).
46      */

47     private static Map instances = new HashMap();
48     
49     private String JavaDoc filename;
50     private ByteBuffer sourceBuffer = null;
51     private CharSequence JavaDoc source = null;
52     
53     private TestAnnotations classAnnotations = null;
54     private Map methodAnnotations = null;
55     
56     private boolean annotationsLoaded = false;
57     
58     /**
59      * Private constructor, use getInstance() to create instances.
60      */

61     private TestAnnotationsParser (Class JavaDoc c)
62     {
63         String JavaDoc className = c.getName();
64         filename = TestUtils.testHome()
65                    + "/src/" + className.replace('.', '/') + ".java";
66     }
67     
68     /**
69      * Gets the annotations from the top-level javadoc comment
70      * of the source file. If there is no such comment, or it
71      * doesn't contain JacORB-specific annotations, returns null.
72      */

73     public TestAnnotations getClassAnnotations()
74     {
75         if (!annotationsLoaded)
76             if (!containsAnnotations())
77                 return null;
78             else
79                 loadAnnotations();
80         
81         return classAnnotations;
82     }
83
84     /**
85      * Gets the annotations for the method that is called methodName.
86      * If there is no such method, or it doesn't have a javadoc comment
87      * with JacORB-specific annotations, returns null. If there are
88      * annotations at the class level, each method of the class is considered
89      * to have the same annotations by default, so you'll get an annotations
90      * object with those values for every method. The defaults are
91      * overridden if the method does have annotations of its own.
92      */

93     public TestAnnotations getMethodAnnotations (String JavaDoc methodName)
94     {
95         if (!annotationsLoaded)
96         {
97             if (!containsAnnotations())
98                 return null;
99             else
100                 loadAnnotations();
101         }
102         
103         if (methodAnnotations == null)
104             return null;
105         else
106             return (TestAnnotations)methodAnnotations.get (methodName);
107     }
108
109     private static Pattern tagPattern =
110         Pattern.compile ("@jacorb-");
111     
112     /**
113      * Returns true if the source file does contain JacORB-specific annotations.
114      * This is intended as a quick check so that we needn't parse the
115      * entire file when there are no annotations in it anyway.
116      */

117     private boolean containsAnnotations()
118     {
119         if (annotationsLoaded)
120             return classAnnotations != null && methodAnnotations != null;
121         else
122         {
123             // It would be even better if we could use getSourceBuffer()
124
// here, because then the file would never actually be read
125
// and converted into Java characters at all. But we'd have to
126
// implement a search at the byte level then.
127
Matcher m = tagPattern.matcher(getSource());
128             if (m.find())
129                 return true;
130             else
131             {
132                 annotationsLoaded = true;
133                 return false;
134             }
135         }
136     }
137     
138     private static Pattern javadocPattern =
139         Pattern.compile ("(/\\*\\*\\s.*?\\*/)\\s*([^\n]*)", Pattern.DOTALL);
140     
141     private static Pattern classPattern =
142         Pattern.compile ("class\\s.*|.*?\\sclass\\s.*");
143     
144     private static Pattern methodPattern =
145         Pattern.compile ("public void ([^\\s(]+)\\s*\\(.*");
146     
147     /**
148      * This method does the actual parsing (loading) of annotations from
149      * the file.
150      */

151     private void loadAnnotations()
152     {
153         Matcher m = javadocPattern.matcher (getSource());
154         boolean isFirst = true;
155         while (m.find())
156         {
157             String JavaDoc javadoc = m.group(1);
158             String JavaDoc item = m.group(2);
159             if (isFirst)
160             {
161                 Matcher cm = classPattern.matcher (item);
162                 if (cm.matches())
163                 {
164                     classAnnotations = createAnnotations (javadoc);
165                     isFirst = false;
166                     continue;
167                 }
168             }
169             Matcher mm = methodPattern.matcher (item);
170             if (mm.matches())
171             {
172                 String JavaDoc methodName = mm.group(1);
173                 TestAnnotations ta = createAnnotations (javadoc);
174                 if (ta != null)
175                 {
176                     if (methodAnnotations == null)
177                         methodAnnotations = new HashMap();
178                     methodAnnotations.put (methodName, ta);
179                 }
180             }
181             isFirst = false;
182         }
183         // unmap the source file and free resources,
184
// now that we have parsed everything we were interested in
185
source = null;
186         sourceBuffer = null;
187     }
188     
189     private static Pattern tagValuePattern =
190         Pattern.compile ("@(jacorb-[a-z-]+)\\s+(\\S+)");
191     
192     /**
193      * Parses a javadoc comment and creates a TestAnnotations object
194      * from it, but only if the javadoc text actually contains
195      * JacORB-specific annotations. Otherwise, the method returns null.
196      */

197     private TestAnnotations createAnnotations (String JavaDoc javadoc)
198     {
199         String JavaDoc clientSince = null;
200         String JavaDoc serverSince = null;
201         if (classAnnotations != null)
202         {
203             // initialize from class-level annotations
204
clientSince = classAnnotations.getClientSince();
205             serverSince = classAnnotations.getServerSince();
206         }
207         Matcher m = tagValuePattern.matcher (javadoc);
208         while (m.find())
209         {
210             if (m.group(1).equals ("jacorb-since"))
211             {
212                 clientSince = m.group(2);
213                 serverSince = m.group(2);
214             }
215             else if (m.group(1).equals ("jacorb-client-since"))
216                 clientSince = m.group(2);
217             else if (m.group(1).equals ("jacorb-server-since"))
218                 serverSince = m.group(2);
219         }
220         if (clientSince != null || serverSince != null)
221             return new TestAnnotations (clientSince, serverSince);
222         else
223             return null;
224     }
225     
226     /**
227      * Returns the source code of the annotated class as a CharSequence.
228      */

229     private CharSequence JavaDoc getSource()
230     {
231         if (source == null)
232         {
233             source = Charset.forName("ISO-8859-1").decode (getSourceBuffer());
234         }
235         return source;
236     }
237     
238     /**
239      * Returns the source code of the annotated class as a memory-mapped
240      * ByteBuffer.
241      */

242     private ByteBuffer getSourceBuffer()
243     {
244         if (sourceBuffer == null)
245         {
246             try
247             {
248                 FileInputStream s = new FileInputStream (filename);
249                 FileChannel fc = s.getChannel();
250                 sourceBuffer = fc.map (FileChannel.MapMode.READ_ONLY, 0, fc.size());
251             }
252             catch (IOException ex)
253             {
254                 throw new RuntimeException JavaDoc(ex);
255             }
256         }
257         return sourceBuffer;
258     }
259
260     /**
261      * Returns the TestAnnotationsParser for the given class c.
262      * There is always at most a single instance for each class.
263      */

264     public static TestAnnotationsParser getInstance (Class JavaDoc c)
265     {
266         TestAnnotationsParser result =
267             (TestAnnotationsParser)instances.get(c.getName());
268         if (result == null)
269         {
270             result = new TestAnnotationsParser(c);
271             instances.put (c.getName(), result);
272         }
273         return result;
274     }
275     
276 }
277
Popular Tags