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