Author: fmeschbe
Date: Mon Jan 19 06:37:41 2009
New Revision: 735715
URL: http://svn.apache.org/viewvc?rev=735715&view=rev
Log:
Documentation update
Modified:
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java
Modified:
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java
URL:
http://svn.apache.org/viewvc/incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java?rev=735715&r1=735714&r2=735715&view=diff
==============================================================================
---
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java
(original)
+++
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java
Mon Jan 19 06:37:41 2009
@@ -32,38 +32,18 @@
import org.apache.sling.launchpad.base.shared.SharedConstants;
/**
- * The <code>Main</code> class is a simple Java Application which interprests
- * the command line and creates the {...@link Sling} launcher class and thus
starts
- * the OSGi framework. In addition a shutdown thread is registered to ensure
- * proper shutdown on VM termination.
+ * The <code>Main</code> is the externally visible Standalone Java Application
+ * launcher for Sling. Please refer to the full description <i>The Sling
+ * Launchpad</i> on the Sling Wiki for a full description of this class.
* <p>
- * The supported command line options are:
- * <dl>
- * <dt>-l loglevel</dt>
- * <dd>Sets the initial loglevel as an integer in the range 0 to 4 or as one of
- * the well known level strings FATAL, ERROR, WARN, INFO or DEBUG. This option
- * overwrites the <code>org.apache.sling.osg.log.level</code> setting the
- * <code>sling.properties</code> file.</dd>
- * <dt>-f logfile</dt>
- * <dd>The log file, \"-\" for stdout (default logs/error.log). This option
- * overwrites the <code>org.apache.sling.osg.log.file</code> setting the
- * <code>sling.properties</code> file.</dd>
- * <dt>-c slinghome</dt>
- * <dd>The directory in which Sling locates its initial configuration file
- * <code>sling.properties</code> and where files of Sling itself such as the
- * Apache Felix bundle archive or the JCR repository files are stored (default
- * sling).</dd>
- * <dt>-a address</dt>
- * <dd>The interfact to bind to (use 0.0.0.0 for any). This option is not
- * implemented yet.</dd>
- * <dt>-p port</dt>
- * <dd>The port to listen (default 8080) to handle HTTP requests. This option
- * overwrites the <code>org.osgi.service.http.port</code> setting the
- * <code>sling.properties</code> file.</dd>
- * <dt>-h</dt>
- * <dd>Prints a simple usage message listing all available command line
options.
- * </dd>
- * </dl>
+ * Logging goes to standard output for informational messages and to standard
+ * error for error messages.
+ * <p>
+ * This class goes into the secondary artifact with the classifier <i>app</i>
to
+ * be used as the main class when starting the Java Application.
+ *
+ * @see <a href="http://cwiki.apache.org/SLING/the-sling-launchpad.html">The
+ * Sling Launchpad</a>
*/
public class Main extends Thread implements Notifiable {
@@ -100,50 +80,13 @@
SharedConstants.DEFAULT_SLING_LAUNCHER_JAR));
}
- private void startSling(URL launcherJar) {
- if (launcherJar != null) {
- try {
- info("Installing " + launcherJar + " to " + slingHome, null);
- Loader.installLauncherJar(launcherJar, slingHome);
- } catch (IOException ioe) {
- error("Failed installing " + launcherJar, ioe);
- }
- } else {
- info("No Launcher JAR to install", null);
- }
-
- Object object;
- try {
- info(
- "Loading launcher class " + SharedConstants.DEFAULT_SLING_MAIN,
- null);
- object = Loader.loadLauncher(SharedConstants.DEFAULT_SLING_MAIN,
- slingHome);
- } catch (IllegalArgumentException iae) {
- error("Failed loading Sling class "
- + SharedConstants.DEFAULT_SLING_MAIN, iae);
- return;
- }
-
- if (object instanceof Launcher) {
-
- // configure the launcher
- Launcher sling = (Launcher) object;
- sling.setNotifiable(this);
- sling.setCommandLine(commandLineArgs);
- sling.setSlingHome(slingHome);
-
- // launch it
- info("Starting launcher ...", null);
- if (sling.start()) {
- info("Startup completed", null);
- this.sling = sling;
- } else {
- error("There was a problem launching Sling", null);
- }
- }
- }
+ // ---------- Notifiable interface
+ /**
+ * The framework has been stopped by calling the <code>Bundle.stop()</code>
+ * on the system bundle. This actually terminates the Sling Standalone
+ * application.
+ */
public void stopped() {
/**
* This method is called if the framework is stopped from within by
@@ -167,6 +110,18 @@
}
}
+ /**
+ * The framework has been stopped with the intent to be restarted by
calling
+ * either of the <code>Bundle.update</code> methods on the system bundle.
+ * <p>
+ * 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.
+ */
public void updated(File updateFile) {
if (updateFile == null) {
@@ -187,6 +142,14 @@
}
}
+ // --------- Thread
+
+ /**
+ * Called when the Java VM is being terminiated, for example because the
+ * KILL signal has been sent to the process. This method calls stop on the
+ * launched Sling instance to terminate the framework before returning.
+ */
+ @Override
public void run() {
info("Java VM is shutting down", null);
if (sling != null) {
@@ -195,8 +158,67 @@
}
}
+ // ---------- internal
+
+ private void startSling(URL launcherJar) {
+ if (launcherJar != null) {
+ try {
+ info("Installing " + launcherJar + " to " + slingHome, null);
+ Loader.installLauncherJar(launcherJar, slingHome);
+ } catch (IOException ioe) {
+ error("Failed installing " + launcherJar, ioe);
+ }
+ } else {
+ info("No Launcher JAR to install", null);
+ }
+
+ Object object;
+ try {
+ info(
+ "Loading launcher class " + SharedConstants.DEFAULT_SLING_MAIN,
+ null);
+ object = Loader.loadLauncher(SharedConstants.DEFAULT_SLING_MAIN,
+ slingHome);
+ } catch (IllegalArgumentException iae) {
+ error("Failed loading Sling class "
+ + SharedConstants.DEFAULT_SLING_MAIN, iae);
+ return;
+ }
+
+ if (object instanceof Launcher) {
+
+ // configure the launcher
+ Launcher sling = (Launcher) object;
+ sling.setNotifiable(this);
+ sling.setCommandLine(commandLineArgs);
+ sling.setSlingHome(slingHome);
+
+ // launch it
+ info("Starting launcher ...", null);
+ if (sling.start()) {
+ info("Startup completed", null);
+ this.sling = sling;
+ } else {
+ error("There was a problem launching Sling", null);
+ }
+ }
+ }
+
+ /**
+ * Define the sling.home parameter implementing the algorithme defined on
+ * the wiki page to find the setting according to this algorithm:
+ * <ol>
+ * <li>Command line option <code>-c</code></li>
+ * <li>System property <code>sling.home</code></li>
+ * <li>Environment variable <code>SLING_HOME</code></li>
+ * <li>Default value <code>sling</code></li>
+ * </ol>
+ *
+ * @param args The command line arguments
+ * @return The value to use for sling.home
+ */
private static String getSlingHome(String[] args) {
- String message = null;
+ String source = null;
String slingHome = null;
for (int argc = 0; argc < args.length; argc++) {
@@ -205,7 +227,7 @@
&& arg.charAt(1) == 'c') {
argc++;
if (argc < args.length) {
- message = "command line";
+ source = "command line";
slingHome = args[argc];
}
break;
@@ -215,34 +237,36 @@
if (slingHome == null) {
slingHome = System.getProperty(SharedConstants.SLING_HOME);
if (slingHome != null) {
- message = "system property sling.home";
+ source = "system property sling.home";
} else {
slingHome = System.getenv(ENV_SLING_HOME);
if (slingHome != null) {
- message = "environment variable SLING_HOME";
+ source = "environment variable SLING_HOME";
} else {
- message = "default";
+ source = "default";
slingHome = SharedConstants.SLING_HOME_DEFAULT;
}
}
}
- info("Setting sling.home=" + slingHome + " (" + message + ")", null);
+ info("Setting sling.home=" + slingHome + " (" + source + ")", null);
return slingHome;
}
+ // ---------- logging
+
+ // emit an informational message to standard out
private static void info(String message, Throwable t) {
log(System.out, "INF: ", message, t);
}
- private static void warn(String message, Throwable t) {
- log(System.out, "WRN: ", message, t);
- }
-
+ // emit an error message to standard err
private static void error(String message, Throwable t) {
log(System.err, "ERR: ", message, t);
}
+ // helper method to format the message on the correct output channel
+ // the throwable if not-null is also prefixed line by line with the prefix
private static void log(PrintStream out, String prefix, String message,
Throwable t) {
out.print(prefix);
Modified:
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java
URL:
http://svn.apache.org/viewvc/incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java?rev=735715&r1=735714&r2=735715&view=diff
==============================================================================
---
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java
(original)
+++
incubator/sling/whiteboard/fmeschbe/launchpad/base/src/main/java/org/apache/sling/launchpad/webapp/SlingServlet.java
Mon Jan 19 06:37:41 2009
@@ -36,6 +36,19 @@
import org.apache.sling.launchpad.base.shared.Notifiable;
import org.apache.sling.launchpad.base.shared.SharedConstants;
+/**
+ * The <code>SlingServlet</code> is the externally visible Web Application
+ * launcher for Sling. Please refer to the full description <i>The Sling
+ * Launchpad</i> on the Sling Wiki for a full description of this class.
+ * <p>
+ * Logging goes to ServletContext.log methods.
+ * <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>
+ */
public class SlingServlet extends GenericServlet implements Notifiable {
/**
@@ -62,7 +75,15 @@
*/
private int startFailureCounter = 0;
- public void init() throws ServletException {
+ // ---------- GenericServlet
+
+ /**
+ * Launches the SLing framework if the sling.home setting can be derived
+ * from the configuration or the SerlvetContext. Otherwise Sling is not
+ * started yet and will be started when the first request comes in.
+ */
+ @Override
+ public void init() {
slingHome = getSlingHome(null);
if (slingHome != null) {
@@ -74,6 +95,7 @@
log("Servlet " + getServletName() + " initialized");
}
+ @Override
public String getServletInfo() {
if (sling != null) {
return sling.getServletInfo();
@@ -82,6 +104,19 @@
return "Sling Launchpad Proxy";
}
+ /**
+ * If Sling has already been started, the request is forwarded to the
+ * started Sling framework. Otherwise the Sling framework is started unless
+ * there were too many startup failures.
+ * <p>
+ * If the request is not forwarded to Sling, this method returns a 404/NOT
+ * FOUND if the startup failure counter has exceeded or 503/SERVICE
+ * UNAVAILABLE if the Sling framework is starting up.
+ * <p>
+ * If a request causes the framework to start, it is immediately terminated
+ * with said response status and framework is started in a separate thread.
+ */
+ @Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
@@ -106,14 +141,87 @@
}
}
+ /**
+ * Stop the Sling framework when the web application is being stopped
+ */
+ @Override
public void destroy() {
if (sling != null) {
sling.destroy();
}
}
- // -----
+ // ---------- Notifiable interface
+
+ /**
+ * The framework has been stopped by calling the <code>Bundle.stop()</code>
+ * on the system bundle. This actually terminates the Sling Standalone
+ * application.
+ * <p>
+ * Note, that a new request coming in while the web application is still
+ * running, will actually cause Sling to restart !
+ */
+ public void stopped() {
+ /**
+ * This method is called if the framework is stopped from within by
+ * calling stop on the system bundle or if the framework is stopped
+ * because the VM is going down and the shutdown hook has initated the
+ * shutdown In any case we ensure the reference to the framework is
+ * removed and remove the shutdown hook (but don't care if that fails).
+ */
+
+ log("Sling has been stopped");
+
+ // clear the reference to the framework
+ sling = null;
+ }
+
+ /**
+ * The framework has been stopped with the intent to be restarted by
calling
+ * either of the <code>Bundle.update</code> methods on the system bundle.
+ * <p>
+ * 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.
+ */
+ public void updated(File updateFile) {
+
+ // drop the sling reference to be able to restart
+ synchronized (this) {
+ if (startingSling == null) {
+ sling = null;
+ }
+ }
+
+ if (updateFile == null) {
+
+ log("Restarting Framework and Sling");
+ startSling((URL) null);
+
+ } else {
+
+ log("Restarting Framework with update from " + updateFile);
+ try {
+ startSling(updateFile.toURI().toURL());
+ } catch (MalformedURLException mue) {
+ log("Cannot get URL for file " + updateFile, mue);
+ } finally {
+ updateFile.delete();
+ }
+
+ }
+ }
+
+ // --------- internal
+ /**
+ * If Sling is not currently starting up, a thread is started to start
Sling
+ * in the background.
+ */
private void startSling(final ServletRequest request) {
if (startingSling == null) {
slingHome = getSlingHome((HttpServletRequest) request);
@@ -130,6 +238,10 @@
}
}
+ /**
+ * Called from the startup thread initiated by a request or from
+ * {...@link #init()} to install the launcher jar and actually start sling.
+ */
private void startSling() {
try {
URL launcherJar = getServletContext().getResource(
@@ -146,6 +258,10 @@
}
}
+ /**
+ * Installs the launcher jar from the given URL (if not <code>null</code>)
+ * and launches Sling from that launcher.
+ */
private void startSling(URL launcherJar) {
synchronized (this) {
if (sling != null) {
@@ -161,15 +277,20 @@
if (launcherJar != null) {
try {
+ log("Installing " + launcherJar + " to " + slingHome);
Loader.installLauncherJar(launcherJar, slingHome);
} catch (IOException ioe) {
- log("Failed installing the launcher JAR " + launcherJar, ioe);
+ log("Failed installing " + launcherJar, ioe);
}
+ } else {
+ log("No Launcher JAR to install");
}
Object object = Loader.loadLauncher(
SharedConstants.DEFAULT_SLING_SERVLET, slingHome);
try {
+ log("Loading launcher class "
+ + SharedConstants.DEFAULT_SLING_SERVLET);
object = Loader.loadLauncher(SharedConstants.DEFAULT_SLING_SERVLET,
slingHome);
} catch (IllegalArgumentException iae) {
@@ -188,9 +309,11 @@
}
try {
+ log("Starting launcher ...");
sling.init(getServletConfig());
this.sling = sling;
-
+ this.startFailureCounter = 0;
+ log("Startup completed");
} catch (ServletException se) {
Throwable cause = se.getCause();
if (cause == null) {
@@ -208,66 +331,53 @@
}
}
- public void stopped() {
- /**
- * This method is called if the framework is stopped from within by
- * calling stop on the system bundle or if the framework is stopped
- * because the VM is going down and the shutdown hook has initated the
- * shutdown In any case we ensure the reference to the framework is
- * removed and remove the shutdown hook (but don't care if that fails).
- */
-
- System.out.println("Sling has been stopped");
-
- // clear the reference to the framework
- sling = null;
- }
-
- public void updated(File updateFile) {
-
- // drop the sling reference to be able to restart
- synchronized (this) {
- if (startingSling == null) {
- sling = null;
- }
- }
-
- if (updateFile == null) {
-
- System.out.println("Restarting ....");
- startSling((URL) null);
-
- } else {
-
- System.out.println("Sling has been updated with " + updateFile);
- try {
- startSling(updateFile.toURL());
- } catch (MalformedURLException mue) {
- // TODO: Shout !
- } finally {
- updateFile.delete();
- }
-
- }
- }
+ /**
+ * Define the sling.home parameter implementing the algorithme defined on
+ * the wiki page to find the setting according to this algorithm:
+ * <ol>
+ * <li>Servlet parameter <code>sling.home</code></li>
+ * <li>Context <code>sling.home</code></li>
+ * <li>Derived from ServletContext path</li>
+ * </ol>
+ * <p>
+ * <code>null</code> may be returned by this method if no
+ * <code>sling.home</code> parameter is set and if the servlet container
+ * 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.
+ */
+ private String getSlingHome(HttpServletRequest request) {
- protected String getSlingHome(HttpServletRequest request) {
+ String source = null;
// 1. servlet config parameter
String slingHome = getServletConfig().getInitParameter(
SharedConstants.SLING_HOME);
- if (slingHome == null) {
+ if (slingHome != null) {
+
+ source = "servlet parameter sling.home";
+
+ } else {
// 2. servlet context parameter
slingHome = getServletContext().getInitParameter(
SharedConstants.SLING_HOME);
- if (slingHome == null) {
+ if (slingHome != null) {
+
+ source = "servlet context parameter sling.home";
+
+ } else {
// 3. servlet context path (Servlet API 2.5 and later)
try {
String contextPath = getServletContext().getContextPath();
slingHome = toSlingHome(contextPath);
+ source = "servlet context path";
} catch (NoSuchMethodError nsme) {
@@ -276,10 +386,12 @@
String contextPath = request.getContextPath();
slingHome = toSlingHome(contextPath);
+ source = "servlet context path (from request)";
} else {
- // TODO: log < 2.5 API and require request for this
+ log("ServletContext path not available here, delaying
startup until first request");
+ return null;
}
}
@@ -287,10 +399,12 @@
}
}
+ log("Setting sling.home=" + slingHome + " (" + source + ")");
return slingHome;
}
- protected String toSlingHome(String contextPath) {
+ // convert the servlet context path to a directory path for sling.home
+ private String toSlingHome(String contextPath) {
String prefix = "sling/";
if (contextPath == null || contextPath.length() == 0) {
return prefix + "_";