/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.util.Collection; import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.apache.commons.lang.StringUtils; import org.reflections.Reflections; import org.reflections.scanners.ResourcesScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.FilterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Sets; import com.opengamma.OpenGammaRuntimeException; /** * Classpath utilities */ public class ClasspathUtils { /** Logger. */ private static final Logger s_logger = LoggerFactory.getLogger(ClasspathUtils.class); /** * The class path. */ private static final ImmutableList<URI> CLASSPATH; static { CLASSPATH = ImmutableList.copyOf(forManifest(forJavaClassPath())); } //------------------------------------------------------------------------- private static Set<URI> forJavaClassPath() { Set<URI> uris = Sets.newLinkedHashSet(); String javaClassPath = System.getProperty("java.class.path"); if (javaClassPath != null) { for (String path : javaClassPath.split(File.pathSeparator)) { try { uris.add(new File(path).toURI()); } catch (Exception e) { e.printStackTrace(); } } } return uris; } private static Set<URI> forManifest(final Iterable<URI> uris) { Set<URI> result = Sets.newLinkedHashSet(); for (URI uri : uris) { result.addAll(forManifest(uri)); } return result; } private static Set<URI> forManifest(final URI uri) { Set<URI> result = Sets.newLinkedHashSet(); result.add(uri); try { final String part = ClasspathHelper.cleanPath(uri.toURL()); File jarFile = new File(part); try (JarFile myJar = new JarFile(part)) { URI validUri = tryToGetValidUri(jarFile.getPath(), new File(part).getParent(), part); if (validUri != null) { result.add(validUri); } final Manifest manifest = myJar.getManifest(); if (manifest != null) { final String classPath = manifest.getMainAttributes().getValue(new Attributes.Name("Class-Path")); if (classPath != null) { for (String jar : classPath.split(" ")) { validUri = tryToGetValidUri(jarFile.getPath(), new File(part).getParent(), jar); if (validUri != null) { result.add(validUri); } } } } } } catch (IOException e) { // don't do anything, we're going on the assumption it is a jar, which could be wrong } return result; } private static URI tryToGetValidUri(String workingDir, String path, String filename) { try { if (new File(filename).exists()) { return new File(filename).toURI(); } if (new File(path + File.separator + filename).exists()) { return new File(path + File.separator + filename).toURI(); } if (new File(workingDir + File.separator + filename).exists()) { return new File(workingDir + File.separator + filename).toURI(); } if (new File(new URL(filename).getFile()).exists()) { return new File(new URL(filename).getFile()).toURI(); } } catch (MalformedURLException e) { // don't do anything, we're going on the assumption it is a jar, which could be wrong } return null; } //------------------------------------------------------------------------- /** * Obtains an array of URLs from an array of file names. * * @param classpath the classpath, may be null * @return an array of URLs, not null */ public static URL[] getClasspathURLs(String[] classpath) { if (classpath == null) { return new URL[0]; } Set<URL> classpathUrls = new HashSet<URL>(); for (String classpathEntry : classpath) { File f = new File(classpathEntry); if (!f.exists()) { s_logger.debug("Skipping non-existent classpath entry '{}'", classpathEntry); continue; } try { classpathUrls.add(f.toURI().toURL()); } catch (MalformedURLException e) { throw new OpenGammaRuntimeException("Error interpreting classpath entry '" + classpathEntry + "' as URL", e); } } URL[] classpathUrlArray = classpathUrls.toArray(new URL[0]); return classpathUrlArray; } public static URL[] getClasspathURLs(Collection<String> classpath) { String[] classpathArray = new String[classpath.size()]; classpathArray = classpath.toArray(classpathArray); return getClasspathURLs(classpathArray); } //------------------------------------------------------------------------- /** * Obtains the class path as URIs. * * @return the classpath, not null */ public static ImmutableList<URI> getURIs() { return CLASSPATH; } /** * Obtains the class path as dependencies. * * @return the dependencies, not null */ public static ImmutableList<DependencyInfo> getDependencies() { return DependencyInfo.DEPENDENCIES; } //------------------------------------------------------------------------- /** * Information about a dependency in the classpath. */ public static class DependencyInfo { static final ImmutableList<DependencyInfo> DEPENDENCIES; private final URL _url; private final String _version; private final String _groupId; private final String _artifactId; static { Builder<DependencyInfo> builder = ImmutableList.builder(); for (URI uri : CLASSPATH) { try { builder.add(new DependencyInfo(uri)); } catch (MalformedURLException ex) { // ignore and continue } } DEPENDENCIES = builder.build(); } public DependencyInfo(URI uri) throws MalformedURLException { _url = uri.toURL(); FilterBuilder filter = new FilterBuilder().include(".*pom[.]properties"); Reflections ref = new Reflections(new ResourcesScanner(), _url, filter); Set<String> resources = ref.getResources(filter); Properties properties = new Properties(); if (resources.size() == 1) { String relativePath = resources.iterator().next(); try (URLClassLoader cl = new URLClassLoader(new URL[] {_url}, null)) { URL resource = cl.getResource(relativePath); if (resource != null) { try (InputStream in = resource.openStream()) { properties.load(in); } catch (IOException ex) { s_logger.debug(ex.getMessage(), ex); } } } catch (IOException ex2) { s_logger.debug(ex2.getMessage(), ex2); } } else if (_url.toString().endsWith(".jar")) { String name = StringUtils.substringAfterLast(_url.toString(), "/"); name = StringUtils.substringBeforeLast(name, ".jar"); properties.setProperty("version", StringUtils.substringAfterLast(name, "-")); properties.setProperty("groupId", "?"); properties.setProperty("artifactId", StringUtils.substringBeforeLast(name, "-")); } _version = properties.getProperty("version", "?"); _groupId = properties.getProperty("groupId", "?"); _artifactId = properties.getProperty("artifactId", "?"); } /** * Is the dependency a Jar file. * @return true if a jar */ public boolean isJarFile() { return _url.toString().endsWith(".jar"); } /** * Is the dependency information parsed. * @return true if a jar */ public boolean isInfoParsed() { return "?".equals(_version) == false; } /** * Is the groupId information parsed. * @return true if a jar */ public boolean isGroupParsed() { return "?".equals(_groupId) == false; } /** * Get URL. * @return the URL */ public URL getUrl() { return _url; } /** * Get version. * @return the version */ public String getVersion() { return _version; } /** * Get group id. * @return the group id */ public String getGroupId() { return _groupId; } /** * Get artifact id. * @return the artifact id */ public String getArtifactId() { return _artifactId; } @Override public String toString() { return _groupId + ":" + _artifactId + ":" + _version; } } }