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.classpath;
17  
18  import java.io.File;
19  import java.io.FileNotFoundException;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.net.URL;
23  import java.util.List;
24  
25  import javassist.bytecode.ClassFile;
26  
27  import org.apache.commons.lang3.builder.ToStringBuilder;
28  import org.apache.commons.lang3.builder.ToStringStyle;
29  import org.jadira.scanner.classfile.ClassFileResolver;
30  import org.jadira.scanner.classpath.types.JClass;
31  import org.jadira.scanner.classpath.types.JElement;
32  import org.jadira.scanner.classpath.types.JInterface;
33  import org.jadira.scanner.classpath.types.JPackage;
34  import org.jadira.scanner.core.api.Allocator;
35  import org.jadira.scanner.core.exception.ClasspathAccessException;
36  import org.jadira.scanner.core.exception.FileAccessException;
37  import org.jadira.scanner.core.helper.FileInputStreamOperation;
38  import org.jadira.scanner.core.helper.FileUtils;
39  import org.jadira.scanner.core.helper.JavassistClassFileHelper;
40  import org.jadira.scanner.core.helper.filenamefilter.ClassFilenameFilter;
41  import org.jadira.scanner.core.spi.AbstractFileResolver;
42  import org.jadira.scanner.core.utils.reflection.ClassLoaderUtils;
43  import org.jadira.scanner.file.locator.JdkBaseClasspathUrlLocator;
44  
45  import de.schlichtherle.io.FileInputStream;
46  
47  public class ClasspathResolver extends AbstractFileResolver<JElement> {
48  
49      private static final List<URL> JDK_BASE_CLASSPATH_JARS = new JdkBaseClasspathUrlLocator().locate();
50      
51  	private static final ClassFilenameFilter CLASSFILE_FILTER = new ClassFilenameFilter();
52  	
53  	private final ClasspathAssigner assigner = new ClasspathAssigner();
54  	
55  	private final ClassFileResolver classFileResolver;
56  
57      private final ClassLoader[] classLoaders;
58  	
59      public ClasspathResolver() {    	
60          super(JDK_BASE_CLASSPATH_JARS);
61          this.classLoaders  = ClassLoaderUtils.getClassLoaders();
62          classFileResolver = new ClassFileResolver(classLoaders);
63  	}
64  
65  	public ClasspathResolver(List<URL> classpaths) {
66  		super();
67  		this.classLoaders = ClassLoaderUtils.getClassLoaders();
68  		classFileResolver = new ClassFileResolver(classpaths, this.classLoaders);
69  		getDriverData().addAll(classpaths);
70  	}
71  	
72      public ClasspathResolver(ClassLoader... classLoaders) {
73          super(JDK_BASE_CLASSPATH_JARS);
74          this.classLoaders  = ClassLoaderUtils.getClassLoaders(classLoaders);
75          classFileResolver = new ClassFileResolver(this.classLoaders);
76  	}
77  
78      public ClasspathResolver(List<URL> classpaths, List<ClassLoader> classLoaders) {
79          super();
80          this.classLoaders  = ClassLoaderUtils.getClassLoaders((ClassLoader[])classLoaders.toArray());
81          classFileResolver = new ClassFileResolver(classpaths, this.classLoaders);
82          getDriverData().addAll(classpaths);
83      }
84      
85  	public ClasspathResolver(List<URL> classpaths, ClassLoader... classLoaders) {
86  		super();
87  		this.classLoaders  = ClassLoaderUtils.getClassLoaders(classLoaders);
88  		classFileResolver = new ClassFileResolver(classpaths, this.classLoaders);
89  		getDriverData().addAll(classpaths);
90  	}
91  
92  	@Override
93  	public String toString() {
94  
95  		ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
96  		builder.append(getDriverData().toArray());
97  
98  		return builder.toString();
99  	}
100 
101 	@Override
102 	protected Allocator<JElement, File> getAssigner() {
103 		return assigner;
104 	}
105 
106 	private final class ClasspathAssigner implements Allocator<JElement, File> {
107 
108 		@Override
109 		public JElement allocate(File e) {
110 
111 			JElement element;
112 			if (e.isDirectory()) {
113 				// Attempt to construct package
114 				element = assignPackage(e);
115 			} else {
116 				try {
117 					ClassFile f = JavassistClassFileHelper.constructClassFileForPath(e.getPath(), new FileInputStream(e));
118 					if (f.isInterface()) {
119 						return JInterface.getJInterface(f, ClasspathResolver.this);
120 					} else {
121 						return JClass.getJClass(f, ClasspathResolver.this);
122 					}
123 				} catch (FileNotFoundException e1) {
124 					throw new ClasspathAccessException("Couldnt find file", e1);
125 				} catch (IOException e1) {
126 					throw new ClasspathAccessException("Couldnt access file", e1);
127 				}
128 			}
129 			return element;
130 		}
131 
132 		private JPackage assignPackage(File e) {
133 
134 			JPackage retVal;
135 
136 			final File[] classes = e.listFiles(CLASSFILE_FILTER);
137 			for (int i = 0; i < classes.length; i++) {
138 
139 				ClassFile classFile = FileUtils.doWithFile(classes[i], new FileInputStreamOperation<ClassFile>() {
140 
141 					@Override
142 					public ClassFile execute(String path, InputStream fileInputStream) {
143 
144 						try {
145 							return JavassistClassFileHelper.constructClassFile(path, fileInputStream);
146 						} catch (IOException e) {
147 							throw new FileAccessException("Cannot access class file: " + e.getMessage(), e);
148 						}
149 					}
150 				});
151 
152 				Package pkg = loadClass(classFile.getName()).getPackage();
153 				retVal = JPackage.getJPackage(pkg, ClasspathResolver.this);
154 
155 				if (retVal != null) {
156 					return retVal;
157 				}
158 			}
159 			return null;
160 		}
161 	}	
162 	
163 	public ClassFileResolver getClassFileResolver() {
164 		return classFileResolver;
165 	}
166 	
167 	public Class<?> loadClass(String className) {
168 	    
169 		if ("java.lang.Class".equals(className)) {
170 			return java.lang.Class.class;
171 		}
172 		
173 	    for (int i = 0; i < classLoaders.length; i++) {
174             try {
175                 return Class.forName(className, true, classLoaders[i]);
176             } catch (ClassNotFoundException e) {
177                 // Ignore
178             }
179 	    }
180 	    throw new ClasspathAccessException("Could not find class: " + className);
181 	}
182 }