sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject [CONF] Apache Sling > Updating the Sling Launcher
Date Mon, 07 Feb 2011 10:17:00 GMT
    <base href="">
            <link rel="stylesheet" href="/confluence/s/2036/9/1/_/styles/combined.css?spaceKey=SLING&amp;forWysiwyg=true"
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="">Updating
the Sling Launcher</a></h2>
    <h4>Page <b>edited</b> by             <a href="">Felix
                         <h4>Changes (2)</h4>
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
            <tr><td class="diff-unchanged" >h1. Updating the Sling Launcher <br>
            <tr><td class="diff-changed-lines" >{excerpt:hidden=true}How we could
get the Sling Launcher to be updated through management interfaces such as the Felix Web Console
or the Felix <span class="diff-changed-words">Shell.<span class="diff-added-chars"style="background-color:
#dfd;"> (IMPLEMENTED)</span>{excerpt}</span> <br></td></tr>
            <tr><td class="diff-unchanged" > <br></td></tr>
            <tr><td class="diff-changed-lines" >Status: <span class="diff-deleted-words"style="color:#999;background-color:#fdd;text-decoration:line-through;">DRAFT</span>
<span class="diff-added-words"style="background-color: #dfd;">IMPLEMENTED</span>
            <tr><td class="diff-unchanged" >Created: 10. January 2009 <br>Author:
fmeschbe <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <h1><a name="UpdatingtheSlingLauncher-UpdatingtheSlingLauncher"></a>Updating
the Sling Launcher</h1>

<p>Status: IMPLEMENTED<br/>
Created: 10. January 2009<br/>
Author: fmeschbe<br/>
Updated: 13. January 2009, fmeschbe, Prototype implementation</p>

    <li><a href='#UpdatingtheSlingLauncher-1ProblemScope'>1 Problem Scope</a></li>
    <li><a href='#UpdatingtheSlingLauncher-2Idea'>2 Idea</a></li>
    <li><a href='#UpdatingtheSlingLauncher-3LauncherJARupdate'>3 Launcher JAR
    <li><a href='#UpdatingtheSlingLauncher-4Launchersupportforstopandupdate'>4
Launcher support for stop and update</a></li>
    <li><a href='#UpdatingtheSlingLauncher-5Prototype'>5 Prototype</a></li>
    <li><a href='#UpdatingtheSlingLauncher-6.1PrimaryArtifact'>6.1 Primary Artifact</a></li>
    <li><a href='#UpdatingtheSlingLauncher-6.2SecondaryArtifact'>6.2 Secondary
    <li><a href='#UpdatingtheSlingLauncher-6.3Buildingtheprototype'>6.3 Building
the prototype</a></li>

<h2><a name="UpdatingtheSlingLauncher-1ProblemScope"></a>1 Problem Scope</h2>

<p>A Sling instance is launched by the Sling launcher, which is a single JAR (standalone
Java Application) or WAR (Web Application) file. This file cannot currently be updated without
physical access to the system, stopping the system, replacing the file and restarting the

<p>It would be a good thing, if we could use existing administration API such as the
Felix Web Console or the Felix (Remote) Shell to update this launcher. This concept is about
how we could slightly restructure the launcher to enable just this functionality.</p>

<h2><a name="UpdatingtheSlingLauncher-2Idea"></a>2 Idea</h2>

<p>We have a single JAR file, which contains the OSGi framework (Apache Felix), the
OSGi core libraries and the actual launcher for the OSGi framework. This single JAR file the
<em>launcher JAR</em> is contained as a JAR file in either the standalone Java
Application JAR or the Web Application WAR file.</p>

<p>The Standalone Java Application JAR File contains a single main class, which reads
the command line and instantiates the actual launcher in the <em>launcher JAR</em>
and waits for its termination.</p>

<p>The Web Application WAR File contains a single servlet, which instantiates the actual
launcher servlet in the <em>launcher JAR</em> and reacts to its termination.</p>

<p>Both the main class and the servlet are very tiny and have the following tasks:</p>

	<li>Read the initial configuration for the launcher. This initial configuration becomes
the overwrite properties for the sling properties used as the framework properties. The initial
configuraiton is read as follows:</li>
	<li>The main class uses the command line arguments and the system properties for the
initial configuration</li>
	<li>The servlet uses the servlet and servlet context init-params for the initial configuration</li>
	<li>After getting the initial configuration, the main class will just have the framework
started. The servlet will create and initialize a servlet provided by the <em>launcher
JAR</em>, which also sets up the OSGi HttpService bridge.</li>
	<li>After starting the framework through the launcher, the main class does nothing
more. The servlet will forward the service requests to the launched servlet.</li>
	<li>To initiate an external shutdown, the main class or servlet terminate the launcher:</li>
	<li>The main class just calls the stop method and waits for its termination</li>
	<li>The servlet calls <tt>destroy()</tt> on the launched internal servlet</li>
	<li>During the lifetime of Sling, the framework may be stopped from within by calling
