Introduced a service interface to allow multiple ClassPathSearchs with its own customized search way

This commit is contained in:
Kefeng Deng
2015-07-28 21:31:49 +12:00
parent 890e924eb0
commit 2fa7c57357
5 changed files with 489 additions and 416 deletions
@@ -0,0 +1,46 @@
package com.avaje.ebeaninternal.api;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import com.avaje.ebeaninternal.server.util.ClassPathSearchMatcher;
import java.io.IOException;
import java.util.List;
import java.util.Set;
/**
* This interface allows us to have more than one ClassPathSearch
* to scan the resources by a customized way.
*
* @author Kefeng Deng (deng@51any.com)
*/
public interface ClassPathSearchService {
/**
* Initialize this ClassPathSearchService with given parameters
*
* @param classLoader is current classLoader
* @param filter is filter
* @param matcher
* @param classPathReaderClassName
*/
void init(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName);
/**
* Searches the class path for all matching classes.
*
* @return a collection of all matching classes
* @throws IOException if a resource is un-reachable
*/
List<Class<?>> findClasses() throws IOException;
/**
* Return the set of jars that contained classes that matched.
*/
Set<String> getJarHits();
/**
* Return the set of packages that contained classes that matched.
*/
Set<String> getPackageHits();
}
@@ -1,12 +1,11 @@
package com.avaje.ebeaninternal.server.core;
import com.avaje.ebeaninternal.server.util.ClassPathSearch;
import com.avaje.ebeaninternal.api.ClassPathSearchService;
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
@@ -21,11 +20,13 @@ public class BootupClassPathSearch {
private final List<String> packages;
private final List<String> jars;
private final List<String> jars;
private List<ClassPathSearchService> classPathSearchServices;
private BootupClasses bootupClasses;
private final String classPathReaderClassName;
private final String classPathReaderClassName;
/**
* Construct and search for interesting classes.
@@ -34,16 +35,18 @@ public class BootupClassPathSearch {
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
this.packages = packages;
this.jars = jars;
this.classPathReaderClassName = classPathReaderClassName;
this.classPathReaderClassName = classPathReaderClassName;
loadAndInitializeClassPathSearchServices();
}
public BootupClasses getBootupClasses() {
synchronized (monitor) {
if (bootupClasses == null){
if (bootupClasses == null) {
bootupClasses = search();
}
return bootupClasses;
}
}
@@ -54,24 +57,26 @@ public class BootupClassPathSearch {
private BootupClasses search() {
synchronized (monitor) {
try {
BootupClasses bc = new BootupClasses();
long st = System.currentTimeMillis();
ClassPathSearchFilter filter = createFilter();
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
Set<String> foundJars = new HashSet<String>();
Set<String> foundPkgs = new HashSet<String>();
finder.findClasses();
Set<String> jars = finder.getJarHits();
Set<String> pkgs = finder.getPackageHits();
for (ClassPathSearchService finder : this.classPathSearchServices) {
finder.init(classLoader, filter, bc, classPathReaderClassName);
finder.findClasses();
foundJars.addAll(finder.getJarHits());
foundPkgs.addAll(finder.getPackageHits());
}
long searchTime = System.currentTimeMillis() - st;
String msg = "Classpath search hits in jars" + jars + " pkgs" + pkgs + " searchTime[" + searchTime+ "]";
logger.info(msg);
logger.info("Classpath search hits in jars {} pkgs {} searchTime [{}]", foundJars, foundPkgs, searchTime);
return bc;
} catch (Exception ex) {
@@ -86,24 +91,37 @@ public class BootupClassPathSearch {
ClassPathSearchFilter filter = new ClassPathSearchFilter();
filter.addDefaultExcludePackages();
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
if (packages != null && packages.size() > 0) {
for (String packageName : packages) {
filter.includePackage(packageName);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
}
// if they specified include packages, they don't want by default to include everything
filter.setDefaultPackageMatch(false);
}
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
if (jars != null && jars.size() > 0) {
for (String jarName : jars) {
filter.includeJar(jarName);
}
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
// if they specified jars to specifically include, they don't want everything included
filter.setDefaultJarMatch(false);
}
return filter;
}
/**
* Load and initialize all ClassPathSearchServices
*/
private void loadAndInitializeClassPathSearchServices() {
if (this.classPathSearchServices == null) {
this.classPathSearchServices = new ArrayList<ClassPathSearchService>();
}
for (ClassPathSearchService searchService : ServiceLoader.load(ClassPathSearchService.class, classLoader)) {
this.classPathSearchServices.add(searchService);
}
}
}
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.util;
import com.avaje.ebeaninternal.api.ClassPathSearchService;
import com.avaje.ebeaninternal.api.ClassUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -22,474 +23,479 @@ import java.util.jar.Manifest;
* For example, used to find all the Entity beans and ScalarTypes for Ebean.
* </p>
*/
public class ClassPathSearch {
public class ClassPathSearch implements ClassPathSearchService {
private static final Logger logger = LoggerFactory.getLogger(ClassPathSearch.class);
private static final Logger logger = LoggerFactory.getLogger(ClassPathSearch.class);
private ClassLoader classLoader;
private ClassLoader classLoader;
private List<Object> classPath = new ArrayList<Object>();
private ClassPathSearchFilter filter;
private List<Object> classPath = new ArrayList<Object>();
private ClassPathSearchMatcher matcher;
private ClassPathSearchFilter filter;
private ArrayList<Class<?>> matchList = new ArrayList<Class<?>>();
private ClassPathSearchMatcher matcher;
private HashSet<String> jarHits = new HashSet<String>();
private ArrayList<Class<?>> matchList = new ArrayList<Class<?>>();
private HashSet<String> packageHits = new HashSet<String>();
private HashSet<String> jarHits = new HashSet<String>();
private ClassPathReader classPathReader = new DefaultClassPathReader();
private HashSet<String> packageHits = new HashSet<String>();
private ArrayList<URI> scannedUris = new ArrayList<URI>();
private ClassPathReader classPathReader = new DefaultClassPathReader();
public ClassPathSearch(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName) {
this.classLoader = classLoader;
this.filter = filter;
this.matcher = matcher;
initClassPaths(classPathReaderClassName);
}
private ArrayList<URI> scannedUris = new ArrayList<URI>();
private void initClassPaths(String classPathReaderCN) {
public ClassPathSearch() {
// Default Construct
}
try {
@Override
public void init(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName) {
this.classLoader = classLoader;
this.filter = filter;
this.matcher = matcher;
initClassPaths(classPathReaderClassName);
}
if (classPathReaderCN != null) {
// use a user defined classPathReader
logger.info("Using [" + classPathReaderCN + "] to read the searchable class path");
classPathReader = (ClassPathReader) ClassUtil.newInstance(classPathReaderCN, this.getClass());
}
private void initClassPaths(String classPathReaderCN) {
Object[] rawClassPaths = classPathReader.readPath(classLoader);
try {
if (rawClassPaths == null || rawClassPaths.length == 0) {
logger.warn("ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]");
return;
}
if (classPathReaderCN != null) {
// use a user defined classPathReader
logger.info("Using [" + classPathReaderCN + "] to read the searchable class path");
classPathReader = (ClassPathReader) ClassUtil.newInstance(classPathReaderCN, this.getClass());
}
for (int i = 0; i < rawClassPaths.length; i++) {
// check for a jarfile with a manifest classpath (e.g. maven surefire)
List<URI> classPathFromManifest = getClassPathFromManifest(rawClassPaths[i]);
if (classPathFromManifest.isEmpty()) {
classPath.add(rawClassPaths[i]);
} else {
classPath.addAll(classPathFromManifest);
}
}
if (rawClassPaths.length == 1) {
// look to add an 'outer' jar when it contains a manifest classpath
if (!classPath.contains(rawClassPaths[0])) {
classPath.add(rawClassPaths[0]);
}
}
if (logger.isDebugEnabled()) {
for (Object entry : classPath) {
logger.debug("Classpath Entry: {}",entry);
}
}
Object[] rawClassPaths = classPathReader.readPath(classLoader);
} catch (Exception e) {
throw new RuntimeException("Error trying to read the classpath entries", e);
}
}
if (rawClassPaths == null || rawClassPaths.length == 0) {
logger.warn("ClassPath is EMPTY using ClassPathReader [" + classPathReader + "]");
return;
}
/**
* Return the set of jars that contained classes that matched.
*/
public Set<String> getJarHits() {
return jarHits;
}
for (int i = 0; i < rawClassPaths.length; i++) {
// check for a jarfile with a manifest classpath (e.g. maven surefire)
List<URI> classPathFromManifest = getClassPathFromManifest(rawClassPaths[i]);
if (classPathFromManifest.isEmpty()) {
classPath.add(rawClassPaths[i]);
} else {
classPath.addAll(classPathFromManifest);
}
}
/**
* Return the set of packages that contained classes that matched.
*/
public Set<String> getPackageHits() {
return packageHits;
}
if (rawClassPaths.length == 1) {
// look to add an 'outer' jar when it contains a manifest classpath
if (!classPath.contains(rawClassPaths[0])) {
classPath.add(rawClassPaths[0]);
}
}
/**
* Register where matching classes where found.
* <p>
* Could use this info to speed up future searches.
* </p>
*/
private void registerHit(String jarFileName, Class<?> cls) {
if (jarFileName != null) {
jarHits.add(jarFileName);
}
Package pkg = cls.getPackage();
if (pkg != null) {
packageHits.add(pkg.getName());
} else {
packageHits.add("");
}
}
if (logger.isDebugEnabled()) {
for (Object entry : classPath) {
logger.debug("Classpath Entry: {}", entry);
}
}
/**
* Searches the class path for all matching classes.
*/
public List<Class<?>> findClasses() throws IOException {
} catch (Exception e) {
throw new RuntimeException("Error trying to read the classpath entries", e);
}
}
if (classPath.isEmpty()) {
// returning an empty list
return matchList;
}
/**
* Return the set of jars that contained classes that matched.
*/
@Override
public Set<String> getJarHits() {
return jarHits;
}
int classPathSize = classPath.size();
for (int i = 0; i < classPathSize; i++) {
/**
* Return the set of packages that contained classes that matched.
*/
@Override
public Set<String> getPackageHits() {
return packageHits;
}
ClassPathElement element = getClassPathElement(classPath.get(i));
/**
* Register where matching classes where found.
* <p>
* Could use this info to speed up future searches.
* </p>
*/
private void registerHit(String jarFileName, Class<?> cls) {
if (jarFileName != null) {
jarHits.add(jarFileName);
}
Package pkg = cls.getPackage();
if (pkg != null) {
packageHits.add(pkg.getName());
} else {
packageHits.add("");
}
}
if (element.isDirectory()) {
scanDirectory(element);
/**
* Searches the class path for all matching classes.
*/
@Override
public List<Class<?>> findClasses() throws IOException {
} else if (element.isJarOrWar()) {
// search name including the ! offset if it is there
if (classPathSize == 1 || filter.isSearchJar(element.getJarNameWithOffset())) {
scanJar(element);
}
if (classPath.isEmpty()) {
// returning an empty list
return matchList;
}
} else {
logger.error("Error: expected classPath entry [" + element+ "] to be a directory or a .jar file but it is not either of those?");
}
}
int classPathSize = classPath.size();
for (int i = 0; i < classPathSize; i++) {
if (matchList.isEmpty()) {
logger.warn("No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched[" + classPath + "]");
}
ClassPathElement element = getClassPathElement(classPath.get(i));
return matchList;
}
if (element.isDirectory()) {
scanDirectory(element);
private ClassPathElement getClassPathElement(Object classPathEntry) throws MalformedURLException {
} else if (element.isJarOrWar()) {
// search name including the ! offset if it is there
if (classPathSize == 1 || filter.isSearchJar(element.getJarNameWithOffset())) {
scanJar(element);
}
URL fileUrl = null;
if (URI.class.isInstance(classPathEntry)) {
fileUrl = ((URI)classPathEntry).toURL();
} else if (!URL.class.isInstance(classPathEntry)) {
// assumed to be a file path
return new ClassPathElement(classPathEntry.toString());
} else {
fileUrl = (URL) classPathEntry;
}
if (!fileUrl.getPath().contains("!")) {
return new ClassPathElement(new File(fileUrl.getFile()));
}
} else {
logger.error("Error: expected classPath entry [" + element + "] to be a directory or a .jar file but it is not either of those?");
}
}
// jar:file:..../file.war!/WEB-INF/classes typically
String[] parts = fileUrl.getPath().split("!");
String fileName = parts[0];
String jarOffset = parts[1];
if (fileName.startsWith("file:")) {
fileName = fileName.substring("file:".length());
}
return new ClassPathElement(new File(fileName), jarOffset);
}
if (matchList.isEmpty()) {
logger.warn("No Entities found in ClassPath using ClassPathReader [" + classPathReader + "] Classpath Searched[" + classPath + "]");
}
private void scanDirectory(ClassPathElement classPathEntry) {
scanDirectory(classPathEntry.classPath);
}
return matchList;
}
private void scanDirectory(File directory) {
List<String> directoryFiles = getDirectoryFiles(directory);
searchFiles(Collections.enumeration(directoryFiles), null, null);
}
private ClassPathElement getClassPathElement(Object classPathEntry) throws MalformedURLException {
private void scanUri(URI uri) throws IOException {
URL fileUrl = null;
if (uri.getScheme().equals("file") && scannedUris.add(uri)) {
File file = new File(uri);
if (file.exists()) {
if (file.isDirectory()) {
scanDirectory(file);
} else {
scanJar(new ClassPathElement(file));
}
}
}
}
if (URI.class.isInstance(classPathEntry)) {
fileUrl = ((URI) classPathEntry).toURL();
} else if (!URL.class.isInstance(classPathEntry)) {
// assumed to be a file path
return new ClassPathElement(classPathEntry.toString());
} else {
fileUrl = (URL) classPathEntry;
}
if (!fileUrl.getPath().contains("!")) {
return new ClassPathElement(new File(fileUrl.getFile()));
}
// jar:file:..../file.war!/WEB-INF/classes typically
String[] parts = fileUrl.getPath().split("!");
String fileName = parts[0];
String jarOffset = parts[1];
if (fileName.startsWith("file:")) {
fileName = fileName.substring("file:".length());
}
return new ClassPathElement(new File(fileName), jarOffset);
}
private void scanDirectory(ClassPathElement classPathEntry) {
scanDirectory(classPathEntry.classPath);
}
private void scanDirectory(File directory) {
List<String> directoryFiles = getDirectoryFiles(directory);
searchFiles(Collections.enumeration(directoryFiles), null, null);
}
private void scanUri(URI uri) throws IOException {
if (uri.getScheme().equals("file") && scannedUris.add(uri)) {
File file = new File(uri);
if (file.exists()) {
if (file.isDirectory()) {
scanDirectory(file);
} else {
scanJar(new ClassPathElement(file));
}
}
}
}
private void scanJar(ClassPathElement classPathEntry) throws IOException {
private void scanJar(ClassPathElement classPathEntry) throws IOException {
JarFile module = null;
try {
// our resource is a jar
File file = classPathEntry.classPath;
module = new JarFile(file);
JarFile module = null;
try {
// our resource is a jar
File file = classPathEntry.classPath;
module = new JarFile(file);
List<URI> classPathFromManifest = getClassPathFromManifest(file, module.getManifest());
for (URI uri : classPathFromManifest) {
scanUri(uri);
}
searchFiles(module.entries(), classPathEntry.getJarName(), classPathEntry.jarOffset);
List<URI> classPathFromManifest = getClassPathFromManifest(file, module.getManifest());
for (URI uri : classPathFromManifest) {
scanUri(uri);
}
} catch (MalformedURLException ex) {
throw new IOException("Bad classpath error: ", ex);
searchFiles(module.entries(), classPathEntry.getJarName(), classPathEntry.jarOffset);
} finally {
if (module != null) {
try {
// close the jar if it was used
module.close();
} catch (IOException e) {
throw new IOException("Error closing jar", e);
}
}
}
}
} catch (MalformedURLException ex) {
throw new IOException("Bad classpath error: ", ex);
private List<String> getDirectoryFiles(File classPath) {
} finally {
if (module != null) {
try {
// close the jar if it was used
module.close();
} catch (IOException e) {
throw new IOException("Error closing jar", e);
}
}
}
}
// list of file names (latter checked as Classes)
ArrayList<String> fileNameList = new ArrayList<String>();
private List<String> getDirectoryFiles(File classPath) {
Set<String> includePkgs = filter.getIncludePackages();
if (includePkgs.size() > 0) {
// just search the relevant directories based on the
// list of included packages
for (String pkg : includePkgs) {
String relativePath = pkg.replace('.', '/');
File dir = new File(classPath, relativePath);
if (dir.exists()) {
recursivelyListDir(fileNameList, dir, new StringBuilder(relativePath));
}
}
// list of file names (latter checked as Classes)
ArrayList<String> fileNameList = new ArrayList<String>();
} else {
// get a recursive listing of this classPath
recursivelyListDir(fileNameList, classPath, new StringBuilder());
}
Set<String> includePkgs = filter.getIncludePackages();
if (includePkgs.size() > 0) {
// just search the relevant directories based on the
// list of included packages
for (String pkg : includePkgs) {
String relativePath = pkg.replace('.', '/');
File dir = new File(classPath, relativePath);
if (dir.exists()) {
recursivelyListDir(fileNameList, dir, new StringBuilder(relativePath));
}
}
return fileNameList;
}
} else {
// get a recursive listing of this classPath
recursivelyListDir(fileNameList, classPath, new StringBuilder());
}
/**
* Searches through the Java Archive (jar or war file) looking for classes
* that match our requirements.
*
* @param files
* - all of the files in the Java Archive, this is an enumeration
* provided by the Jar file
* @param jarFileName
* - the name of the java archive
* @param jarOffset
* - an offset inside the archive to chop off the name of the class -
* this is used when we have bang path offsets (e.g.
* file:///myfile.war!/WEB-INF/classes)
*/
private void searchFiles(Enumeration<?> files, String jarFileName, String jarOffset) {
return fileNameList;
}
if (files == null) {
return;
}
/*
/**
* Searches through the Java Archive (jar or war file) looking for classes
* that match our requirements.
*
* @param files - all of the files in the Java Archive, this is an enumeration
* provided by the Jar file
* @param jarFileName - the name of the java archive
* @param jarOffset - an offset inside the archive to chop off the name of the class -
* this is used when we have bang path offsets (e.g.
* file:///myfile.war!/WEB-INF/classes)
*/
private void searchFiles(Enumeration<?> files, String jarFileName, String jarOffset) {
if (files == null) {
return;
}
/*
* Strips the first character off as all entries in a jar file have no /
* prefix. We want to come out with a name like WEB-INF/classes/ to ensure
* we filter the contents of the war/jar file by this.
*/
if (jarOffset != null) {
if (jarOffset.startsWith("/")) {
jarOffset = jarOffset.substring(1);
}
if (jarOffset != null) {
if (jarOffset.startsWith("/")) {
jarOffset = jarOffset.substring(1);
}
if (!jarOffset.endsWith("/")) {
jarOffset += "/";
}
}
if (!jarOffset.endsWith("/")) {
jarOffset += "/";
}
}
while (files.hasMoreElements()) {
while (files.hasMoreElements()) {
String fileName = files.nextElement().toString();
String fileName = files.nextElement().toString();
// we only want the class files
if (fileName.endsWith(".class") && (jarOffset == null || fileName.startsWith(jarOffset))) {
// we only want the class files
if (fileName.endsWith(".class") && (jarOffset == null || fileName.startsWith(jarOffset))) {
if (jarOffset != null) {
// we got through here only if there is an offset and we
// matched it, so strip it off the file
// as we are trying to find the className
fileName = fileName.substring(jarOffset.length());
}
if (jarOffset != null) {
// we got through here only if there is an offset and we
// matched it, so strip it off the file
// as we are trying to find the className
fileName = fileName.substring(jarOffset.length());
}
String className = fileName.replace('/', '.').substring(0, fileName.length() - 6);
int lastPeriod = className.lastIndexOf(".");
String className = fileName.replace('/', '.').substring(0, fileName.length() - 6);
int lastPeriod = className.lastIndexOf(".");
String pckgName;
if (lastPeriod > 0) {
pckgName = className.substring(0, lastPeriod);
} else {
pckgName = "";
}
String pckgName;
if (lastPeriod > 0) {
pckgName = className.substring(0, lastPeriod);
} else {
pckgName = "";
}
if (filter.isSearchPackage(pckgName)) {
// get the class for our class name
try {
Class<?> theClass = Class.forName(className, false, classLoader);
if (filter.isSearchPackage(pckgName)) {
// get the class for our class name
try {
Class<?> theClass = Class.forName(className, false, classLoader);
if (matcher.isMatch(theClass)) {
matchList.add(theClass);
registerHit(jarFileName, theClass);
}
if (matcher.isMatch(theClass)) {
matchList.add(theClass);
registerHit(jarFileName, theClass);
}
} catch (ClassNotFoundException e) {
// expected to get this hence trace
logger.trace("Error searching classpath" + e.getMessage());
} catch (NoClassDefFoundError e) {
// expected to get this hence trace
logger.trace("Error searching classpath" + e.getMessage());
}
}
}
}
}
} catch (ClassNotFoundException e) {
// expected to get this hence trace
logger.trace("Error searching classpath" + e.getMessage());
} catch (NoClassDefFoundError e) {
// expected to get this hence trace
logger.trace("Error searching classpath" + e.getMessage());
}
}
}
}
}
private void recursivelyListDir(List<String> fileNameList, File dir, StringBuilder relativePath) {
private void recursivelyListDir(List<String> fileNameList, File dir, StringBuilder relativePath) {
if (!dir.isDirectory()) {
// add class fileName to the list
fileNameList.add(relativePath.toString());
if (!dir.isDirectory()) {
// add class fileName to the list
fileNameList.add(relativePath.toString());
} else {
} else {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
// store our original relative path string length
int prevLen = relativePath.length();
relativePath.append(prevLen == 0 ? "" : "/").append(files[i].getName());
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
// store our original relative path string length
int prevLen = relativePath.length();
relativePath.append(prevLen == 0 ? "" : "/").append(files[i].getName());
recursivelyListDir(fileNameList, files[i], relativePath);
recursivelyListDir(fileNameList, files[i], relativePath);
// delete sub directory from our relative path
relativePath.delete(prevLen, relativePath.length());
}
}
}
// delete sub directory from our relative path
relativePath.delete(prevLen, relativePath.length());
}
}
}
/**
* If URL and actually a jarfile with manifest return the derived classpath.
*/
private static List<URI> getClassPathFromManifest(Object classPathElement) {
/**
* If URL and actually a jarfile with manifest return the derived classpath.
*/
private static List<URI> getClassPathFromManifest(Object classPathElement) {
try {
if (classPathElement instanceof URL) {
File file = new File(((URL)classPathElement).getFile());
if (file.isDirectory()) {
return Collections.emptyList();
}
JarFile jarFile = new JarFile(file);
try {
return getClassPathFromManifest(file, jarFile.getManifest());
} finally {
jarFile.close();
}
}
return Collections.emptyList();
} catch (IOException e) {
return Collections.emptyList();
}
}
/**
* If a jarfile with a manifest claspath return that.
*/
private static List<URI> getClassPathFromManifest(File jarFile, Manifest manifest) {
try {
if (classPathElement instanceof URL) {
File file = new File(((URL) classPathElement).getFile());
if (file.isDirectory()) {
return Collections.emptyList();
}
JarFile jarFile = new JarFile(file);
try {
return getClassPathFromManifest(file, jarFile.getManifest());
} finally {
jarFile.close();
}
}
return Collections.emptyList();
if (manifest == null) {
return Collections.emptyList();
}
List<URI> list = new ArrayList<URI>();
String classpathAttribute = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH.toString());
} catch (IOException e) {
return Collections.emptyList();
}
}
if (classpathAttribute != null) {
String[] split = classpathAttribute.split(" ");
for (String path : split) {
try {
path = path.trim();
if (path.length() > 0) {
URI uri = getClassPathEntry(jarFile, path);
list.add(uri);
}
} catch (URISyntaxException e) {
// Ignore bad entry
logger.warn("Invalid Class-Path entry: " + path);
}
}
}
return list;
}
/**
* If a jarfile with a manifest claspath return that.
*/
private static List<URI> getClassPathFromManifest(File jarFile, Manifest manifest) {
private static URI getClassPathEntry(File jarFile, String path) throws URISyntaxException {
URI uri = new URI(path);
if (uri.isAbsolute()) {
return uri;
} else {
return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI();
}
}
if (manifest == null) {
return Collections.emptyList();
}
List<URI> list = new ArrayList<URI>();
String classpathAttribute = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH.toString());
private static File decodePath(File classPath) {
if (classpathAttribute != null) {
String[] split = classpathAttribute.split(" ");
for (String path : split) {
try {
path = path.trim();
if (path.length() > 0) {
URI uri = getClassPathEntry(jarFile, path);
list.add(uri);
}
} catch (URISyntaxException e) {
// Ignore bad entry
logger.warn("Invalid Class-Path entry: " + path);
}
}
}
return list;
}
try {
String charsetName = Charset.defaultCharset().name();
private static URI getClassPathEntry(File jarFile, String path) throws URISyntaxException {
URI uri = new URI(path);
if (uri.isAbsolute()) {
return uri;
} else {
return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI();
}
}
// URL Decode the path replacing %20 to space characters.
String path = URLDecoder.decode(classPath.getAbsolutePath(), charsetName);
return new File(path);
private static File decodePath(File classPath) {
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
try {
String charsetName = Charset.defaultCharset().name();
/**
* Element that has both underlying file and ! jarOffset.
*/
private static class ClassPathElement {
// URL Decode the path replacing %20 to space characters.
String path = URLDecoder.decode(classPath.getAbsolutePath(), charsetName);
return new File(path);
private final File classPath;
private final String jarOffset;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
ClassPathElement(String path) {
this(new File(path));
}
/**
* Element that has both underlying file and ! jarOffset.
*/
private static class ClassPathElement {
ClassPathElement(File file) {
this(file, null);
}
private final File classPath;
private final String jarOffset;
ClassPathElement(File file, String jarOffset) {
classPath = decodePath(file);
this.jarOffset = jarOffset;
}
ClassPathElement(String path) {
this(new File(path));
}
public String toString() {
return classPath.getAbsolutePath();
}
ClassPathElement(File file) {
this(file, null);
}
boolean isDirectory() {
return classPath.isDirectory();
}
ClassPathElement(File file, String jarOffset) {
classPath = decodePath(file);
this.jarOffset = jarOffset;
}
boolean isJarOrWar() {
return classPath.getName().endsWith(".jar") || classPath.getName().endsWith(".war");
}
public String toString() {
return classPath.getAbsolutePath();
}
String getJarName() {
return classPath.getName();
}
boolean isDirectory() {
return classPath.isDirectory();
}
String getJarNameWithOffset() {
return (jarOffset == null) ? classPath.getName() : classPath.getName() + "!" + jarOffset;
}
}
boolean isJarOrWar() {
return classPath.getName().endsWith(".jar") || classPath.getName().endsWith(".war");
}
String getJarName() {
return classPath.getName();
}
String getJarNameWithOffset() {
return (jarOffset == null) ? classPath.getName() : classPath.getName() + "!" + jarOffset;
}
}
}