diff options
Diffstat (limited to 'gerrit-main')
-rw-r--r-- | gerrit-main/pom.xml | 38 | ||||
-rw-r--r-- | gerrit-main/src/main/java/Main.java | 38 | ||||
-rw-r--r-- | gerrit-main/src/main/java/com/google/gerrit/main/GerritLauncher.java | 469 |
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() { - } -} |