the <tt>stop</tt> or <tt>update</tt> methods. To inform the main class
or servlet of this situation, the launcher takes to <tt>Runnable</tt> instances:
One is called by the launcher when the framework has been stopped. The other is called if
the framework has been stopped, but should be restarted again. These <tt>Runnable</tt>
instances are only called when the framework has completely been shut down.</li>
	<li>If instructed by having the <tt>Runnable</tt> being called, which is
notified of a required restart, the main class or servlet will start from scratch at the first

<h2><a name="UpdatingtheSlingLauncher-3LauncherJARupdate"></a>3 Launcher
JAR update</h2>

<p>Since the <em>launcher JAR</em> is a single JAR file, it may be updated.
But it must also be possible to make sure the new code is actually being used after restart.
To implement this requirement the main class or servlet follow this algorithm:</p>

	<li>Place or replace the <em>launcher JAR</em> file in the filesystem inside
	<li>Create an <tt>URLClassLoader</tt> with this JAR file and the class
loader of the main class or servlet as the parent class loader</li>
	<li>The main class uses reflection to instantiate and start the launcher. The main
servlet uses reflection only to instantiate the launcher servlet. After that the normal servlet
API is used for further interaction.</li>

<p>After the launcher terminates either by the <tt>stop</tt> or <tt>update</tt>
method being called on the system bundle or by being requested from the main class or servlet,
the class loader is just dropped and thus given to the garbage collector. It may be, that
there will have to be some cleanup for the garbage collector to be operational. Notable areas
are the Java VM JavaBeans cache and any caches of the Java Logging API.</p>

<h2><a name="UpdatingtheSlingLauncher-4Launchersupportforstopandupdate"></a>4
Launcher support for stop and update</h2>

<p>The <em>launcher JAR</em> must have two basic features:</p>

	<li>Know when the framework is stopped by the <tt>stop</tt> or <tt>update</tt>
method being called on the system bundle</li>
	<li>Take the appropriate measure after the framework has been stopped</li>

<p>To implement these two features, the <em>launcher JAR</em> overwrites
the <tt>stop</tt> and <tt>update</tt> methods of the <tt>Felix</tt>
class, which implements the system bundle. The <tt>update(InputStream)</tt> method
is overwritten to take the new <em>launcher JAR</em> file and place it such, that
it can be used to restart. All method overwrites, start a separate thread which waits for
the framework to terminate. When the framework has been terminated, the main class or servlet
is notified.</p>

<p>The main class or servlet provide the launcher with a <tt>Notifiable</tt>
instances. The <tt>Notifiable.stopped()</tt> is called if the framework has been
stopped. The <tt>Notifiable.updated(File)</tt> is called if the framework has
been stopped for it to be restarted, where the file argument may be the new <em>launcher
JAR</em> to use.</p>

<p>The <tt>Notifiable.stopped</tt> method enables the main class or servlet
to react to the situation that the framework has gone and take appropriate actions. The <tt>Notifiable.updated(File)</tt>
method enables the main class or servlet to drop the framework and classloader and restart
the framework in a new class loader with a potentially new <em>launcher JAR</em>.</p>

<h2><a name="UpdatingtheSlingLauncher-5Prototype"></a>5 Prototype</h2>

<p>I have prepared a prototype of this concept in my white board at <a href=""
class="external-link" rel="nofollow"></a>.</p>

<p>The launchpad/base module creates two artifacts: The primary artifact is included
with the final application. The secondary artifact is the actual <em>launcher JAR</em>

<h3><a name="UpdatingtheSlingLauncher-6.1PrimaryArtifact"></a>6.1 Primary

<p>The primary artifact contains three elements:</p>

	<li><tt>Notifiable</tt> interface with two methods <tt>stopped</tt>
&#8211; called when the framework has been stopped &#8211; and <tt>updated</tt>
&#8211; called when the framework has been updated and needs to be restarted. This interface
is to be implemented by the main class or servlet.</li>
	<li><tt>Loader</tt> creates the  <tt>URLClassLoader</tt> with
the <em>launcher JAR</em> and instantiates the launcher class. This class is implemented
as a utility class with a two methods <tt>loadLauncher</tt> and <tt>cleanupVM</tt>:</li>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
 * Creates an URLClassLoader from a _launcher JAR_ file in the given
 * slingHome directory and loads and returns the launcher class
 * identified by the launcherClassName.
 * @param launcherClassName The fully qualified name of a class
 *     implementing the Launcher <span class="code-keyword">interface</span>.
This class must have
 *     a <span class="code-keyword">public</span> constructor taking no arguments.
 * @param slingHome The value to be used as ${slingHome}. This may
 *     be <span class="code-keyword">null</span> in which <span class="code-keyword">case</span>
the sling folder in the current working
 *     directory is assumed. If <span class="code-keyword">this</span> name is
empty, the current working
 *     directory is assumed to be used as ${slingHome}.
 * @<span class="code-keyword">return</span> the Launcher instance loaded from
the newly created classloader
 * @<span class="code-keyword">throws</span> NullPointerException <span class="code-keyword">if</span>
