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