1
19
20 package com.liferay.portal.kernel.util;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileReader;
25 import java.io.IOException;
26 import java.io.Reader;
27 import java.io.StreamTokenizer;
28 import java.io.StringReader;
29
30 import java.util.ArrayList;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Set;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37
44 public class ClassUtil {
45
46 public static Set<String> getClasses(File file) throws IOException {
47 String fileName = file.getName();
48
49 if (fileName.endsWith(".java")) {
50 fileName = fileName.substring(0, fileName.length() - 5);
51 }
52
53 return getClasses(new FileReader(file), fileName);
54 }
55
56 public static Set<String> getClasses(Reader reader, String className)
57 throws IOException {
58
59 Set<String> classes = new HashSet<String>();
60
61 StreamTokenizer st = new StreamTokenizer(new BufferedReader(reader));
62
63 _setupParseTableForAnnotationProcessing(st);
64
65 while (st.nextToken() != StreamTokenizer.TT_EOF) {
66 if (st.ttype == StreamTokenizer.TT_WORD) {
67 if (st.sval.equals("class") || st.sval.equals("interface") ||
68 st.sval.equals("@interface")) {
69
70 break;
71 }
72 else if (st.sval.startsWith("@")) {
73 st.ordinaryChar(' ');
74 st.wordChars('=', '=');
75
76 String[] las = _processAnnotation(st.sval, st);
77
78 for (int i = 0; i < las.length; i++) {
79 classes.add(las[i]);
80 }
81
82 _setupParseTableForAnnotationProcessing(st);
83 }
84 }
85 }
86
87 _setupParseTable(st);
88
89 while (st.nextToken() != StreamTokenizer.TT_EOF) {
90 if (st.ttype == StreamTokenizer.TT_WORD) {
91 if (st.sval.indexOf('.') >= 0) {
92 classes.add(st.sval.substring(0, st.sval.indexOf('.')));
93 }
94 else {
95 classes.add(st.sval);
96 }
97 }
98 else if (st.ttype != StreamTokenizer.TT_NUMBER &&
99 st.ttype != StreamTokenizer.TT_EOL) {
100
101 if (Character.isUpperCase((char)st.ttype)) {
102 classes.add(String.valueOf((char)st.ttype));
103 }
104 }
105 }
106
107 classes.remove(className);
108
109 return classes;
110 }
111
112 public static boolean isSubclass(Class<?> a, Class<?> b) {
113 if (a == b) {
114 return true;
115 }
116
117 if (a == null || b == null) {
118 return false;
119 }
120
121 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
122 if (x == b) {
123 return true;
124 }
125
126 if (b.isInterface()) {
127 Class<?>[] interfaces = x.getInterfaces();
128
129 for (int i = 0; i < interfaces.length; i++) {
130 if (isSubclass(interfaces[i], b)) {
131 return true;
132 }
133 }
134 }
135 }
136
137 return false;
138 }
139
140 public static boolean isSubclass(Class<?> a, String s) {
141 if (a == null || s == null) {
142 return false;
143 }
144
145 if (a.getName().equals(s)) {
146 return true;
147 }
148
149 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
150 if (x.getName().equals(s)) {
151 return true;
152 }
153
154 Class<?>[] interfaces = x.getInterfaces();
155
156 for (int i = 0; i < interfaces.length; i++) {
157 if (isSubclass(interfaces[i], s)) {
158 return true;
159 }
160 }
161 }
162
163 return false;
164 }
165
166 private static String[] _processAnnotation(String s, StreamTokenizer st)
167 throws IOException {
168
169 s = s.trim();
170
171 List<String> tokens = new ArrayList<String>();
172
173 Matcher annotationNameMatcher = _ANNOTATION_NAME_REGEXP.matcher(s);
174 Matcher annotationParametersMatcher =
175 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
176
177 if (annotationNameMatcher.matches()) {
178 String annotationName = annotationNameMatcher.group();
179
180 tokens.add(annotationName.replace("@", ""));
181 }
182 else if (annotationParametersMatcher.matches()) {
183 if (!s.trim().endsWith(")")) {
184 while (st.nextToken() != StreamTokenizer.TT_EOF) {
185 if (st.ttype == StreamTokenizer.TT_WORD) {
186 s += st.sval;
187 if (s.trim().endsWith(")")) {
188 break;
189 }
190 }
191 }
192 }
193
194 annotationParametersMatcher =
195 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
196
197 if (annotationParametersMatcher.matches()) {
198 String annotationName =
199 annotationParametersMatcher.group(1);
200 String annotationParameters =
201 annotationParametersMatcher.group(2);
202
203 tokens.add(annotationName.replace("@", ""));
204
205 tokens = _processAnnotationParameters(
206 annotationParameters,tokens);
207 }
208 }
209
210 return tokens.toArray(new String[tokens.size()]);
211 }
212
213 private static List<String> _processAnnotationParameters(
214 String s, List<String> tokens)
215 throws IOException {
216
217 StreamTokenizer st = new StreamTokenizer(new StringReader(s));
218
219 _setupParseTable(st);
220
221 while (st.nextToken() != StreamTokenizer.TT_EOF) {
222 if (st.ttype == StreamTokenizer.TT_WORD) {
223 if (st.sval.indexOf('.') >= 0) {
224 tokens.add(st.sval.substring(0, st.sval.indexOf('.')));
225 }
226 else {
227 tokens.add(st.sval);
228 }
229 }
230 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
231 (st.ttype != StreamTokenizer.TT_EOL)) {
232
233 if (Character.isUpperCase((char)st.ttype)) {
234 tokens.add(String.valueOf((char)st.ttype));
235 }
236 }
237 }
238
239 return tokens;
240 }
241
242 private static void _setupParseTable(StreamTokenizer st) {
243 st.resetSyntax();
244 st.slashSlashComments(true);
245 st.slashStarComments(true);
246 st.wordChars('a', 'z');
247 st.wordChars('A', 'Z');
248 st.wordChars('.', '.');
249 st.wordChars('0', '9');
250 st.wordChars('_', '_');
251 st.lowerCaseMode(false);
252 st.eolIsSignificant(false);
253 st.quoteChar('"');
254 st.quoteChar('\'');
255 st.parseNumbers();
256 }
257
258 private static void _setupParseTableForAnnotationProcessing(
259 StreamTokenizer st) {
260
261 _setupParseTable(st);
262
263 st.wordChars('@', '@');
264 st.wordChars('(', '(');
265 st.wordChars(')', ')');
266 st.wordChars('{', '{');
267 st.wordChars('}', '}');
268 st.wordChars(',',',');
269 }
270
271 private static final Pattern _ANNOTATION_NAME_REGEXP =
272 Pattern.compile("@(\\w+)$");
273
274 private static final Pattern _ANNOTATION_PARAMETERS_REGEXP =
275 Pattern.compile("@(\\w+)\\({0,1}\\{{0,1}([^)}]+)\\}{0,1}\\){0,1}");
276
277 }