/*
* Copyright 2012 Chris Pheby
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jadira.scanner.classfile;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.List;
import java.util.WeakHashMap;
import javassist.bytecode.ClassFile;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.jadira.scanner.classfile.filter.ClassFileFilter;
import org.jadira.scanner.classfile.filter.NameFilter;
import org.jadira.scanner.classfile.filter.PackageFileFilter;
import org.jadira.scanner.classpath.projector.ClasspathProjector;
import org.jadira.scanner.core.api.Allocator;
import org.jadira.scanner.core.api.Projector;
import org.jadira.scanner.core.helper.JavassistClassFileHelper;
import org.jadira.scanner.core.spi.AbstractFileResolver;
import org.jadira.scanner.core.utils.reflection.ClassLoaderUtils;
import org.jadira.scanner.file.locator.JdkBaseClasspathUrlLocator;
import de.schlichtherle.io.FileInputStream;
public class ClassFileResolver extends AbstractFileResolver<ClassFile> {
private static final WeakHashMap<File, ClassFile> CACHED_CLASSFILES = new WeakHashMap<File, ClassFile>();
private static final Projector<File> CLASSPATH_PROJECTOR = ClasspathProjector.SINGLETON;
private static final List<URL> JDK_BASE_CLASSPATH_JARS = new JdkBaseClasspathUrlLocator().locate();
private final ClassFileAssigner assigner = new ClassFileAssigner();
private final ClassLoader[] classLoaders;
public ClassFileResolver() {
this.classLoaders = ClassLoaderUtils.getClassLoaders();
}
public ClassFileResolver(ClassLoader... classLoaders) {
super(JDK_BASE_CLASSPATH_JARS);
this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
}
public ClassFileResolver(List<URL> classpaths, ClassLoader... classLoaders) {
super(JDK_BASE_CLASSPATH_JARS);
getDriverData().addAll(classpaths);
this.classLoaders = ClassLoaderUtils.getClassLoaders(classLoaders);
}
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
builder.append(getDriverData().toArray());
return builder.toString();
}
@Override
protected Allocator<ClassFile, File> getAssigner() {
return assigner;
}
private final class ClassFileAssigner implements Allocator<ClassFile, File> {
@Override
public ClassFile allocate(File e) {
ClassFile res = CACHED_CLASSFILES.get(e);
if (res != null) {
return res;
}
FileInputStream tis = null;
try {
tis = new FileInputStream(e);
res = JavassistClassFileHelper.constructClassFileForPath(e.getPath(), tis);
CACHED_CLASSFILES.put(e, res);
return res;
} catch (FileNotFoundException e1) {
throw new IllegalArgumentException(e + " is not a valid File", e1);
} catch (IOException e1) {
throw new IllegalArgumentException("Could not load ClassFile for " + e, e1);
} finally {
if (tis != null) {
try {
tis.close();
} catch (IOException e1) {
// Ignore
}
}
}
}
}
public ClassFile resolveClassFile(String name) {
ClassFile cf = null;
String className = name.replace('.', '/').concat(".class");
for (ClassLoader classLoader : classLoaders) {
if (classLoader != null) {
InputStream is = classLoader.getResourceAsStream(className);
if (is == null) {
continue;
}
BufferedInputStream fin = new BufferedInputStream(is);
try {
cf = new ClassFile(new DataInputStream(fin));
if (cf != null) {
return cf;
}
} catch (IOException e) {
// Ignore
}
}
}
cf = resolveFirst(null, CLASSPATH_PROJECTOR, new PackageFileFilter(name, true), new NameFilter(name));
if (cf == null) {
cf = resolveFirst(null, CLASSPATH_PROJECTOR, new ClassFileFilter(name));
}
return cf;
}
}