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(new FileReader(file), fileName);
053 }
054
055 public static Set<String> getClasses(Reader reader, String className)
056 throws IOException {
057
058 Set<String> classes = new HashSet<String>();
059
060 StreamTokenizer st = new StreamTokenizer(
061 new UnsyncBufferedReader(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, StringPool.PERIOD, StringPool.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 = new URI(url.getPath()).getPath();
135 }
136 catch (URISyntaxException urise) {
137 path = url.getFile();
138 }
139
140 if (_log.isDebugEnabled()) {
141 _log.debug("Path " + path);
142 }
143
144 int pos = path.indexOf(className);
145
146 String parentPath = path.substring(0, pos);
147
148 if (parentPath.startsWith("jar:")) {
149 parentPath = parentPath.substring(4, parentPath.length());
150 }
151
152 if (parentPath.startsWith("file:/")) {
153 parentPath = parentPath.substring(6, parentPath.length());
154 }
155
156 if (_log.isDebugEnabled()) {
157 _log.debug("Parent path " + parentPath);
158 }
159
160 return parentPath;
161 }
162
163 public static boolean isSubclass(Class<?> a, Class<?> b) {
164 if (a == b) {
165 return true;
166 }
167
168 if (a == null || b == null) {
169 return false;
170 }
171
172 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
173 if (x == b) {
174 return true;
175 }
176
177 if (b.isInterface()) {
178 Class<?>[] interfaces = x.getInterfaces();
179
180 for (int i = 0; i < interfaces.length; i++) {
181 if (isSubclass(interfaces[i], b)) {
182 return true;
183 }
184 }
185 }
186 }
187
188 return false;
189 }
190
191 public static boolean isSubclass(Class<?> a, String s) {
192 if (a == null || s == null) {
193 return false;
194 }
195
196 if (a.getName().equals(s)) {
197 return true;
198 }
199
200 for (Class<?> x = a; x != null; x = x.getSuperclass()) {
201 if (x.getName().equals(s)) {
202 return true;
203 }
204
205 Class<?>[] interfaces = x.getInterfaces();
206
207 for (int i = 0; i < interfaces.length; i++) {
208 if (isSubclass(interfaces[i], s)) {
209 return true;
210 }
211 }
212 }
213
214 return false;
215 }
216
217 private static String[] _processAnnotation(String s, StreamTokenizer st)
218 throws IOException {
219
220 s = s.trim();
221
222 List<String> tokens = new ArrayList<String>();
223
224 Matcher annotationNameMatcher = _ANNOTATION_NAME_REGEXP.matcher(s);
225 Matcher annotationParametersMatcher =
226 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
227
228 if (annotationNameMatcher.matches()) {
229 String annotationName = annotationNameMatcher.group();
230
231 tokens.add(annotationName.replace("@", ""));
232 }
233 else if (annotationParametersMatcher.matches()) {
234 if (!s.trim().endsWith(")")) {
235 while (st.nextToken() != StreamTokenizer.TT_EOF) {
236 if (st.ttype == StreamTokenizer.TT_WORD) {
237 s += st.sval;
238 if (s.trim().endsWith(")")) {
239 break;
240 }
241 }
242 }
243 }
244
245 annotationParametersMatcher =
246 _ANNOTATION_PARAMETERS_REGEXP.matcher(s);
247
248 if (annotationParametersMatcher.matches()) {
249 String annotationName =
250 annotationParametersMatcher.group(1);
251 String annotationParameters =
252 annotationParametersMatcher.group(2);
253
254 tokens.add(annotationName.replace("@", ""));
255
256 tokens = _processAnnotationParameters(
257 annotationParameters,tokens);
258 }
259 }
260
261 return tokens.toArray(new String[tokens.size()]);
262 }
263
264 private static List<String> _processAnnotationParameters(
265 String s, List<String> tokens)
266 throws IOException {
267
268 StreamTokenizer st = new StreamTokenizer(new UnsyncStringReader(s));
269
270 _setupParseTable(st);
271
272 while (st.nextToken() != StreamTokenizer.TT_EOF) {
273 if (st.ttype == StreamTokenizer.TT_WORD) {
274 if (st.sval.indexOf('.') >= 0) {
275 tokens.add(st.sval.substring(0, st.sval.indexOf('.')));
276 }
277 else {
278 tokens.add(st.sval);
279 }
280 }
281 else if ((st.ttype != StreamTokenizer.TT_NUMBER) &&
282 (st.ttype != StreamTokenizer.TT_EOL)) {
283
284 if (Character.isUpperCase((char)st.ttype)) {
285 tokens.add(String.valueOf((char)st.ttype));
286 }
287 }
288 }
289
290 return tokens;
291 }
292
293 private static void _setupParseTable(StreamTokenizer st) {
294 st.resetSyntax();
295 st.slashSlashComments(true);
296 st.slashStarComments(true);
297 st.wordChars('a', 'z');
298 st.wordChars('A', 'Z');
299 st.wordChars('.', '.');
300 st.wordChars('0', '9');
301 st.wordChars('_', '_');
302 st.lowerCaseMode(false);
303 st.eolIsSignificant(false);
304 st.quoteChar('"');
305 st.quoteChar('\'');
306 st.parseNumbers();
307 }
308
309 private static void _setupParseTableForAnnotationProcessing(
310 StreamTokenizer st) {
311
312 _setupParseTable(st);
313
314 st.wordChars('@', '@');
315 st.wordChars('(', '(');
316 st.wordChars(')', ')');
317 st.wordChars('{', '{');
318 st.wordChars('}', '}');
319 st.wordChars(',',',');
320 }
321
322 private static final Pattern _ANNOTATION_NAME_REGEXP =
323 Pattern.compile("@(\\w+)$");
324
325 private static final Pattern _ANNOTATION_PARAMETERS_REGEXP =
326 Pattern.compile("@(\\w+)\\({0,1}\\{{0,1}([^)}]+)\\}{0,1}\\){0,1}");
327
328 private static final String _CLASS_EXTENSION = ".class";
329
330 private static Log _log = LogFactoryUtil.getLog(ClassUtil.class);
331
332 }