Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id E7A0776B9 for ; Thu, 1 Dec 2011 14:10:07 +0000 (UTC) Received: (qmail 94834 invoked by uid 500); 1 Dec 2011 14:10:07 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 94769 invoked by uid 500); 1 Dec 2011 14:10:07 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 94762 invoked by uid 99); 1 Dec 2011 14:10:07 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Dec 2011 14:10:07 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_FRT_PROFILE2 X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 01 Dec 2011 14:10:05 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id EDAA02388A64; Thu, 1 Dec 2011 14:09:44 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1209095 - in /sling/trunk/launchpad/base/src: main/java/org/apache/sling/launchpad/app/ main/java/org/apache/sling/launchpad/base/app/ main/java/org/apache/sling/launchpad/base/impl/ main/java/org/apache/sling/launchpad/base/shared/ main/j... Date: Thu, 01 Dec 2011 14:09:39 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111201140944.EDAA02388A64@eris.apache.org> Author: cziegeler Date: Thu Dec 1 14:09:34 2011 New Revision: 1209095 URL: http://svn.apache.org/viewvc?rev=1209095&view=rev Log: SLING-2203 : Allow for better configuration of sling home folder Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/app/MainDelegate.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/webapp/SlingServletDelegate.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/MainTest.java Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java Thu Dec 1 14:09:34 2011 @@ -293,7 +293,9 @@ public class Main { // The Loader helper Loader loaderTmp = null; try { - loaderTmp = new Loader(slingHome) { + final File launchpadHome = getLaunchpadHome(slingHome, + commandLineArgs); + loaderTmp = new Loader(launchpadHome) { @Override protected void info(String msg) { Main.info(msg, null); @@ -461,6 +463,39 @@ public class Main { return slingHome; } + /** + * Define the sling.launchpad parameter implementing the algorithme defined + * on the wiki page to find the setting according to this algorithm: + *
    + *
  1. Configuration property sling.launchpad. This path is + * resolved against the slingHome folder if relative.
  2. + *
  3. Default to same as sling.home
  4. + *
