package org.jboss.loom.utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Works with classpaths, classes, various searching etc.
*
* @author Ondrej Zizka, ozizka at redhat.com
*/
public class ClassUtils {
private static final Logger log = LoggerFactory.getLogger( ClassUtils.class );
public static File findClassOriginFile( Class cls ){
// Try to find the class file.
try {
final URL url = cls.getClassLoader().getResource( cls.getName().replace('.', '/') + ".class");
final File file = new File( url.getFile() ); // toString()
if( file.exists() )
return file;
}
catch( Exception ex ) { }
// Method 2
try {
URL url = cls.getProtectionDomain().getCodeSource().getLocation();
final File file = new File( url.getFile() ); // toString()
if( file.exists() )
return file;
}
catch( Exception ex ) { }
return null;
}
public static String findClassPathRootFor( Class cls ) {
File clsFile = findClassOriginFile( cls );
log.debug("Class' file: " + clsFile);
if( clsFile == null ) return null;
//clsFile.getName().endsWith(".class") )
String clsSubPath = cls.getName().replace('.','/') + ".class";
return StringUtils.removeEnd( clsFile.getPath(), clsSubPath );
}
// ======= Class utils ====== //
/**
* Copies content of the resource <code>path</code> to a same-named file in <code>dir</code>.
* The directories up to <code>dir</code> will be created if they don't already exist.
* The file will be overwritten if it already exists.
* <br/><br/>
* <p>
* com.foo.Bar + "my/File.xml" --> resource path is "/com/foo/Bar/my/File.xml"
* </p>
*
* @param cls resPath will be relative to this class' package directory.
* Can be null, in which case "" is used as prefix and ClassUtils' classloader is used.
* @param resPath Path to the resource, relative to class'es "directory".
* @param dir Directory to copy to.
*/
public static File copyResourceToDir( Class cls, String resPath, File dir ) throws IOException {
String packageDir = cls == null ? "" : "/" + cls.getPackage().getName().replace( '.', '/' );
String path = packageDir + "/" + resPath;
if( cls == null )
cls = ClassUtils.class;
InputStream is = cls.getResourceAsStream( path );
if( is == null ) {
throw new IllegalArgumentException( "Resource not found: " + path );
}
File file = new File( dir, resPath );
FileUtils.copyInputStreamToFile( is, file );
return file;
}
static boolean containsClass( JarFile jarFile, String classFilePath ) {
final Enumeration<JarEntry> entries = jarFile.entries();
while( entries.hasMoreElements() ) {
final JarEntry entry = entries.nextElement();
if( (!entry.isDirectory()) && entry.getName().contains( classFilePath ) ) {
return true;
}
}
return false;
}
/**
* TODO: Return a list of files.
*/
public static File lookForJarWithClass( String className, File... dirs ) throws IOException {
for( File dir : dirs ) {
log.debug( " Looking in " + dir.getPath() + " for a .jar with: " + className );
if( !dir.isDirectory() ) {
log.trace( " Not a directory: " + dir.getPath() );
continue;
}
Collection<File> jarFiles = FileUtils.listFiles( dir, new String[]{ "jar" }, true );
log.trace( " Found .jar files: " + jarFiles.size() );
String classFilePath = className.replace( ".", "/" );
for( File file : jarFiles ) {
try (final JarFile jarFile = new JarFile( file )) {
if( containsClass( jarFile, classFilePath ) ) {
return file;
}
}
catch( Throwable ex ){
log.warn(" Can't scan {}: {}", file.getPath(), ex.getMessage());
}
}
}
return null;
}
}// class