package org.eclipse.hudson.war;
/**
* *****************************************************************************
*
* Copyright (c) 2012 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Winston Prakash
*
******************************************************************************
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* Simple boot class to make the war executable
*
* @author Winston Prakash
*/
public class Executable {
private final String[] jettyJars = {
"libs/jetty-server.jar",
"libs/jetty-web-app.jar",
"libs/jetty-continuation.jar",
"libs/jetty-http.jar",
"libs/jetty-io.jar",
"libs/jetty-security.jar",
"libs/jetty-servlet.jar",
"libs/jetty-util.jar",
"libs/jetty-xml.jar",
"libs/javax-servlet-api.jar",
"libs/hudson-jetty-war-executable.jar"
};
private List<String> arguments;
public static final int MIN_REQUIRED_JAVA_VERSION = 7;
public static void main(String[] args) throws Exception {
String javaVersionStr = System.getProperty("java.version");
String[] javaVersionElements = javaVersionStr.split("\\.");
int major = Integer.parseInt(javaVersionElements[1]);
if (major < MIN_REQUIRED_JAVA_VERSION) {
System.err.println("Hudson 3.3.x and above requires JDK " + MIN_REQUIRED_JAVA_VERSION + " or later.");
System.err.println("Your java version is " + javaVersionStr);
System.err.println("Java Home: " + System.getProperty("java.home"));
System.exit(0);
}
Executable executable = new Executable();
executable.parseArguments(args);
executable.launchJetty();
}
private void parseArguments(String[] args) throws IOException {
arguments = Arrays.asList(args);
for (String arg : arguments) {
if (arg.startsWith("--version")) {
System.out.println("Hudson Continuous Integration Server" + getHudsonVersion());
System.exit(0);
} else if (arg.startsWith("--usage")) {
printUsage();
break;
} else if (arg.startsWith("--logfile=")) {
String logFile = arg.substring("--logfile=".length());
System.out.println("Logging information is send to file " + logFile);
FileOutputStream fos = new FileOutputStream(new File(logFile));
PrintStream ps = new PrintStream(fos);
System.setOut(ps);
System.setErr(ps);
break;
}
}
}
private void printUsage() throws IOException {
String usageStr = "Hudson Continuous Integration Server " + getHudsonVersion() + "\n"
+ "Usage: java -jar hudson.war [--option=value] [--option=value] ... \n"
+ "\n"
+ "Options:\n"
+ " --version Show Hudson version and quit\n"
+ " --logfile=<filename> Send the output log to this file\n"
+ " --prefix=<prefix-string> Add this prefix to all URLs (eg http://localhost:8080/prefix/resource). Default is none\n\n"
+ " --httpPort=<value> HTTP listening port. Default value is 8080\n\n"
+ " --httpsPort=<value> HTTPS listening port. Disabled by default\n"
+ " --httpsKeyStore=<filepath> Location of the SSL KeyStore file.\n"
+ " --httpsKeyStorePassword=<value> Password for the SSL KeyStore file\n\n"
+ " --httpsKeyManagerPassword=<value> Manager Password for the trustStore \n\n"
+ " --updateServer=<your server> Specify your own update server (eg http://updates.mycompany.com/).\n"
+ " For details see http://wiki.hudson-ci.org/Alternate+Update+Server\n\n"
+ " --disableUpdateCenterSwitch Disable the ability to specify alternate Update Center URL via Plugin Manager Advanced tab\n\n"
+ " --skipInitSetup Skip the initial setup screen and start Hudson directly";
System.out.println(usageStr);
System.exit(0);
}
private void launchJetty() throws Exception {
ProtectionDomain protectionDomain = Executable.class.getProtectionDomain();
URL warUrl = protectionDomain.getCodeSource().getLocation();
// For Testing purpose
// File file = new File("/Users/winstonp/hudson/hudson-eclipse/org.eclipse.hudson.core/hudson-war/target/hudson-war-3.0.0-SNAPSHOT.war");
// URL warUrl = file.toURI().toURL();
System.out.println(warUrl.getPath());
List<URL> jarUrls = extractJettyJarsFromWar(warUrl.getPath());
ClassLoader urlClassLoader = new URLClassLoader(jarUrls.toArray(new URL[jarUrls.size()]));
Thread.currentThread().setContextClassLoader(urlClassLoader);
Class jettyUtil = urlClassLoader.loadClass("org.eclipse.hudson.jetty.JettyLauncher");
Method mainMethod = jettyUtil.getMethod("start", new Class[]{String[].class, URL.class});
mainMethod.invoke(null, new Object[]{arguments.toArray(new String[arguments.size()]), warUrl});
}
/**
* Find the Hudson version from war manifest
*
* @return
* @throws IOException
*/
private static String getHudsonVersion() throws IOException {
Enumeration manifests = Executable.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (manifests.hasMoreElements()) {
URL manifestUrl = (URL) manifests.nextElement();
Manifest manifest = new Manifest(manifestUrl.openStream());
String hudsonVersion = manifest.getMainAttributes().getValue("Hudson-Version");
if (hudsonVersion != null) {
return hudsonVersion;
}
}
return "Unknown Version";
}
/**
* Extract the Jetty Jars from the war
*
* @throws IOException
*/
private List<URL> extractJettyJarsFromWar(String warPath) throws IOException {
JarFile jarFile = new JarFile(warPath);
List<URL> jarUrls = new ArrayList<URL>();
InputStream inStream = null;
try {
for (String entryPath : jettyJars) {
File tmpFile;
try {
tmpFile = File.createTempFile(entryPath.replaceAll("/", "_"), "hudson");
} catch (IOException e) {
String tmpdir = System.getProperty("java.io.tmpdir");
throw new IOException("Failed to extract " + entryPath + " to " + tmpdir, e);
}
JarEntry jarEntry = jarFile.getJarEntry(entryPath);
inStream = jarFile.getInputStream(jarEntry);
OutputStream outStream = new FileOutputStream(tmpFile);
try {
byte[] buffer = new byte[8192];
int readLength;
while ((readLength = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, readLength);
}
} catch (Exception exc) {
exc.printStackTrace();
} finally {
outStream.close();
}
tmpFile.deleteOnExit();
//System.out.println("Extracted " + entryPath + " to " + tmpFile);
jarUrls.add(tmpFile.toURI().toURL());
}
} catch (Exception exc) {
exc.printStackTrace();
} finally {
if (inStream != null) {
inStream.close();
}
}
return jarUrls;
}
}