1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jadira.scanner.classfile;
17
18 import java.io.BufferedInputStream;
19 import java.io.DataInputStream;
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URL;
25 import java.util.List;
26 import java.util.WeakHashMap;
27
28 import javassist.bytecode.ClassFile;
29
30 import org.apache.commons.lang3.builder.ToStringBuilder;
31 import org.apache.commons.lang3.builder.ToStringStyle;
32 import org.jadira.scanner.classfile.filter.ClassFileFilter;
33 import org.jadira.scanner.classfile.filter.NameFilter;
34 import org.jadira.scanner.classfile.filter.PackageFileFilter;
35 import org.jadira.scanner.classpath.projector.ClasspathProjector;
36 import org.jadira.scanner.core.api.Allocator;
37 import org.jadira.scanner.core.api.Projector;
38 import org.jadira.scanner.core.helper.JavassistClassFileHelper;
39 import org.jadira.scanner.core.spi.AbstractFileResolver;
40 import org.jadira.scanner.core.utils.reflection.ClassLoaderUtils;
41 import org.jadira.scanner.file.locator.JdkBaseClasspathUrlLocator;
42
43 import de.schlichtherle.io.FileInputStream;
44
45 public class ClassFileResolver extends AbstractFileResolver<ClassFile> {
46
47 private static final WeakHashMap<File, ClassFile> CACHED_CLASSFILES = new WeakHashMap<File, ClassFile>();
48
49 private static final Projector<File> CLASSPATH_PROJECTOR = ClasspathProjector.SINGLETON;
50
51 private static final List<URL> JDK_BASE_CLASSPATH_JARS = new JdkBaseClasspathUrlLocator().locate();
52
53 private final ClassFileAssigner assigner = new ClassFileAssigner();
54
55 private final ClassLoader[] classLoaders;
56
57 public ClassFileResolver() {
58 this.classLoaders = ClassLoaderUtils.getClassLoaders();
59 }
60
61 public ClassFileResolver(ClassLoader... classLoaders) {
62 super(JDK_BASE_CLASSPATH_JARS);
63 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
64 }
65
66 public ClassFileResolver(List<URL> classpaths, ClassLoader... classLoaders) {
67 super(JDK_BASE_CLASSPATH_JARS);
68 getDriverData().addAll(classpaths);
69 this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
70 }
71
72 @Override
73 public String toString() {
74
75 ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
76 builder.append(getDriverData().toArray());
77
78 return builder.toString();
79 }
80
81 @Override
82 protected Allocator<ClassFile, File> getAssigner() {
83 return assigner;
84 }
85
86 private final class ClassFileAssigner implements Allocator<ClassFile, File> {
87
88 @Override
89 public ClassFile allocate(File e) {
90
91 ClassFile res = CACHED_CLASSFILES.get(e);
92 if (res != null) {
93 return res;
94 }
95
96 FileInputStream tis = null;
97
98 try {
99 tis = new FileInputStream(e);
100 res = JavassistClassFileHelper.constructClassFileForPath(e.getPath(), tis);
101 CACHED_CLASSFILES.put(e, res);
102 return res;
103 } catch (FileNotFoundException e1) {
104 throw new IllegalArgumentException(e + " is not a valid File", e1);
105 } catch (IOException e1) {
106 throw new IllegalArgumentException("Could not load ClassFile for " + e, e1);
107 } finally {
108 if (tis != null) {
109 try {
110 tis.close();
111 } catch (IOException e1) {
112
113 }
114 }
115 }
116 }
117 }
118
119 public ClassFile resolveClassFile(String name) {
120
121 ClassFile cf = null;
122
123 String className = name.replace('.', '/').concat(".class");
124
125 for (ClassLoader classLoader : classLoaders) {
126
127 if (classLoader != null) {
128
129 InputStream is = classLoader.getResourceAsStream(className);
130 if (is == null) {
131 continue;
132 }
133 BufferedInputStream fin = new BufferedInputStream(is);
134
135 try {
136 cf = new ClassFile(new DataInputStream(fin));
137 if (cf != null) {
138 return cf;
139 }
140 } catch (IOException e) {
141
142 }
143 }
144 }
145
146 cf = resolveFirst(null, CLASSPATH_PROJECTOR, new PackageFileFilter(name, true), new NameFilter(name));
147 if (cf == null) {
148 cf = resolveFirst(null, CLASSPATH_PROJECTOR, new ClassFileFilter(name));
149 }
150 return cf;
151 }
152 }