package io.cattle.platform.launcher;
import io.cattle.platform.launcher.url.JarInJarHandler;
import io.cattle.platform.launcher.url.JarInJarHandlerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
public class Main {
public static final String LIB_PREFIX = "WEB-INF/lib";
public static final String JETTY_PREFIX = "WEB-INF/jetty";
public static final String[] URL_PATHS = new String[] { JETTY_PREFIX, LIB_PREFIX };
public static final String JETTY_LAUNCHER = "io.cattle.platform.launcher.jetty.Main";
JarInJarHandlerFactory factory = new JarInJarHandlerFactory();
protected URL getThisLocation() {
ProtectionDomain domain = Main.class.getProtectionDomain();
CodeSource source = domain.getCodeSource();
return source.getLocation();
}
protected void runMain(ClassLoader cl, String... args) throws Exception {
Thread.currentThread().setContextClassLoader(cl);
Class<?> mainClass = cl.loadClass(JETTY_LAUNCHER);
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) args);
}
protected boolean isJar(URL url) {
JarFile jarFile = null;
try {
File file = new File(url.getPath());
jarFile = new JarFile(file);
jarFile.getManifest();
return true;
} catch (IOException e) {
return false;
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException e) {
}
}
}
}
protected ClassLoader getClassLoader() throws Exception {
URL thisLocation = getThisLocation();
List<URL> urls = Collections.emptyList();
if (isJar(thisLocation)) {
urls = collectJarUrls(thisLocation);
} else {
urls = collectDirectoryUrls(thisLocation);
}
if (urls.size() == 0)
return this.getClass().getClassLoader();
urls.addAll(getPlugins());
urls.add(0, thisLocation);
URL[] urlArray = urls.toArray(new URL[urls.size()]);
ClassLoader cl = Boolean.getBoolean("cattle.main.inherit.cl") ? Main.class.getClassLoader() : null;
return new URLClassLoader(urlArray, cl, factory);
}
protected List<URL> collectDirectoryUrls(URL url) throws IOException {
if (!url.getProtocol().equals("file")) {
return Collections.emptyList();
}
File dir = new File(url.getPath());
List<URL> urls = new ArrayList<URL>();
for (String name : URL_PATHS) {
File path = new File(dir, name);
if (path.exists()) {
File[] children = path.listFiles();
if (children != null) {
for (File child : path.listFiles()) {
if (!child.isDirectory() && child.getName().endsWith(".jar")) {
urls.add(child.toURI().toURL());
}
}
}
}
}
return urls;
}
protected List<URL> collectJarUrls(URL jarUrl) throws IOException {
List<URL> jarsInJar = new ArrayList<URL>();
InputStream is = null;
JarInputStream jis = null;
try {
is = jarUrl.openStream();
jis = new JarInputStream(is);
for (JarEntry e = jis.getNextJarEntry(); e != null; e = jis.getNextJarEntry()) {
String name = e.getName();
if (!name.endsWith(".jar"))
continue;
if (name.startsWith(LIB_PREFIX) || name.startsWith(JETTY_PREFIX)) {
factory.register();
jarsInJar.add(JarInJarHandler.createJarInJar(jarUrl, name));
}
}
} finally {
if (jis != null) {
jis.close();
}
if (is != null) {
is.close();
}
}
return jarsInJar;
}
protected String getMain() {
return System.getProperty("main", JETTY_LAUNCHER);
}
protected void setupHome() {
String homeEnv = System.getenv("CATTLE_HOME");
String homeProperty = System.getProperty("cattle.home");
String home = homeProperty;
if (home == null) {
home = homeEnv;
}
if (home != null && !home.endsWith(File.separator)) {
home += File.separator;
}
if (home != null && !home.equals(homeProperty)) {
System.setProperty("cattle.home", home);
}
}
public void run(String... args) throws Exception {
/*
* The world is better place without time zones. Well, at least for
* computers
*/
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
setupHome();
try {
ClassLoader cl = getClassLoader();
Thread.currentThread().setContextClassLoader(cl);
Class<?> mainClass = cl.loadClass(getMain());
Method mainMethod = mainClass.getMethod("main", String[].class);
mainMethod.invoke(null, (Object) args);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
protected List<URL> getPlugins() throws IOException {
String base = System.getenv("CATTLE_HOME");
if (base == null) {
base = System.getProperty("cattle.home", ".");
}
String pathStrings = System.getenv("CATTLE_EXTENSIONS");
if (pathStrings == null) {
pathStrings = System.getProperty("cattle.extensions", "etc/cattle,extensions");
}
String[] paths = pathStrings.trim().split("\\s*[,;:]\\s*");
final List<URL> result = new ArrayList<URL>();
for (String path : paths) {
if (path.length() == 0)
continue;
File file = new File(base, path);
if (file.exists()) {
result.add(file.toURI().toURL());
System.out.println("[MAIN] Scanning [" + path + "] for extensions");
traverse(file.getAbsolutePath(), result);
}
}
return result;
}
protected void traverse(String path, List<URL> result) {
File file = new File(path);
if (!file.exists()) {
System.err.println("[MAIN] Failed to find : " + path);
return;
}
for (File testFile : file.listFiles()) {
if (testFile.isDirectory()) {
traverse(testFile.getAbsolutePath(), result);
} else if (testFile.getName().endsWith(".jar")) {
try {
URL plugin = testFile.toURI().toURL();
System.out.println("[MAIN] Plugin : " + plugin);
result.add(plugin);
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
}
public static void main(String... args) {
try {
new Main().run(args);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}