Author: fmeschbe
Date: Tue Nov 10 10:16:13 2009
New Revision: 834413
URL: http://svn.apache.org/viewvc?rev=834413&view=rev
Log:
SLING-1095 Ensure proper updates of the Sling launcher JAR (see issue
for full description of the changes)
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/shared/LauncherClassLoader.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/webapp/SlingServlet.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=834413&r1=834412&r2=834413&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
Tue Nov 10 10:16:13 2009
@@ -51,7 +51,7 @@
// The name of the environment variable to consult to find out
// about sling.home
private static final String ENV_SLING_HOME = "SLING_HOME";
-
+
public static void main(String[] args) {
new Main(args);
}
@@ -60,6 +60,8 @@
private final String slingHome;
+ private final Loader loader;
+
private Launcher sling;
private Main(String[] args) {
@@ -71,13 +73,28 @@
// support usage first
doHelp();
-
+
// check for control commands (might exit)
doControlCommand();
-
+
// sling.home from the command line or system properties, else default
this.slingHome = getSlingHome(commandLineArgs);
- info("Starting Sling in " + slingHome, null);
+ File slingHomeFile = new File(slingHome);
+ if (slingHomeFile.isAbsolute()) {
+ info("Starting Sling in " + slingHome, null);
+ } else {
+ info("Starting Sling in " + slingHome + " ("
+ + slingHomeFile.getAbsolutePath() + ")", null);
+ }
+
+ // The Loader helper
+ Loader loaderTmp = null;
+ try {
+ loaderTmp = new Loader(slingHome);
+ } catch (IllegalArgumentException iae) {
+ startupFailure(iae.getMessage(), null);
+ }
+ this.loader = loaderTmp;
Runtime.getRuntime().addShutdownHook(this);
@@ -104,7 +121,7 @@
sling.stop();
}
}
-
+
// ---------- Notifiable interface
/**
@@ -148,6 +165,13 @@
* used again.
*/
public void updated(File updateFile) {
+
+ // clear the reference to the framework
+ sling = null;
+
+ // ensure we have a VM as clean as possible
+ loader.cleanupVM();
+
if (updateFile == null) {
info("Restarting Framework and Sling", null);
@@ -186,30 +210,28 @@
if (launcherJar != null) {
try {
info("Checking launcher JAR in " + slingHome, null);
- if (Loader.installLauncherJar(launcherJar, slingHome)) {
+ if (loader.installLauncherJar(launcherJar)) {
info("Installed or Updated launcher JAR file from "
+ launcherJar, null);
} else {
info("Existing launcher JAR file already up to date",
null);
}
} catch (IOException ioe) {
- error("Failed installing " + launcherJar, ioe);
+ startupFailure("Failed installing " + launcherJar, ioe);
}
} else {
info("No Launcher JAR to install", null);
}
- Object object;
+ Object object = null;
try {
info(
"Loading launcher class " + SharedConstants.DEFAULT_SLING_MAIN,
null);
- object = Loader.loadLauncher(SharedConstants.DEFAULT_SLING_MAIN,
- slingHome);
+ object = loader.loadLauncher(SharedConstants.DEFAULT_SLING_MAIN);
} catch (IllegalArgumentException iae) {
- error("Failed loading Sling class "
+ startupFailure("Failed loading Sling class "
+ SharedConstants.DEFAULT_SLING_MAIN, iae);
- return;
}
if (object instanceof Launcher) {
@@ -246,9 +268,9 @@
* <tr><td>-y -z</td><td>y -> y, z -> z</td></tr>
* <tr><td>-y x - -z a</td><td>y -> x, -z -> -z, a -> a</td></tr>
* </table>
- *
+ *
* @param args The command line to parse
- *
+ *
* @return The map of command line options and their values
*/
static Map<String, String> parseCommandLine(String[] args) {
@@ -256,7 +278,7 @@
boolean readUnparsed = false;
for (int argc = 0; args != null && argc < args.length; argc++) {
String arg = args[argc];
-
+
if (readUnparsed) {
commandLine.put(arg, arg);
} else if (arg.startsWith("-")) {
@@ -283,7 +305,7 @@
}
return commandLine;
}
-
+
/**
* Define the sling.home parameter implementing the algorithme defined on
* the wiki page to find the setting according to this algorithm:
@@ -302,28 +324,28 @@
String slingHome = commandLine.get("c");
if (slingHome != null) {
-
+
source = "command line";
} else {
-
+
slingHome = System.getProperty(SharedConstants.SLING_HOME);
if (slingHome != null) {
-
+
source = "system property sling.home";
-
+
} else {
-
+
slingHome = System.getenv(ENV_SLING_HOME);
if (slingHome != null) {
-
+
source = "environment variable SLING_HOME";
-
+
} else {
-
+
source = "default";
slingHome = SharedConstants.SLING_HOME_DEFAULT;
-
+
}
}
}
@@ -332,6 +354,12 @@
return slingHome;
}
+ private void startupFailure(String message, Throwable cause) {
+ error("Launcher JAR access failure: " + message, cause);
+ error("Shutting Down", null);
+ System.exit(1);
+ }
+
// ---------- logging
// emit an informational message to standard out
@@ -383,7 +411,7 @@
System.out.println("usage: "
+ Main.class.getName()
+ " [ start | stop | status ] [ -j adr ] [ -l loglevel ] [ -f
logfile ] [ -c slinghome ] [ -a address ] [ -p port ] [ -h ]");
-
+
System.out.println(" start listen for control
connection (uses -j)");
System.out.println(" stop terminate running Sling
(uses -j)");
System.out.println(" start check whether Sling is
running (uses-j)");
@@ -394,11 +422,11 @@
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(" -h prints this usage message");
-
+
System.exit(0);
}
}
-
+
private void doControlCommand() {
String commandSocketSpec = commandLineArgs.remove("j");
if ("j".equals(commandSocketSpec)) {
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=834413&r1=834412&r2=834413&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
Tue Nov 10 10:16:13 2009
@@ -158,7 +158,7 @@
try {
ResourceProvider resProvider = new ClassLoaderResourceProvider(
- MainDelegate.class.getClassLoader());
+ getClass().getClassLoader());
// creating the instance launches the framework and we are done
here
// ..
Modified:
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
URL:
http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java?rev=834413&r1=834412&r2=834413&view=diff
==============================================================================
---
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
(original)
+++
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/LauncherClassLoader.java
Tue Nov 10 10:16:13 2009
@@ -74,7 +74,7 @@
private final Set<String> launcherPackages;
LauncherClassLoader(File launcherJar) throws MalformedURLException {
- super(new URL[] { launcherJar.toURL() },
+ super(new URL[] { launcherJar.toURI().toURL() },
LauncherClassLoader.class.getClassLoader());
Set<String> collectedPackages = new HashSet<String>();
@@ -171,7 +171,7 @@
* <p>
* Example: Called for <i>org.osgi.framework.Bundle</i> this method returns
* <i>org.osgi.framework</i>.
- *
+ *
* @param name The fully qualified name of the class or resource to check
* @param separator The separator for package segments
*/
@@ -183,7 +183,7 @@
/**
* Returns <code>true</code> if the launcher JAR file provides the package
* to which the named class or resource belongs.
- *
+ *
* @param name The fully qualified name of the class or resource to check
* @param separator The separator for package segments
*/
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=834413&r1=834412&r2=834413&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
Tue Nov 10 10:16:13 2009
@@ -20,13 +20,17 @@
import java.beans.Introspector;
import java.io.File;
+import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.JarURLConnection;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
+import java.util.jar.JarFile;
/**
* The <code>Loader</code> class provides utility methods for the actual
@@ -35,6 +39,36 @@
public class Loader {
/**
+ * The Sling home folder set by the constructor
+ */
+ private final File slingHome;
+
+ /**
+ * The current launcher JAR file in use. Set on-demand by the
+ * {...@link #getLauncherJarFile()} method and reset to the installed or
+ * updated launcher JAR file by the {...@link #installLauncherJar(URL)}
method.
+ */
+ private File launcherJarFile;
+
+ /**
+ * 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).
+ *
+ * @param slingHome The Sling home folder. If this is <code>null</code> 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.
+ */
+ public Loader(final String slingHome) throws IllegalArgumentException {
+ this.slingHome = getSlingHomeFile(slingHome);
+ 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.
@@ -52,15 +86,15 @@
* instantiated. The cause of the failure is contained as the
* cause of the exception.
*/
- public static Object loadLauncher(String launcherClassName, String
slingHome) {
+ public Object loadLauncher(String launcherClassName) {
- File launcherJarFile = getLauncherJarFile(slingHome);
+ final File launcherJarFile = getLauncherJarFile();
if (!launcherJarFile.canRead()) {
throw new IllegalArgumentException("Sling Launcher JAR "
+ launcherJarFile + " is not accessible");
}
- ClassLoader loader;
+ final ClassLoader loader;
try {
loader = new LauncherClassLoader(launcherJarFile);
} catch (MalformedURLException e) {
@@ -69,7 +103,7 @@
}
try {
- Class<?> launcherClass = loader.loadClass(launcherClassName);
+ final Class<?> launcherClass = loader.loadClass(launcherClassName);
return launcherClass.newInstance();
} catch (ClassNotFoundException cnfe) {
throw new IllegalArgumentException("Cannot find class "
@@ -88,16 +122,23 @@
* Java VM as possible. Most notably the following traces are removed:
* <ul>
* <li>JavaBeans property caches
+ * <li>Close the Launcher Jar File (if opened by the platform)
* </ul>
* <p>
* This method must be called when the notifier is called.
+ *
+ * @param slingHome The home directory of Sling. This is used to ensure the
+ * launcher jar file is not open anymore (as much as possible).
*/
- public static void cleanupVM() {
+ public void cleanupVM() {
// ensure the JavaBeans introspector lets go of any classes it
// may haved cached after introspection
Introspector.flushCaches();
+ // if sling home is set, check whether we have to close the
+ // launcher JAR JarFile, which might be cached in the platform
+ closeLauncherJarFile(getLauncherJarFile());
}
/**
@@ -111,27 +152,82 @@
* <code>false</code> is returned.
* @throws IOException If an error occurrs transferring the contents
*/
- public static boolean installLauncherJar(URL launcherJar, String slingHome)
- throws IOException {
- File launcherJarDestFile = getLauncherJarFile(slingHome);
+ public boolean installLauncherJar(URL launcherJar) throws IOException {
+ final File currentLauncherJarFile = getLauncherJarFile();
// check whether we have to overwrite
- URLConnection launcherJarConn = launcherJar.openConnection();
- long lastModifTime = launcherJarConn.getLastModified();
- if (launcherJarDestFile.exists()) {
- if (lastModifTime <= launcherJarDestFile.lastModified()) {
+ final URLConnection launcherJarConn = launcherJar.openConnection();
+ launcherJarConn.setUseCaches(false);
+ final long lastModifTime = launcherJarConn.getLastModified();
+ final File newLauncherJarFile;
+ if (currentLauncherJarFile.exists()) {
+
+ // nothing to do if there is no update
+ if (lastModifTime <= currentLauncherJarFile.lastModified()) {
return false;
}
- launcherJarDestFile.delete();
+
+ // use a new timestamped name for the new version
+ newLauncherJarFile = new File(slingHome,
+ SharedConstants.LAUNCHER_JAR_REL_PATH + "." + lastModifTime);
+
+ } else {
+
+ // create the current file
+ newLauncherJarFile = currentLauncherJarFile;
+
}
- spool(launcherJarConn.getInputStream(), launcherJarDestFile);
+ // store the new launcher JAR and set the last modification time
+ spool(launcherJarConn.getInputStream(), newLauncherJarFile);
+ newLauncherJarFile.setLastModified(lastModifTime);
+ launcherJarFile = newLauncherJarFile;
- launcherJarDestFile.setLastModified(lastModifTime);
return true;
}
/**
+ * 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
+ * candidate launcher JAR files.
+ */
+ private void removeOldLauncherJars() {
+ final File[] launcherJars = getLauncherJarFiles();
+ if (launcherJars != null && launcherJars.length > 0) {
+
+ // start with the first entry being the newest
+ File mostRecentJarFile = launcherJars[0];
+ long mostRecentLastModification = mostRecentJarFile.lastModified();
+ for (int i = 1; i < launcherJars.length; i++) {
+
+ if (mostRecentLastModification <
launcherJars[i].lastModified()) {
+ // if this entry is newer than the fromer newest, remove
+ // the former file and use this entry as the newest
+ mostRecentJarFile.delete();
+ mostRecentJarFile = launcherJars[i];
+ mostRecentLastModification =
mostRecentJarFile.lastModified();
+
+ } else {
+ // otherwise remove this entry and keep on using the
current
+ launcherJars[i].delete();
+ }
+
+ }
+ // fact: mostRecentJarFile is the only remaining and the most
recent
+
+ // ensure the most recent file has the common name
+ if
(!SharedConstants.LAUNCHER_JAR_REL_PATH.equals(mostRecentJarFile.getName())) {
+ File launcherFileName = new File(
+ mostRecentJarFile.getParentFile(),
+ SharedConstants.LAUNCHER_JAR_REL_PATH);
+ mostRecentJarFile.renameTo(launcherFileName);
+ }
+ }
+ }
+
+ /**
* Spools the contents of the input stream to the given file replacing the
* contents of the file with the contents of the input stream. When this
* method returns, the input stream is guaranteed to be closed.
@@ -164,14 +260,84 @@
}
}
+ // ---------- internal helper
+
/**
* Returns a <code>File</code> object representing the Launcher JAR file
* found in the sling home folder.
+ */
+ private File getLauncherJarFile() {
+ if (launcherJarFile == null) {
+ final File[] launcherJars = getLauncherJarFiles();
+ if (launcherJars == null || launcherJars.length == 0) {
+
+ // return a non-existing file naming the desired primary name
+ launcherJarFile = new File(slingHome,
+ SharedConstants.LAUNCHER_JAR_REL_PATH);
+
+ } else if (launcherJars.length == 1) {
+
+ // only a single file existing, that's it
+ launcherJarFile = launcherJars[0];
+
+ } else {
+
+ // start with the first entry being the newest
+ File mostRecentJarFile = launcherJars[0];
+ long mostRecentLastModification =
mostRecentJarFile.lastModified();
+ for (int i = 1; i < launcherJars.length; i++) {
+
+ // if this entry is newer than the fromer newest, use this
+ // entry
+ // as the newest
+ if (mostRecentLastModification <
launcherJars[i].lastModified()) {
+ mostRecentJarFile = launcherJars[i];
+ mostRecentLastModification =
mostRecentJarFile.lastModified();
+ }
+
+ }
+ launcherJarFile = mostRecentJarFile;
+ }
+ }
+
+ return launcherJarFile;
+ }
+
+ /**
+ * Returns all files in the <code>slingHome</code> directory which may be
+ * considered as launcher JAR files. 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
+ * @return The list of candidate launcher JAR files, which may be empty.
+ * <code>null</code> is returned if an IO error occurrs trying to
+ * list the files.
+ */
+ private File[] getLauncherJarFiles() {
+ return slingHome.listFiles(new FileFilter() {
+ public boolean accept(File pathname) {
+ return pathname.isFile()
+ && pathname.getName().startsWith(
+ SharedConstants.LAUNCHER_JAR_REL_PATH);
+ }
+ });
+ }
+
+ /**
+ * Returns the <code>slingHome</code> path as a directory. If the directory
+ * does not exist it is created. If creation fails or if
+ * <code>slingHome</code> exists but is not a directory a
+ * <code>IllegalArgumentException</code> is thrown.
*
- * @throws IllegalArgumentException if the sling home folder cannot be
- * created or exists as a non-directory filesystem entry.
+ * @param slingHome The sling home directory where the launcher JAR files
+ * are stored
+ * @return The Sling home directory
+ * @throws IllegalArgumentException if <code>slingHome</code> exists and is
+ * not a directory or cannot be created as a directory.
*/
- private static File getLauncherJarFile(String slingHome) {
+ private static File getSlingHomeFile(String slingHome) {
if (slingHome == null) {
slingHome = SharedConstants.SLING_HOME_DEFAULT;
}
@@ -187,6 +353,20 @@
+ " cannot be created as a directory");
}
- return new File(slingDir, SharedConstants.LAUNCHER_JAR_REL_PATH);
+ return slingDir;
+ }
+
+ private static void closeLauncherJarFile(final File launcherJar) {
+ try {
+ final URI launcherJarUri = launcherJar.toURI();
+ final URL launcherJarRoot = new URL("jar:" + launcherJarUri +
"!/");
+ final URLConnection conn = launcherJarRoot.openConnection();
+ if (conn instanceof JarURLConnection) {
+ final JarFile jarFile = ((JarURLConnection) conn).getJarFile();
+ jarFile.close();
+ }
+ } catch (Exception e) {
+ // better logging here
+ }
}
}
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=834413&r1=834412&r2=834413&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
Tue Nov 10 10:16:13 2009
@@ -45,7 +45,7 @@
* <p>
* This class goes into the secondary artifact with the classifier
<i>webapp</i>
* to be used as the main servlet to be registered in the servlet container.
- *
+ *
* @see <a href="http://cwiki.apache.org/SLING/the-sling-launchpad.html">The
* Sling Launchpad</a>
*/
@@ -61,6 +61,8 @@
private String slingHome;
+ private Loader loader;
+
private Servlet sling;
/**
@@ -149,6 +151,11 @@
if (sling != null) {
sling.destroy();
}
+
+ // clear fields
+ slingHome = null;
+ loader = null;
+ sling = null;
}
// ---------- Notifiable interface
@@ -183,7 +190,7 @@
* If an <code>InputStream</code> was provided, this has been copied to a
* temporary file, which will be used in place of the existing launcher jar
* file.
- *
+ *
* @param updateFile The temporary file to replace the existing launcher
jar
* file. If <code>null</code> the existing launcher jar will be
* used again.
@@ -197,6 +204,9 @@
}
}
+ // ensure we have a VM as clean as possible
+ loader.cleanupVM();
+
if (updateFile == null) {
log("Restarting Framework and Sling");
@@ -243,6 +253,14 @@
* {...@link #init()} to install the launcher jar and actually start sling.
*/
private void startSling() {
+
+ try {
+ this.loader = new Loader(slingHome);
+ } catch (IllegalArgumentException iae) {
+ startupFailure(null, iae);
+ return;
+ }
+
try {
URL launcherJar = getServletContext().getResource(
SharedConstants.DEFAULT_SLING_LAUNCHER_JAR);
@@ -278,27 +296,26 @@
if (launcherJar != null) {
try {
log("Checking launcher JAR in " + slingHome);
- if (Loader.installLauncherJar(launcherJar, slingHome)) {
+ if (loader.installLauncherJar(launcherJar)) {
log("Installed or Updated launcher JAR file from " +
launcherJar);
} else {
log("Existing launcher JAR file is already up to date");
}
} catch (IOException ioe) {
- log("Failed installing " + launcherJar, ioe);
+ startupFailure("Failed installing " + launcherJar, ioe);
+ return;
}
} else {
log("No Launcher JAR to install");
}
- Object object = Loader.loadLauncher(
- SharedConstants.DEFAULT_SLING_SERVLET, slingHome);
+ Object object = null;
try {
log("Loading launcher class "
+ SharedConstants.DEFAULT_SLING_SERVLET);
- object = Loader.loadLauncher(SharedConstants.DEFAULT_SLING_SERVLET,
- slingHome);
+ object =
loader.loadLauncher(SharedConstants.DEFAULT_SLING_SERVLET);
} catch (IllegalArgumentException iae) {
- log("Cannot load Launcher Servlet "
+ startupFailure("Cannot load Launcher Servlet "
+ SharedConstants.DEFAULT_SLING_SERVLET, iae);
return;
}
@@ -319,13 +336,7 @@
this.startFailureCounter = 0;
log("Startup completed");
} catch (ServletException se) {
- Throwable cause = se.getCause();
- if (cause == null) {
- cause = se;
- }
-
- log("Failed to start Sling in " + slingHome, cause);
- startFailureCounter++;
+ startupFailure(null, se);
}
}
@@ -349,7 +360,7 @@
* does not provide the Servlet API 2.5
* <code>ServletContext.getContextPath()</code> method and the
* <code>request</code> parameter is <code>null</code>.
- *
+ *
* @param args The command line arguments
* @return The value to use for sling.home or <code>null</code> if the
value
* cannot be retrieved.
@@ -417,4 +428,25 @@
return prefix + contextPath.replace('/', '_');
}
+ private void startupFailure(String message, Throwable cause) {
+
+ // ensure message
+ if (message == null) {
+ message = "Failed to start Sling in " + slingHome;
+ }
+
+ // unwrap to get the real cause
+ while (cause.getCause() != null) {
+ cause = cause.getCause();
+ }
+
+ // log it now and increase the failure counter
+ log(message, cause);
+ startFailureCounter++;
+
+ // ensure the startingSling fields is not set
+ synchronized (this) {
+ startingSling = null;
+ }
+ }
}