/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * 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. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.agent.common.util; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.net.URLConnection; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; import org.apache.commons.io.FileUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class JarUtil { private static final Log LOG = LogFactory.getLog(JarUtil.class); public static final String GO_VERSION = "Go-Version"; public static final String EXPLODED_DEPENDENCIES_DIR_NAME = "exploded_agent_launcher_dependencies"; public static String getGoVersion(String jar) { String version = getManifestKey(jar, GO_VERSION); return version == null ? "Unknown" : version; } public static String getManifestKey(String jar, String key) { String version = null; try { JarFile jarFile = new JarFile(jar); Manifest manifest = jarFile.getManifest(); if (manifest != null) { Attributes attributes = manifest.getMainAttributes(); version = attributes.getValue(key); } } catch (IOException e) { LOG.error("Exception while trying to read Go-Version from " + jar + ":" + e.toString()); } return version; } public static Object objectFromJar(final String jarFileName, final String manifestClassKey) { return objectFromJar(jarFileName, manifestClassKey, null); } public static Object objectFromJar(String jarFileName, String manifestClassKey, String manifestLibDirKey, final Class... allowedForLoadingFromParent) { LOG.info(String.format("Attempting to load %s from %s File: ", manifestClassKey, jarFileName)); try { File agentJar = new File(jarFileName); String absolutePath = agentJar.getAbsolutePath(); List<URL> urls = new ArrayList<>(); urls.add(agentJar.toURI().toURL()); if (manifestLibDirKey != null) { String libDirPrefix = getManifestKey(absolutePath, manifestLibDirKey); LOG.info(String.format("manifestLibDirKey: %s: %s", manifestLibDirKey, libDirPrefix)); prepareRefferedJars(jarFileName, absolutePath, urls, libDirPrefix); } ParentClassAccessFilteringClassloader filteringLoader = new ParentClassAccessFilteringClassloader(JarUtil.class.getClassLoader(), allowedForLoadingFromParent); URLClassLoader classLoader = new URLClassLoader(urls.toArray(new URL[0]), filteringLoader); String bootClassName = getManifestKey(absolutePath, manifestClassKey); LOG.info(String.format("manifestClassKey: %s: %s", manifestClassKey, bootClassName)); return classLoader.loadClass(bootClassName).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } private static void prepareRefferedJars(String jarFileName, String absolutePath, List<URL> urlsExtracted, String libDirPrefix) throws IOException { JarFile jarFile = new JarFile(absolutePath); Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); String entryName = jarEntry.getName(); if (entryName.startsWith(libDirPrefix) && entryName.endsWith(".jar")) { File depsDir = new File(EXPLODED_DEPENDENCIES_DIR_NAME, jarFileName); depsDir.mkdirs(); String entryBaseName = entryName.replaceAll(".*/", ""); File extractedJar = new File(depsDir, entryBaseName); String escapedJarURL = new File(absolutePath).toURI().toURL().toExternalForm(); InputStream jarStream = null; FileOutputStream fileOutputStream = null; try { URL jarUrl = new URL("jar:" + escapedJarURL + "!/" + entryName); URLConnection conn = jarUrl.openConnection(); conn.setUseCaches(false); jarStream = conn.getInputStream(); fileOutputStream = new FileOutputStream(extractedJar); org.apache.commons.io.IOUtils.copyLarge(jarStream, fileOutputStream); } finally { try { if (jarStream != null) { jarStream.close(); } } finally { if (fileOutputStream != null) { fileOutputStream.close(); } } } urlsExtracted.add(extractedJar.toURI().toURL()); } } } public static boolean cleanup(String inUseLauncher) { File depsDir = new File(EXPLODED_DEPENDENCIES_DIR_NAME, inUseLauncher); return FileUtils.deleteQuietly(depsDir); } public static boolean tempFileExist(String inUseLauncher) { File depsDir = new File(EXPLODED_DEPENDENCIES_DIR_NAME, inUseLauncher); return depsDir.exists(); } }