summaryrefslogtreecommitdiffstats
path: root/gerrit-main
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-main')
-rw-r--r--gerrit-main/pom.xml38
-rw-r--r--gerrit-main/src/main/java/Main.java38
-rw-r--r--gerrit-main/src/main/java/com/google/gerrit/main/GerritLauncher.java469
3 files changed, 74 insertions, 471 deletions
diff --git a/gerrit-main/pom.xml b/gerrit-main/pom.xml
index 71bfd89a52..57eb32ba21 100644
--- a/gerrit-main/pom.xml
+++ b/gerrit-main/pom.xml
@@ -31,4 +31,42 @@ limitations under the License.
<description>
Main class to bootstrap out of a WAR
</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.gerrit</groupId>
+ <artifactId>gerrit-launcher</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.2</source>
+ <target>1.2</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <createDependencyReducedPom>false</createDependencyReducedPom>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
</project>
diff --git a/gerrit-main/src/main/java/Main.java b/gerrit-main/src/main/java/Main.java
index 087a8e3a64..30a55fb5c8 100644
--- a/gerrit-main/src/main/java/Main.java
+++ b/gerrit-main/src/main/java/Main.java
@@ -16,12 +16,46 @@
public final class Main {
// We don't do any real work here because we need to import
// the archive lookup code and we cannot import a class in
- // the default package. So this is just a tiny springboard
+ // the default package. So this is just a tiny springboard
// to jump into the real main code.
//
public static void main(final String argv[]) throws Exception {
- com.google.gerrit.main.GerritLauncher.main(argv);
+ if (onSupportedJavaVersion()) {
+ com.google.gerrit.launcher.GerritLauncher.main(argv);
+
+ } else {
+ System.exit(1);
+ }
+ }
+
+ private static boolean onSupportedJavaVersion() {
+ final String version = System.getProperty("java.specification.version");
+ if (1.6 <= parse(version)) {
+ return true;
+
+ } else {
+ System.err.println("fatal: Gerrit Code Review requires Java 6 or later");
+ System.err.println(" (trying to run on Java " + version + ")");
+ return false;
+ }
+ }
+
+ private static double parse(String version) {
+ if (version == null || version.length() == 0) {
+ return 0.0;
+ }
+
+ try {
+ final int fd = version.indexOf('.');
+ final int sd = version.indexOf('.', fd + 1);
+ if (0 < sd) {
+ version = version.substring(0, sd);
+ }
+ return Double.parseDouble(version);
+ } catch (NumberFormatException e) {
+ return 0.0;
+ }
}
private Main() {
diff --git a/gerrit-main/src/main/java/com/google/gerrit/main/GerritLauncher.java b/gerrit-main/src/main/java/com/google/gerrit/main/GerritLauncher.java
deleted file mode 100644
index cbc2b4a95a..0000000000
--- a/gerrit-main/src/main/java/com/google/gerrit/main/GerritLauncher.java
+++ /dev/null
@@ -1,469 +0,0 @@
-package com.google.gerrit.main;
-
-// Copyright (C) 2009 The Android Open Source Project
-//
-// 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.
-
-import static java.util.concurrent.TimeUnit.DAYS;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.net.JarURLConnection;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.CodeSource;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.jar.Attributes;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-
-/** Main class for a JAR file to run code from "WEB-INF/lib". */
-public final class GerritLauncher {
- private static final String pkg = "com.google.gerrit.pgm";
- public static final String NOT_ARCHIVED = "NOT_ARCHIVED";
-
- public static void main(final String argv[]) throws Exception {
- System.exit(mainImpl(argv));
- }
-
- private static int mainImpl(final String argv[]) throws Exception {
- if (argv.length == 0) {
- File me;
- try {
- me = getDistributionArchive();
- } catch (FileNotFoundException e) {
- me = null;
- }
-
- String jar = me != null ? me.getName() : "gerrit.war";
- System.err.println("Gerrit Code Review " + getVersion(me));
- System.err.println("usage: java -jar " + jar + " command [ARG ...]");
- System.err.println();
- System.err.println("The most commonly used commands are:");
- System.err.println(" init Initialize a Gerrit installation");
- System.err.println(" daemon Run the Gerrit network daemons");
- System.err.println(" gsql Run the interactive query console");
- System.err.println(" version Display the build version number");
- System.err.println();
- System.err.println(" ls List files available for cat");
- System.err.println(" cat FILE Display a file from the archive");
- System.err.println();
- return 1;
- }
-
- // Special cases, a few global options actually are programs.
- //
- if ("-v".equals(argv[0]) || "--version".equals(argv[0])) {
- argv[0] = "version";
- } else if ("-p".equals(argv[0]) || "--cat".equals(argv[0])) {
- argv[0] = "cat";
- } else if ("-l".equals(argv[0]) || "--ls".equals(argv[0])) {
- argv[0] = "ls";
- }
-
- // Run the application class
- //
- final ClassLoader cl = libClassLoader();
- Thread.currentThread().setContextClassLoader(cl);
- return invokeProgram(cl, argv);
- }
-
- private static String getVersion(final File me) {
- if (me == null) {
- return "";
- }
-
- try {
- final JarFile jar = new JarFile(me);
- try {
- Manifest mf = jar.getManifest();
- Attributes att = mf.getMainAttributes();
- String val = att.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
- return val != null ? val : "";
- } finally {
- jar.close();
- }
- } catch (IOException e) {
- return "";
- }
- }
-
- private static int invokeProgram(final ClassLoader loader,
- final String[] origArgv) throws Exception {
- String name = origArgv[0];
- final String[] argv = new String[origArgv.length - 1];
- System.arraycopy(origArgv, 1, argv, 0, argv.length);
-
- Class<?> clazz;
- try {
- try {
- clazz = Class.forName(pkg + "." + name, true, loader);
- } catch (ClassNotFoundException cnfe) {
- if (name.equals(name.toLowerCase())) {
- String first = name.substring(0, 1).toUpperCase();
- String cn = first + name.substring(1);
- clazz = Class.forName(pkg + "." + cn, true, loader);
- } else {
- throw cnfe;
- }
- }
- } catch (ClassNotFoundException cnfe) {
- System.err.println("fatal: unknown command " + name);
- System.err.println(" (no " + pkg + "." + name + ")");
- return 1;
- }
-
- final Method main;
- try {
- main = clazz.getMethod("main", argv.getClass());
- } catch (SecurityException e) {
- System.err.println("fatal: unknown command " + name);
- return 1;
- } catch (NoSuchMethodException e) {
- System.err.println("fatal: unknown command " + name);
- return 1;
- }
-
- final Object res;
- try {
- if ((main.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
- res = main.invoke(null, new Object[] {argv});
- } else {
- res = main.invoke(clazz.newInstance(), new Object[] {argv});
- }
- } catch (InvocationTargetException ite) {
- if (ite.getCause() instanceof Exception) {
- throw (Exception) ite.getCause();
- } else if (ite.getCause() instanceof Error) {
- throw (Error) ite.getCause();
- } else {
- throw ite;
- }
- }
- if (res instanceof Number) {
- return ((Number) res).intValue();
- } else {
- return 0;
- }
- }
-
- private static ClassLoader libClassLoader() throws IOException {
- final File path;
- try {
- path = getDistributionArchive();
- } catch (FileNotFoundException e) {
- if (NOT_ARCHIVED == e.getMessage()) {
- // Assume the CLASSPATH was made complete by the calling process,
- // as we are likely being run from within a developer's IDE.
- //
- return GerritLauncher.class.getClassLoader();
- }
- throw e;
- }
-
- final ArrayList<URL> jars = new ArrayList<URL>();
- try {
- final ZipFile zf = new ZipFile(path);
- try {
- final Enumeration<? extends ZipEntry> e = zf.entries();
- while (e.hasMoreElements()) {
- final ZipEntry ze = e.nextElement();
- if (ze.isDirectory()) {
- continue;
- }
-
- if (ze.getName().startsWith("WEB-INF/lib/")) {
- final File tmp = createTempFile(safeName(ze), ".jar");
- final FileOutputStream out = new FileOutputStream(tmp);
- try {
- final InputStream in = zf.getInputStream(ze);
- try {
- final byte[] buf = new byte[4096];
- int n;
- while ((n = in.read(buf, 0, buf.length)) > 0) {
- out.write(buf, 0, n);
- }
- } finally {
- in.close();
- }
- } finally {
- out.close();
- }
- jars.add(tmp.toURI().toURL());
- }
- }
- } finally {
- zf.close();
- }
- } catch (IOException e) {
- throw new IOException("Cannot obtain libraries from " + path, e);
- }
-
- if (jars.isEmpty()) {
- return GerritLauncher.class.getClassLoader();
- }
- return new URLClassLoader(jars.toArray(new URL[jars.size()]));
- }
-
- private static String safeName(final ZipEntry ze) {
- // Try to derive the name of the temporary file so it
- // doesn't completely suck. Best if we can make it
- // match the name it was in the archive.
- //
- String name = ze.getName();
- if (0 <= name.lastIndexOf('/')) {
- name = name.substring(name.lastIndexOf('/') + 1);
- }
- if (0 <= name.lastIndexOf('.')) {
- name = name.substring(0, name.lastIndexOf('.'));
- }
- if (name.isEmpty()) {
- name = "code";
- }
- return name;
- }
-
- private static File myArchive;
-
- /**
- * Locate the JAR/WAR file we were launched from.
- *
- * @return local path of the Gerrit WAR file.
- * @throws FileNotFoundException if the code cannot guess the location.
- */
- public static File getDistributionArchive() throws FileNotFoundException {
- if (myArchive == null) {
- myArchive = locateMyArchive();
- }
- return myArchive;
- }
-
- private static File locateMyArchive() throws FileNotFoundException {
- final ClassLoader myCL = GerritLauncher.class.getClassLoader();
- final String myName =
- GerritLauncher.class.getName().replace('.', '/') + ".class";
-
- final URL myClazz = myCL.getResource(myName);
- if (myClazz == null) {
- throw new FileNotFoundException("Cannot find JAR: no " + myName);
- }
-
- // ZipFile may have the path of our JAR hiding within itself.
- //
- try {
- Field nameField = ZipFile.class.getDeclaredField("name");
- nameField.setAccessible(true);
-
- JarFile jar = ((JarURLConnection) myClazz.openConnection()).getJarFile();
- File path = new File((String) nameField.get(jar));
- if (path.isFile()) {
- return path;
- }
- } catch (Exception e) {
- // Nope, that didn't work. Try a different method.
- //
- }
-
- // Maybe this is a local class file, running under a debugger?
- //
- if ("file".equals(myClazz.getProtocol())) {
- final File path = new File(myClazz.getPath());
- if (path.isFile() && path.getParentFile().isDirectory()) {
- throw new FileNotFoundException(NOT_ARCHIVED);
- }
- }
-
- // The CodeSource might be able to give us the source as a stream.
- // If so, copy it to a local file so we have random access to it.
- //
- final CodeSource src =
- GerritLauncher.class.getProtectionDomain().getCodeSource();
- if (src != null) {
- try {
- final InputStream in = src.getLocation().openStream();
- try {
- final File tmp = createTempFile("gerrit_", ".zip");
- final FileOutputStream out = new FileOutputStream(tmp);
- try {
- final byte[] buf = new byte[4096];
- int n;
- while ((n = in.read(buf, 0, buf.length)) > 0) {
- out.write(buf, 0, n);
- }
- } finally {
- out.close();
- }
- return tmp;
- } finally {
- in.close();
- }
- } catch (IOException e) {
- // Nope, that didn't work.
- //
- }
- }
-
- throw new FileNotFoundException("Cannot find local copy of JAR");
- }
-
- private static boolean temporaryDirectoryFound;
- private static File temporaryDirectory;
-
- /**
- * Creates a temporary file within the application's unpack location.
- * <p>
- * The launcher unpacks the nested JAR files into a temporary directory,
- * allowing the classes to be loaded from local disk with standard Java APIs.
- * This method constructs a new temporary file in the same directory.
- * <p>
- * The method first tries to create {@code prefix + suffix} within the
- * directory under the assumption that a given {@code prefix + suffix}
- * combination is made at most once per JVM execution. If this fails (e.g. the
- * named file already exists) a mangled unique name is used and returned
- * instead, with the unique string appearing between the prefix and suffix.
- * <p>
- * Files created by this method will be automatically deleted by the JVM when
- * it terminates. If the returned file is converted into a directory by the
- * caller, the caller must arrange for the contents to be deleted before the
- * directory is.
- * <p>
- * If supported by the underlying operating system, the temporary directory
- * which contains these temporary files is accessible only by the user running
- * the JVM.
- *
- * @param prefix prefix of the file name.
- * @param suffix suffix of the file name.
- * @return the path of the temporary file. The returned object exists in the
- * filesystem as a file; caller may need to delete and recreate as a
- * directory if a directory was preferred.
- * @throws IOException the file could not be created.
- */
- public static File createTempFile(String prefix, String suffix)
- throws IOException {
- if (!temporaryDirectoryFound) {
- final File d = File.createTempFile("gerrit_", "_app", tmproot());
- if (d.delete() && d.mkdir()) {
- // Try to lock the directory down to be accessible by us.
- // We first have to remove all permissions, then add back
- // only the owner permissions.
- //
- d.setWritable(false, false /* all */);
- d.setReadable(false, false /* all */);
- d.setExecutable(false, false /* all */);
-
- d.setWritable(true, true /* owner only */);
- d.setReadable(true, true /* owner only */);
- d.setExecutable(true, true /* owner only */);
-
- d.deleteOnExit();
- temporaryDirectory = d;
- }
- temporaryDirectoryFound = true;
- }
-
- if (temporaryDirectory != null) {
- // If we have a private directory and this name has not yet
- // been used within the private directory, create it as-is.
- //
- final File tmp = new File(temporaryDirectory, prefix + suffix);
- if (tmp.createNewFile()) {
- tmp.deleteOnExit();
- return tmp;
- }
- }
-
- if (!prefix.endsWith("_")) {
- prefix += "_";
- }
-
- final File tmp = File.createTempFile(prefix, suffix, temporaryDirectory);
- tmp.deleteOnExit();
- return tmp;
- }
-
- private static File tmproot() {
- // Try to find the user's home directory. If we can't find it
- // return null so the JVM's default temporary directory is used
- // instead. This is probably /tmp or /var/tmp.
- //
- String userHome = System.getProperty("user.home");
- if (userHome == null || "".equals(userHome)) {
- userHome = System.getenv("HOME");
- if (userHome == null || "".equals(userHome)) {
- System.err.println("warning: cannot determine home directory");
- System.err.println("warning: using system temporary directory instead");
- return null;
- }
- }
-
- // Ensure the home directory exists. If it doesn't, try to make it.
- //
- final File home = new File(userHome);
- if (!home.exists()) {
- if (home.mkdirs()) {
- System.err.println("warning: created " + home.getAbsolutePath());
- } else {
- System.err.println("warning: " + home.getAbsolutePath() + " not found");
- System.err.println("warning: using system temporary directory instead");
- return null;
- }
- }
-
- // Use $HOME/.gerritcodereview/tmp for our temporary file area.
- //
- final File tmp = new File(new File(home, ".gerritcodereview"), "tmp");
- if (!tmp.exists() && !tmp.mkdirs()) {
- System.err.println("warning: cannot create " + tmp.getAbsolutePath());
- System.err.println("warning: using system temporary directory instead");
- return null;
- }
-
- // Try to clean up any stale empty directories. Assume any empty
- // directory that is older than 7 days is one of these dead ones
- // that we can clean up.
- //
- final File[] tmpEntries = tmp.listFiles();
- if (tmpEntries != null) {
- final long now = System.currentTimeMillis();
- final long expired = now - MILLISECONDS.convert(7, DAYS);
- for (final File tmpEntry : tmpEntries) {
- if (tmpEntry.isDirectory() && tmpEntry.lastModified() < expired) {
- final String[] all = tmpEntry.list();
- if (all == null || all.length == 0) {
- tmpEntry.delete();
- }
- }
- }
- }
-
- try {
- return tmp.getCanonicalFile();
- } catch (IOException e) {
- return tmp;
- }
- }
-
- private GerritLauncher() {
- }
-}