001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
018 import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021
022 import java.io.File;
023 import java.io.FileReader;
024 import java.io.IOException;
025 import java.io.Reader;
026 import java.io.StreamTokenizer;
027
028 import java.net.URI;
029 import java.net.URISyntaxException;
030 import java.net.URL;
031
032 import java.util.ArrayList;
033 import java.util.HashSet;
034 import java.util.List;
035 import java.util.Set;
036 import java.util.regex.Matcher;
037 import java.util.regex.Pattern;
038
039
043 public class ClassUtil {
044
045 public static Set<String> getClasses(File file) throws IOException {
046 String fileName = file.getName();
047
048 if (fileName.endsWith(".java")) {
049 fileName = fileName.substring(0, fileName.length() - 5);
050 }
051
052 return getClasses(
053 new UnsyncBufferedReader(new FileReader(file)), fileName);
054 }
055
056 public static Set<String> getClasses(Reader reader, String className)
057 throws IOException {
058
059 Set<String> classes = new HashSet<String>();
060
061 StreamTokenizer st = new StreamTokenizer(reader);
062
063 _setupParseTableForAnnotationProcessing(st);
064
065 while (st.nextToken() != StreamTokenizer.TT_EOF) {
066 if (st.ttype == StreamTokenizer.TT_WORD) {
067 if (st.sval.equals("class") || st.sval.equals("enum") ||
068 st.sval.equals("interface") ||
069 st.sval.equals("@interface")) {
070
071 break;
072 }
073 else if (st.sval.startsWith("@")) {
074 st.ordinaryChar(' ');
075 st.wordChars('=', '=');
076
077 String[] annotationClasses = _processAnnotation(
078 st.sval, st);
079
080 for (String annotationClass : annotationClasses) {
081 classes.add(annotationClass);
082 }
083
084 _setupParseTableForAnnotationProcessing(st);
085 }
086 }
087 }
088
089 _setupParseTable(st);
090
091 while (st.nextToken() != StreamTokenizer.TT_EOF) {
092 if (st.ttype == StreamTokenizer.TT_WORD) {
093 if (st.sval.indexOf('.') >= 0) {
094 classes.add(st.sval.substring(0, st.sval.indexOf('.')));
095 }
096 else {
097 classes.add(st.sval);
098 }
099 }
100 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
101 (st.ttype != StreamTokenizer.TT_EOL)) {
102
103 if (Character.isUpperCase((char)st.ttype)) {
104 classes.add(String.valueOf((char)st.ttype));
105 }
106 }
107 }
108
109 classes.remove(className);
110
111 return classes;
112 }
113
114 public static String getParentPath(
115 ClassLoader classLoader, String className) {
116
117 if (_log.isDebugEnabled()) {
118 _log.debug("Class name " + className);
119 }
120
121 if (!className.endsWith(_CLASS_EXTENSION)) {
122 className += _CLASS_EXTENSION;
123 }
124
125 className = StringUtil.replace(
126 className, CharPool.PERIOD, CharPool.SLASH);
127
128 className = StringUtil.replace(className, "/class", _CLASS_EXTENSION);
129
130 URL url = classLoader.getResource(className);
131
132 String path = null;
133
134 try {
135 path = url.getPath();
136
137 URI uri = new URI(path);
138
139 String scheme = uri.getScheme();
140
141 if (path.contains(StringPool.EXCLAMATION) &&
142 ((scheme == null) || (scheme.length() <= 1))) {
143
144 if (!path.startsWith(StringPool.SLASH)) {
145 path = StringPool.SLASH + path;
146 }
147 }
148 else {
149 path = uri.getPath();
150
151 if (path == null) {
152 path = url.getFile();
153 }
154 }
155 }
156 catch (URISyntaxException urise) {
157 path = url.getFile();
158 }
159
160 if (ServerDetector.isJBoss()) {
161 if (path.startsWith("file:") && !path.startsWith("file:/")) {
162 path = path.substring(5);
163
164 path = "file:/".concat(path);
165
166 path = StringUtil.replace(path, "%5C", StringPool.SLASH);
167 }
168 }
169
170 if (_log.isDebugEnabled()) {
171 _log.debug("Path " + path);
172 }
173
174 int pos = path.indexOf(className);
175
176 String parentPath = path.substring(0, pos);
177
178 if (parentPath.startsWith("jar:")) {
179 parentPath = parentPath.substring(4);
180 }
181
182 if (parentPath.startsWith("file:/")) {
183 parentPath = parentPath.substring(6);
184 }
185
186 if (_log.isDebugEnabled()) {
187 _log.debug("Parent path " + parentPath);
188 }
189
190 return parentPath;
191 }
192
193 public static boolean isSubclass(Class<?> a, Class<?> b) {
194 if (a == b) {
195 return true;
196 }
197
198 if ((a == null) || (b == null)) {
199 return false;
200 }
201
202 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
203 if (x == b) {
204 return true;
205 }
206
207 if (b.isInterface()) {
208 Class<?>[] interfaceClasses = x.getInterfaces();
209
210 for (Class<?> interfaceClass : interfaceClasses) {
211 if (isSubclass(interfaceClass, b)) {
212 return true;
213 }
214 }
215 }
216 }
217
218 return false;
219 }
220
221 public static boolean isSubclass(Class<?> a, String s) {
222 if ((a == null) || (s == null)) {
223 return false;
224 }
225
226 if (a.getName().equals(s)) {
227 return true;
228 }
229
230 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
231 if (x.getName().equals(s)) {
232 return true;
233 }
234
235 Class<?>[] interfaceClasses = x.getInterfaces();
236
237 for (Class<?> interfaceClass : interfaceClasses) {
238 if (isSubclass(interfaceClass, s)) {
239 return true;
240 }
241 }
242 }
243
244 return false;
245 }
246
247 private static String[] _processAnnotation(String s, StreamTokenizer st)
248 throws IOException {
249
250 s = s.trim();
251
252 List<String> tokens = new ArrayList<String>();
253
254 Matcher annotationNameMatcher = _ANNOTATION_NAME_REGEXP.matcher(s);
255 Matcher annotationParametersMatcher =
256 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
257
258 if (annotationNameMatcher.matches()) {
259 String annotationName = annotationNameMatcher.group();
260
261 tokens.add(annotationName.replace("@", ""));
262 }
263 else if (annotationParametersMatcher.matches()) {
264 if (!s.trim().endsWith(")")) {
265 while (st.nextToken() != StreamTokenizer.TT_EOF) {
266 if (st.ttype == StreamTokenizer.TT_WORD) {
267 s += st.sval;
268 if (s.trim().endsWith(")")) {
269 break;
270 }
271 }
272 }
273 }
274
275 annotationParametersMatcher = _ANNOTATION_PARAMETERS_REGEXP.matcher(
276 s);
277
278 if (annotationParametersMatcher.matches()) {
279 String annotationName = annotationParametersMatcher.group(1);
280 String annotationParameters = annotationParametersMatcher.group(
281 2);
282
283 tokens.add(annotationName.replace("@", ""));
284
285 tokens = _processAnnotationParameters(
286 annotationParameters, tokens);
287 }
288 }
289
290 return tokens.toArray(new String[tokens.size()]);
291 }
292
293 private static List<String> _processAnnotationParameters(
294 String s, List<String> tokens)
295 throws IOException {
296
297 StreamTokenizer st = new StreamTokenizer(new UnsyncStringReader(s));
298
299 _setupParseTable(st);
300
301 while (st.nextToken() != StreamTokenizer.TT_EOF) {
302 if (st.ttype == StreamTokenizer.TT_WORD) {
303 if (st.sval.indexOf('.') >= 0) {
304 tokens.add(st.sval.substring(0, st.sval.indexOf('.')));
305 }
306 else {
307 tokens.add(st.sval);
308 }
309 }
310 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
311 (st.ttype != StreamTokenizer.TT_EOL)) {
312
313 if (Character.isUpperCase((char)st.ttype)) {
314 tokens.add(String.valueOf((char)st.ttype));
315 }
316 }
317 }
318
319 return tokens;
320 }
321
322 private static void _setupParseTable(StreamTokenizer st) {
323 st.resetSyntax();
324 st.slashSlashComments(true);
325 st.slashStarComments(true);
326 st.wordChars('a', 'z');
327 st.wordChars('A', 'Z');
328 st.wordChars('.', '.');
329 st.wordChars('0', '9');
330 st.wordChars('_', '_');
331 st.lowerCaseMode(false);
332 st.eolIsSignificant(false);
333 st.quoteChar('"');
334 st.quoteChar('\'');
335 st.parseNumbers();
336 }
337
338 private static void _setupParseTableForAnnotationProcessing(
339 StreamTokenizer st) {
340
341 _setupParseTable(st);
342
343 st.wordChars('@', '@');
344 st.wordChars('(', '(');
345 st.wordChars(')', ')');
346 st.wordChars('{', '{');
347 st.wordChars('}', '}');
348 st.wordChars(',',',');
349 }
350
351 private static final Pattern _ANNOTATION_NAME_REGEXP = Pattern.compile(
352 "@(\\w+)$");
353
354 private static final Pattern _ANNOTATION_PARAMETERS_REGEXP =
355 Pattern.compile("@(\\w+)\\({0,1}\\{{0,1}([^)}]+)\\}{0,1}\\){0,1}");
356
357 private static final String _CLASS_EXTENSION = ".class";
358
359 private static Log _log = LogFactoryUtil.getLog(ClassUtil.class);
360
361 }