View Javadoc
1   /*
2    *  Copyright 2012 Chris Pheby
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
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 						// Ignore
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     				// Ignore
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 }