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 + "_";


Reply via email to