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 getClassName(Object object) {
115 if (object == null) {
116 return null;
117 }
118
119 Class<?> clazz = object.getClass();
120
121 return clazz.getName();
122 }
123
124 public static String getParentPath(
125 ClassLoader classLoader, String className) {
126
127 if (_log.isDebugEnabled()) {
128 _log.debug("Class name " + className);
129 }
130
131 if (!className.endsWith(_CLASS_EXTENSION)) {
132 className += _CLASS_EXTENSION;
133 }
134
135 className = StringUtil.replace(
136 className, CharPool.PERIOD, CharPool.SLASH);
137
138 className = StringUtil.replace(className, "/class", _CLASS_EXTENSION);
139
140 URL url = classLoader.getResource(className);
141
142 String path = null;
143
144 try {
145 path = url.getPath();
146
147 URI uri = new URI(path);
148
149 String scheme = uri.getScheme();
150
151 if (path.contains(StringPool.EXCLAMATION) &&
152 ((scheme == null) || (scheme.length() <= 1))) {
153
154 if (!path.startsWith(StringPool.SLASH)) {
155 path = StringPool.SLASH + path;
156 }
157 }
158 else {
159 path = uri.getPath();
160
161 if (path == null) {
162 path = url.getFile();
163 }
164 }
165 }
166 catch (URISyntaxException urise) {
167 path = url.getFile();
168 }
169
170 if (ServerDetector.isJBoss()) {
171 if (path.startsWith("file:") && !path.startsWith("file:/")) {
172 path = path.substring(5);
173
174 path = "file:/".concat(path);
175
176 path = StringUtil.replace(path, "%5C", StringPool.SLASH);
177 }
178 }
179
180 if (_log.isDebugEnabled()) {
181 _log.debug("Path " + path);
182 }
183
184 int pos = path.indexOf(className);
185
186 String parentPath = path.substring(0, pos);
187
188 if (parentPath.startsWith("jar:")) {
189 parentPath = parentPath.substring(4);
190 }
191
192 if (parentPath.startsWith("file:/")) {
193 parentPath = parentPath.substring(6);
194 }
195
196 if (_log.isDebugEnabled()) {
197 _log.debug("Parent path " + parentPath);
198 }
199
200 return parentPath;
201 }
202
203 public static boolean isSubclass(Class<?> a, Class<?> b) {
204 if (a == b) {
205 return true;
206 }
207
208 if ((a == null) || (b == null)) {
209 return false;
210 }
211
212 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
213 if (x == b) {
214 return true;
215 }
216
217 if (b.isInterface()) {
218 Class<?>[] interfaceClasses = x.getInterfaces();
219
220 for (Class<?> interfaceClass : interfaceClasses) {
221 if (isSubclass(interfaceClass, b)) {
222 return true;
223 }
224 }
225 }
226 }
227
228 return false;
229 }
230
231 public static boolean isSubclass(Class<?> a, String s) {
232 if ((a == null) || (s == null)) {
233 return false;
234 }
235
236 if (a.getName().equals(s)) {
237 return true;
238 }
239
240 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
241 if (x.getName().equals(s)) {
242 return true;
243 }
244
245 Class<?>[] interfaceClasses = x.getInterfaces();
246
247 for (Class<?> interfaceClass : interfaceClasses) {
248 if (isSubclass(interfaceClass, s)) {
249 return true;
250 }
251 }
252 }
253
254 return false;
255 }
256
257 private static String[] _processAnnotation(String s, StreamTokenizer st)
258 throws IOException {
259
260 s = s.trim();
261
262 List<String> tokens = new ArrayList<String>();
263
264 Matcher annotationNameMatcher = _ANNOTATION_NAME_REGEXP.matcher(s);
265 Matcher annotationParametersMatcher =
266 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
267
268 if (annotationNameMatcher.matches()) {
269 String annotationName = annotationNameMatcher.group();
270
271 tokens.add(annotationName.replace("@", ""));
272 }
273 else if (annotationParametersMatcher.matches()) {
274 String annotationName = annotationParametersMatcher.group(1);
275
276 tokens.add(annotationName);
277
278 String annotationParameters = null;
279
280 if (s.trim().endsWith(")")) {
281 annotationParameters = annotationParametersMatcher.group(2);
282 }
283 else {
284 StringBundler sb = new StringBundler();
285
286 while (st.nextToken() != StreamTokenizer.TT_EOF) {
287 if (st.ttype == StreamTokenizer.TT_WORD) {
288 sb.append(st.sval);
289
290 if (st.sval.trim().endsWith(")")) {
291 break;
292 }
293 }
294 }
295
296 annotationParameters = sb.toString();
297 }
298
299 tokens = _processAnnotationParameters(annotationParameters, tokens);
300 }
301
302 return tokens.toArray(new String[tokens.size()]);
303 }
304
305 private static List<String> _processAnnotationParameters(
306 String s, List<String> tokens)
307 throws IOException {
308
309 StreamTokenizer st = new StreamTokenizer(new UnsyncStringReader(s));
310
311 _setupParseTable(st);
312
313 while (st.nextToken() != StreamTokenizer.TT_EOF) {
314 if (st.ttype == StreamTokenizer.TT_WORD) {
315 if (st.sval.indexOf('.') >= 0) {
316 tokens.add(st.sval.substring(0, st.sval.indexOf('.')));
317 }
318 else {
319 tokens.add(st.sval);
320 }
321 }
322 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
323 (st.ttype != StreamTokenizer.TT_EOL)) {
324
325 if (Character.isUpperCase((char)st.ttype)) {
326 tokens.add(String.valueOf((char)st.ttype));
327 }
328 }
329 }
330
331 return tokens;
332 }
333
334 private static void _setupParseTable(StreamTokenizer st) {
335 st.resetSyntax();
336 st.slashSlashComments(true);
337 st.slashStarComments(true);
338 st.wordChars('a', 'z');
339 st.wordChars('A', 'Z');
340 st.wordChars('.', '.');
341 st.wordChars('0', '9');
342 st.wordChars('_', '_');
343 st.lowerCaseMode(false);
344 st.eolIsSignificant(false);
345 st.quoteChar('"');
346 st.quoteChar('\'');
347 st.parseNumbers();
348 }
349
350 private static void _setupParseTableForAnnotationProcessing(
351 StreamTokenizer st) {
352
353 _setupParseTable(st);
354
355 st.wordChars('@', '@');
356 st.wordChars('(', '(');
357 st.wordChars(')', ')');
358 st.wordChars('{', '{');
359 st.wordChars('}', '}');
360 st.wordChars(',',',');
361 }
362
363 private static final Pattern _ANNOTATION_NAME_REGEXP = Pattern.compile(
364 "@(\\w+)$");
365
366 private static final Pattern _ANNOTATION_PARAMETERS_REGEXP =
367 Pattern.compile("@(\\w+)\\({0,1}\\{{0,1}([^)}]+)\\}{0,1}\\){0,1}");
368
369 private static final String _CLASS_EXTENSION = ".class";
370
371 private static Log _log = LogFactoryUtil.getLog(ClassUtil.class);
372
373 }