6.4 Form Tags Shared Services WAR

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
UserManager
.

This scenario has two separate deployables, the
service
bundle and the WAR file.
The following image shows the two separate
source trees:

Note

Note that the WAR does not contain the
.domain
or
.service
packages as these will be imported from the separate service bundle.

The Service Bundle

The responsibility of the first bundle (
formtags-shared-services-service
)
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
/META-INF/MANIFEST.MF
, so are exports.
The following is the
/META-INF/MANIFEST.MF
listing from the service bundle.

The symbolic name of this bundle is
org.springframework.showcase.formtags.service-shared-services
.
Note that the name of the bundle typically describes the package
that the bundle primarily exports.
If you take a look at the
repository/bundles/ext
in the VTS
directory, you’ll see that
names are almost always indicative of the contents of the bundle.
For this example, however, we have also appended
"
-shared-services
"
in order to avoid possible clashes with other bundle symbolic
names.
You will see later that the PAR also contains a service
bundle.

Note

In OSGi, the combination of
Bundle-SymbolicName
and
Bundle-Version
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
pickup
directory, a bundle’s filename is also used to uniquely
identify it for
the purpose of supporting
hot deployment
via
the file system.

As well as exporting types (i.e. the domain classes and service
API), the service bundle also publishes an implementation of the
UserManager
. The actual implementation is
StubUserManager
; however, that should remain an
implementation detail of this
bundle.

The fact that this bundle publishes a service is not captured in
the
/META-INF/MANIFEST.MF
, as it is a Spring-DM concept.
The following image is of
src/main/resources/spring
.

As you can see there are two Spring configuration files:
module-context.xml
and
osgi-context.xml
.

Tip

These names are abitrary; however, they follow an informal
convention:
module-context.xml
typically bootstraps the Spring context
(usually delegating to
smaller fine grained context files inside another directory),
whilst
osgi-context.xml
contains all the OSGi service exports and references.

This single bean definition exports the
userManager
defined in
module-context.xml
to the
OSGi service registry and makes it available under the public
org.springframework.showcase.formtags.service.UserManager
API.

The service bundle should now be ready to deploy on the
VTS.
So copy
/dist/formtags-shared-services-services*
to the
SERVER_HOME/pickup
directory.
Output similar to the following should appear in the
VTS’s console:

Accessing the Service and Types from the WAR

The WAR file now needs to access the types and service exported
by
the service bundle. The following listing is the WAR’s
/META-INF/MANIFEST.MF
which imports the types
exported by the service bundle. The
Import-Bundle
statement has also been extended to import
org.springframework.osgi.core
,
which is necessary in order to load an OSGi-enabled
WebApplicationContext
.

In addition to importing the exported types of the service bundle,
the WAR must also obtain a reference to the
UserManager
published by the service bundle. The following image shows the
directory
structure of the Shared Services WAR.

As you can see in the above image, the Form Tags Shared Services
WAR’s
/WEB-INF/web.xml
directory contains a standard
web.xml
deployment descriptor,
applicationContext.xml
which defines the configuration
for the
rootWebApplicationContext
, and
formtags-servlet.xml
which defines the configuration specific to the
configured
formtagsDispatcherServlet
.

As is typical for Spring MVC based web applications, you configure a
ContextLoaderListener
in
web.xml
to load your root
WebApplicationContext
; however, to enable your
WebApplicationContext
to be able to reference services from the OSGi Service Registry,
you
must explicitly set the
contextClass
Servlet context parameter to the fully qualified
class name of a
ConfigurableWebApplicationContext
which is OSGi-enabled. When deploying
Shared Services WARs to the
Virgo Server for Apache Tomcat, you should use
org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext
.
This will
then enable the use of Spring-DM’s
<reference ... />
within your root
WebApplicationContext
(i.e., in
applicationContext.xml
).
The following listing is an excerpt from
/WEB-INF/web.xml
.

The Form Tags Shared Services WAR contains a
/WEB-INF/applicationContext.xml
file which is the default configuration location used to create the
rootWebApplicationContext
for Spring MVC’s
ContextLoaderListener
.

Note

As already mentioned, in the OSGi world, bundle configuration
takes
place in the root
/META-INF/
directory.
Typically Spring-DM powered configuration files will live
there as well (e.g., in
/META-INF/spring/*.xml
).
In a WAR, however, the root
WebApplicationContext
loaded by
ContextLoaderListener
and the
DispatcherServlet’s
application context typically live in
/WEB-INF/
.

The following is the listing of the WAR’s
/WEB-INF/applicationContext.xml
.

The single bean declaration is retrieving a service that implements
the
org.springframework.showcase.formtags.service.UserManager
API from the OSGi Service Registry.

Tip

You might have been expecting a reference to the service bundle,
but that isn’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’t care where the
implementation
comes from.

Tip

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
mandatory
,
how long to wait for a service reference, etc. Please consult the
Spring Dynamic Modules for OSGi
home page for further information.

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.

To deploy the WAR, copy
/dist/formtags-shared-services-war*
to the
SERVER_HOME/pickup
directory.
You should then see console output similar to the
following: