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