/**
* Licensed under the GNU LGPL v.2.1 or later.
*/
package info.freelibrary.util;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utilities for working with the Java classpath.
*
* @author <a href="mailto:ksclarke@ksclarke.io">Kevin S. Clarke</a>
*/
public class ClasspathUtils {
private static final String CLASSPATH = "java.class.path";
private static final Logger LOGGER = LoggerFactory.getLogger(ClasspathUtils.class);
private ClasspathUtils() {
}
/**
* Returns an String array of all the directory names in the system classpath
*
* @return The names of directories from the system classpath
*/
public static String[] getDirs() {
final ArrayList<String> list = new ArrayList<>();
for (final String filename : System.getProperty(CLASSPATH).split(":")) {
final File file = new File(filename);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking to see if {} is a dir ({})", file.getAbsolutePath(), file.isDirectory() ? "yes"
: "no");
}
if (file.isDirectory()) {
list.add(file.getAbsolutePath());
}
}
return list.toArray(new String[list.size()]);
}
/**
* Returns an array of all the directories in the system classpath
*
* @return The directories from the system classpath
*/
public static File[] getDirFiles() {
final ArrayList<File> list = new ArrayList<>();
for (final String filename : System.getProperty(CLASSPATH).split(":")) {
final File file = new File(filename);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking to see if {} is a dir ({})", file.getAbsolutePath(), file.isDirectory() ? "yes"
: "no");
}
if (file.isDirectory()) {
list.add(file);
}
}
return list.toArray(new File[list.size()]);
}
/**
* Returns an String array of all the directory names in the system classpath that match the supplied
* <code>FilenameFilter</code>
*
* @param aFilter A filter to use while retrieving directories
* @return The names of directories from the system classpath that match the supplied <code>FilenameFilter</code>
*/
public static String[] getDirs(final FilenameFilter aFilter) {
final ArrayList<String> list = new ArrayList<>();
for (final String filename : System.getProperty(CLASSPATH).split(":")) {
final File file = new File(filename);
if (aFilter.accept(file.getParentFile(), file.getName()) && file.isDirectory()) {
list.add(file.getAbsolutePath());
}
}
return list.toArray(new String[list.size()]);
}
/**
* Returns an array of all the directories in the system classpath that match the supplied
* <code>FilenameFilter</code>
*
* @param aFilter A filter to use while retrieving directories
* @return The directories from the system classpath that match the supplied <code>FilenameFilter</code>
*/
public static File[] getDirFiles(final FilenameFilter aFilter) {
final ArrayList<File> list = new ArrayList<>();
for (final String filename : System.getProperty(CLASSPATH).split(":")) {
final File file = new File(filename);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking to see if {} is a dir ({})", file.getAbsolutePath(), file.isDirectory() ? "yes"
: "no");
}
if (aFilter.accept(file.getParentFile(), file.getName()) && file.isDirectory()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("{} is a directory", file.getAbsolutePath());
}
list.add(file);
}
}
return list.toArray(new File[list.size()]);
}
/**
* Returns an String array of all the names of the jars in the system classpath
*
* @return The names of jars from the system classpath
*/
public static String[] getJars() {
final ArrayList<String> list = new ArrayList<>();
final FileExtFileFilter filter = new FileExtFileFilter("jar");
for (final String part : System.getProperty(CLASSPATH).split(File.pathSeparator)) {
final File file = new File(part);
if (filter.accept(file.getParentFile(), file.getName())) {
list.add(file.getAbsolutePath());
}
}
return list.toArray(new String[list.size()]);
}
/**
* Returns an String array of all the names of the jars in the system classpath that match the supplied
* <code>FilenameFilter</code>
*
* @param aFilter A file name filter to use while retrieving Jar files
* @return The names of jars from the system classpath that match the supplied <code>FilenameFilter</code>
*/
public static String[] getJars(final FilenameFilter aFilter) {
final ArrayList<String> list = new ArrayList<>();
final FileExtFileFilter filter = new FileExtFileFilter("jar");
for (final String part : System.getProperty(CLASSPATH).split(File.pathSeparator)) {
final File file = new File(part);
final File parent = file.getParentFile();
final String name = file.getName();
if (filter.accept(parent, name) && aFilter.accept(parent, name)) {
list.add(file.getAbsolutePath());
}
}
return list.toArray(new String[list.size()]);
}
/**
* Returns an array of all the jar files in the system classpath
*
* @return The jar files from the system classpath
* @throws IOException If there is trouble reading the file system while looking for Jar files
*/
public static JarFile[] getJarFiles() throws IOException {
final ArrayList<JarFile> list = new ArrayList<>();
final FileExtFileFilter filter = new FileExtFileFilter("jar");
for (final String part : System.getProperty(CLASSPATH).split(File.pathSeparator)) {
final File file = new File(part);
if (filter.accept(file.getParentFile(), file.getName())) {
list.add(new JarFile(file));
}
}
return list.toArray(new JarFile[list.size()]);
}
/**
* Returns an array of all the jar files in the system classpath that match the supplied <code>FilenameFilter</code>
*
* @param aFilter A file name filter to use while retrieving Jar files
* @return The jar files from the system classpath that match the supplied <code>FilenameFilter</code>
* @throws IOException If there is trouble reading the file system while looking for Jar files
*/
public static JarFile[] getJarFiles(final FilenameFilter aFilter) throws IOException {
final ArrayList<JarFile> list = new ArrayList<>();
final FileExtFileFilter filter = new FileExtFileFilter("jar");
for (final String part : System.getProperty(CLASSPATH).split(File.pathSeparator)) {
final File file = new File(part);
final File parent = file.getParentFile();
final String name = file.getName();
if (filter.accept(parent, name) && aFilter.accept(parent, name)) {
list.add(new JarFile(file));
}
}
return list.toArray(new JarFile[list.size()]);
}
/**
* Finds the first instance of the supplied file name in the classpath (in either a directory or a jar file) and
* returns a {@link URL} for it.
*
* @param aFileName The name of the file we want to read
* @return The {@link URL} of the file we want to read
* @throws IOException If there is trouble reading from the file system or jars
*/
public static URL findFirst(final String aFileName) throws IOException {
final FileExtFileFilter filter = new FileExtFileFilter("jar");
for (final String cpEntry : System.getProperty(CLASSPATH).split(File.pathSeparator)) {
final File file = new File(cpEntry);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking {} for {}", cpEntry, aFileName);
}
if (file.isDirectory()) {
final File target = new File(file, aFileName);
if (target.exists()) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Found {} in {}", aFileName, cpEntry);
}
return target.toURI().toURL();
}
} else if (filter.accept(file.getParentFile(), file.getName())) {
final JarFile jarFile = new JarFile(file);
final JarEntry jarEntry = jarFile.getJarEntry(aFileName);
if (jarEntry != null && jarEntry.getSize() > 0) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Found {} in {}", aFileName, cpEntry);
}
jarFile.close();
return file.toURI().toURL();
} else if (LOGGER.isDebugEnabled()) {
if (jarEntry != null) {
LOGGER.debug("Jar entry {} did not match search pattern", jarEntry.getName());
} else {
LOGGER.debug("Could not get {} from jar file", aFileName);
}
}
jarFile.close();
} else if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Did not check {} because not a directory or jar file", file);
}
}
return null;
}
/**
* Finds the first instance of the supplied file name in the classpath (in either a directory or jar file) and
* returns a URL for it.
*
* @param aFileName The name of the file we want to read
* @return True if the file is found in the classpath; else, false
* @throws IOException If a directory or jar file can't be read
*/
public static boolean find(final String aFileName) throws IOException {
return findFirst(aFileName) != null;
}
}