launcherClassName is <span class="code-keyword">null</span>
 * @<span class="code-keyword">throws</span> IllegalArgumentException <span
class="code-keyword">if</span> the launcherClassName cannot be
 *     instantiated. The cause of the failure is contained as the cause
 *     of the exception.
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
Launcher loadLauncher(<span class="code-object">String</span> launcherClassName,
<span class="code-object">String</span> slingHome);

 * Tries to remove as many traces of class loaded by the framework from
 * the Java VM as possible. Most notably the following traces are removed:
 * &lt;ul&gt;
 * &lt;li&gt;JavaBeans property caches
 * &lt;li&gt;Java Logging caches
 * &lt;/ul&gt;
 * &lt;p&gt;
 * This method must be called when the notifier is called.
<span class="code-keyword">public</span> <span class="code-keyword">static</span>
void cleanupVM();

	<li><tt>Launcher</tt> interface which is implemented by classes in the
secondary artifact. This interface has a method to support the standaline Java Application
case (<tt>setCommandLine</tt>). To support the Web Application, the launcher class
is expected to implement the <tt>javax.servlet.Servlet</tt> interface. The <tt>Launcher</tt>
interface is defined as follows:</li>

<div class="code panel" style="border-width: 1px;"><div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">// set sling home <span class="code-keyword">for</span>
the framework
</span><span class="code-keyword">public</span> void setSlingHome(<span
class="code-object">String</span> slingHome);

<span class="code-comment">// set the Notifiable to be informed on stop/update
</span><span class="code-keyword">public</span> void setNotifiable(Notifiable

<span class="code-comment">// sets command line arguments, mainly used by the main class
</span><span class="code-keyword">public</span> void setCommandLine(<span
class="code-object">String</span>[] args);

<span class="code-comment">// starts the framework
</span><span class="code-keyword">public</span> void start();

<span class="code-comment">// stops the framework
</span><span class="code-comment">// <span class="code-keyword">this</span>
method only returns when the framework has actually been stopped.
</span><span class="code-comment">// <span class="code-keyword">this</span>
method may be used by the main class or servlet to initiate a
</span><span class="code-comment">// shutdown of the framework
</span><span class="code-keyword">public</span> void stop();

<h3><a name="UpdatingtheSlingLauncher-6.2SecondaryArtifact"></a>6.2 Secondary

<p>The secondary artifact is just what is the launchpad/base artifact today. The extension
is just the support for the new API defined in the primary artifact. This secondary artifact
is included as the <em>launcher JAR</em> in the final application.</p>

<h3><a name="UpdatingtheSlingLauncher-6.3Buildingtheprototype"></a>6.3 Building
the prototype</h3>

<p>To build an test drive the prototype do the following:</p>

<p>1. Checkout the prototype:</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent
<pre>$ svn checkout

<p>2. Build and locally install the base artifact</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent
<pre>$ cd prototype/base
$ mvn clean install

<p>This install three artifacts: the primary artifact later used as the <em>launcher
JAR</em> and two secondary artifacts with classifier <tt>shared</tt> and
<tt>sources</tt>. The <tt>shared</tt> artifact is used by the <em>app</em>
and <em>webapp</em> modules to get the <tt>Loader</tt> class and the
<tt>Notifiable</tt> and <tt>Launcher</tt> interfaces.</p>

<p>3. Build the standalone application</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent
<pre>$ cd ../app
$ mvn -PwithBase,withBundles,withShell clean install

<p>The module has three profiles, which are not enabled by default:</p>

	<li><em>withBase</em> &#8211; Include the <em>launcher JAR</em>
with the build</li>
	<li><em>withBundles</em> &#8211; Include the Sling Bundles with the
	<li><em>withShell</em> &#8211; Add the Apache Felix Shell and Shell
Remote bundles</li>

<p>You may omit the <em>withShell</em> profile, but generally want to include
the <em>withBase</em> and <em>withBundles</em> artifacts. These profiles
will also later be enabled by default.</p>

<p>The standalone application can of course directly be used by launching it with</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent
<pre>$ java -jar target/

<p>4. Build the Web Application</p>

<p>The web application depends on the standalone application to share the list of bundles
included. The web application is easily built by</p>

<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent
<pre>$ cd ../webapp
$ mvn clean install

<p>This creates the web application.</p>

<p>Note: The web application also contains support for <a href=""
class="external-link" rel="nofollow">SLING-711</a>. This results in modified behaviour
for the definition for the defualt sling.home value. Previously the system property sling.home
was considered if no sling.home servlet init-param or context init-param was available with
a final fallback to "sling". Now the system property is ignored altogether and the default
value is derived from the servlet context path as <em>sling/&lt;path&gt;</em>
where <em>&lt;path&gt;</em> is the servlet context path with all slashes
replaced by underscores and the root context being a single underscore. For example: If Sling
is running in the context <em>/sling</em> the defualt sling.home is <em>sling/_sling</em>.</p>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href=""
class="grey">Change Notification Preferences</a>
        <a href="">View
        <a href="">View
        <a href=";showCommentArea=true#addcomment">Add

View raw message