+ * + * @param slingHome The absolute path to the Sling Home folder (aka the + * sling.home. + * @param commandLineArgs The configuration properties from where to get the + * sling.launchpad property. + * @return The absolute File indicating the launchpad folder. + */ + private static File getLaunchpadHome(final String slingHome, + final Map commandLineArgs) { + String launchpadHomeParam = commandLineArgs.get(SharedConstants.SLING_LAUNCHPAD); + if (launchpadHomeParam == null || launchpadHomeParam.length() == 0) { + commandLineArgs.put(SharedConstants.SLING_LAUNCHPAD, slingHome); + return new File(slingHome); + } + + File launchpadHome = new File(launchpadHomeParam); + if (!launchpadHome.isAbsolute()) { + launchpadHome = new File(slingHome, launchpadHomeParam); + } + + commandLineArgs.put(SharedConstants.SLING_LAUNCHPAD, + launchpadHome.getAbsolutePath()); + return launchpadHome; + } + private void startupFailure(String message, Throwable cause) { error("Launcher JAR access failure: " + message, cause); error("Shutting Down", null); @@ -567,7 +602,7 @@ public class Main { if (args.remove("h") != null) { System.out.println("usage: " + Main.class.getName() - + " [ start | stop | status ] [ -j adr ] [ -l loglevel ] [ -f logfile ] [ -c slinghome ] [ -i launchpadhome ] [ -a address ] [ -p port ] [ -h ]"); + + " [ start | stop | status ] [ -j adr ] [ -l loglevel ] [ -f logfile ] [ -c slinghome ] [ -i launchpadhome ] [ -a address ] [ -p port ] { -D n=v } [ -h ]"); System.out.println(" start listen for control connection (uses -j)"); System.out.println(" stop terminate running Apache Sling (uses -j)"); @@ -579,6 +614,7 @@ public class Main { System.out.println(" -i launchpadhome the launchpad directory (default slinghome)"); System.out.println(" -a address the interfact to bind to (use 0.0.0.0 for any) (not supported yet)"); System.out.println(" -p port the port to listen to (default 8080)"); + System.out.println(" -D n=v sets property n to value v"); System.out.println(" -h prints this usage message"); return true; @@ -633,6 +669,15 @@ public class Main { props.put(SharedConstants.SLING_HOME, value); break; + case 'i': + if (value == arg.getKey()) { + errorArg("-i", "Missing launchpad directory value"); + errorArg = true; + continue; + } + props.put(SharedConstants.SLING_LAUNCHPAD, value); + break; + case 'a': if (value == arg.getKey()) { errorArg("-a", "Missing address value"); @@ -660,6 +705,17 @@ public class Main { } break; + case 'D': + if (value == arg.getKey()) { + errorArg("-D", "Missing property assignment"); + errorArg = true; + continue; + } + String[] parts = value.split("="); + int valueIdx = (parts.length > 1) ? 1 : 0; + props.put(parts[0], parts[valueIdx]); + break; + default: errorArg("-" + arg.getKey(), "Unrecognized option"); errorArg = true; Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/app/MainDelegate.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/app/MainDelegate.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/app/MainDelegate.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/app/MainDelegate.java Thu Dec 1 14:09:34 2011 @@ -136,6 +136,17 @@ public class MainDelegate implements Lau commandLine.get(SharedConstants.SLING_HOME)); } + // ensure sling.launchpad is set + if (!commandLine.containsKey(SharedConstants.SLING_LAUNCHPAD)) { + commandLine.put(SharedConstants.SLING_LAUNCHPAD, slingHome); + } + + // check sling.properties in the command line + final String slingPropertiesProp = commandLine.remove(SharedConstants.SLING_PROPERTIES); + if (slingPropertiesProp != null) { + props.put(SharedConstants.SLING_PROPERTIES, slingPropertiesProp); + } + // set up and configure Felix Logger int logLevel; if (!commandLine.containsKey(PROP_LOG_LEVEL)) { Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java Thu Dec 1 14:09:34 2011 @@ -171,11 +171,15 @@ class BootstrapInstaller { */ boolean install() throws IOException { - String slingHome = bundleContext.getProperty(SharedConstants.SLING_HOME); - File slingStartupDir = getSlingStartupDir(slingHome); + String launchpadHome = bundleContext.getProperty(SharedConstants.SLING_LAUNCHPAD); + if (launchpadHome == null) { + launchpadHome = bundleContext.getProperty(SharedConstants.SLING_HOME); + } + File slingStartupDir = getSlingStartupDir(launchpadHome); // execute bootstrap commands, if needed - final BootstrapCommandFile cmd = new BootstrapCommandFile(logger, new File(slingHome, BOOTSTRAP_CMD_FILENAME)); + final BootstrapCommandFile cmd = new BootstrapCommandFile(logger, + new File(launchpadHome, BOOTSTRAP_CMD_FILENAME)); boolean requireRestart = cmd.execute(bundleContext); boolean shouldInstall = false; Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java Thu Dec 1 14:09:34 2011 @@ -394,7 +394,7 @@ public class Sling { // Try to load it from one of these places. final Map staticProps = new HashMap(); - // Read the properties file. + // Read the embedded (default) properties file. this.load(staticProps, CONFIG_PROPERTIES); // resolve inclusions (and remove property) @@ -418,7 +418,7 @@ public class Sling { // overlay with ${sling.home}/sling.properties this.logger.log(Logger.LOG_INFO, "Starting Apache Sling in " + slingHome); - File propFile = new File(slingHome, CONFIG_PROPERTIES); + File propFile = getSlingProperties(slingHome, staticProps); this.load(staticProps, propFile); // migrate old properties to new properties @@ -545,6 +545,7 @@ public class Sling { // remove properties where overlay makes no sense tmp.remove(SharedConstants.SLING_HOME); + tmp.remove(SharedConstants.SLING_LAUNCHPAD); tmp.remove(SharedConstants.SLING_PROPERTIES); tmp.store(os, "Overlay properties for configuration"); @@ -771,6 +772,20 @@ public class Sling { // ---------- Property file support ---------------------------------------- /** + * Returns the abstract path name to the sling.properties file. + */ + private File getSlingProperties(final String slingHome, + final Map properties) { + final String prop = properties.get(SharedConstants.SLING_PROPERTIES); + if (prop == null) { + return new File(slingHome, CONFIG_PROPERTIES); + } + + final File propFile = new File(prop); + return propFile.isAbsolute() ? propFile : new File(slingHome, prop); + } + + /** * Looks for sling.include and sling.include.* * properties in the props and loads properties form the * respective locations. @@ -1054,8 +1069,8 @@ public class Sling { OutputStream os = null; try { final long lastModified = url.openConnection().getLastModified(); - final File slingHome = new File(props.get(SharedConstants.SLING_HOME)); - final File cmdFile = new File(slingHome, BootstrapInstaller.BOOTSTRAP_CMD_FILENAME); + final File launchpadHome = new File(props.get(SharedConstants.SLING_LAUNCHPAD)); + final File cmdFile = new File(launchpadHome, BootstrapInstaller.BOOTSTRAP_CMD_FILENAME); boolean copyFile = true; if ( cmdFile.exists() && cmdFile.lastModified() >= lastModified ) { copyFile = false; Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/SlingFelix.java Thu Dec 1 14:09:34 2011 @@ -33,7 +33,7 @@ public class SlingFelix extends Felix { private final Notifiable notifiable; - private Notifier notifierThread; + private Thread notifierThread; public SlingFelix(Notifiable notifiable, Map props) throws Exception { super(props); @@ -47,8 +47,17 @@ public class SlingFelix extends Felix { @Override public void update(InputStream is) throws BundleException { - // get the update file - startNotifier(true, is); + // get the update file and make sure, the stream is closed + try { + startNotifier(true, is); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException ignore) { + } + } + } // just stop the framework now super.stop(); @@ -67,20 +76,20 @@ public class SlingFelix extends Felix { private synchronized void startNotifier(boolean restart, InputStream ins) { if (notifierThread == null) { - notifierThread = new Notifier(restart, ins); + notifierThread = new Thread(new Notifier(restart, ins), + "Sling Notifier"); notifierThread.setDaemon(false); notifierThread.start(); } } - private class Notifier extends Thread { + private class Notifier implements Runnable { private final boolean restart; private final File updateFile; private Notifier(boolean restart, InputStream ins) { - super("Sling Notifier"); this.restart = restart; if (ins != null) { @@ -92,25 +101,24 @@ public class SlingFelix extends Felix { // TOOD: log tmpFile = null; } - updateFile = tmpFile; + this.updateFile = tmpFile; } else { - updateFile = null; + this.updateFile = null; } } - @Override public void run() { try { - waitForStop(0); + SlingFelix.this.waitForStop(0); } catch (InterruptedException ie) { // TODO: log } if (restart) { - notifiable.updated(updateFile); + SlingFelix.this.notifiable.updated(updateFile); } else { - notifiable.stopped(); + SlingFelix.this.notifiable.stopped(); } } } Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/Loader.java Thu Dec 1 14:09:34 2011 @@ -46,32 +46,37 @@ import org.apache.sling.commons.osgi.bun public class Loader { /** - * The Sling home folder set by the constructor + * The launchpad home folder set by the constructor */ - private final File slingHome; + private final File launchpadHome; /** - * Creates a loader instance to load from the given Sling home folder. - * Besides ensuring the existence of the Sling home folder, the constructor - * also removes all but the most recent launcher JAR files from the Sling - * home folder (thus cleaning up from previous upgrades). + * Creates a loader instance to load from the given launchpad home folder. + * Besides ensuring the existence of the launchpad home folder, the + * constructor also removes all but the most recent launcher JAR files from + * the Sling home folder (thus cleaning up from previous upgrades). * - * @param slingHome The Sling home folder. If this is null the - * default value {@link SharedConstants#SLING_HOME_DEFAULT} is - * assumed. - * @throws IllegalArgumentException If the Sling home folder exists but is - * not a directory or if the Sling home folder cannot be - * created. + * @param launchpadHome The launchpad home folder. This must not be + * null or an empty string. + * @throws IllegalArgumentException If the launchpadHome + * argument is null or an empty string or if the + * launchpad home folder exists but is not a directory or if the + * Sling home folder cannot be created. */ - public Loader(final String slingHome) throws IllegalArgumentException { - this.slingHome = getSlingHomeFile(slingHome); + public Loader(final File launchpadHome) { + if (launchpadHome == null) { + throw new IllegalArgumentException( + "Launchpad Home folder must not be null or empty"); + } + + this.launchpadHome = getLaunchpadHomeFile(launchpadHome); removeOldLauncherJars(); } /** * Creates an URLClassLoader from a _launcher JAR_ file in the given - * slingHome directory and loads and returns the launcher class identified - * by the launcherClassName. + * launchpadHome directory and loads and returns the launcher class + * identified by the launcherClassName. * * @param launcherClassName The fully qualified name of a class implementing * the Launcher interface. This class must have a public @@ -123,7 +128,6 @@ public class Loader { * *

* This method must be called when the notifier is called. - * */ public void cleanupVM() { @@ -138,35 +142,36 @@ public class Loader { /** * Copies the contents of the launcher JAR as indicated by the URL to the - * sling home directory. If the existing file is is a more recent bundle version - * than the supplied launcher JAR file, it is is not replaced. + * sling home directory. If the existing file is is a more recent bundle + * version than the supplied launcher JAR file, it is is not replaced. * * @return true if the launcher JAR file has been installed or * updated, false otherwise. * @throws IOException If an error occurrs transferring the contents */ public boolean installLauncherJar(URL launcherJar) throws IOException { + info("Checking launcher JAR in folder " + launchpadHome); final File currentLauncherJarFile = getLauncherJarFile(); // Copy the new launcher jar to a temporary file, and // extract bundle version info final URLConnection launcherJarConn = launcherJar.openConnection(); launcherJarConn.setUseCaches(false); - final File tmp = new File(slingHome, "Loader_tmp_" + System.currentTimeMillis() + SharedConstants.LAUNCHER_JAR_REL_PATH); + final File tmp = new File(launchpadHome, "Loader_tmp_" + System.currentTimeMillis() + SharedConstants.LAUNCHER_JAR_REL_PATH); spool(launcherJarConn.getInputStream(), tmp); final FileBundleVersionInfo newVi = new FileBundleVersionInfo(tmp); boolean installNewLauncher = true; - + try { if(!newVi.isBundle()) { throw new IllegalArgumentException("New launcher jar is not a bundle, cannot get version info:" + launcherJar); } - + // Compare versions to decide whether to use the existing or new launcher jar if (currentLauncherJarFile.exists()) { final FileBundleVersionInfo currentVi = new FileBundleVersionInfo(currentLauncherJarFile); if(!currentVi.isBundle()) { - throw new IllegalArgumentException("Existing launcher jar is not a bundle, cannot get version info:" + throw new IllegalArgumentException("Existing launcher jar is not a bundle, cannot get version info:" + currentLauncherJarFile.getAbsolutePath()); } @@ -178,9 +183,9 @@ public class Loader { info = "more recent than ours"; installNewLauncher = false; } - + if(info != null) { - info("Existing launcher is " + info + ", using it: " + info("Existing launcher is " + info + ", using it: " + getBundleInfo(currentVi) + " (" + currentLauncherJarFile.getName() + ")"); } } @@ -200,7 +205,7 @@ public class Loader { return installNewLauncher; } - + /** Return relevant bundle version info for logging */ static String getBundleInfo(BundleVersionInfo v) { final StringBuilder sb = new StringBuilder(); @@ -216,13 +221,13 @@ public class Loader { * Removes old candidate launcher JAR files leaving the most recent one as * the launcher JAR file to use on next Sling startup. * - * @param slingHome The Sling home directory location containing the + * @param launchpadHome The Sling home directory location containing the * candidate launcher JAR files. */ private void removeOldLauncherJars() { final File[] launcherJars = getLauncherJarFiles(); if (launcherJars != null && launcherJars.length > 0) { - + // Remove all files except current one final File current = getLauncherJarFile(); for(File f : launcherJars) { @@ -241,7 +246,7 @@ public class Loader { // And ensure the current file has the standard launcher name if (!SharedConstants.LAUNCHER_JAR_REL_PATH.equals(current.getName())) { - info("Renaming current launcher jar " + current.getName() + info("Renaming current launcher jar " + current.getName() + " to " + SharedConstants.LAUNCHER_JAR_REL_PATH); File launcherFileName = new File( current.getParentFile(), @@ -296,7 +301,7 @@ public class Loader { if (launcherJars == null || launcherJars.length == 0) { // return a non-existing file naming the desired primary name - result = new File(slingHome, + result = new File(launchpadHome, SharedConstants.LAUNCHER_JAR_REL_PATH); } else { @@ -308,28 +313,28 @@ public class Loader { } /** - * Returns all files in the slingHome directory which may be - * considered as launcher JAR files, sorted based on their bundle version + * Returns all files in the launchpadHome directory which may + * be considered as launcher JAR files, sorted based on their bundle version * information, most recent last. These files all start with the * {@link SharedConstants#LAUNCHER_JAR_REL_PATH}. This list may be empty if * the launcher JAR file has not been installed yet. * - * @param slingHome The sling home directory where the launcher JAR files - * are stored + * @param launchpadHome The sling home directory where the launcher JAR + * files are stored * @return The list of candidate launcher JAR files, which may be empty. * null is returned if an IO error occurs trying to * list the files. */ private File[] getLauncherJarFiles() { // Get list of files with names starting with our prefix - final File[] rawList = slingHome.listFiles(new FileFilter() { + final File[] rawList = launchpadHome.listFiles(new FileFilter() { public boolean accept(File pathname) { return pathname.isFile() && pathname.getName().startsWith( SharedConstants.LAUNCHER_JAR_REL_PATH); } }); - + // Keep only those which have valid Bundle headers, and // sort them according to the bundle version numbers final List list = new ArrayList(); @@ -355,34 +360,29 @@ public class Loader { } /** - * Returns the slingHome path as a directory. If the directory - * does not exist it is created. If creation fails or if - * slingHome exists but is not a directory a + * Returns the launchpadHome path as a directory. If the + * directory does not exist it is created. If creation fails or if + * launchpadHome exists but is not a directory a * IllegalArgumentException is thrown. * - * @param slingHome The sling home directory where the launcher JAR files - * are stored + * @param launchpadHome The sling home directory where the launcher JAR + * files are stored * @return The Sling home directory - * @throws IllegalArgumentException if slingHome exists and is - * not a directory or cannot be created as a directory. + * @throws IllegalArgumentException if launchpadHome exists and + * is not a directory or cannot be created as a directory. */ - private static File getSlingHomeFile(String slingHome) { - if (slingHome == null) { - slingHome = SharedConstants.SLING_HOME_DEFAULT; - } - - File slingDir = new File(slingHome).getAbsoluteFile(); - if (slingDir.exists()) { - if (!slingDir.isDirectory()) { - throw new IllegalArgumentException("Sling Home " + slingDir + private static File getLaunchpadHomeFile(File launchpadHome) { + if (launchpadHome.exists()) { + if (!launchpadHome.isDirectory()) { + throw new IllegalArgumentException("Sling Home " + launchpadHome + " exists but is not a directory"); } - } else if (!slingDir.mkdirs()) { - throw new IllegalArgumentException("Sling Home " + slingDir + } else if (!launchpadHome.mkdirs()) { + throw new IllegalArgumentException("Sling Home " + launchpadHome + " cannot be created as a directory"); } - return slingDir; + return launchpadHome; } private static void closeLauncherJarFile(final File launcherJar) { Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java Thu Dec 1 14:09:34 2011 @@ -108,4 +108,11 @@ public interface SharedConstants { */ public static final String SLING_PROPERTIES_URL = "sling.properties.url"; + /** + * The name of the configuration property defining the location for the + * Sling launchpad JAR file and the startup folder containing bundles + * to be installed by the Bootstrap Installer (value is "sling.launchpad"). + * @since 2.4.0 + */ + public static final String SLING_LAUNCHPAD = "sling.launchpad"; } Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/webapp/SlingServletDelegate.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/webapp/SlingServletDelegate.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/webapp/SlingServletDelegate.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/webapp/SlingServletDelegate.java Thu Dec 1 14:09:34 2011 @@ -46,7 +46,6 @@ import org.apache.sling.launchpad.base.s import org.apache.sling.launchpad.base.shared.SharedConstants; import org.osgi.framework.Bundle; import org.osgi.framework.BundleException; -import org.osgi.framework.ServiceEvent; import org.osgi.framework.ServiceReference; /** @@ -153,6 +152,8 @@ public class SlingServletDelegate extend private Notifiable notifiable; + private Map properties; + private String slingHome; public void setNotifiable(Notifiable notifiable) { @@ -160,7 +161,7 @@ public class SlingServletDelegate extend } public void setCommandLine(Map args) { - // ignore this for now + this.properties = args; } public void setSlingHome(String slingHome) { @@ -343,20 +344,24 @@ public class SlingServletDelegate extend // prevent system properties from being considered props.put(Sling.SLING_IGNORE_SYSTEM_PROPERTIES, "true"); - // copy context init parameters - @SuppressWarnings("unchecked") - Enumeration cpe = getServletContext().getInitParameterNames(); - while (cpe.hasMoreElements()) { - String name = cpe.nextElement(); - props.put(name, getServletContext().getInitParameter(name)); - } + if (this.properties != null) { + props.putAll(this.properties); + } else { + // copy context init parameters + @SuppressWarnings("unchecked") + Enumeration cpe = getServletContext().getInitParameterNames(); + while (cpe.hasMoreElements()) { + String name = cpe.nextElement(); + props.put(name, getServletContext().getInitParameter(name)); + } - // copy servlet init parameters - @SuppressWarnings("unchecked") - Enumeration pe = getInitParameterNames(); - while (pe.hasMoreElements()) { - String name = pe.nextElement(); - props.put(name, getInitParameter(name)); + // copy servlet init parameters + @SuppressWarnings("unchecked") + Enumeration pe = getInitParameterNames(); + while (pe.hasMoreElements()) { + String name = pe.nextElement(); + props.put(name, getInitParameter(name)); + } } // ensure the Felix Logger loglevel matches the Sling log level @@ -376,6 +381,11 @@ public class SlingServletDelegate extend // set sling home props.put(SharedConstants.SLING_HOME, slingHome); + // ensure sling.launchpad is set + if (!props.containsKey(SharedConstants.SLING_LAUNCHPAD)) { + props.put(SharedConstants.SLING_LAUNCHPAD, slingHome); + } + return props; } Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java Thu Dec 1 14:09:34 2011 @@ -22,6 +22,7 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -80,6 +81,8 @@ public class SlingServlet extends Generi */ private static final String SLING_HOME_PREFIX_DEFAULT = "sling/"; + private Map properties; + private String slingHome; private Loader loader; @@ -107,9 +110,10 @@ public class SlingServlet extends Generi */ @Override public void init() { + this.properties = collectInitParameters(); - slingHome = getSlingHome(null); - if (slingHome != null) { + this.slingHome = getSlingHome(null); + if (this.slingHome != null) { startSling(); } else { log("Apache Sling cannot be started yet, because sling.home is not defined yet"); @@ -260,13 +264,11 @@ public class SlingServlet extends Generi private void startSling(final ServletRequest request) { if (startingSling == null) { slingHome = getSlingHome((HttpServletRequest) request); - Thread starter = new Thread("SlingStarter_" - + System.currentTimeMillis()) { - @Override + Thread starter = new Thread(new Runnable() { public void run() { startSling(); } - }; + }, "SlingStarter_" + System.currentTimeMillis()); starter.setDaemon(true); starter.start(); @@ -280,7 +282,8 @@ public class SlingServlet extends Generi private void startSling() { try { - this.loader = new Loader(slingHome) { + File launchpadHome = getLaunchpadHome(slingHome); + this.loader = new Loader(launchpadHome) { @Override protected void info(String msg) { log(msg); @@ -350,6 +353,7 @@ public class SlingServlet extends Generi if (sling instanceof Launcher) { Launcher slingLauncher = (Launcher) sling; slingLauncher.setNotifiable(this); + slingLauncher.setCommandLine(properties); slingLauncher.setSlingHome(slingHome); } @@ -386,6 +390,9 @@ public class SlingServlet extends Generi * does not provide the Servlet API 2.5 * ServletContext.getContextPath() method and the * request parameter is null. + *

+ * If sling.home can be retrieved, it is returned as an + * absolute path. * * @param args The command line arguments * @return The value to use for sling.home or null if the value @@ -395,6 +402,8 @@ public class SlingServlet extends Generi String source = null; + // access config and context to be able to log the sling.home source + // 1. servlet config parameter String slingHome = getServletConfig().getInitParameter( SharedConstants.SLING_HOME); @@ -440,13 +449,50 @@ public class SlingServlet extends Generi } } - slingHome = substVars(slingHome, null, null, null); + // substitute any ${...} references and make absolute + slingHome = substVars(slingHome); + slingHome = new File(slingHome).getAbsolutePath(); log("Setting sling.home=" + slingHome + " (" + source + ")"); return slingHome; } /** + * Define the sling.launchpad parameter implementing the algorithme defined + * on the wiki page to find the setting according to this algorithm: + *

    + *
  1. Servlet init parameter sling.launchpad. This path is + * resolved against the slingHome folder if relative.
  2. + *
  3. Servlet context init parameter sling.launchpad. This + * path is resolved against the slingHome folder if relative.
  4. + *
  5. Default to same as sling.home
  6. + *
+ *

+ * The absolute path of the returned file is stored as the + * sling.launchpad property in the {@link #properties} map. + * + * @param slingHome The absolute path to the Sling Home folder (aka the + * sling.home. + * @return The absolute File indicating the launchpad folder. + */ + private File getLaunchpadHome(final String slingHome) { + String launchpadHomeParam = properties.get(SharedConstants.SLING_LAUNCHPAD); + if (launchpadHomeParam == null || launchpadHomeParam.length() == 0) { + properties.put(SharedConstants.SLING_LAUNCHPAD, slingHome); + return new File(slingHome); + } + + File launchpadHome = new File(launchpadHomeParam); + if (!launchpadHome.isAbsolute()) { + launchpadHome = new File(slingHome, launchpadHomeParam); + } + + properties.put(SharedConstants.SLING_LAUNCHPAD, + launchpadHome.getAbsolutePath()); + return launchpadHome; + } + + /** * Converts the servlet context path to a path used for the sling.home * property. The servlet context path is converted to a simple name by * replacing all slash characters in the path with underscores (or a single @@ -497,6 +543,19 @@ public class SlingServlet extends Generi // ---------- Property file variable substition support -------------------- + private Map collectInitParameters() { + HashMap props = new HashMap(); + for (Enumeration keys = getServletContext().getInitParameterNames(); keys.hasMoreElements();) { + String key = keys.nextElement(); + props.put(key, getServletContext().getInitParameter(key)); + } + for (Enumeration keys = getServletConfig().getInitParameterNames(); keys.hasMoreElements();) { + String key = keys.nextElement(); + props.put(key, getServletConfig().getInitParameter(key)); + } + return props; + } + /** * The starting delimiter of variable names (value is "${"). */ @@ -507,6 +566,14 @@ public class SlingServlet extends Generi */ private static final String DELIM_STOP = "}"; + private String substVars(final String val) { + if (val.contains(DELIM_START)) { + return substVars(val, null, null, properties); + } + + return val; + } + /** * This method performs property variable substitution on the specified * value. If the specified value contains the syntax Modified: sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/MainTest.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/MainTest.java?rev=1209095&r1=1209094&r2=1209095&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/MainTest.java (original) +++ sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/MainTest.java Thu Dec 1 14:09:34 2011 @@ -271,6 +271,25 @@ public class MainTest extends TestCase { assertNull(props2); } + public void test_converCommandLineArgs_i() { + Map props = Main.convertCommandLineArgs(new HashMap() { + { + put("i", "launchpad"); + } + }); + assertNotNull(props); + assertEquals(1, props.size()); + assertEquals("launchpad", props.get(SharedConstants.SLING_LAUNCHPAD)); + + Map props2 = Main.convertCommandLineArgs(new HashMap() { + { + final String i = "i"; + put(i, i); + } + }); + assertNull(props2); + } + public void test_converCommandLineArgs_a() { Map props = Main.convertCommandLineArgs(new HashMap() { { @@ -306,4 +325,32 @@ public class MainTest extends TestCase { }); assertNull(props2); } + + public void test_converCommandLineArgs_D() { + Map props = Main.convertCommandLineArgs(new HashMap() { + { + put("D", "name=value"); + } + }); + assertNotNull(props); + assertEquals(1, props.size()); + assertEquals("value", props.get("name")); + + Map props2 = Main.convertCommandLineArgs(new HashMap() { + { + put("D", "flag"); + } + }); + assertNotNull(props2); + assertEquals(1, props2.size()); + assertEquals("flag", props2.get("flag")); + + Map props1 = Main.convertCommandLineArgs(new HashMap() { + { + final String d = "D"; + put(d, d); + } + }); + assertNull(props1); + } }