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