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