1
22
23 package com.liferay.portal.kernel.util;
24
25 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
26 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
27 import com.liferay.portal.kernel.log.Log;
28 import com.liferay.portal.kernel.log.LogFactoryUtil;
29
30 import java.io.File;
31 import java.io.FileReader;
32 import java.io.IOException;
33 import java.io.Reader;
34 import java.io.StreamTokenizer;
35
36 import java.net.URI;
37 import java.net.URISyntaxException;
38 import java.net.URL;
39
40 import java.util.ArrayList;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Set;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46
47
53 public class ClassUtil {
54
55 public static Set<String> getClasses(File file) throws IOException {
56 String fileName = file.getName();
57
58 if (fileName.endsWith(".java")) {
59 fileName = fileName.substring(0, fileName.length() - 5);
60 }
61
62 return getClasses(new FileReader(file), fileName);
63 }
64
65 public static Set<String> getClasses(Reader reader, String className)
66 throws IOException {
67
68 Set<String> classes = new HashSet<String>();
69
70 StreamTokenizer st = new StreamTokenizer(
71 new UnsyncBufferedReader(reader));
72
73 _setupParseTableForAnnotationProcessing(st);
74
75 while (st.nextToken() != StreamTokenizer.TT_EOF) {
76 if (st.ttype == StreamTokenizer.TT_WORD) {
77 if (st.sval.equals("class") || st.sval.equals("enum") ||
78 st.sval.equals("interface") ||
79 st.sval.equals("@interface")) {
80
81 break;
82 }
83 else if (st.sval.startsWith("@")) {
84 st.ordinaryChar(' ');
85 st.wordChars('=', '=');
86
87 String[] las = _processAnnotation(st.sval, st);
88
89 for (int i = 0; i < las.length; i++) {
90 classes.add(las[i]);
91 }
92
93 _setupParseTableForAnnotationProcessing(st);
94 }
95 }
96 }
97
98 _setupParseTable(st);
99
100 while (st.nextToken() != StreamTokenizer.TT_EOF) {
101 if (st.ttype == StreamTokenizer.TT_WORD) {
102 if (st.sval.indexOf('.') >= 0) {
103 classes.add(st.sval.substring(0, st.sval.indexOf('.')));
104 }
105 else {
106 classes.add(st.sval);
107 }
108 }
109 else if (st.ttype != StreamTokenizer.TT_NUMBER &&
110 st.ttype != StreamTokenizer.TT_EOL) {
111
112 if (Character.isUpperCase((char)st.ttype)) {
113 classes.add(String.valueOf((char)st.ttype));
114 }
115 }
116 }
117
118 classes.remove(className);
119
120 return classes;
121 }
122
123 public static String getParentPath(
124 ClassLoader classLoader, String className) {
125
126 if (_log.isDebugEnabled()) {
127 _log.debug("Class name " + className);
128 }
129
130 if (!className.endsWith(_CLASS_EXTENSION)) {
131 className += _CLASS_EXTENSION;
132 }
133
134 className = StringUtil.replace(
135 className, StringPool.PERIOD, StringPool.SLASH);
136
137 className = StringUtil.replace(className, "/class", _CLASS_EXTENSION);
138
139 URL url = classLoader.getResource(className);
140
141 String path = null;
142
143 try {
144 path = new URI(url.getPath()).getPath();
145 }
146 catch (URISyntaxException urise) {
147 path = url.getFile();
148 }
149
150 if (_log.isDebugEnabled()) {
151 _log.debug("Path " + path);
152 }
153
154 int pos = path.indexOf(className);
155
156 String parentPath = path.substring(0, pos);
157
158 if (parentPath.startsWith("jar:")) {
159 parentPath = parentPath.substring(4, parentPath.length());
160 }
161
162 if (parentPath.startsWith("file:/")) {
163 parentPath = parentPath.substring(6, parentPath.length());
164 }
165
166 if (_log.isDebugEnabled()) {
167 _log.debug("Parent path " + parentPath);
168 }
169
170 return parentPath;
171 }
172
173 public static boolean isSubclass(Class<?> a, Class<?> b) {
174 if (a == b) {
175 return true;
176 }
177
178 if (a == null || b == null) {
179 return false;
180 }
181
182 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
183 if (x == b) {
184 return true;
185 }
186
187 if (b.isInterface()) {
188 Class<?>[] interfaces = x.getInterfaces();
189
190 for (int i = 0; i < interfaces.length; i++) {
191 if (isSubclass(interfaces[i], b)) {
192 return true;
193 }
194 }
195 }
196 }
197
198 return false;
199 }
200
201 public static boolean isSubclass(Class<?> a, String s) {
202 if (a == null || s == null) {
203 return false;
204 }
205
206 if (a.getName().equals(s)) {
207 return true;
208 }
209
210 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
211 if (x.getName().equals(s)) {
212 return true;
213 }
214
215 Class<?>[] interfaces = x.getInterfaces();
216
217 for (int i = 0; i < interfaces.length; i++) {
218 if (isSubclass(interfaces[i], s)) {
219 return true;
220 }
221 }
222 }
223
224 return false;
225 }
226
227 private static String[] _processAnnotation(String s, StreamTokenizer st)
228 throws IOException {
229
230 s = s.trim();
231
232 List<String> tokens = new ArrayList<String>();
233
234 Matcher annotationNameMatcher = _ANNOTATION_NAME_REGEXP.matcher(s);
235 Matcher annotationParametersMatcher =
236 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
237
238 if (annotationNameMatcher.matches()) {
239 String annotationName = annotationNameMatcher.group();
240
241 tokens.add(annotationName.replace("@", ""));
242 }
243 else if (annotationParametersMatcher.matches()) {
244 if (!s.trim().endsWith(")")) {
245 while (st.nextToken() != StreamTokenizer.TT_EOF) {
246 if (st.ttype == StreamTokenizer.TT_WORD) {
247 s += st.sval;
248 if (s.trim().endsWith(")")) {
249 break;
250 }
251 }
252 }
253 }
254
255 annotationParametersMatcher =
256 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
257
258 if (annotationParametersMatcher.matches()) {
259 String annotationName =
260 annotationParametersMatcher.group(1);
261 String annotationParameters =
262 annotationParametersMatcher.group(2);
263
264 tokens.add(annotationName.replace("@", ""));
265
266 tokens = _processAnnotationParameters(
267 annotationParameters,tokens);
268 }
269 }
270
271 return tokens.toArray(new String[tokens.size()]);
272 }
273
274 private static List<String> _processAnnotationParameters(
275 String s, List<String> tokens)
276 throws IOException {
277
278 StreamTokenizer st = new StreamTokenizer(new UnsyncStringReader(s));
279
280 _setupParseTable(st);
281
282 while (st.nextToken() != StreamTokenizer.TT_EOF) {
283 if (st.ttype == StreamTokenizer.TT_WORD) {
284 if (st.sval.indexOf('.') >= 0) {
285 tokens.add(st.sval.substring(0, st.sval.indexOf('.')));
286 }
287 else {
288 tokens.add(st.sval);
289 }
290 }
291 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
292 (st.ttype != StreamTokenizer.TT_EOL)) {
293
294 if (Character.isUpperCase((char)st.ttype)) {
295 tokens.add(String.valueOf((char)st.ttype));
296 }
297 }
298 }
299
300 return tokens;
301 }
302
303 private static void _setupParseTable(StreamTokenizer st) {
304 st.resetSyntax();
305 st.slashSlashComments(true);
306 st.slashStarComments(true);
307 st.wordChars('a', 'z');
308 st.wordChars('A', 'Z');
309 st.wordChars('.', '.');
310 st.wordChars('0', '9');
311 st.wordChars('_', '_');
312 st.lowerCaseMode(false);
313 st.eolIsSignificant(false);
314 st.quoteChar('"');
315 st.quoteChar('\'');
316 st.parseNumbers();
317 }
318
319 private static void _setupParseTableForAnnotationProcessing(
320 StreamTokenizer st) {
321
322 _setupParseTable(st);
323
324 st.wordChars('@', '@');
325 st.wordChars('(', '(');
326 st.wordChars(')', ')');
327 st.wordChars('{', '{');
328 st.wordChars('}', '}');
329 st.wordChars(',',',');
330 }
331
332 private static final Pattern _ANNOTATION_NAME_REGEXP =
333 Pattern.compile("@(\\w+)$");
334
335 private static final Pattern _ANNOTATION_PARAMETERS_REGEXP =
336 Pattern.compile("@(\\w+)\\({0,1}\\{{0,1}([^)}]+)\\}{0,1}\\){0,1}");
337
338 private static final String _CLASS_EXTENSION = ".class";
339
340 private static Log _log = LogFactoryUtil.getLog(ClassUtil.class);
341
342 }