blob: ca977d4fddbed31808be60ed6feaf2415d60f3f0 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>6.4&nbsp;Form Tags Shared Services WAR</title><link rel="stylesheet" href="css/stylesheet.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"><link rel="home" href="index.html" title="Virgo Programmer Guide"><link rel="up" href="ch06.html" title="6.&nbsp;Case Study: Migrating the Form Tags Sample Application"><link rel="prev" href="ch06s03.html" title="6.3&nbsp;Form Tags Shared Libraries WAR"><link rel="next" href="ch06s05.html" title="6.5&nbsp;Form Tags PAR"><!--Begin Google Analytics code--><script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script><script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2728886-3");
pageTracker._setDomainName("none");
pageTracker._setAllowLinker(true);
pageTracker._trackPageview();
</script><!--End Google Analytics code--></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">6.4&nbsp;Form Tags Shared Services WAR</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch06s03.html">Prev</a>&nbsp;</td><th width="60%" align="center">6.&nbsp;Case Study: Migrating the Form Tags Sample Application</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ch06s05.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="formtags-case-study-war-shared-services"></a>6.4&nbsp;Form Tags Shared Services WAR</h2></div></div></div><p>
The next step in the migration is to deploy the services as a
separate
OSGi bundle which the WAR then references.
The Form Tags
sample has a single service
<code class="literal">UserManager</code>
.
</p><p>
This scenario has two separate deployables, the
<code class="literal">service</code>
bundle and the WAR file.
The following image shows the two separate
source trees:
</p><p>
<img src="images/formtags-case-study-shared-services-eclipse.png">
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.gif"></td><th align="left">Note</th></tr><tr><td align="left" valign="top">
Note that the WAR does not contain the
<code class="literal">.domain</code>
or
<code class="literal">.service</code>
packages as these will be imported from the separate service bundle.
</td></tr></table></div><p>
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="formtags-case-study-war-shared-services-service"></a>The Service Bundle</h3></div></div></div><p>
The responsibility of the first bundle (
<code class="literal">formtags-shared-services-service</code>
)
is to provide the API of the formtags service. This includes both
the
domain and the service API. In the same way that imports are
defined
in the
<code class="literal">/META-INF/MANIFEST.MF</code>
, so are exports.
The following is the
<code class="literal">/META-INF/MANIFEST.MF</code>
listing from the service bundle.
</p><pre class="programlisting">
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_13-119 (Apple Inc.)
Bundle-ManifestVersion: 2
Bundle-Name: FormTags Service (and implementation)
Bundle-SymbolicName: org.springframework.showcase.formtags.service-shared-services
<span class="bold"><strong>Export-Package</strong></span>: org.springframework.showcase.formtags.service,org.spri
ngframework.showcase.formtags.domain
Import-Library: org.springframework.spring;version="[3.0.0,4.0.0)"
</pre><p>
</p><p>
The symbolic name of this bundle is
<code class="literal">org.springframework.showcase.formtags.service-shared-services
</code>
.
Note that the name of the bundle typically describes the package
that the bundle primarily exports.
If you take a look at the
<code class="literal">repository/bundles/ext</code>
in the VTS
directory, you&#8217;ll see that
names are almost always indicative of the contents of the bundle.
For this example, however, we have also appended
"
<code class="literal">-shared-services</code>
"
in order to avoid possible clashes with other bundle symbolic
names.
You will see later that the PAR also contains a service
bundle.
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.gif"></td><th align="left">Note</th></tr><tr><td align="left" valign="top">
In OSGi, the combination of
<code class="literal">Bundle-SymbolicName</code>
and
<code class="literal">Bundle-Version</code>
is used to uniquely identify
a bundle within the OSGi container.
Furthermore, when you deploy
a bundle to the Virgo Server for Apache Tomcat,
for example via the
<code class="literal">pickup</code>
directory, a bundle&#8217;s filename is also used to uniquely
identify it for
the purpose of supporting
<span class="emphasis"><em>hot deployment</em></span>
via
the file system.
</td></tr></table></div><p>
</p><p>
As well as exporting types (i.e. the domain classes and service
API), the service bundle also publishes an implementation of the
<code class="literal">UserManager</code>
. The actual implementation is
<code class="literal">StubUserManager</code>
; however, that should remain an
implementation detail of this
bundle.
</p><p>
The fact that this bundle publishes a service is not captured in
the
<code class="literal">/META-INF/MANIFEST.MF</code>
, as it is a Spring-DM concept.
The following image is of
<code class="literal">src/main/resources/spring</code>
.
</p><p>
<img src="images/formtags-case-study-shared-services-service-resources.png">
</p><p>
As you can see there are two Spring configuration files:
<code class="literal">module-context.xml</code>
and
<code class="literal">osgi-context.xml</code>
.
</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.gif"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top">
These names are abitrary; however, they follow an informal
convention:
<code class="literal">module-context.xml</code>
typically bootstraps the Spring context
(usually delegating to
smaller fine grained context files inside another directory),
whilst
<code class="literal">osgi-context.xml</code>
contains all the OSGi service exports and references.
</td></tr></table></div><p>
The following is a listing of
<code class="literal">module-context.xml</code>
.
</p><pre class="programlisting">
&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>&gt;
&lt;<span class="hl-tag">beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"</span>&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"userManager"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.showcase.formtags.service.internal.StubUserManager"</span>/&gt;
&lt;<span class="hl-tag">/beans</span>&gt; </pre><p>
As you can see, this simply defines a bean called
<code class="literal">userManager</code>
.
The following is a listing of
<code class="literal">osgi-context.xml</code>
.
</p><pre class="programlisting">
&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>&gt;
&lt;<span class="hl-tag">beans:beans</span>
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/osgi"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="hl-attribute">xmlns:beans</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"</span>&gt;
&lt;<span class="hl-tag">service</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"userManager"</span>
<span class="hl-attribute">interface</span>=<span class="hl-value">"org.springframework.showcase.formtags.service.UserManager"</span>/&gt;
&lt;<span class="hl-tag">/beans:beans</span>&gt; </pre><p>
This single bean definition exports the
<code class="literal">userManager</code>
defined in
<code class="literal">module-context.xml</code>
to the
OSGi service registry and makes it available under the public
<code class="literal">org.springframework.showcase.formtags.service.UserManager
</code>
API.
</p><p>
The service bundle should now be ready to deploy on the
VTS.
So copy
<code class="literal">/dist/formtags-shared-services-services*</code>
to the
<code class="literal">SERVER_HOME/pickup</code>
directory.
Output similar to the following should appear in the
VTS&#8217;s console:
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.gif"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The console output has been reformatted to fit this document.
</p></td></tr></table></div><pre class="programlisting">
[2009-07-01 15:05:03.511] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-shared-services-service-2.0.0.RELEASE.jar'.
[2009-07-01 15:05:03.688] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'org.springframework.showcase.formtags.service_shared_services' version '2.0.0.RELEASE' completed.
</pre></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="formtags-case-study-war-shared-services-war"></a>Accessing the Service and Types from the WAR</h3></div></div></div><p>
The WAR file now needs to access the types and service exported
by
the service bundle. The following listing is the WAR&#8217;s
<code class="literal">/META-INF/MANIFEST.MF</code>
which imports the types
exported by the service bundle. The
<code class="literal">Import-Bundle</code>
statement has also been extended to import
<code class="literal">org.springframework.osgi.core</code>
,
which is necessary in order to load an OSGi-enabled
<code class="literal">WebApplicationContext</code>
.
</p><pre class="programlisting">
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_13-119 (Apple Inc.)
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.springframework.showcase.formtags.web-shared-
services
<span class="bold"><strong>Import-Package</strong></span>: org.springframework.showcase.formtags.domain,org.sprin
gframework.showcase.formtags.service, org.eclipse.virgo.web.dm;version="[1.0,2.1)"
Import-Library: org.springframework.spring;version="[2.5.4,3.1.0)"
Import-Bundle: com.springsource.org.apache.taglibs.standard;version="1
.1.2",<span class="bold"><strong>org.springframework.osgi.core</strong></span>
</pre><p>
</p><p>
In addition to importing the exported types of the service bundle,
the WAR must also obtain a reference to the
<code class="literal">UserManager</code>
published by the service bundle. The following image shows the
directory
structure of the Shared Services WAR.
</p><p>
<img src="images/formtags-case-study-shared-services-war-resources.png">
</p><p>
As you can see in the above image, the Form Tags Shared Services
WAR&#8217;s
<code class="literal">/WEB-INF/web.xml</code>
directory contains a standard
<code class="literal">web.xml</code>
deployment descriptor,
<code class="literal">applicationContext.xml</code>
which defines the configuration
for the
<span class="emphasis"><em>root</em></span>
<code class="literal">WebApplicationContext</code>
, and
<code class="literal">formtags-servlet.xml</code>
which defines the configuration specific to the
configured
<span class="emphasis"><em>formtags</em></span>
<code class="literal">DispatcherServlet</code>
.
</p><p>
As is typical for Spring MVC based web applications, you configure a
<code class="literal">ContextLoaderListener</code>
in
<code class="literal">web.xml</code>
to load your root
<code class="literal">WebApplicationContext</code>
; however, to enable your
<code class="literal">WebApplicationContext</code>
to be able to reference services from the OSGi Service Registry,
you
must explicitly set the
<code class="literal">contextClass</code>
Servlet context parameter to the fully qualified
class name of a
<code class="literal">ConfigurableWebApplicationContext</code>
which is OSGi-enabled. When deploying
Shared Services WARs to the
Virgo Server for Apache Tomcat, you should use
<code class="literal">org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
</code>.
This will
then enable the use of Spring-DM&#8217;s
<code class="literal">&lt;reference ... /&gt;</code>
within your root
<code class="literal">WebApplicationContext</code>
(i.e., in
<code class="literal">applicationContext.xml</code>
).
The following listing is an excerpt from
<code class="literal">/WEB-INF/web.xml</code>
.
</p><pre class="programlisting">
&lt;<span class="hl-tag">context-param</span>&gt;
&lt;<span class="hl-tag">param-name</span>&gt;contextClass&lt;<span class="hl-tag">/param-name</span>&gt;
&lt;<span class="hl-tag">param-value</span>&gt;org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext&lt;<span class="hl-tag">/param-value</span>&gt;
&lt;<span class="hl-tag">/context-param</span>&gt;
&lt;<span class="hl-tag">listener</span>&gt;
&lt;<span class="hl-tag">listener-class</span>&gt;org.springframework.web.context.ContextLoaderListener&lt;<span class="hl-tag">/listener-class</span>&gt;
&lt;<span class="hl-tag">/listener</span>&gt;
</pre><p>
The Form Tags Shared Services WAR contains a
<code class="literal">/WEB-INF/applicationContext.xml</code>
file which is the default configuration location used to create the
<span class="emphasis"><em>root</em></span>
<code class="literal">WebApplicationContext</code>
for Spring MVC&#8217;s
<code class="literal">ContextLoaderListener</code>
.
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.gif"></td><th align="left">Note</th></tr><tr><td align="left" valign="top">
As already mentioned, in the OSGi world, bundle configuration
takes
place in the root
<code class="literal">/META-INF/</code>
directory.
Typically Spring-DM powered configuration files will live
there as well (e.g., in
<code class="literal">/META-INF/spring/*.xml</code>
).
In a WAR, however, the root
<code class="literal">WebApplicationContext</code>
loaded by
<code class="literal">ContextLoaderListener</code>
and the
<code class="literal">DispatcherServlet&#8217;s</code>
application context typically live in
<code class="literal">/WEB-INF/</code>
.
</td></tr></table></div><p>
The following is the listing of the WAR&#8217;s
<code class="literal">/WEB-INF/applicationContext.xml</code>
.
</p><pre class="programlisting">
&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>&gt;
&lt;<span class="hl-tag">beans:beans</span>
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/osgi"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="hl-attribute">xmlns:beans</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xsi:schemaLocation</span>=<span class="hl-value">"http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"</span>&gt;
&lt;<span class="hl-tag">reference</span> <span class="hl-attribute">id</span>=<span class="hl-value">"userManager"</span>
<span class="hl-attribute">interface</span>=<span class="hl-value">"org.springframework.showcase.formtags.service.UserManager"</span>/&gt;
&lt;<span class="hl-tag">/beans:beans</span>&gt; </pre><p>
The single bean declaration is retrieving a service that implements
the
<code class="literal">org.springframework.showcase.formtags.service.UserManager
</code>
API from the OSGi Service Registry.
</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.gif"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top">
You might have been expecting a reference to the service bundle,
but that isn&#8217;t how OSGi works. OSGi provides a service
registry, and this bean definition is accessing a service in that
registry that meets the specified restriction (i.e. implements
the
specified interface). This leads to a very loosely coupled
programming model: the WAR really doesn&#8217;t care where the
implementation
comes from.
</td></tr></table></div><p>
</p><div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.gif"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top">
What happens if there is no service at runtime?
What if there are
multiple services that match the criteria?
Spring-DM provides a lot
of configuration options, including
whether or not the reference is
<span class="emphasis"><em>mandatory</em></span>
,
how long to wait for a service reference, etc. Please consult the
<a class="ulink" href="http://www.springframework.org/osgi/" target="_top">Spring Dynamic Modules for OSGi</a>
home page for further information.
</td></tr></table></div><p>
</p><p>
One of the benefits of programming to interfaces is that you
are
decoupled from the actual implementation; Spring-DM provides a
proxy. This
has enormous benefits including the ability to
dynamically refresh individual bundles without
cascading that
refresh to unrelated bundles.
</p><p>
</p><p>
To deploy the WAR, copy
<code class="literal">/dist/formtags-shared-services-war*</code>
to the
<code class="literal">SERVER_HOME/pickup</code>
directory.
You should then see console output similar to the
following:
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.gif"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The console output has been reformatted to fit this document.
</p></td></tr></table></div><pre class="programlisting">
[2009-07-01 15:09:19.819] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-shared-services-war-3.0.0.RELEASE.war'.
[2009-07-01 15:09:20.167] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'org.springframework.showcase.formtags.web_shared_services' version '3' completed.
[2009-07-01 15:09:20.168] Thread-20
&lt;SPWE0000I&gt; Starting web bundle '/formtags-shared-services-war-3.0.0.RELEASE'.
[2009-07-01 15:09:20.647] Thread-20
&lt;SPWE0001I&gt; Started web bundle '/formtags-shared-services-war-3.0.0.RELEASE'.
</pre>
Navigating to the appropriate link should render the welcome page.
</div></div><!--Begin LoopFuse code--><script src="http://loopfuse.net/webrecorder/js/listen.js" type="text/javascript"></script><script type="text/javascript">
_lf_cid = "LF_48be82fa";
_lf_remora();
</script><!--End LoopFuse code--><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch06s03.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ch06.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ch06s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">6.3&nbsp;Form Tags Shared Libraries WAR&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;6.5&nbsp;Form Tags PAR</td></tr></table></div></body></html>