blob: 30acf6b9e3f9ec24ca885e822a28990500c94b04 [file]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Creating an application with EclipseRT Virgo Web Server</title><link rel="stylesheet" href="css/stylesheet.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"><meta name="description" content="Spring application programmers are introduced to Virgo Web Server by installing the Web Server and examining a small application called GreenPages. Despite its simplicity, GreenPages is designed to demonstrate many different Web Server features and to act as a template from which other modular applications can be built. This version of the guide is based on the following software versions: Web Server2.1.0.RELEASEGreenPages2.3.0.RELEASESpringSource Tool Suite2.5.0.RELEASEApache Maven2.2.0"><!--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="book" lang="en"><div class="titlepage"><div><div><h1 class="title"><a name="d0e1"></a>Creating an application with EclipseRT Virgo Web Server</h1></div><div><h2 class="subtitle">GreenPages: a demonstration</h2></div><div><div class="authorgroup"><div class="author"><h3 class="author"><span class="firstname">Christopher</span> <span class="surname">Frost</span></h3></div><div class="author"><h3 class="author"><span class="firstname">Ben</span> <span class="surname">Hale</span></h3></div><div class="author"><h3 class="author"><span class="firstname">Rob</span> <span class="surname">Harrop</span></h3></div><div class="author"><h3 class="author"><span class="firstname">Glyn</span> <span class="surname">Normington</span></h3></div><div class="author"><h3 class="author"><span class="firstname">Steve</span> <span class="surname">Powell</span></h3></div><div class="author"><h3 class="author"><span class="firstname">Andy</span> <span class="surname">Wilkinson</span></h3></div></div></div><div><div class="mediaobject" align="right"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0"><tr><td align="right" valign="bottom"><img src="images/virgo-logo-large.png" align="right"></td></tr></table></div></div><div><span class="productname">Web Server<br></span></div><div><p class="releaseinfo">2.1.0.RELEASE</p></div><div><div class="abstract"><p class="title"><b>Abstract</b></p><p>
Spring application programmers are introduced to Virgo Web Server
by installing the Web Server and examining a small application called GreenPages.
Despite its simplicity, GreenPages is designed to demonstrate many different Web Server features and to
act as a template from which other modular applications can be built.
</p><p>
This version of the guide is based on the following software versions:
</p><table class="simplelist" border="0" summary="Simple list"><tr><td></td><td><span class="emphasis"><em>Web Server</em></span></td><td>2.1.0.RELEASE</td></tr><tr><td></td><td><span class="emphasis"><em>GreenPages</em></span></td><td>2.3.0.RELEASE</td></tr><tr><td></td><td><span class="emphasis"><em>SpringSource Tool Suite</em></span></td><td>2.5.0.RELEASE</td></tr><tr><td></td><td><span class="emphasis"><em>Apache Maven</em></span></td><td>2.2.0</td></tr></table><p>
</p></div></div></div><div><div><div class="legalnotice"><a name="d0e82"></a><p>
Copyright &copy; 2009, 2010 VMware Inc.
</p><div class="mediaobject"><img src="images/virgo-logo-small.png"></div><p>
</p><p>
All rights reserved. This document is made available under the terms of the Eclipse Public License v1.0
which is available at
<a class="ulink" href="http://www.eclipse.org/legal/epl-v10.html" target="_top">http://www.eclipse.org/legal/epl-v10.html</a>.
</p><p>Java, Sun, and Sun Microsystems
are trademarks or registered
trademarks of Sun Microsystems, Inc. in the United
States and other countries.
</p><p>OSGi is a trademark or a registered trademark of the OSGi Alliance in
the United States, other countries, or both.
</p><p>Eclipse is a trademark of Eclipse Foundation, Inc.</p><p>UNIX is a registered trademark of The Open Group.</p><p>Windows is a registered trademark of Microsoft Corporation in the
United States and other countries.</p><p>Mac and Mac OS are trademarks of Apple Inc., registered in the U.S. and other countries.</p></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="preface"><a href="#d0e111">Preface</a></span></dt><dt><span class="chapter"><a href="#concepts">1. Concepts</a></span></dt><dd><dl><dt><span class="section"><a href="#concepts.osgi">1.1. OSGi concepts</a></span></dt><dt><span class="section"><a href="#concepts.springdm">1.2. Spring DM concepts</a></span></dt><dt><span class="section"><a href="#concepts.grouping">1.3. Grouping bundles in Web Server</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installation">2. Installation</a></span></dt><dd><dl><dt><span class="section"><a href="#installation.prereqs">2.1. Pre-requisites</a></span></dt><dt><span class="section"><a href="#installation.dmserver">2.2. Installing Web Server</a></span></dt><dt><span class="section"><a href="#installation.sts">2.3. Installing the SpringSource Tool Suite</a></span></dt><dt><span class="section"><a href="#installation.maven">2.4. Installing Apache Maven</a></span></dt></dl></dd><dt><span class="chapter"><a href="#installing.greenpages">3. Installing GreenPages</a></span></dt><dd><dl><dt><span class="section"><a href="#installing.greenpages.introduction">3.1. Introduction</a></span></dt><dt><span class="section"><a href="#installing.greenpages.obtaining">3.2. Obtaining GreenPages</a></span></dt><dt><span class="section"><a href="#installing.greenpages.building">3.3. Building and installing GreenPages</a></span></dt><dt><span class="section"><a href="#installing.greenpages.browsing">3.4. Browsing the GreenPages application</a></span></dt><dt><span class="section"><a href="#installing.greenpages.tools">3.5. Running GreenPages from Eclipse</a></span></dt></dl></dd><dt><span class="chapter"><a href="#web.module">4. The Web Module</a></span></dt><dd><dl><dt><span class="section"><a href="#web.module.introduction">4.1. Introduction</a></span></dt><dt><span class="section"><a href="#setting.up">4.2. GreenPages set up</a></span></dt><dt><span class="section"><a href="#controller">4.3. The controller</a></span></dt><dt><span class="section"><a href="#deploy.bundle">4.4. Deploying a bundle</a></span></dt><dt><span class="section"><a href="#par.project">4.5. Creating a PAR</a></span></dt><dt><span class="section"><a href="#osgi.reference">4.6. Referencing an OSGi Service</a></span></dt><dt><span class="section"><a href="#osgi.service">4.7. Publishing an OSGi Service</a></span></dt></dl></dd><dt><span class="chapter"><a href="#middle-tier">5. The Middle Tier</a></span></dt><dd><dl><dt><span class="section"><a href="#middle-tier.introduction">5.1. Introduction</a></span></dt><dt><span class="section"><a href="#middle-tier.create-db-project">5.2. Creating the DataSource project</a></span></dt><dt><span class="section"><a href="#middle-tier.building-jpa-module">5.3. Building the JPA module</a></span></dt><dt><span class="section"><a href="#middle-tier.trying-it-out">5.4. Trying out the JPA middle tier</a></span></dt><dt><span class="section"><a href="#middle-tier.applying-best-practices">5.5. Applying best practices to the middle tier</a></span></dt></dl></dd><dt><span class="chapter"><a href="#testing.greenpages">6. Testing GreenPages</a></span></dt><dd><dl><dt><span class="section"><a href="#testing.greenpages.introduction">6.1. Introduction</a></span></dt><dt><span class="section"><a href="#testing.greenpages.single.bundle">6.2. Single bundle integration testing</a></span></dt><dt><span class="section"><a href="#testing.greenpages.contributing.osgi">6.3. Contributing OSGi sourced dependencies</a></span></dt><dt><span class="section"><a href="#testing.greenpages.application">6.4. Multi bundle integration testing</a></span></dt></dl></dd><dt><span class="chapter"><a href="#automated.build">7. Automated Build</a></span></dt><dd><dl><dt><span class="section"><a href="#automated.build.introduction">7.1. Introduction</a></span></dt><dt><span class="section"><a href="#automated.build.setup">7.2. Setting up for Automated Build</a></span></dt><dt><span class="section"><a href="#automated.build.create.pom">7.3. Create POM</a></span></dt><dt><span class="section"><a href="#automated.build.par.plugin">7.4. Adding the par plugin</a></span></dt><dt><span class="section"><a href="#automated.build.dependency.plugin">7.5. Adding the dependency plugin</a></span></dt><dt><span class="section"><a href="#running.tests">7.6. Automatically running the tests</a></span></dt><dt><span class="section"><a href="#automated.build.deploy.application">7.7. Deploying the application</a></span></dt></dl></dd><dt><span class="appendix"><a href="#further.resources">A. Further Resources</a></span></dt><dd><dl><dt><span class="section"><a href="#further.resources.projects">A.1. Projects</a></span></dt><dt><span class="section"><a href="#further.resources.documentation">A.2. Documentation</a></span></dt></dl></dd></dl></div><div class="preface" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="d0e111"></a>Preface</h2></div></div></div><p>
This Guide introduces some basic concepts, explains how to install Virgo Web Server
and the associated Eclipse<span class="trademark"></span>&#8482; tools, and examines a sample
web application in detail, including how the application is built and tested.
</p><p>It is intended for Spring application programmers and assumes little or no
understanding of OSGi<span class="trademark"></span>&#8482; or Virgo Web Server.</p><p>Questions about Web Server and SpringSource Tool Suite (or this Guide) may be posted to the Web Server Community Forums
(<a class="ulink" href="http://www.eclipse.org/forums" target="_top">http://www.eclipse.org/forums</a>).</p></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="concepts"></a>1.&nbsp;Concepts</h2></div></div></div><p>
Virgo Web Server is a Java application server composed of a
collection of modules which supports applications which are also composed of a
collection of modules.
These may be traditional Java web applications packaged as Web ARchive (<code class="literal">.war</code>)
files as well as other modular applications.
Modules may be shared between applications and multiple versions of modules
can co-exist.
</p><p>This chapter introduces concepts
necessary for developing Web Server applications.
These concepts will become clearer as the GreenPages application is explored
in later chapters.</p><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="concepts.osgi"></a>1.1&nbsp;OSGi concepts</h2></div></div></div><p>Modules in Virgo are represented using a standard Java
module system known as <span class="emphasis"><em>OSGi</em></span>.
Modules consist of programs and resources organised by Java package together
with metadata which declares imported and exported packages.
A module <span class="emphasis"><em>exports</em></span> a package to make the corresponding programs and resources
available for use by other modules.
A module <span class="emphasis"><em>imports</em></span> a package to use the corresponding programs and resources of
another module.</p><p>
Representing a program as a collection of modules makes it easier for the
programmer to manage it and modify it and for teams of programmers to divide
responsibilities between themselves.
A module is similar to a Java class in this respect. Design principles similar to those for
organising data and programs into classes can be applied
to organising applications into modules.
</p><p>
An industry consortium known as the
<span class="emphasis"><em>OSGi Alliance</em></span> (see <a class="xref" href="#further.resources.projects" title="A.1&nbsp;Projects">the appendix Projects</a>) develops OSGi
specifications, reference implementations, and compliance tests.
Virgo Web Server is built on the Equinox OSGi framework which is also
the reference implementation for the OSGi framework specification.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e164"></a>Bundles</h3></div></div></div><p>Modules in OSGi are known as <span class="emphasis"><em>bundles</em></span>.
Each bundle is stored in a file which conforms to the JAR file format and
can contain Java classes, a manifest (in <code class="literal">META-INF/MANIFEST.MF</code>),
and further resource files.</p><p>The OSGi framework enables bundles to be installed and run.</p><p>OSGi identifies bundles &#8220;<span class="quote">by name</span>&#8221; or &#8220;<span class="quote">by identifier</span>&#8221; (id).</p><p>The <span class="emphasis"><em>symbolic name</em></span> and
<span class="emphasis"><em>version</em></span> of a bundle is an attribute of the bundle itself and uniquely identifies that bundle (by name) in an OSGi framework.
A bundle usually declares its <span class="emphasis"><em>symbolic name</em></span> and <span class="emphasis"><em>version</em></span>
in its manifest (a file called <code class="literal">MANIFEST.MF</code>) like this:
</p><pre class="programlisting">Bundle-SymbolicName: org.foo.bundle
Bundle-Version: 1.2.3.BUILD-2009-06-04
</pre><p>
</p><p>Additionally, the OSGi framework
assigns a distinct number, known as a <span class="emphasis"><em>bundle id</em></span>, to each bundle
as it is installed. Bundles may be referred to &#8220;<span class="quote">by identifier</span>&#8221; using this number.
The OSGi framework itself resides in a
bundle with bundle id <code class="literal">0</code>.</p><p>The
dependencies between bundles are expressed statically in terms of packages and
dynamically in terms of services. A package is familiar to Java programmers.
For example, a Java program may depend on a class <code class="literal">org.foo.X</code>,
from package <code class="literal">org.foo</code>, and a bundle
containing that program
would either need to contain <code class="literal">org.foo.X</code> or depend on the
package <code class="literal">org.foo</code>.
Package dependencies are specified in the bundle manifest, for example:
</p><pre class="programlisting">Import-Package: org.foo
</pre><p>
</p><p>A bundle which provides a package for use by other bundles <span class="emphasis"><em>must</em></span>
export the package in its manifest. For example:
</p><pre class="programlisting">Export-Package: org.foo
</pre><p>
</p><p>The OSGi framework ensures that a given bundle&#8217;s package dependencies
can be <span class="emphasis"><em>satisfied</em></span> before the bundle runs. This process is known as
<span class="emphasis"><em>resolution</em></span>.</p><p>After a bundle is resolved, its classes and resources are available for
loading.
In OSGi, bundles and their packages do not appear on the application classpath.
Instead, each bundle has a class loader which loads its own classes and loads classes belonging to each of its
imported packages by deferring to the bundle class loader that exports the package.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e252"></a>Life cycle</h3></div></div></div><p>The OSGi framework manages the <span class="emphasis"><em>life cycle</em></span> of each bundle. A bundle is
first of all <span class="emphasis"><em>install</em></span>ed and will be in the INSTALLED state.
If a request is made to <span class="emphasis"><em>start</em></span> the bundle, the OSGi framework <span class="emphasis"><em>resolve</em></span>s the bundle
and, if resolution was successful, will subsequently move the bundle to the ACTIVE state.
If a request is made to <span class="emphasis"><em>stop</em></span> the bundle, the OSGi framework will move the
bundle back to the RESOLVED state. A request may then be made to <span class="emphasis"><em>uninstall</em></span>
the bundle.</p><p>While the bundle is INSTALLED, ACTIVE or RESOLVED, it may be <span class="emphasis"><em>updated</em></span> to pick up
some changes. These changes are not detected by bundles which were depending
on the bundle before it was updated.
A &#8220;<span class="quote">refresh packages</span>&#8221; operation may be performed to ripple the
changes out to those bundles. (See <a class="xref" href="#concepts.services" title="Services">Services concepts</a>.)</p><p>The life cycle of a bundle can be summarised by a state transition diagram.
This diagram shows some more of the intermediate states of a bundle not described in the overview above:
</p><div class="figure"><a name="d0e287"></a><p class="title"><b>Figure&nbsp;1.1.&nbsp;Bundle life cycle</b></p><div class="figure-contents"><div class="mediaobject" align="center"><img src="images/concepts/bundle-lifecycle.png" align="middle" alt="Bundle life cycle"></div></div></div><p><br class="figure-break"></p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="concepts.services"></a>Services</h3></div></div></div><p>Bundles may publish Java objects, known as <span class="emphasis"><em>services</em></span>,
to a registry managed by the OSGi framework. Other bundles running in
the same OSGi framework can then find and use those services. Services
are typically instances of some shared Java interface. A bundle which
provides a service need not then export the package containing the
<span class="emphasis"><em>implementation</em></span>
class of the service.
</p><p>For example, a bundle could export a package containing the interface
<code class="literal">org.bar.SomeInterface</code>, thus:
</p><pre class="programlisting">Export-Package: org.bar
</pre><p>
</p><p>&#8230;implement the interface with a class <code class="literal">SomeImpl</code>:
</p><pre class="programlisting">package org.bar.impl;
class SomeImpl implements SomeInterface {
&#8230;
}
</pre><p>
</p><p>&#8230;create an instance of <code class="literal">SomeImpl</code> and
then publish this instance (as an instance of the interface <code class="literal">SomeInterface</code>).
</p><p>An OSGi framework publishes a number of standard services. For example, the
<span class="emphasis"><em>Package Admin</em></span> service provides the &#8220;<span class="quote">refresh packages</span>&#8221; life cycle operation
mentioned above.</p><p>OSGi provides an <em class="glossterm">API</em> which can be used to publish and find services,
but it is much simpler to use Spring DM to accomplish this. (See <a class="xref" href="#concepts.springdm" title="1.2&nbsp;Spring DM concepts">Spring DM concepts</a>.)</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e347"></a>Versioning</h3></div></div></div><p>
OSGi allows different versions of bundles, packages, and several
other entities, to co-exist in the same framework
and provides some mechanisms for managing these versions.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e352"></a>Version numbers</h4></div></div></div><p>An OSGi <span class="emphasis"><em>version number</em></span> consists of up to three numeric components,
or exactly three
numeric components followed by a string component. These components are
separated by a period (&#8220;<span class="quote"><code class="literal">.</code></span>&#8221;) and
are called the <span class="emphasis"><em>major</em></span>, <span class="emphasis"><em>minor</em></span>, <span class="emphasis"><em>micro</em></span>,
and <span class="emphasis"><em>qualifier</em></span> components, respectively.
</p><p>For example, the version <code class="literal">2.4.1.ga</code> has major component <code class="literal">2</code>, minor component
<code class="literal">4</code>, micro component <code class="literal">1</code>,
and a qualifier component <code class="literal">ga</code>. (There are restrictions on the characters that can appear in
a qualifier. For example: letters, digits, underscores and hyphens are allowed; periods and commas are not.)</p><p>Trailing components may be omitted along with their period (<code class="literal">.</code>). So, for example, the version
numbers <code class="literal">2</code>, <code class="literal">2.0</code>, and <code class="literal">2.0.0</code>
all denote the same version. This example demonstrates that <code class="literal">0</code> is assumed if a numeric component is omitted,
and the empty string is assumed for an omitted qualifier.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e410"></a>Version ranges</h4></div></div></div><p>Dependencies on bundles and packages have an associated <span class="emphasis"><em>version range</em></span>
which is specified using an interval notation: a square bracket
&#8220;<span class="quote"><code class="literal">[</code></span>&#8221; or &#8220;<span class="quote"><code class="literal">]</code></span>&#8221; denotes
an <span class="emphasis"><em>inclusive</em></span> end of the range and a round bracket
&#8220;<span class="quote"><code class="literal">(</code></span>&#8221; or &#8220;<span class="quote"><code class="literal">)</code></span>&#8221; denotes
an <span class="emphasis"><em>exclusive</em></span> end of the range. Where one end of the range is to be included and the other excluded, it is permitted to
pair a round bracket with a square bracket.
The examples below make this clear.</p><p>If a single version number is used where a version <span class="emphasis"><em>range</em></span> is
required this does <span class="emphasis"><em>not</em></span> indicate a single version, but the range <span class="emphasis"><em>starting</em></span> from that version and
including all higher versions.</p><p>There are three common cases:
</p><div class="itemizedlist"><ul type="disc"><li><p>A &#8220;<span class="quote">strict</span>&#8221; version range, such as <code class="literal">[1.2,1.2]</code>, which
denotes that version and only that version.</p></li><li><p>A &#8220;<span class="quote">half-open</span>&#8221; range, such as
<code class="literal">[1.2,2)</code>, which has an inclusive lower limit
and an exclusive upper limit, denoting version <code class="literal">1.2.0</code> and any version after this, up
to, <span class="emphasis"><em>but not including</em></span>, version <code class="literal">2.0.0</code>.
</p></li><li><p>An &#8220;<span class="quote">unbounded</span>&#8221; version range, such as <code class="literal">1.2</code>, which
denotes version <code class="literal">1.2</code> and <span class="emphasis"><em>all</em></span> later versions.</p></li></ul></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e497"></a>Versioning policies</h4></div></div></div><p>A <span class="emphasis"><em>versioning policy</em></span> is a way of using version numbers to indicate compatible
and incompatible changes.
OSGi does not mandate a particular versioning policy.
Instead, a specific versioning policy may be implemented using version ranges.</p><p>Strict and half-open version ranges are most useful in representing versioning
policies.
Unbounded version ranges can lead to problems as they (unrealistically) assume that
compatibility will be preserved indefinitely.</p><p>For example, a conservative versioning policy might assume that any change, other than
in the qualifier component of a version, implies an incompatible
change to the object.
Such a policy would employ version ranges such as <code class="literal">[1.2.1.beta,1.2.2)</code>
which accept any version from <code class="literal">1.2.1.beta</code> (inclusive) up to but not including
<code class="literal">1.2.2</code> (exclusive).
</p><p>Alternatively, a relaxed versioning policy might assume that only changes in the major component of
a version denote an incompatible change.
Such a policy would employ version ranges such as <code class="literal">[1.2,2)</code> to capture this.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e524"></a>Bundle version</h4></div></div></div><p>Each bundle has a version.
The bundle&#8217;s version may be specified in the manifest using a
<code class="literal">Bundle-Version</code> header:
</p><div class="informalexample"><pre class="programlisting">Bundle-Version: 1.4.3.BUILD-20090302
</pre></div><p>
If not specified the bundle version is assumed to be <code class="literal">0</code>.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e540"></a>Package version</h4></div></div></div><p>Each exported package has a version.
The exported package&#8217;s version may be specified on the Export-Package manifest header. For example
</p><div class="informalexample"><pre class="programlisting">Export-Package: org.foo;version="2.9",org.bar;version="1"
</pre></div><p>
exports two packages: <code class="literal">org.foo</code>, at version <code class="literal">2.9.0</code> and
<code class="literal">org.bar</code>, at version <code class="literal">1.0.0</code>.
</p><p>If the version attribute is omitted the version is assumed to be <code class="literal">0</code>.</p><p>Each package <span class="emphasis"><em>import</em></span> has a version <span class="emphasis"><em>range</em></span>.
The package import version range may be specified on the <code class="literal">Import-Package</code> manifest header.
If interval notation is used, the version range must be enclosed in double quotes, for example:
</p><div class="informalexample"><pre class="programlisting">Import-Package: org.foo;version="[2,3)",org.bar;version="[1,1]"</pre></div><p>
seeks to import a package <code class="literal">org.foo</code> in the range <code class="literal">[2.0.0,3.0.0)</code> and a package
<code class="literal">org.bar</code> with the (exact) version <code class="literal">1.0.0</code>.
</p><p>If a version range is not specified on an import, the range <code class="literal">0</code> is assumed, meaning that
any version of this package would satisfy the import.</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e599"></a>Bundle manifest version</h4></div></div></div><p>Bundle manifests have a version which is <code class="literal">1</code> by default,
indicating OSGi Release 3 semantics.
Web Server is based on OSGi Release 4 and therefore expects bundle manifests to be
at version <code class="literal">2</code>, indicating OSGi Release 4 semantics. (See <a class="xref" href="#further.resources.projects" title="A.1&nbsp;Projects">the appendix Projects</a>.)
The bundle manifest&#8217;s version should be specified on the Bundle-ManifestVersion manifest header, exactly as follows:
</p><div class="informalexample"><pre class="programlisting">Bundle-ManifestVersion: 2
</pre></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e617"></a>Manifest version</h4></div></div></div><p>Manifests themselves also have a version which <span class="emphasis"><em>must</em></span> be specified as <code class="literal">1.0</code>.
This is not an OSGi definition but part of the JAR file specification
(<a class="ulink" href="http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html" target="_top">http://java.sun.com/javase/6/docs/technotes/guides/jar/jar.html</a>).
</p><div class="informalexample"><pre class="programlisting">Manifest-Version: 1.0
</pre></div><p>
</p></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="concepts.springdm"></a>1.2&nbsp;Spring DM concepts</h2></div></div></div><p>Spring DM is a project which enables <span class="emphasis"><em>services</em></span> to be published and consumed
using descriptions written in XML.
Web Server has Spring DM built-in.</p><p>The XML descriptions reside in files with extension <code class="literal">.xml</code> in the
bundle&#8217;s <code class="literal">META-INF/spring</code> sub-directory.</p><p>
To publish a service, an <code class="literal">&lt;osgi:service&gt;</code> tag is used, specifying the
implementation class of the service and the interface class to be used.
Spring DM constructs an instance of the implementation class and
publishes that instance in the OSGi service registry under the interface when the bundle is started.
</p><p>To consume a service, an <code class="literal">&lt;osgi:reference&gt;</code> tag is used and the
service may be passed into other Spring beans using Spring&#8217;s dependency
injection facilities.</p><p>Spring DM automatically creates proxies for OSGi services so that the actual service
object may come and go at runtime.
If a service disappears, any proxies to the service will wait for the service to re-appear.
This effect is known as <span class="emphasis"><em>damping</em></span>.</p><p>When a bundle is started, Spring DM builds the application contexts
specified by the XML descriptions, creates proxies for the specified services, and publishes
the specified services to the OSGi service registry.</p><p>When a bundle is stopped, Spring DM retracts any services it published on behalf of the bundle
and closes the bundle&#8217;s application contexts.
Web Server turns off damping of a service proxy while the proxy&#8217;s application context
is being closed.</p><p>(Spring DM has been contributed to Eclipse as the <span class="emphasis"><em>Gemini Blueprint</em></span> project.)</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="concepts.grouping"></a>1.3&nbsp;Grouping bundles in Web Server</h2></div></div></div><p>Web Server provides a way of grouping together a collection
of OSGi bundles which comprise a single application.
These bundles are placed in a JAR file with extension &#8220;<span class="quote"><code class="literal">.par</code></span>&#8221;. This is called a PAR file.</p><p>All the bundles in a PAR file are resolved together and so mutual dependencies are permitted.</p><p>At runtime a PAR file provides a <span class="emphasis"><em>scope</em></span> in the sense that bundles
inside the PAR file may depend on packages and services outside the PAR file,
but bundles outside the PAR file may not depend on packages and services
provided by the PAR file.</p><p>Virgo also provides the plan artifact as another way of grouping bundles and other artifacts into an application.
A <span class="emphasis"><em>plan</em></span> is a file (in XML format) listing a collection of artifacts.
This Guide makes no further reference to plans.
See <a class="xref" href="#further.resources.documentation" title="A.2&nbsp;Documentation">Section&nbsp;A.2, &#8220;Documentation&#8221;</a> for a link to more Virgo documentation.</p><p>PAR files (or individual bundles) are <span class="emphasis"><em>deployed</em></span> into Web Server by dropping them into a &#8220;<span class="quote">pickup</span>&#8221;
directory or using the Administration Console web application provided with Web Server.
During deployment, the bundles in the PAR file are installed into OSGi, resolved together, and then started together.</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="installation"></a>2.&nbsp;Installation</h2></div></div></div><p>
Before developing an application with Web Server, it is essential to install <span class="emphasis"><em>Web Server</em></span>,
an <span class="emphasis"><em>Integrated Development Environment</em></span> (IDE), and a build system integrated with Eclipse.
The IDE used here is the
Eclipse-based <span class="emphasis"><em>SpringSource Tool Suite</em></span> (STS), and
the build system used here is <span class="emphasis"><em>Apache Maven</em></span>.
</p><p>STS is supplied as a fully configured Eclipse IDE, with Virgo Web Server and Maven plugins built-in.</p><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installation.prereqs"></a>2.1&nbsp;Pre-requisites</h2></div></div></div><p>
Before proceeding, ensure that a Java<span class="trademark"></span>&#8482; Standard Edition Development Kit (JDK)
for Java 6 or later is installed and that the <code class="literal">JAVA_HOME</code> environment variable
is set to the root directory of the JDK.
(<span class="emphasis"><em>A Java Runtime Environment (JRE) alone is not sufficient,
a development kit is necessary to use the facilities in STS.</em></span>)
</p><p>
To verify this, issue the command <code class="literal">"%JAVA_HOME%"\bin\java -version</code> from
a command prompt on Windows (or <code class="literal">$JAVA_HOME/bin/java -version</code> from a terminal window on UNIX)
and ensure that the command completes successfully and reports
a Java version <code class="literal">1.6.</code><span class="emphasis"><em>x</em></span> (denoting Java 6) or greater.
</p><p>
Also issue the command <code class="literal">"%JAVA_HOME%"\bin\jar</code> to ensure that there is a means of
extracting files from zip archives.
If the <code class="literal">jar</code> command is unavailable, download and install a suitable zip program
such as <code class="literal">7zip</code>, <code class="literal">gzip</code>, or <code class="literal">WinZip</code>.
This is most relevant for Windows operating systems where the inbuilt zip extraction utility may
not handle long pathnames correctly.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installation.dmserver"></a>2.2&nbsp;Installing Web Server</h2></div></div></div><p>
Although the steps are similar, the details of installing the Virgo Web Server
depend on the operating system.
</p><p>
Obtain Web Server from the
download site (<a class="ulink" href="http://www.eclipse.org/virgo/download" target="_top">http://www.eclipse.org/virgo/download</a>).
This guide is consistent with version 2.1.0.RELEASE of Web Server.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e780"></a>Installing Web Server on Windows<span class="trademark"></span>&#8482; operating systems</h3></div></div></div><p>
Unzip the download of Web Server to the root directory of
a drive (this will avoid possible problems with long pathnames).
Set an environment variable <code class="literal">%VWS_HOME%</code> to refer to the unzipped folder&#8230;
</p><pre class="programlisting">prompt&gt; cd C:\
prompt&gt; "%JAVA_HOME%"\bin\jar xf <span class="emphasis"><em>\path\to\</em></span>virgo-web-server-2.1.0.RELEASE.zip
prompt&gt; set VWS_HOME=C:\virgo-web-server-2.1.0.RELEASE
</pre><p>
</p><p>
To verify the installation, issue the command:
<code class="literal">"%VWS_HOME%"\bin\startup.bat</code> and ensure a message numbered <code class="literal">UR0001I</code>
is displayed.
Many other messages about starting and installing other required artifacts are produced,
but the <code class="literal">UR0001I</code> message indicates that the user region is ready for use.
(<span class="emphasis"><em>Timestamps have been removed
and thread names and other details may vary with different installations and versions.</em></span>)
</p><pre class="programlisting">system-artifacts &lt;TC0000I&gt; Starting Tomcat.
system-artifacts &lt;TC0010I&gt; Creating HTTP/1.1 connector with scheme http on port 8080.
system-artifacts &lt;TC0010I&gt; Creating HTTP/1.1 connector with scheme https on port 8443.
system-artifacts &lt;TC0010I&gt; Creating AJP/1.3 connector with scheme http on port 8009.
system-artifacts &lt;TC0001I&gt; Started Tomcat.
system-artifacts &lt;DE0004I&gt; Starting bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'.
system-artifacts &lt;DE0004I&gt; Starting bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'.
start-signalling-1 &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'.
system-artifacts &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.tomcat' version '2.1.0.RELEASE'.
start-signalling-1 &lt;DE0005I&gt; Started bundle 'org.eclipse.gemini.web.tomcat' version '1.1.0.RELEASE'.
start-signalling-2 &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'.
start-signalling-2 &lt;DE0005I&gt; Started plan 'org.eclipse.virgo.web' version '2.1.0'.
Thread-2 &lt;UR0001I&gt; User region ready. </pre><p>
</p><p>Shut down the server by pressing <code class="literal">Ctrl-C</code>.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e818"></a>Installing Web Server on UNIX<span class="trademark"></span>&#8482; operating systems</h3></div></div></div><p>
Unzip the download of Web Server to a suitable location on the file system, such
as the home directory. (If the download was automatically unzipped by the operating
system, simply move the unzipped directory to the chosen location.)
Set an environment variable <code class="literal">$VWS_HOME</code> to refer to the unzipped folder&#8230;
</p><pre class="programlisting">prompt$ mkdir <span class="emphasis"><em>/path/to/home/</em></span>springsource
prompt$ cd <span class="emphasis"><em>/path/to/home/</em></span>springsource
prompt$ unzip <span class="emphasis"><em>/path/to/</em></span>virgo-web-server-2.1.0.RELEASE.zip
prompt$ export VWS_HOME=<span class="emphasis"><em>/path/to/home/</em></span>springsource/virgo-web-server-2.1.0.RELEASE
</pre><p>
</p><p>
To verify the installation, use a terminal window to issue the command:
<code class="literal">$VWS_HOME/bin/startup.sh</code> and ensure a message numbered <code class="literal">UR0001I</code> is displayed.
Many other messages about starting and installing other required artifacts are produced,
but the <code class="literal">UR0001I</code> message indicates that the user region is ready for use.
(<span class="emphasis"><em>Timestamps have been removed
and thread names and other details may vary with different installations and versions.</em></span>)
</p><pre class="programlisting">system-artifacts &lt;TC0000I&gt; Starting Tomcat.
system-artifacts &lt;TC0010I&gt; Creating HTTP/1.1 connector with scheme http on port 8080.
system-artifacts &lt;TC0010I&gt; Creating HTTP/1.1 connector with scheme https on port 8443.
system-artifacts &lt;TC0010I&gt; Creating AJP/1.3 connector with scheme http on port 8009.
system-artifacts &lt;TC0001I&gt; Started Tomcat.
system-artifacts &lt;DE0004I&gt; Starting bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'.
system-artifacts &lt;DE0004I&gt; Starting bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'.
start-signalling-1 &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'.
system-artifacts &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.tomcat' version '2.1.0.RELEASE'.
start-signalling-1 &lt;DE0005I&gt; Started bundle 'org.eclipse.gemini.web.tomcat' version '1.1.0.RELEASE'.
start-signalling-2 &lt;DE0005I&gt; Started bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'.
start-signalling-2 &lt;DE0005I&gt; Started plan 'org.eclipse.virgo.web' version '2.1.0'.
Thread-2 &lt;UR0001I&gt; User region ready. </pre><p>
</p><p>Shut down the server by pressing <code class="literal">Ctrl-C</code>. </p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installation.sts"></a>2.3&nbsp;Installing the SpringSource Tool Suite</h2></div></div></div><p>
The SpringSource Tool Suite (STS) is a development environment based on Eclipse that
is already configured with
the plugins needed to
work with Web Server and OSGi.
Although the steps are similar, the details of installing STS depend on the operating system.
</p><p>
Go to the STS download site (<a class="ulink" href="http://www.springsource.com/products/springsource-tool-suite-download" target="_top">http://www.springsource.com/products/springsource-tool-suite-download</a>)
and download the variant appropriate to the operating system being used.
This guide is consistent with STS version 2.5.0.RELEASE. Previous versions may not work properly with
the latest revision of GreenPages, currently 2.3.0.RELEASE.
</p><p>
It is possible to use vanilla Eclipse, and add the SpringSource Tools to it. Please refer to the installation instructions in the
<a class="ulink" href="http://www.eclipse.org/virgo/documentation/" target="_top">Virgo Programmer Guide</a>.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e882"></a>Installing STS on Windows<span class="trademark"></span>&#8482; operating systems</h3></div></div></div><p>
Unzip the download of STS to the root directory of
a drive (this will avoid possible problems with long pathnames).
</p><pre class="programlisting">prompt&gt; cd C:\
prompt&gt; "%JAVA_HOME%"\bin\jar xf \<span class="emphasis"><em>full&#8230;path&#8230;to</em></span>\springsource-tool-suite-2.5.0.RELEASE-e3.6.1-win32.zip
</pre><p>
</p><p>
To verify the installation, run the <code class="literal">eclipse.exe</code> (or <code class="literal">sts.exe</code>) executable in the unzipped directory
and check that STS displays a welcome panel.
The first time there may be a short delay due to the initial set-up of indexes.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h4 class="title"><a name="d0e903"></a>Installing STS on UNIX<span class="trademark"></span>&#8482; operating systems</h4></div></div></div><p>
Unpack the download of STS to a suitable location on the file system, such
as <code class="literal">/opt</code> or, if root access is not available, the home directory.
(If the download was automatically unpacked by the operating
system, simply move the unpacked directory to the chosen location.)
</p><p>
To verify the installation, run the STS executable (<code class="literal">STS.app</code> on Mac OS X)
in the unpacked directory and check that STS displays a welcome panel.
The first time there may be a short delay due to the initial set-up of indexes.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="d0e918"></a>Note about Java versions in STS</h3></div></div></div><p>
SpringSource Tool Suite runs on Eclipse using Java Version 1.6, and Web Server requires Java Version 1.6.
The GreenPages application built here also requires Java Version 1.6.
The default Java compiler settings in STS should not need adjusting, but should be checked.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installation.maven"></a>2.4&nbsp;Installing Apache Maven</h2></div></div></div><p>
<span class="emphasis"><em>Apache Maven</em></span>, or Maven for short, is a software project management and comprehension tool
which uses a central <span class="emphasis"><em>Project Object Model</em></span> (POM) to manage a project&#8217;s build, reporting
and documentation generation. POM files (<code class="literal">pom.xml</code>) are included in the projects for
GreenPages.
</p><p>
To install Maven, visit the Maven website (<a class="ulink" href="http://maven.apache.org" target="_top">http://maven.apache.org</a>)
and follow the download instructions from there.
This document has been written and tested with Maven version 2.2.0. The rest of the document
assumes that Maven
commands (<code class="literal">mvn &#8230;</code>) are available from the command line.
</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="installing.greenpages"></a>3.&nbsp;Installing and exploring GreenPages</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installing.greenpages.introduction"></a>3.1&nbsp;Introduction</h2></div></div></div><p>GreenPages is a simple application that allows users to search an online email address directory. Each listing
in the directory details the relevant email addresses and the name of the owner. GreenPages has only three screens:
the search screen, the results screen and the listing detail screen.</p><p>In the search screen, users can enter search criteria to be matched against the listings in the directory.
The result screen displays any listings that match the criteria entered by the user. The listing detail screen
shows all the data known about a given listing.</p><p>Despite its simplicity, GreenPages is designed to demonstrate many different Web Server features and to
act as a template from which other modular applications can be built. In particular, GreenPages demonstrates:
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc"><p>module dependencies with <code class="literal">Import-Package</code>,</p></li><li style="list-style-type: disc"><p>load-time weaving with JPA and AspectJ,</p></li><li style="list-style-type: disc"><p>bundle classpath scanning, and</p></li><li style="list-style-type: disc"><p>service export, lookup and injection.</p></li></ul></div><p>In addition to demonstrating common Web Server features, GreenPages demonstrates integration with:
</p><div class="itemizedlist"><ul type="bullet"><li style="list-style-type: disc"><p>Spring Framework 3.0;</p></li><li style="list-style-type: disc"><p>FreeMarker 2.3;</p></li><li style="list-style-type: disc"><p>EclipseLink 1.0.0;</p></li><li style="list-style-type: disc"><p>H2 1.0.71; and</p></li><li style="list-style-type: disc"><p>Commons DBCP 1.2.2.</p></li></ul></div><p>
</p><p>The GreenPages application is packaged as a PAR file containing four modules.
</p><div class="mediaobject" align="center"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="461"><tr><td align="center"><img src="images/installing-greenpages/greenpages.png" align="middle" width="461"></td></tr></table></div><p>
</p><p>
The <code class="literal">greenpages.db</code> module provides access to an external database and publishes a
<code class="literal">javax.sql.DataSource</code> service.
</p><p>
The <code class="literal">greenpages.app</code> module exports a <code class="literal">greenpages</code> package containing
<code class="literal">Directory</code> and <code class="literal">Listing</code> interfaces.
</p><p>
The <code class="literal">greenpages.jpa</code> module imports the <code class="literal">greenpages</code> package and
uses the <code class="literal">javax.sql.DataSource</code> service to
access the external database and publishes its contents as a <code class="literal">greenpages.Directory</code> service.
</p><p>
The <code class="literal">greenpages.web</code> module imports the <code class="literal">greenpages</code> package and uses the
<code class="literal">greenpages.Directory</code> service to respond to web requests.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installing.greenpages.obtaining"></a>3.2&nbsp;Obtaining GreenPages</h2></div></div></div><p>This document provides instructions for building the complete GreenPages application and running it in Web Server as well as running tests and executing it from the SpringSource Tool Suite.
In addition, the application is examined in development stages from SpringSource Tool Suite, stepping through the development process and comparing this to the solution.
</p><p>To get the completed GreenPages application, including tests and explanatory skeleton parts:
</p><div class="orderedlist"><ol type="1"><li><p>download the latest ZIP file from </p><pre class="programlisting">http://eclipse.org/virgo/download/</pre></li><li><p>extract all the files from the ZIP file to a convenient directory (preserving the directory structure).</p></li></ol></div><p>
</p><p>To extract the files on Windows:
</p><pre class="programlisting">prompt&gt; mkdir c:\springsource\samples
prompt&gt; cd c:\springsource\samples
prompt&gt; jar xf c:\path\to\greenpages-2.3.0.RELEASE.zip
prompt&gt; set GREENPAGES_HOME=c:\springsource\samples\greenpages-2.3.0.RELEASE</pre><p>
</p><p>To extract the files on Unix systems:
</p><pre class="programlisting">prompt$ mkdir -p /opt/springsource/samples
prompt$ cd /opt/springsource/samples
prompt$ unzip /path/to/greenpages-2.3.0.RELEASE.zip
prompt$ export GREENPAGES_HOME=/opt/springsource/samples/greenpages-2.3.0.RELEASE
</pre><p>
</p><p>The environment variable <code class="literal">GREENPAGES_HOME</code> set here is not used by the projects, but is used as a shorthand
in the instructions that follow.
</p><p>The GreenPages zip file contains two main directories called <code class="literal">solution</code> and <code class="literal">start</code>.
The <code class="literal">solution</code> directory contains the completed application which can be built and tested (as described in the next section).
The <code class="literal">start</code> directory contains an initial skeleton of the GreenPages application which can be used to generate the full application.
The examination steps refer to this skeleton by way of illustration.
</p><p>To follow the examination steps read <a class="xref" href="#web.module" title="4.&nbsp;The Web Module">Chapter&nbsp;4, <i>The Web Module</i></a> <span class="emphasis"><em>after</em></span> installing the full application in the following section.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installing.greenpages.building"></a>3.3&nbsp;Building and installing GreenPages</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.building.mvn"></a>Building with Apache Maven</h3></div></div></div><p>GreenPages uses Apache Maven as its primary build system. Each module of the application can be built
separately and the entire application can built and assembled into a PAR file from a single location.
To build the application and assemble it into a PAR
file:
</p><div class="orderedlist"><ol type="1"><li><p>Make <code class="code">$GREENPAGES_HOME/solution</code> the current directory.</p></li><li><p>Run the command
<code class="code">mvn package</code>. The first time this is run several files will be downloaded
from Maven repositories and SpringSource repositories. Subsequent runs will not need to do this.
</p></li><li><p>Verify that the
<code class="code">greenpages-2.3.0.RELEASE.par</code> file exists in
<code class="code">$GREENPAGES_HOME/solution/greenpages/target</code>.
</p></li></ol></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.building.par.provided"></a>Installing dependencies into Web Server</h3></div></div></div><p>
Unlike traditional Java EE applications, GreenPages does not package all of its dependencies inside its
deployment unit. Instead, it relies on the mechanisms of OSGi to locate its dependencies at runtime.
When running an OSGi application on Web Server, these dependencies can be loaded into memory as needed, but first they
must be made available to Web Server.
</p><p>The Maven build included with GreenPages uses the <code class="code">dependency:copy-dependencies</code> plugin to gather
all the artifacts that GreenPages depends on that are not supplied by the Web Server runtime. These dependencies
can then be installed into the Web Server repository. Dependencies are gathered automatically during the
<code class="code">package</code> phase. These dependencies can be found in
<code class="literal">$GREENPAGES_HOME/solution/greenpages/target/par-provided</code>. To install dependencies
simply copy all the <code class="code">*.jar</code> files from this directory into <code class="literal">$VWS_HOME/repository/usr</code>.
</p><p>Installing dependencies on Windows:
</p><pre class="programlisting">prompt&gt; cd %GREENPAGES_HOME%\solution\greenpages
prompt&gt; copy target\par-provided\* %VWS_HOME%\repository\usr
</pre><p>
</p><p>Installing Dependencies on UNIX:
</p><pre class="programlisting">prompt$ cd $GREENPAGES_HOME/solution/greenpages
prompt$ cp target/par-provided/* $VWS_HOME/repository/usr
</pre><p>
</p><p>
Notice that Web Server will not necessarily see these dependencies unless its repository indexes are rebuilt.
Different repositories behave differently in this respect; some are passive (their indexes are built only once upon startup)
and some are active (they can detect new files or files being removed dynamically).
The <code class="literal">usr</code> repository is active so there is no
need to restart Web Server when copying these files.
The next time Web Server is started the <code class="literal">-clean</code> option will cause Web Server to re-scan the repository directories in any case.
It is always safe to start Web Server with the <code class="literal">-clean</code> option.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.building.db"></a>Starting and configuring the database</h3></div></div></div><p>GreenPages uses the H2 database to store all its data. Before starting the application, start the database server and populate the database with data.</p><div class="orderedlist"><ol type="1"><li><p>Change to the <code class="code">$GREENPAGES_HOME/db</code> current directory. On Unix:</p><pre class="programlisting">prompt$ cd $GREENPAGES_HOME/db</pre><p>On Windows:</p><pre class="programlisting">prompt&gt; cd %GREENPAGES_HOME%\db</pre></li><li><p>Run the database startup script appropriate to the operating system. For Unix, this is <code class="literal">run.sh</code>, run in the background:</p><pre class="programlisting">prompt$ sh run.sh &amp;</pre><p>Press Return to continue.</p><p>On Windows, run the <code class="literal">run.bat</code> command:</p><pre class="programlisting">prompt&gt; run</pre><p>For both platforms, the command might invoke a browser window offering a connection to the database; close this window.</p></li><li><p>Run the data population script appropriate to the operating system. For Unix, this is <code class="literal">data.sh</code>:</p><pre class="programlisting">prompt$ sh data.sh</pre><p>On Windows, run the <code class="literal">data.bat</code> command:</p><pre class="programlisting">prompt&gt; data</pre></li></ol></div><p>
Run these commands once to start a database server for H2; the server will continue to run in the background.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.building.par"></a>Installing and starting GreenPages PAR</h3></div></div></div><p>To install the GreenPages PAR into Web Server and start it:
</p><div class="orderedlist"><ol type="1"><li><p>Copy the GreenPages PAR to the <code class="code">$VWS_HOME/pickup</code> directory. On Unix:</p><pre class="programlisting">prompt$ cd $VWS_HOME
prompt$ cp $GREENPAGES_HOME/solution/greenpages/target/greenpages-solution-2.3.0.RELEASE.par pickup/</pre><p>On Windows:</p><pre class="programlisting">prompt&gt; cd %VWS_HOME%
prompt&gt; copy %GREENPAGES_HOME%\solution\greenpages\target\greenpages-solution-2.3.0.RELEASE.par pickup\</pre></li><li><p>Start Web Server with the <code class="literal">-clean</code> option. On Unix:</p><pre class="programlisting">prompt$ $VWS_HOME/bin/startup.sh -clean</pre><p>On Windows:</p><pre class="programlisting">prompt&gt; "%VWS_HOME%"\bin\startup.bat -clean</pre></li><li><p>Verify that GreenPages starts correctly by checking in the Web Server output for the log message:
</p><pre class="programlisting">&lt;DE0005I&gt; Started par 'greenpages' version '2.3.0.RELEASE'. </pre><p>
</p></li></ol></div><p>
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installing.greenpages.browsing"></a>3.4&nbsp;Browsing the GreenPages application</h2></div></div></div><p>
Once installed and started, the GreenPages
application can be accessed with a web browser using the address
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
</p><p>
From the home page, a search query can be entered into the search box:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/browse-1.png" align="middle"></div><p>
</p><p>
After entering a query into the search box, the results page shows all the matches from the
directory:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/browse-2.png" align="middle"></div><p>
</p><p>
Clicking on <span class="emphasis"><em>view</em></span> next to an entry in the search listing displays the full details for that
listing entry:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/browse-3.png" align="middle"></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="installing.greenpages.tools"></a>3.5&nbsp;Running GreenPages from Eclipse</h2></div></div></div><p>Using Eclipse and the Web Server tools, it is possible to run applications directly from the IDE.
As changes are made to the application in the IDE,
they can be automatically applied to the running application allowing for rapid feedback of changes in function.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.tools.importing"></a>Importing the GreenPages projects into Eclipse</h3></div></div></div><p>
Before starting the GreenPages application from Eclipse, import the projects:
</p><div class="orderedlist"><ol type="1"><li><p>Open the Import Wizard using
<span class="guimenu">File</span> &#8594; <span class="guimenuitem">Import</span>.
</p></li><li><p>From the Import Wizard select
<span class="guimenu">General</span> &#8594; <span class="guimenuitem">Existing Projects into Workspace</span>
and click <span class="emphasis"><em>Next</em></span>:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/import-projects2.png" align="middle"></div><p>
</p></li><li><p>Click <span class="guibutton">Browse&#8230;</span> and select <code class="code">$GREENPAGES_HOME/solution</code> as the root directory.</p></li><li><p>In the <span class="emphasis"><em>Import Projects</em></span> window, select all the projects and click <span class="emphasis"><em>Finish</em></span>:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/import-projects3.png" align="middle"></div><p>
</p></li><li><p>Validate that the imported projects appear in Package Explorer:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/import-projects4.png" align="middle"></div><p>
There may be compilation errors at this stage.
</p></li></ol></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.tools.configuring"></a>Configuring Web Server target runtime</h3></div></div></div><p>
Projects for Web Server are associated with a Virgo Web Server runtime environment in Eclipse. This is to allow
launching and testing from within Eclipse, and also to allow classpath construction in Eclipse to
mirror the dynamic classpath in the Web Server runtime.
</p><p>
Compilation errors in the previous step will be resolved here.
</p><p>
To configure a Web Server runtime environment:
</p><div class="orderedlist"><ol type="1"><li><p>Open <span class="guimenu">Window</span> &#8594; <span class="guisubmenu">Show View</span> &#8594; <span class="guimenuitem">Other&#8230;</span>.</p></li><li><p>In the <span class="emphasis"><em>Show View</em></span> dialog choose
<span class="guimenu">Server</span> &#8594; <span class="guimenuitem">Servers</span> to make the servers view visible:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/servers.png" align="middle"></div><p>
</p></li><li><p>Right-click in the <span class="emphasis"><em>Servers</em></span> (which may not be empty) view and select
<span class="guimenu">New</span> &#8594; <span class="guimenuitem">Server</span>.
</p></li><li><p>In the <span class="emphasis"><em>New Server</em></span> dialog, choose
<span class="guimenu">EclipseRT</span> &#8594; <span class="guimenuitem">Virgo Web Server</span>
and click <span class="emphasis"><em>Next</em></span>.
</p></li><li><p>Click <span class="guibutton">Browse</span> and select the <code class="code">$VWS_HOME</code> directory. Ensure that a JRE is selected
supporting Java 1.6 or above.
Click <span class="guibutton">Finish</span> to complete creation of the server:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/new-server.png" align="middle"></div><p>
</p></li><li><p>Select all projects (except <span class="emphasis"><em>Servers</em></span>) in <span class="emphasis"><em>Package Explorer</em></span>.
Right-click on the projects and choose <span class="guimenuitem">Close Project</span>
and then <span class="guimenuitem">Open Project</span>.
</p></li></ol></div><p>
It is possible that there remain spurious build errors from Eclipse (see the <span class="emphasis"><em>Problems</em></span> view), in which case
a project clean build may clear the problems. Select <span class="guimenu">Project</span> &#8594; <span class="guimenuitem">Clean&#8230;</span>
from the main menu, and choose to <span class="emphasis"><em>Clean all projects</em></span>.
It may be necessary to repeat this on a few projects.
(This process is sometimes known as the &#8220;<span class="quote">Eclipse dance</span>&#8221;.)
</p><p>
Despite the dance steps outlined, there will remain some <span class="emphasis"><em>Warnings</em></span> like this:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/problem-warning.png" align="middle"></div><p>
It is safe to ignore these.
</p><p>
When STS starts the Web Server it uses a &#8216;warm start&#8217; by default.
It is useful to set the <code class="literal">-clean</code> option so that every server start is a clean one.
This is done by an option on the Web Server Overview window, which is obtained by opening the Web Server entry in the Servers window in STS.
(Double-click, or right-click and choose Open.)
The check box is labelled &#8216;Start server with -clean option&#8217;.
Close the window before proceeding.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="installing.greenpages.tools.run"></a>Running GreenPages from within Eclipse</h3></div></div></div><p>
Now that GreenPages is successfully imported into Eclipse, run the project directly from within the IDE.</p><p>If the GreenPages PAR file was copied to the <code class="literal">pickup</code> directory, be sure it is now removed so that it does not conflict with the deployment of the Eclipse project. On Unix:</p><pre class="programlisting">prompt$ cd $VWS_HOME/pickup
prompt$ rm greenpages-solution-2.3.0.RELEASE.par</pre><p>On Windows:</p><pre class="programlisting">prompt&gt; cd %VWS_HOME%\pickup
prompt&gt; del greenpages-solution-2.3.0.RELEASE.par</pre><p>Also, to prevent conflicts with the server configured in Eclipse, stop a currently-running Web Server by typing <code class="literal">Control-C</code> in the console window.</p><p>
To run GreenPages from within Eclipse:
</p><div class="orderedlist"><ol type="1"><li><p>
Right click on the Web Server instance in the <span class="emphasis"><em>Servers</em></span> view and select the <span class="guimenu">Add and Remove&#8230;</span>
menu item.
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/addedtoserver.png" align="middle"></div><p>
</p></li><li><p>
Add <span class="emphasis"><em>greenpages-solution</em></span> (which is the containing project or PAR) to the server and finish.
</p></li><li><p>To start Web Server from within Eclipse right-click on the Web Server node in the Servers window and choose <span class="guimenuitem">Start</span>.
The <span class="emphasis"><em>Servers</em></span> view should now show the server and the added project:
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/installed.png" align="middle"></div><p>
</p></li><li><p>
Verify that GreenPages is started correctly by checking for
<code class="code">&lt;DE0005I&gt; Started par 'greenpages' version '2.3.0.RELEASE'.</code> in the Console window.
</p><div class="mediaobject" align="center"><img src="images/installing-greenpages/success.png" align="middle"></div><p>
</p></li></ol></div><p>
</p><p>
(<span class="emphasis"><em>If errors are shown implying that GreenPages failed to be installed, this may be because some dependencies were not
copied to Web Server, as described in section <a class="xref" href="#installing.greenpages.building.par.provided" title="Installing dependencies into Web Server">the section called &#8220;Installing dependencies into Web Server&#8221;</a>. Check this.</em></span>)
</p><p>Once installed and started GreenPages is again available from a web browser at the address
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
</p></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="web.module"></a>4.&nbsp;The Web Module</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="web.module.introduction"></a>4.1&nbsp;Introduction</h2></div></div></div><p>
In common with most Enterprise Java applications GreenPages uses a web-based interface for user interactions.
The following steps show how the controller for the application is constructed,
using a service from the OSGi Service Registry.
</p><p>
It is assumed that the instructions in <a class="xref" href="#installation" title="2.&nbsp;Installation">Chapter&nbsp;2, <i>Installation</i></a> have been followed already
and that the GreenPages
zip file has been downloaded and unzipped as described in <a class="xref" href="#installing.greenpages" title="3.&nbsp;Installing and exploring GreenPages">Chapter&nbsp;3, <i>Installing and exploring GreenPages</i></a>.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="setting.up"></a>4.2&nbsp;GreenPages set up</h2></div></div></div><p>
Before beginning, configure the development environment to work with the
application. In the case of GreenPages this means Maven and Eclipse.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="setting.up.eclipse"></a>Setting up Eclipse (STS)</h3></div></div></div><p>
The following sections are most easily followed in the Java (or Spring) perspective (not, for example, the Java EE
perspective). If not already in an appropriate perspective, switch in SpringSource Tool Suite using the
<span class="guimenu">Open Perspective</span> menu:
</p><div class="mediaobject" align="center"><img src="images/web-module/java-perspective.png" align="middle"></div><p>
</p><p>
In this step create a reference to the Web Server instance that the GreenPages application
integrates with (the instance may already be created if the GreenPages solution has been run from STS).
</p><p>
In STS open <span class="guimenu">Preferences</span> &#8594; <span class="guimenuitem">Server</span> &#8594; <span class="guimenuitem">Runtime Environments</span>. Select <span class="emphasis"><em>Add&#8230;</em></span> to create a
new Web Server runtime environment. In the dialog that opens, select the <span class="emphasis"><em>Virgo Web Server
(runtime) v2.1</em></span> and check the box to <span class="emphasis"><em>Create a new local server</em></span>.
When complete, press <span class="emphasis"><em>Next</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/new-server-runtime-environment.png" align="middle"></div><p>
</p><p>
In the next dialog, set the <span class="emphasis"><em>Virgo Web Server installation directory</em></span> field to the
<span class="emphasis"><em>value</em></span> of <code class="literal">$VWS_HOME</code> and
check that the <span class="emphasis"><em>JRE:</em></span> option is set to Java 1.6 or later.
<span class="emphasis"><em>This may not be the workbench default.</em></span>
When complete, press <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/virgo-web-server.png" align="middle"></div><p>
</p><p>
After returning to the <span class="emphasis"><em>Preferences</em></span> window, press <span class="emphasis"><em>OK</em></span> to return to
Eclipse.
The <span class="emphasis"><em>Servers</em></span> view has opened and now shows an instance of
<span class="emphasis"><em>Virgo Web Server</em></span> in it.
</p><div class="mediaobject" align="center"><img src="images/web-module/servers-view.png" align="middle"></div><p>
There is also a <span class="emphasis"><em>Servers</em></span> project, in which the server is listed.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="controller"></a>4.3&nbsp;The controller</h2></div></div></div><p>
The Spring&#8217;s MVC style of web application development is used in which the central type
is the <code class="literal">Controller</code> class.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="import.greenpages.web"></a>Import the web project</h3></div></div></div><p>
The GreenPages application is divided into OSGi bundles that are represented as Eclipse
projects. In this step import the <code class="literal">greenpages.web</code> project.
</p><p>
Starting with no projects, import the web project by right-clicking in the <span class="emphasis"><em>Package Explorer</em></span>
view and selecting the <span class="emphasis"><em>Import&#8230;</em></span> menu item.
In the dialog that opens, choose <span class="guimenuitem">General</span> &#8594; <span class="guimenuitem">Existing Projects into Workspace</span> and select <span class="emphasis"><em>Next</em></span>.
In the following dialog set the <span class="emphasis"><em>root directory</em></span> to the value of
<code class="literal">$GREENPAGES_HOME/start/greenpages.web</code> and press <span class="emphasis"><em>Finish</em></span>.
</p><p>
(Initially this project may have compiler errors;
this is to be expected particularly if the Maven repository hasn&#8217;t yet been created.)
When this project is imported go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="controller.controller"></a>The controller class</h3></div></div></div><p>
In the <code class="literal">src/main/java</code> source folder of the <code class="literal">greenpages.web</code> project
the package <code class="classname">greenpages.web</code>
should contain the controller class named
<code class="classname">GreenPagesController</code>.
Create this by right-clicking on the <code class="literal">greenpages.web</code> package in the
<code class="literal">src/main/java</code> source folder and selecting
<span class="guimenuitem">New</span> &#8594; <span class="guimenuitem">Class</span>.
(If <span class="emphasis"><em>Class</em></span> is not offered on the <span class="emphasis"><em>New</em></span> menu
the <span class="emphasis"><em>Java</em></span> perspective may not be being used, in which case look for
the <span class="emphasis"><em>Class</em></span> option under <span class="emphasis"><em>Other&#8230;</em></span> in the <span class="emphasis"><em>Java</em></span> section.)
</p><p>
Name the new class <code class="classname">GreenPagesController</code> and press <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/new-greenpages-controller.png" align="middle"></div><p>
</p><p>
The code should be edited to look like this:
</p><pre class="programlisting">@Controller
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> GreenPagesController {
&#8230;
@RequestMapping(<span class="hl-string">"/home.htm"</span>)
<span class="hl-keyword">public</span> <span class="hl-keyword">void</span> home() {
}
&#8230;
</pre><p>
</p><p>
The annotations <code class="classname">Controller</code> and <code class="classname">RequestMapping</code>
are from Spring Framework and are imported by adding the lines:
</p><pre class="programlisting"><span class="hl-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hl-keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;
</pre><p>
</p><p>
STS will offer (as a <span class="emphasis"><em>Quick Fix</em></span>) to insert imports for these Spring Framework annotations
the first time they are used.
(Java 1.6 supports annotations, and the Spring Framework libraries are accessible by
linking to the correct Web Server runtime environment or generating the correct dependencies for the Maven plug-in.)
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="controller.component.scanning"></a>Enabling component scanning</h3></div></div></div><p>
Spring will detect the <code class="classname">@Controller</code> annotation and create a bean of controller type,
<span class="emphasis"><em>provided that</em></span> it scans the classpath for these.
Spring&#8217;s component scanning is enabled by inserting a <code class="literal">context</code> tag
in one of the Spring bean definition files.
</p><p>
Open the <code class="filename">WEB-INF/greenpages-servlet.xml</code> file in the
<code class="literal">src/main/webapp</code> folder and ensure the following lines are present:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!-- enable classpath scanning --</span>&gt;
&lt;<span class="hl-tag">context:component-scan</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"greenpages.web"</span> /&gt;
</pre><p>
</p><p>
Experiment by adding and removing this line, saving the file after each change.
(<span class="emphasis"><em>Easily done by commenting it&#8212;use the
<span class="emphasis"><em>Toggle Comment</em></span>
shortcut in STS.</em></span>)
Look in the <span class="emphasis"><em>Spring Explorer</em></span> view for a bean named <code class="literal">greenPagesController</code>
dynamically created by the <code class="literal">component-scan</code> tag.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="deploy.bundle"></a>4.4&nbsp;Deploying a bundle</h2></div></div></div><p>
During development time, it can be helpful to run an application inside of the deployment container. In the case
of GreenPages, this means deploying the <code class="literal">greenpages.web</code> bundle to the Virgo Web Server.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="deploy.bundle.deploy.and.start"></a>Deploying the <code class="literal">greenpages.web</code> bundle and starting the Web Server</h3></div></div></div><p>
The Web Server can be used while working in Eclipse.
In this step the <code class="literal">greenpages.web</code> bundle is deployed and the Web Server instance is started.
</p><p>
Drag the <code class="literal">greenpages.web</code> project from the <span class="emphasis"><em>Package Explorer</em></span> and drop it
on the Web Server instance in the <span class="emphasis"><em>Servers</em></span> view.
Because <code class="literal">greenpages.web</code> is a web bundle the server will start automatically, and
a browser window may open.
Expand the Web Server instance and the bundle <code class="literal">greenpages.web</code> will be listed as a child.
</p><div class="mediaobject" align="center"><img src="images/web-module/web-bundle-deployed.png" align="middle"></div><p>
</p><p>
If deployment is successful the console will contain the message:
</p><pre class="programlisting">&lt;DE0005I&gt; Started bundle 'greenpages.web' version '2.3.0'</pre><p>
</p><p>
Leave the server instance running and go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="deploy.bundle.web.module.manifest"></a>Creating web module metadata</h3></div></div></div><p>
The Web Server has special knowledge of web application bundles. In this step web bundle
metadata is added to the bundle and a web browser is used to navigate to it.
</p><p>
Open a web browser and navigate to
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
If the link is not currently served by any bundle in the Web Server there may be an error displayed:
</p><div class="mediaobject" align="center"><img src="images/web-module/greenpages-home-fail.png" align="middle"></div><p>
or else there is a blank page displayed. No pages are served.
</p><p>
To fix this issue the <code class="literal">greenpages.web</code> bundle must be declared to be a web bundle and a
context path defined.
</p><p>
Open the <code class="filename">template.mf</code> file (at the top level under the <code class="literal">greenpages.web</code> project)
and add (and save) the following entry (using the <span class="emphasis"><em>template.mf</em></span> pane of the editor):
</p><pre class="programlisting">Web-ContextPath: greenpages
</pre><p>
Be careful not to insert any blank lines or trailing spaces in this file.
</p><p>
Once added, right-click on the <code class="literal">greenpages.web</code> project and select
<span class="guimenu">Spring Tools</span> &#8594; <span class="guimenuitem">Run generation of MANIFEST.MF file</span>.
This will use a tool called Bundlor (included in STS) to update the OSGi metadata in the
<code class="filename">MANIFEST.MF</code> file. Once Bundlor has finished running, open the
<code class="filename">META-INF/MANIFEST.MF</code> file in the <code class="literal">src/main/webapp</code> folder.
</p><p>It should look something like the following:
</p><pre class="programlisting">Manifest-Version: 1.0
Bundle-Name: GreenPages Web
Import-Library: org.springframework.spring;version="[3.0, 3.1)"
Import-Bundle: com.springsource.org.apache.taglibs.standard;version="[
1.1.2,1.3)"
Web-ContextPath: greenpages
Import-Package: org.eclipse.virgo.web.dm;version="[2.0.0, 3.0.0)
",freemarker.cache;version="[2.3.15,2.3.15]",javax.servlet.jsp.jstl.c
ore;version="[1.1.2,1.2.0)",javax.sql,org.apache.commons.dbcp,org.spr
ingframework.core.io,org.springframework.stereotype,org.springframewo
rk.web.bind.annotation,org.springframework.web.context,org.springfram
ework.web.servlet
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages.web
Tool: Bundlor 1.0.0.RELEASE
Bundle-Version: 2.3.0
</pre><p>
although the order of the entries may be different.
</p><p>
The server (if it is still running) will track these changes and automatically refresh
(or restart) the <code class="literal">greenpages.web</code> bundle as required.
Observe the context path for the web bundle being announced
(it should now be <code class="literal">'/greenpages'</code>
whereas previously it would have been a default context path
derived from the bundle name: <code class="literal">'/greenpages.web'</code>).
</p><p>
By default, Bundlor generates <code class="literal">Import-Package</code> entries with no version range specified.
In the absence of a version range, the OSGi default (which denotes <span class="emphasis"><em>any</em></span> version) is used.
While this is very flexible it is generally a good idea to restrict an import by specifying a narrower range.
This can be achieved by providing Bundlor with some additional information in the manifest template,
as in the next step.
</p><p>
Add (and save) the following entry to the <code class="filename">template.mf</code> file:
</p><pre class="programlisting">Import-Template:
org.springframework.*;version="[3.0.0, 3.1.0)"
</pre><p>
(Again, be careful not to leave trailing spaces on lines or insert blank lines in this file, except that there
must be one trailing space after the colon to indicate that the header continues on the next line.)
</p><p>
Re-run the MANIFEST.MF generation as described earlier.
In the <code class="filename">MANIFEST.MF</code> file the <code class="literal">Import-Package</code> entry
should now have version ranges on each of the <code class="literal">springframework</code> packages:
</p><pre class="programlisting">Import-Package: org.eclipse.virgo.web.dm;version="[2.0.0, 3.0.0)
",freemarker.cache;version="[2.3.15,2.3.15]",javax.servlet.jsp.jstl.c
ore;version="[1.1.2,1.2.0)",javax.sql,org.apache.commons.dbcp,org.spr
ingframework.core.io;version="[3.0.0, 3.1.0)",org.springframework.ste
reotype;version="[3.0.0, 3.1.0)",org.springframework.web.bind.annotat
ion;version="[3.0.0, 3.1.0)",org.springframework.web.context;version=
"[3.0.0, 3.1.0)",org.springframework.web.servlet;version="[3.0.0, 3.1
.0)"
</pre><p>
</p><p>
Behind the scenes the Web Server Tools have refreshed the deployed bundle as changes were made. Once again
navigate to
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
This page now displays an entry field.
</p><div class="mediaobject" align="center"><img src="images/web-module/greenpages-home-success.png" align="middle"></div><p>
Put any characters into the entry field and press <span class="emphasis"><em>Submit</em></span>.
This should display a &#8220;<span class="quote">404</span>&#8221; error page with the description:
</p><pre class="programlisting">description The requested resource () is not available.</pre><p>
This is because there is no search page (<code class="literal">search.htm</code>) to process this request yet.
The next section will address this.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="par.project"></a>4.5&nbsp;Creating a PAR</h2></div></div></div><p>
At the end of the previous step, the Web Server instance was started
and the <code class="literal">greenpages.web</code> bundle deployed.
This bundle shows a static home page but a search value causes an error.
The error appears because the URL for that search is not serviced by the controller.
The application logic behind the search request is not in the <code class="literal">greenpages.web</code> project but
in another project called <code class="literal">greenpages.app</code>.
This section creates the <code class="literal">greenpages.app</code> project
and then combines the two projects into a PAR so as to deploy them together as a single unit.
</p><p>
While executing these instructions it is not necessary to remove bundles from the Web Server instance,
nor to stop the instance.
As changes are made the bundle will be refreshed (or redeployed) and the server instance
may report errors if the changes are incomplete.
These may safely be ignored.
Alternatively, the <code class="literal">greenpages.web</code> bundle can be removed from the Web Server instance,
or the server can be stopped while these changes are made.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="parent.project.importing"></a>Importing the parent project</h3></div></div></div><p>
All of the bundles in the GreenPages sample are Maven projects which refer to a &#8216;parent&#8217; project.
To allow STS to accommodate references to the parent, import this project first.
</p><p>
In the same way that the starting <code class="literal">greenpages.web</code> project was imported
(see <a class="xref" href="#controller" title="4.3&nbsp;The controller">Section&nbsp;4.3, &#8220;The controller&#8221;</a>)
import the <code class="literal">$GREENPAGES_HOME/start/parent</code> project.
</p><div class="mediaobject" align="center"><img src="images/web-module/import-parent-project.png" align="middle"></div><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="par.project.importing.project"></a>Importing the <code class="literal">greenpages.app</code> project</h3></div></div></div><p>
In this step, the <code class="literal">greenpages.app</code> project is imported which contains the business
interfaces (and stub implementations of these interfaces).
</p><p>
In the same way that the starting <code class="literal">greenpages.web</code> project was imported
(see <a class="xref" href="#controller" title="4.3&nbsp;The controller">Section&nbsp;4.3, &#8220;The controller&#8221;</a>)
import the <code class="literal">$GREENPAGES_HOME/start/greenpages.app</code> project.
</p><div class="mediaobject" align="center"><img src="images/web-module/import-greenpages-app.png" align="middle"></div><p>
</p><p>
When Eclipse finishes importing the project, go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="par.project.add.implementation"></a>Adding the controller implementation</h3></div></div></div><p>
The controller implementation will depend on the <code class="interfacename">Directory</code> and
<code class="interfacename">Listing</code> interfaces found in the <code class="literal">greenpages.app</code> project. In
this step, the implementation is added.
</p><p>
Open the <code class="classname">GreenPagesController</code> class.
Add the following field and methods to the class:
</p><pre class="programlisting">@Autowired
<span class="hl-keyword">private</span> Directory directory;
@RequestMapping(<span class="hl-string">"/search.htm"</span>)
<span class="hl-keyword">public</span> List&lt;Listing&gt; search(@RequestParam(<span class="hl-string">"query"</span>) String query) {
<span class="hl-keyword">return</span> <span class="hl-keyword">this</span>.directory.search(query);
}
@RequestMapping(<span class="hl-string">"/entry.htm"</span>)
<span class="hl-keyword">public</span> Listing entry(@RequestParam(<span class="hl-string">"id"</span>) <span class="hl-keyword">int</span> id) {
<span class="hl-keyword">return</span> <span class="hl-keyword">this</span>.directory.findListing(id);
}
</pre><p>
Add the (<span class="emphasis"><em>Quick Fix</em></span>) suggested imports for the annotations <code class="classname">Autowired</code>
and <code class="classname">RequestParam</code>,
and choose the import for <code class="classname">List&lt; &gt;</code> from <code class="classname">java.util.List</code>.
</p><p>
Eclipse will not be able to suggest import statements for the
<code class="interfacename">Listing</code> and <code class="interfacename">Directory</code> types. This is because
the <code class="literal">greenpages.web</code> and <code class="literal">greenpages.app</code> projects are not linked together
and therefore cannot see each other&#8217;s types.
</p><p>
Proceed to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="par.project.new.par"></a>Creating a PAR project</h3></div></div></div><p>
In Web Server, applications consisting of multiple bundles can be packaged as part of a PAR.
In this step a PAR project
containing the <code class="literal">greenpages.web</code> and <code class="literal">greenpages.app</code> bundles is
created and deployed to the server.
</p><p>
Right-click in the <span class="emphasis"><em>Package Explorer</em></span> and select <span class="guimenu">New</span> &#8594; <span class="guimenuitem">Project&#8230;</span>. In the dialog that opens select
<span class="guimenu">EclipseRT</span> &#8594; <span class="guimenuitem">PAR Project</span> and press
<span class="emphasis"><em>Next</em></span>:
</p><div class="mediaobject" align="center"><img src="images/web-module/new-par-project.png" align="middle"></div><p>
</p><p>
In the New PAR Project dialog, ensure the <span class="emphasis"><em>Use default location</em></span> option is unchecked,
name the project <code class="literal">greenpages</code>, set the location to
<code class="filename">$GREENPAGES_HOME/start/greenpages</code> and press <span class="emphasis"><em>Next</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/create-par-project.png" align="middle"></div><p>
</p><p>
In the next dialog, some of the PAR properties are pre-populated.
Change the Application Name to <code class="literal">Greenpages PAR</code> and the Version to
<code class="literal">2.3.0</code>, then
ensure that the <span class="emphasis"><em>Target Runtime</em></span>
is set to <span class="emphasis"><em>Virgo Web Server (Runtime) v2.1</em></span> and press <span class="emphasis"><em>Next</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/par-content.png" align="middle"></div><p>
</p><p>
In the next dialog, select the <code class="literal">greenpages.app</code> and <code class="literal">greenpages.web</code>
bundles so that they are contained in the PAR and press <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/bundle-references.png" align="middle"></div><p>
The project <code class="literal">greenpages.web</code> still shows errors; these are soon to be fixed.
</p><p>
The package explorer view will now show the following:
</p><div class="mediaobject" align="center"><img src="images/web-module/package-explorer-par.png" align="middle"></div><p>
</p><p>
PAR project creation is complete, go to the next section.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="osgi.reference"></a>4.6&nbsp;Referencing an OSGi Service</h2></div></div></div><p>
In an OSGi-based application, the business logic behind a controller is typically accessed through the OSGi
Service Registry.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.reference.export.package"></a>Exporting Packages</h3></div></div></div><p>
By default, Bundlor detects and exports all packages in a bundle.
In this step Bundlor is told what to
export from the <code class="literal">greenpages.app</code> bundle and which types from those packages to use in the
<code class="literal">greenpages.web</code> bundle.
</p><p>
Add and save the following entry to the <code class="filename">template.mf</code> file in the
<code class="literal">greenpages.app</code> project and then run the <code class="literal">MANIFEST.MF</code> generation on the project as
explained in <a class="xref" href="#deploy.bundle.web.module.manifest" title="Creating web module metadata">the section called &#8220;Creating web module metadata&#8221;</a>.
</p><pre class="programlisting">Excluded-Exports:
greenpages.internal
</pre><p>
(As before, be careful not to leave trailing spaces on the ends of lines, except for the one space after the colon,
and not to add any blank lines to the file. The second line of this entry has a leading space&#8212;do not omit it.)
</p><p>
Check that the package is no longer exported in the <code class="literal">greenpages.app</code> <code class="literal">MANIFEST.MF</code> file
which should look something like this:
</p><pre class="programlisting">Manifest-Version: 1.0
Bundle-Name: GreenPages Service
Bundle-ManifestVersion: 2
Bundle-SymbolicName: greenpages
Tool: Bundlor 1.0.0.RELEASE
Export-Package: greenpages;version="2.3.0"
Bundle-Version: 2.3.0
</pre><p>
Go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.reference.referencing.projects.packages"></a>Referencing Projects and Packages</h3></div></div></div><p>
Now that the <code class="literal">greenpages.app</code> bundle exports the package that the
<code class="interfacename">Directory</code> and <code class="interfacename">Listing</code> interfaces reside in,
the <code class="literal">greenpages.web</code> bundle must import it.
In this step the Maven
<code class="filename">pom.xml</code> file is updated to depend on the <code class="literal">greenpages.app</code> bundle and import the
package.
</p><p>
Open the <code class="filename">pom.xml</code> file in the <code class="literal">greenpages.web</code> project.
(Edit the source directly by using the <code class="literal">pom.xml</code> tab in the editor.)
In this file add
the following entry (between the <code class="literal">&lt;dependencies&gt;</code> tags):
</p><pre class="programlisting">&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.app&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
</p><p>
Open the <code class="classname">GreenPagesController</code> class and import the <code class="classname">Listing</code> and
<code class="classname">Directory</code> types.
(Eclipse should now offer these as a <span class="emphasis"><em>Quick Fix</em></span>.
It it does not, set <code class="literal">greenpages.app</code> as a project dependency of <code class="literal">greenpages.web</code>
in the Build Path of the web project.)
The class should now compile cleanly.
</p><p>
The following imports should now have been added to the <code class="classname">GreenPagesController</code> class:
</p><pre class="programlisting">import greenpages.Directory;
import greenpages.Listing;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
</pre><p>
</p><p>
Add the following package clause to the <code class="literal">Import-Template</code> entry in the
<code class="filename">template.mf</code> file in the <code class="literal">greenpages.web</code> project. When added run the
MANIFEST.MF generation on the project as described in <a class="xref" href="#deploy.bundle.web.module.manifest" title="Creating web module metadata">the section called &#8220;Creating web module metadata&#8221;</a>.
</p><pre class="programlisting">greenpages.*;version="[2.3, 2.4)"</pre><p>
Be careful to include the &#8220;<span class="quote"><code class="literal">.*</code></span>&#8221; in the package pattern.
</p><p>
Once Bundlor has finished, go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.reference.deploy.par"></a>Deploying a PAR</h3></div></div></div><p>
Currently the Web Server instance has a single web module bundle deployed. In this step, the
<code class="literal">greenpages.web</code> bundle is undeployed and <code class="literal">greenpages</code> PAR is deployed.
</p><p>
Right-click on the Web Server in the <span class="emphasis"><em>Servers</em></span> view, and select
<span class="emphasis"><em>Add and Remove&#8230;</em></span>. In the dialog that opens, remove the
<code class="literal">greenpages.web</code> bundle and add the <code class="literal">greenpages</code> PAR to the server. When
the configuration is complete, press <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/web-module/add-remove-projects.png" align="middle"></div><p>
</p><p>
Eclipse automatically undeploys the <code class="literal">greenpages.web</code> bundle and deploys the
<code class="literal">greenpages</code> PAR.
When this happens, the deployment may fail with an error.
If it does not, open the browser again at
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>
and observe the failure which should have a root cause similar to:
</p><pre class="programlisting">org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [greenpages.Directory] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
</pre><p>
This error is caused by there being no instance of <code class="classname">Directory</code> to inject into the controller.
The next section will supply one.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.reference.reference"></a>Referencing an OSGi Service</h3></div></div></div><p>
There is no instance of <code class="interfacename">Directory</code> to be
injected into the controller.
In the GreenPages application, it is intended that this
implementation is used through an interface in
the OSGi <span class="emphasis"><em>Service Registry</em></span>.
Using a service in the Service Registry enables
another bundle to
provide an implementation without revealing the implementation or the provider to all clients of the
service.
Web Server supports the use of the Spring DM <span class="emphasis"><em>namespace</em></span> for
referencing elements in the OSGi Service Registry.
This step adds an OSGi Service Reference to an implementation of the
<code class="interfacename">Directory</code> interface.
</p><p>
In the <code class="filename">webapp/WEB-INF/applicationContext.xml</code> file in the <code class="literal">greenpages.web</code>
projects add a reference to a
<code class="interfacename">greenpages.Directory</code> instance in the OSGi service registry using
the <code class="literal">&lt;osgi:reference/&gt;</code> tag as follows:
</p><pre class="programlisting">&lt;<span class="hl-tag">osgi:reference</span> <span class="hl-attribute">id</span>=<span class="hl-value">"directory"</span> <span class="hl-attribute">interface</span>=<span class="hl-value">"greenpages.Directory"</span>/&gt;
</pre><p>
</p><p>
The tools will automatically redeploy the <code class="literal">greenpages.web</code> bundle when the change to the
bean definition has been saved.
The web bundle will not completely start.
</p><p>
This is because there is no provider of a <code class="interfacename">greenpages.Directory</code> in
the Service Registry. The next step will address this.
</p><p>
The error is re-issued as the Web Server instance waits for the service to be supplied. After about five minutes
the server will &#8220;<span class="quote">time-out</span>&#8221; and the deploy will be abandoned. This same error (and time-out)
will occur each time the PAR is redeployed as each change is made.
</p><p>Stop the server instance by right-clicking on the server in the <span class="emphasis"><em>Servers</em></span> view and
selecting <span class="emphasis"><em>Stop</em></span>. This will avoid unnecessary delays as changes are made.
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="osgi.service"></a>4.7&nbsp;Publishing an OSGi Service</h2></div></div></div><p>
At the end of the previous step, a dependency was created on an OSGi Service Registry exposed instance of
<code class="classname">greenpages.Directory</code>. The application would not start because no other bundle was
contributing an instance of this service to the Service Registry.
</p><p>Stop the server instance before proceeding.</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.service.implementation"></a>Add Implementation</h3></div></div></div><p>
In this step Spring&#8217;s context scanning is added which will create an instance of the
<code class="classname">DirectoryImpl</code> class.
</p><p>
Open the <code class="classname">greenpages.internal.DirectoryImpl</code> class in the <code class="literal">greenpages.app</code>
project. Add the <code class="interfacename">@Component</code> annotation to the class:
</p><pre class="programlisting">@Component(<span class="hl-string">"directory"</span>)
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> DirectoryImpl <span class="hl-keyword">implements</span> Directory {
&#8230;
</pre><p>
generating imports with Eclipse&#8217;s help if necessary.
</p><p>
Open the <code class="filename">META-INF/spring/module-context.xml</code> in the <code class="literal">greenpages.app</code>
project. Add component scanning to this file:
</p><pre class="programlisting">&lt;<span class="hl-tag">context:component-scan</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"greenpages.internal"</span>/&gt;
</pre><p>
</p><p>
When complete, go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.service.publish"></a>Publish OSGi Service</h3></div></div></div><p>
In this step the <code class="classname">DirectoryImpl</code> instance is published to the OSGi Service
Registry.
</p><p>
Open the <code class="filename">META-INF/spring/osgi-context.xml</code> file. Add the
<code class="literal">&lt;osgi:service/&gt;</code> tag to publish the <code class="literal">directory</code> bean with an
interface of <code class="interfacename">greenpages.Directory</code>.
</p><pre class="programlisting">&lt;<span class="hl-tag">osgi:service</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"directory"</span> <span class="hl-attribute">interface</span>=<span class="hl-value">"greenpages.Directory"</span>/&gt;
</pre><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="osgi.server.working"></a>A Working Web Application</h3></div></div></div><p>
Start (or restart) the Web Server instance from the <code class="literal">Servers</code> view. If the GreenPages PAR was not
removed before, it will be automatically deployed, otherwise deploy it as before. There should be no errors reported.
When GreenPages is deployed successfully, open a web browser and navigate to
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>. On
the home page type <code class="literal">wilkinson</code> into the search field and press <span class="emphasis"><em>Submit</em></span>.
Unlike the previous attempt, this should return a list (of size 1) of search results. From here, select
<span class="emphasis"><em>view</em></span> to get the &#8220;<span class="quote">detailed</span>&#8221; listing.
</p><div class="mediaobject" align="center"><img src="images/web-module/greenpages-listing-success.png" align="middle"></div><p>
This uses a stub implementation of the <code class="classname">Directory</code> interface which only knows about &#8220;<span class="quote">Andy Wilkinson</span>&#8221;.
</p><p>
The web interface is complete enough. Go to the next chapter to see the middle tier implementation.
</p></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="middle-tier"></a>5.&nbsp;The Middle Tier</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="middle-tier.introduction"></a>5.1&nbsp;Introduction</h2></div></div></div><p>
GreenPages&#8217; middle-tier provides implementations of the <code class="literal">Directory</code> and <code class="literal">Listing</code>
interfaces that can be used by the Web bundle.
The implementation will use EclipseLink JPA to access a database via a <code class="literal">DataSource</code> published in the
OSGi service registry.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.introduction.database"></a>The database</h3></div></div></div><p>
The GreenPages application uses a very simple database that contains a single table.
The table, named <code class="literal">LISTING</code>, consists of four columns:
</p><div class="informaltable"><table style="border-collapse: collapse;border-top: 1.0pt solid ; border-bottom: 1.0pt solid ; border-left: 1.0pt solid ; border-right: 1.0pt solid ; "><colgroup><col><col><col><col></colgroup><tbody><tr><td style="border-right: 1.0pt solid ; "><code class="literal">LISTING_NUMBER</code></td><td style="border-right: 1.0pt solid ; "><code class="literal">FIRST_NAME</code></td><td style="border-right: 1.0pt solid ; "><code class="literal">LAST_NAME</code></td><td style=""><code class="literal">EMAIL_ADDRESS</code></td></tr></tbody></table></div><p>
Scripts are provided with the sample source code (in <code class="literal">$GREENPAGES_HOME/db</code>) to start, create, and populate the database.
These will be used during the creation of the middle tier.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.introduction.jpa"></a>Using JPA</h3></div></div></div><p>
The middle tier will provide JPA-based implementations of the <code class="literal">Directory</code> and <code class="literal">Listing</code> interfaces with the four
attributes of a <code class="literal">Listing</code> (first name, last name, email address, and id) being mapped to the corresponding columns in the
<code class="literal">LISTING</code>.
JPA will be used to implement the queries that search the database and return <code class="literal">Listings</code>.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.introduction.structure"></a>Structure</h3></div></div></div><p>
The middle tier consists of two bundles, <code class="literal">greenpages.jpa</code> that publishes a <code class="literal">Directory</code>
implementation for consumption by the Web bundle, and <code class="literal">greenpages.db</code> to configure and publish the
<code class="literal">DataSource</code> used to access the database.
</p><div class="mediaobject" align="center"><img src="images/middle-tier/structure.png" align="middle"></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="middle-tier.create-db-project"></a>5.2&nbsp;Creating the DataSource project</h2></div></div></div><p>
This section describes how to use
the bundle project creation wizard to create a new <code class="literal">Bundle Project</code>. The project&#8217;s Spring bean
definition files will also be created using the Spring bean configuration file creation wizard.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.create-db-project.new-bundle-project"></a>Creating a new Bundle Project</h3></div></div></div><p>
Create a new project by right-clicking in the <span class="emphasis"><em>Package Explorer</em></span> view and selecting
<span class="guimenu">New</span> &#8594; <span class="guimenuitem">Project&#8230;</span>. In the resulting
dialog select <span class="guimenu">EclipseRT</span> &#8594; <span class="guimenuitem">Bundle
Project</span> and press <span class="emphasis"><em>Next</em></span>:
</p><div class="mediaobject" align="center"><img src="images/middle-tier/new-bundle-project.png" align="middle"></div><p>
</p><p>
In the <span class="emphasis"><em>New Bundle Project</em></span> dialog, name the project <code class="literal">greenpages.db</code>.
Choose the create the project from an existing source location and specify a location that will place the new
<code class="literal">greenpages.db</code> alongside the project skeletons that were imported into the workspace
earlier. If the <code class="literal">start</code> directory of the GreenPages sample is being used this will
be <code class="literal">$GREENPAGES_HOME/start/greenpages.db</code> (and, <span class="emphasis"><em>mutatis mutandis</em></span> on Windows).
Click <span class="emphasis"><em>Next</em></span>.
</p><div class="mediaobject" align="center"><img src="images/middle-tier/create-bundle-project.png" align="middle"></div><p>
</p><p>
In this page of the wizard, many of the <span class="emphasis"><em>Bundle Properties</em></span> are already populated. The
<code class="literal">Bundle-SymbolicName</code> is the name of the project. The <code class="literal">Bundle-Name</code> is
derived from the <code class="literal">Bundle-SymbolicName</code>. The <code class="literal">Bundle-Version</code> is
set, and there is no <code class="literal">Bundle-Description</code>.
</p><p>
Change the <code class="literal">Bundle-Name</code> to &#8220;<span class="quote"><code class="literal">GreenPages DataSource</code></span>&#8221; to more accurately
describe the bundle&#8217;s purpose. An option to &#8216;Enable Bundle Classpath Container&#8217; is already selected. It should
be <span class="emphasis"><em>de</em></span>-selected, as a Maven Classpath container will be configured later.
Ensure that the <span class="emphasis"><em>Target Runtime</em></span>
is set to <span class="emphasis"><em>Virgo Web Server (Runtime) v2.1</em></span>.
Click <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/middle-tier/config-bundle-project.png" align="middle"></div><p>
The <code class="literal">greenpages.db</code> project appears in the <span class="emphasis"><em>Package Explorer</em></span> view.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.create-db-project.configuring-classpath"></a>Configuring the project&#8217;s classpath container</h3></div></div></div><p>
Before a Maven Classpath Container can be added to the project, a <code class="literal">pom.xml</code> file must
be created.
Create a new file in the root of the <code class="literal">greenpages.db</code> project named
<code class="literal">pom.xml</code> and add the following contents to it:
</p><pre class="programlisting">&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>&gt;
&lt;<span class="hl-tag">project</span>
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://maven.apache.org/POM/4.0.0"</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://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>&gt;
&lt;<span class="hl-tag">parent</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.parent&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;2.3.0.RELEASE&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">relativePath</span>&gt;../parent&lt;<span class="hl-tag">/relativePath</span>&gt;
&lt;<span class="hl-tag">/parent</span>&gt;
&lt;<span class="hl-tag">modelVersion</span>&gt;4.0.0&lt;<span class="hl-tag">/modelVersion</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.db&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">name</span>&gt;greenpages.db&lt;<span class="hl-tag">/name</span>&gt;
&lt;<span class="hl-tag">packaging</span>&gt;jar&lt;<span class="hl-tag">/packaging</span>&gt;
&lt;<span class="hl-tag">dependencies</span>&gt;
&lt;<span class="hl-tag">/dependencies</span>&gt;
&lt;<span class="hl-tag">/project</span>&gt;
</pre><p>
Save the file.
</p><p>
A Maven Classpath Container can now be added to the project. Right-click the
<code class="literal">greenpages.db</code> project in the Package Explorer and select
<span class="guimenu">Maven 2</span> &#8594; <span class="guimenuitem">Enable dependency management</span>.
Eclipse will perform some workspace building, and the <code class="literal">greenpages.db</code> project will now be marked as a Maven project.
(If the error <code class="literal">Cannot find artifact for parent POM</code> occurs check that the version is correct.
It may differ from the one given here.)
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.create-db-project.config-src-folders"></a>Configuring the source folders</h3></div></div></div><p>
The last part of the setup of the project is to configure its source folders.
Return to the <span class="emphasis"><em>Properties</em></span> dialog of
the <code class="literal">greenpages.db</code> project (from the <span class="emphasis"><em>Package Explorer</em></span> view).
Select <span class="emphasis"><em>Java Build Path</em></span> on the left-hand side and the <span class="emphasis"><em>Source</em></span> tab
on the right-hand side.
Remove any pre-configured source folders by selecting them and
clicking <span class="emphasis"><em>Remove</em></span>.
</p><p>
Now click <span class="emphasis"><em>Add folder</em></span> and then
<span class="emphasis"><em>Create new folder&#8230;</em></span>.
Specify <code class="literal">src/main/resources</code> as the folder
name and click <span class="emphasis"><em>Finish</em></span>, then <span class="emphasis"><em>OK</em></span> and <span class="emphasis"><em>OK</em></span> again.
</p><p>
The final change to be made is to drag the <code class="literal">META-INF</code> folder from <code class="literal">src</code>
to <code class="literal">src/main/resources</code>.
Once these changes have been made the project will appear
similar to the following in the <span class="emphasis"><em>Package Explorer</em></span> view:
</p><div class="mediaobject" align="center"><img src="images/middle-tier/db-project.png" align="middle"></div><p>
</p><p>
(It is useful to check that the Maven project just configured has the correct Java System library associated with it and that
the <code class="literal">MANIFEST.MF</code> file that we have just moved is correctly generated when necessary.
To ensure this, disable the dependency management (enabled in the previous section) and then re-enable it, saving the changes in between.
This step may also change the Java system libraries associated with the build (right-click on the <code class="literal">greenpages.db</code> project, under Properties, Java build path and Libraries).
If the Java system libraries look incorrect, simply remove them in the Libraries window and reset them.)
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.create-db-project.config-datasource"></a>Configuring the DataSource</h3></div></div></div><p>
The DataSource bundle&#8217;s main r&ocirc;le is to configure and create a <code class="literal">DataSource</code> object and to
publish this to the OSGi service registry. This will be done by creating
a handful of Spring beans.
</p><p>
By default, Spring DM looks for application context files in a bundle&#8217;s <code class="literal">META-INF/spring</code>
directory. Create a new folder named <code class="literal">spring</code> in the <code class="literal">greenpages.db</code>
project&#8217;s <code class="literal">META-INF</code> folder. Having created the new folder, right-click it in the
Package Explorer and select
<span class="guimenu">New </span> &#8594; <span class="guimenuitem">Spring Bean Configuration File</span>.
This will open the wizard for creating Spring bean configuration files.
</p><p>
In the wizard enter a <code class="literal">File name</code> of <code class="literal">module-context.xml</code> and click
<span class="emphasis"><em>Next</em></span>:
</p><div class="mediaobject" align="center"><img src="images/middle-tier/db-module-create-module-context.png" align="middle"></div><p>
</p><p>
Add the <span class="emphasis"><em>p - http://www.springframework.org/schema/p</em></span> namespace declaration to the pre-selected
<span class="emphasis"><em>beans</em></span> declaration and then click <span class="emphasis"><em>Finish</em></span>.
</p><div class="mediaobject" align="center"><img src="images/middle-tier/db-module-namespace-declaration-configuration.png" align="middle"></div><p>
</p><p>
Update the newly-created file (which is opened by Eclipse) to declare a bean that defines the <code class="literal">DataSource</code>
object that will be used to access the GreenPages database.
Do this by adding the following bean declaration:
</p><pre class="programlisting"> &lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"dataSource"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.apache.commons.dbcp.BasicDataSource"</span>
<span class="hl-attribute">p:driverClassName</span>=<span class="hl-value">"org.h2.Driver"</span> <span class="hl-attribute">p:url</span>=<span class="hl-value">"jdbc:h2:~/greenpages-db/greenpages"</span>
<span class="hl-attribute">p:username</span>=<span class="hl-value">"greenpages"</span> <span class="hl-attribute">p:password</span>=<span class="hl-value">"pass"</span>
<span class="hl-attribute">init-method</span>=<span class="hl-value">"createDataSource"</span> <span class="hl-attribute">destroy-method</span>=<span class="hl-value">"close"</span> /&gt;
</pre><p>
The new bean has introduced a dependency on Commons DBCP, which will cause an error to be reported by Eclipse.
</p><p>
This dependency must be recorded in the project&#8217;s pom file. Open the pom file for <code class="literal">greenpages.db</code> and add
the following dependency between the <code class="literal">&lt;dependencies&gt;</code> tags:
</p><pre class="programlisting"> &lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.apache.commons&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;com.springsource.org.apache.commons.dbcp&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
Save the updated pom and then switch back to the editor for <code class="literal">module-context.xml</code>.
Save the updated file and
observe that the previously reported problem is now resolved as Commons DBCP is available on the classpath.
</p><p>
Now that the <code class="literal">DataSource</code> bean is available, it can be published into the OSGi service registry.
</p><p>
Right-click the <code class="literal">spring</code> folder and select
<span class="guimenu">New </span> &#8594; <span class="guimenuitem">Spring Bean Configuration File</span> again.
This time specify
a name of <code class="literal">osgi-context.xml</code>, click <span class="emphasis"><em>Next</em></span>, and add the <code class="literal">osgi</code>
namespace declaration
(ensure that the resultant schema location string contains the URL
<code class="literal">http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd</code>
as
<code class="literal">http://www.springframework.org/schema/osgi/spring-osgi-2.0-m1.xsd</code>
will result in an obscure deployment failure due to an invalid 'cacheTarget' property).
Click <span class="emphasis"><em>Finish</em></span> and then add the following to the new file to publish the
<code class="literal">DataSource</code> as a service:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!--
export the dataSource bean to the OSGi service registry under the
DataSource interface
--</span>&gt;
&lt;<span class="hl-tag">osgi:service</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"dataSource"</span> <span class="hl-attribute">interface</span>=<span class="hl-value">"javax.sql.DataSource"</span> /&gt;
</pre><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="id=middle-tier.create-db-project.config-bundlor-template"></a>Configuring Bundlor&#8217;s manifest template</h3></div></div></div><p>
Bundlor uses a manifest <span class="emphasis"><em>template</em></span> to control the contents of the generated manifest.
Create a new file named
<code class="literal">template.mf</code> in the root of the <code class="literal">greenpages.db</code> project.
Open the existing
<code class="literal">MANIFEST.MF</code> and switch to the <code class="literal">MANIFEST.MF</code> tab to view its source. Copy
the contents. Switch to the editor for <code class="literal">template.mf</code>, switch to the
<code class="literal">template.mf</code> tab and paste the contents from <code class="literal">MANIFEST.MF</code>. These entries
will tell Bundlor what the resulting manifest&#8217;s bundle symbolic name, bundle version, etc. should be. Save the
updated template.
</p><p>
Still in the <code class="literal">template.mf</code> editor switch to the <span class="emphasis"><em>Overview</em></span> tab
and click <span class="emphasis"><em>Update MANIFEST.MF</em></span> which is under the &#8220;<span class="quote">Bundle Actions</span>&#8221; section.
</p><p>
At this point Bundlor will scan the project to determine its
dependencies. It will scan both <code class="literal">module-context.xml</code> and <code class="literal">osgi-context.xml</code>
looking for references to classes. For each class to which it finds a reference, an import for the class&#8217;s
package will be added to the resulting manifest.
</p><p>
In this case, Bundlor will generate imports for
both <code class="code">javax.sql</code> and <code class="code">org.apache.commons.dbcp</code>.
These imports may not be resolved.
The <code class="literal">greenpages.db</code> project needs to be associated with a Web Server instance which has the
Commons DBCP bundle in its repository to resolve them.
In any event the next step adds the <code class="literal">greenpages.db</code>
project to the GreenPages PAR and will result in it inheriting the PAR project&#8217;s targetted runtime
configuration.
</p><p>
Double-click the <code class="literal">MANIFEST.MF</code> file in the <code class="literal">greenpages</code> project in the
<span class="emphasis"><em>Package Explorer</em></span> view.
Switch to the <code class="literal">Dependencies</code> tab and click <span class="emphasis"><em>Add&#8230;</em></span>.
Select <code class="literal">greenpages.db</code> and click <span class="emphasis"><em>OK</em></span>.
Save the updated file.
A problem concerning the <code class="code">org.apache.commons.dbcp</code> dependency should now be resolved
(along with any other resolution errors) and (if the server is running) the
GreenPages application will be redeployed due to the addition of the <code class="literal">greenpages.db</code>
module.
Start the server if it is not already running and observe that this deployment fails.
</p><p>
The deployment will fail because the <code class="code">org.h2.Driver</code> class that is referenced in the
<code class="literal">DataSource</code> bean&#8217;s definition in <code class="literal">module-context.xml</code> is not available to
the bundle.
(Check for the exception <code class="code">org.springframework.beans.factory.BeanCreationException</code> with
text something like:
</p><pre class="programlisting">Error creating bean with name 'dataSource'
defined in URL [bundleentry://68.fwk504117357/META-INF/spring/ module-context.xml]:
Invocation of init method failed;
nested exception is org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class 'org.h2.Driver'
</pre><p>
though the numbers might be different.)
</p><p>
There are a few cases where Bundlor will not identify a dependency on a class and, at the moment,
this is one of them, although this is an area of Bundlor that is being improved all the time.
Thankfully, it is easy to add the required import by making a simple update to the template.
</p><p>
Open the editor for the
<code class="literal">template.mf</code> file in the <code class="literal">greenpages.db</code> project and add the following
<code class="literal">Import-Package</code> header and save the updated manifest:
</p><pre class="programlisting">Import-Package: org.h2;version="[1.0.71,1.0.71]"
</pre><p>
</p><p>
Saving the manifest will trigger a redeployment (or click on <span class="emphasis"><em>Update MANIFEST.MF</em></span> as before)
which will fail if the H2 database is not available.
(Refer to the section <a class="xref" href="#installing.greenpages.building.db" title="Starting and configuring the database">the section called &#8220;Starting and configuring the database&#8221;</a>
in <a class="xref" href="#installing.greenpages" title="3.&nbsp;Installing and exploring GreenPages">Chapter&nbsp;3, <i>Installing and exploring GreenPages</i></a> to run and configure the database.)
</p><p>
If the database is running the GreenPages application should correctly deploy.
Although the application web front-end will run, the database contents is
not visible, of course, because we are still running with the <span class="emphasis"><em>stub</em></span> version of the <code class="code">search</code> method on the controller.
The implementation of the <code class="code">Directory</code> service needs to be changed to exploit the database.</p><p>
(One possible cause of failure here is the username and password on the <code class="literal">dataSource</code>
bean defined in <code class="literal">module-context.xml</code>. Check that these are exactly correct.)
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="middle-tier.building-jpa-module"></a>5.3&nbsp;Building the JPA module</h2></div></div></div><p>
In this section the JPA module in GreenPages is created, building upon an existing skeleton.
JPA and its metadata are configured, and a JPA-based Directory service implementation
is published which is then consumed by the application&#8217;s Web bundle.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.building-jpa-module.completing-jpadirectory"></a>Completing the JPA-based Directory implementation</h3></div></div></div><p>
The <code class="literal">greenpages.jpa</code> starter project provides the beginnings of a JPA-based implementation of
<code class="literal">Directory</code> named <code class="literal">JpaDirectory</code>. Import the <code class="literal">greenpages.jpa</code> project
from the <code class="literal">$GREENPAGES_HOME/start</code> directory.
</p><p>
Open the <code class="code">JpaDirectory.java</code> source file
in the <code class="literal">greenpages.jpa</code> package of <code class="literal">greenpages.jpa</code> project (under <code class="code">src/main/java</code>).
</p><p>
The source file
contains a Java Persistence Query Language (JPQL) search query that will be used to retrieve
listings from the database, and empty
implementations of the <code class="literal">search</code> and <code class="literal">findListing</code> methods.
</p><p>
First add an <code class="literal">EntityManager</code> to it.
Before the new field
can be added, <code class="literal">EntityManager</code> must be available on the classpath.
Open the pom for
<code class="literal">greenpages.jpa</code> and add the following dependency:
</p><pre class="programlisting"> &lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;javax.persistence&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;com.springsource.javax.persistence&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
</p><p>
Now return to <code class="literal">JpaDirectory</code> and add the following field to the class along with an
import for <code class="literal">javax.persistence.EntityManager</code> (which should be suggested by Eclipse):
</p><pre class="programlisting"> <span class="hl-keyword">private</span> EntityManager em;
</pre><p>
</p><p>
This <code class="literal">EntityManager</code> can now be used to implement the <code class="literal">search</code> and
<code class="literal">findListing</code> methods. Update the implementations of these two methods to match the
following implementations and then save the updated class:
</p><pre class="programlisting"> <span class="hl-keyword">public</span> Listing findListing(<span class="hl-keyword">int</span> id) {
<span class="hl-keyword">return</span> em.find(JpaListing.<span class="hl-keyword">class</span>, id);
}
@SuppressWarnings(<span class="hl-string">"unchecked"</span>)
<span class="hl-keyword">public</span> List&lt;Listing&gt; search(String term) {
<span class="hl-keyword">return</span> em.createQuery(SEARCH_QUERY).setParameter(<span class="hl-string">"term"</span>,
<span class="hl-string">"%"</span> + term.toUpperCase() + <span class="hl-string">"%"</span>).getResultList();
}
</pre><p>
(Warnings from Eclipse should now be absent.)
</p><p>
The application context now needs to be updated to create <code class="literal">JpaDirectory</code> and to create
an <code class="literal">EntityManager</code> that can be injected into <code class="literal">JpaDirectory</code>.
</p><p>
Open
<code class="literal">module-context.xml</code> in the <code class="literal">META-INF/spring</code> folder of the
<code class="literal">greenpages.jpa</code>. Add the following beans that will create <code class="literal">JpaDirectory</code>
and an <code class="literal">EntityManager</code>, enable load-time weaving that is required by JPA, and enable
annotation-based configuration that will allow the <code class="literal">EntityManager</code> to be injected into
<code class="literal">JpaDirectory</code>:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!--
Activates a load-time weaver for the context. Any bean within the
context that implements LoadTimeWeaverAware (such as
LocalContainerEntityManagerFactoryBean) will receive a reference to
the autodetected load-time weaver.
--</span>&gt;
&lt;<span class="hl-tag">context:load-time-weaver</span> <span class="hl-attribute">aspectj-weaving</span>=<span class="hl-value">"on"</span> /&gt;
&lt;<span class="hl-comment">!-- JPA EntityManagerFactory --</span>&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"entityManagerFactory"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"</span>
<span class="hl-attribute">p:dataSource-ref</span>=<span class="hl-value">"dataSource"</span>&gt;
&lt;<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"jpaVendorAdapter"</span>&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"jpaVendorAdapter"</span>
<span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"</span>
<span class="hl-attribute">p:databasePlatform</span>=<span class="hl-value">"org.eclipse.persistence.platform.database.HSQLPlatform"</span>
<span class="hl-attribute">p:showSql</span>=<span class="hl-value">"true"</span> /&gt;
&lt;<span class="hl-tag">/property</span>&gt;
&lt;<span class="hl-tag">/bean</span>&gt;
&lt;<span class="hl-comment">!--
Activates various annotations to be detected in bean classes: Spring's
@Required and @Autowired, as well as JSR 250's @PostConstruct,
@PreDestroy and @Resource (if available) and JPA's @PersistenceContext
and @PersistenceUnit (if available).
--</span>&gt;
&lt;<span class="hl-tag">context:annotation-config</span> /&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"directory"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"greenpages.jpa.JpaDirectory"</span> /&gt;
</pre><p>
</p><p>
The addition of the new beans to the context has introduced a new dependency upon Spring&#8217;s ORM support and upon
EclipseLink and its JPA implementation. Add the following dependencies to the pom file for
<code class="literal">greenpages.jpa</code> and save it:
</p><pre class="programlisting"> &lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.springframework&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;org.springframework.spring-library&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">type</span>&gt;libd&lt;<span class="hl-tag">/type</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.eclipse.persistence&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;com.springsource.org.eclipse.persistence&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.eclipse.persistence&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;com.springsource.org.eclipse.persistence.jpa&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
</p><p>
Now switch back to <code class="literal">module-context.xml</code> for <code class="literal">greenpages.jpa</code> and observe
that the errors relating to Spring&#8217;s ORM types have now been resolved.
Save <code class="literal">module-context.xml</code>.
</p><p>
The application context now contains a factory that will create an <code class="literal">EntityManager</code> and is
configured for annotation-based configuration.
The last step in completing <code class="literal">JpaDirectory</code>
is to annotate the <code class="literal">EntityManager</code> field so that Spring will inject the
<code class="literal">EntityManager</code> created by the factory into the field.
</p><p>
Open <code class="literal">JpaDirectory.java</code> again and add an annotation <code class="literal">@PersistenceContext</code> to the
<code class="literal">EntityManager</code> field.
</p><pre class="programlisting">@PersistenceContext
<span class="hl-keyword">private</span> EntityManager em;
</pre><p>
Eclipse will suggest an import for
<code class="literal">javax.persistence.PersistenceContext</code>; accept this and save the file.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.building-jpa-module.providing-jpa-metadata"></a>Providing the JPA metadata</h3></div></div></div><p>
JPA uses a file named <code class="literal">META-INF/persistence.xml</code> to describe persistence units.
<code class="literal">persistence.xml</code> refers to a second file, typically named
<code class="literal">META-INF/orm.xml</code>, to define entity mappings.
In the case of GreenPages the
<code class="literal">persistence.xml</code> file specifies a single persistence unit that points to the
<code class="literal">greenpages.JpaListing</code> class.
The specified mapping file
(<code class="literal">META-INF/orm.xml</code>) tells the JPA implementation how to map
<code class="literal">JpaListing</code> to the <code class="literal">LISTING</code> database table described above.
(For more information on JPA consult the Documentation section in the appendix.)
</p><p>
Create a new file named <code class="literal">persistence.xml</code> in the <code class="literal">META-INF</code> folder of
the <code class="literal">greenpages.jpa</code> project. Add the following contents to the new file and then save it:
</p><pre class="programlisting">&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8" ?</span>&gt;
&lt;<span class="hl-tag">persistence</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://java.sun.com/xml/ns/persistence"</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://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"</span>
<span class="hl-attribute">version</span>=<span class="hl-value">"1.0"</span>&gt;
&lt;<span class="hl-tag">persistence-unit</span> <span class="hl-attribute">name</span>=<span class="hl-value">"GreenPages"</span> <span class="hl-attribute">transaction-type</span>=<span class="hl-value">"RESOURCE_LOCAL"</span>&gt;
&lt;<span class="hl-tag">class</span>&gt;greenpages.jpa.JpaListing&lt;<span class="hl-tag">/class</span>&gt;
&lt;<span class="hl-tag">/persistence-unit</span>&gt;
&lt;<span class="hl-tag">/persistence</span>&gt;
</pre><p>
</p><p>
Now create a new file named <code class="literal">orm.xml</code> also in the <code class="literal">META-INF</code> folder
alongside <code class="literal">persistence.xml</code>. Add the following contents to the new file and then save it:
</p><pre class="programlisting">&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8" ?</span>&gt;
&lt;<span class="hl-tag">entity-mappings</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://java.sun.com/xml/ns/persistence/orm"</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://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"</span>
<span class="hl-attribute">version</span>=<span class="hl-value">"1.0"</span>&gt;
&lt;<span class="hl-tag">package</span>&gt;greenpages.jpa&lt;<span class="hl-tag">/package</span>&gt;
&lt;<span class="hl-tag">entity</span> <span class="hl-attribute">class</span>=<span class="hl-value">"greenpages.jpa.JpaListing"</span> <span class="hl-attribute">name</span>=<span class="hl-value">"Listing"</span>&gt;
&lt;<span class="hl-tag">table</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LISTING"</span> /&gt;
&lt;<span class="hl-tag">attributes</span>&gt;
&lt;<span class="hl-tag">id</span> <span class="hl-attribute">name</span>=<span class="hl-value">"listingNumber"</span>&gt;
&lt;<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LISTING_NUMBER"</span> /&gt;
&lt;<span class="hl-tag">generated-value</span> <span class="hl-attribute">strategy</span>=<span class="hl-value">"TABLE"</span> /&gt;
&lt;<span class="hl-tag">/id</span>&gt;
&lt;<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"firstName"</span>&gt;
&lt;<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"FIRST_NAME"</span> /&gt;
&lt;<span class="hl-tag">/basic</span>&gt;
&lt;<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"lastName"</span>&gt;
&lt;<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LAST_NAME"</span> /&gt;
&lt;<span class="hl-tag">/basic</span>&gt;
&lt;<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"emailAddress"</span>&gt;
&lt;<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"EMAIL_ADDRESS"</span> /&gt;
&lt;<span class="hl-tag">/basic</span>&gt;
&lt;<span class="hl-tag">/attributes</span>&gt;
&lt;<span class="hl-tag">/entity</span>&gt;
&lt;<span class="hl-tag">/entity-mappings</span>&gt;
</pre><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.building-jpa-module.consuming-datasource"></a>Consuming the DataSource from the service registry</h3></div></div></div><p>
The <code class="literal">entityManagerFactory</code> bean that was added earlier depends upon a bean named
<code class="literal">dataSource</code> which it will use to connect the <code class="literal">EntityManager</code>
to the GreenPages database.
The <code class="literal">greenpages.db</code> module already publishes a
<code class="literal">DataSource</code> to the service registry.
<code class="literal">greenpages.jpa</code> must now be
updated to consume this.
</p><p>
Open <code class="literal">osgi-context.xml</code> in the <code class="literal">META-INF/spring</code> folder of the
<code class="literal">greenpages.jpa</code> project and add the following:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!-- import the DataSource from OSGi --</span>&gt;
&lt;<span class="hl-tag">osgi:reference</span> <span class="hl-attribute">id</span>=<span class="hl-value">"dataSource"</span> <span class="hl-attribute">interface</span>=<span class="hl-value">"javax.sql.DataSource"</span> /&gt;
</pre><p>
</p><p>
This will result in a bean being created in the application context that is named <code class="literal">dataSource</code>.
The bean will be of type <code class="literal">javax.sql.DataSource</code> and will be backed by a service found in the
OSGi service registry that implements the <code class="literal">javax.sql.DataSource</code> interface.
(Some warnings concerning the <code class="literal">dataSource</code> bean will now disappear.)
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.building-jpa-module.publishing-directory"></a>Publishing the Directory implementation to the service registry</h3></div></div></div><p>
To make the JPA-based <code class="literal">Directory</code> implementation available to GreenPages&#8217;
Web module it must be &#8220;<span class="quote">published</span>&#8221; to the OSGi service registry.
</p><p>
Open <code class="literal">osgi-context.xml</code> in the <code class="literal">META-INF/spring</code> folder of the
<code class="literal">greenpages.jpa</code> project, add the following and then save the updated file:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!-- export the directory bean to OSGi under the Directory interface --</span>&gt;
&lt;<span class="hl-tag">osgi:service</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"directory"</span> <span class="hl-attribute">interface</span>=<span class="hl-value">"greenpages.Directory"</span> /&gt;
</pre><p>
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.building-jpa-module.generating-manifest"></a>Generating greenpages.jpa&#8217;s manifest using Bundlor</h3></div></div></div><p>
Open the <code class="literal">template.mf</code> file in the root of the <code class="literal">greenpages.jpa</code>
project and switch to the <code class="literal">template.mf</code> tab. Add the following entries to the template
and save it.
</p><pre class="programlisting">Import-Bundle: com.springsource.org.eclipse.persistence;version="[1.0.0,1.0.0]",
com.springsource.org.eclipse.persistence.jpa;version="[1.0.0,1.0.0]"
Import-Package: org.springframework.context.weaving;version="[3.0,3.1)",
org.springframework.transaction.aspectj;version="[3.0,3.1)"
Excluded-Exports: greenpages.jpa
</pre><p>
</p><p>
The <code class="literal">Excluded-Exports</code> header tells Bundlor that the
<code class="literal">greenpages.jpa</code> should not be exported from the <code class="literal">greenpages.jpa</code>
bundle.
</p><p>
The <code class="literal">Import-Package</code> entries for
<code class="literal">org.springframework.context.weaving</code> and
<code class="literal">org.springframework.transaction.aspectj</code> are needed as Bundlor cannot, yet,
detect that these packages are required.
</p><p>
Lastly, the <code class="literal">Import-Bundle</code> entries for EclipseLink and its JPA implementation
are needed as Bundlor cannot, yet, detect that EclipseLink is the JPA implementation that is
being used by GreenPages.
</p><p>
Switch to the <span class="emphasis"><em>Overview</em></span> tab and click <span class="emphasis"><em>Update MANIFEST.MF</em></span>.
As with <code class="literal">greenpages.db</code> before, this update may result in some errors being
reported in the manifest as the project is not associated with a targetted runtime. Double-click the
<code class="literal">MANIFEST.MF</code> file in the <code class="literal">greenpages</code> project in the Package Explorer.
Switch to the <span class="emphasis"><em>Dependencies</em></span> tab and click <span class="emphasis"><em>Add&#8230;</em></span>. Select
<code class="literal">greenpages.jpa</code> and click <span class="emphasis"><em>OK</em></span>. Save the updated file. The
problems in the manifest should now be resolved and the GreenPages application should be redeployed
due to the addition of the <code class="literal">greenpages.jpa</code> module. This redeployment should succeed
and it&#8217;s now time to try the application again.
</p><p>
(A possible action if this fails is to Update (Maven) Dependencies on the project right-click menu in the Maven sub-menu.)
</p></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="middle-tier.trying-it-out"></a>5.4&nbsp;Trying out the JPA middle tier</h2></div></div></div><p>
Open a Web browser and navigate to <a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
Click the <span class="emphasis"><em>Submit</em></span> button. Unfortunately the search will not return any results
as the Web bundle is still using the stub <code class="literal">Directory</code> implementation provided by the
<code class="literal">greenpages.app</code> module, rather than the JPA-based implementation that is provided
by <code class="literal">greenpages.jpa</code>.
This can be confirmed by using the Equinox console or the web-based admin console to examine the services being used
by <code class="literal">greenpages.web</code>.
</p><p>
The service which is being used by the Web bundle can be changed at runtime without having to restart the
application or the Web Server. This can be achieved by changing <code class="literal">greenpages.app</code> so that it no longer
publishes its <code class="literal">Directory</code> implementation. As a result of this <code class="literal">Directory</code>
service no longer being available, the Web bundle will automatically switch to using the JPA-based
implementation.
</p><p>
Open the <code class="literal">osgi-context.xml</code> file in the <code class="literal">META-INF/spring</code> folder of the
<code class="literal">greenpages.app</code> project and comment out the publication of the directory service:
</p><pre class="programlisting">&lt;!-- &lt;osgi:service interface="greenpages.Directory" ref="directory"/&gt; --&gt;
</pre><p>
</p><p>
Now save the updated file which will cause the application to be updated and refreshed on the server.
Switch back to the Web browser and click
<span class="emphasis"><em>Submit</em></span> again.
</p><p>
This time eight results should be returned. Clicking on any of the
<span class="emphasis"><em>View</em></span> links will display the listing&#8217;s details.
The application is now working.
All that remains is to apply some best practices to the middle tier.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="middle-tier.applying-best-practices"></a>5.5&nbsp;Applying best practices to the middle tier</h2></div></div></div><p>
While the application middle tier now works as required, it does not observe a few Spring-related best practices.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.applying-best-practices.transactions"></a>Using transactions</h3></div></div></div><p>
At the moment, the middle tier does not make any use of transactions. This isn&#8217;t a problem while the
database access methods are only running single queries, but could lead to problems in the future if the
application is made more complex. Thankfully, adding the use of transactions to the middle tier is simple.
</p><p>
Open <code class="literal">module-context.xml</code> in the <code class="literal">META-INF/spring</code> folder of
<code class="literal">greenpages.jpa</code>. Add the following bean definition to create a transaction manager and
associate it with the context&#8217;s <code class="literal">EntityManager</code>:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!--
Transaction manager for a single JPA EntityManagerFactory (alternative to JTA)
--</span>&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"transactionManager"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.orm.jpa.JpaTransactionManager"</span>
<span class="hl-attribute">p:entityManagerFactory-ref</span>=<span class="hl-value">"entityManagerFactory"</span> /&gt;
</pre><p>
(Save it, and the <code class="literal">greenpages.jpa</code> module will be refreshed.)
</p><p>
Next, Spring must be told to enable transaction management. In keeping with the use of annotation-based configuration
for the <code class="literal">EntityManager</code>, annotation-based transaction configuration will also be used. Add the following
to enable AspectJ-powered transaction demarcation for appropriately annotated beans:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!--
Instruct Spring to perform declarative transaction management
automatically on annotated classes.
--</span>&gt;
&lt;<span class="hl-tag">tx:annotation-driven</span> <span class="hl-attribute">mode</span>=<span class="hl-value">"aspectj"</span> /&gt;
</pre><p>
</p><p>
Save the updated file which will trigger (another) successful refresh of <code class="literal">greenpages.jpa</code>.
</p><p>
Lastly, <code class="literal">JpaDirectory</code> needs to be annotated so that it is identified as requiring Spring-based
transaction management. Open <code class="literal">JpaDirectory.java</code> in <code class="literal">greenpages.jpa</code>.
Annotate the class with
<code class="literal">@Transactional</code> and add an
import for <code class="literal">org.springframework.transaction.annotation.Transactional</code>, which Eclipse should suggest:
</p><pre class="programlisting"><span class="hl-keyword">import</span> org.springframework.transaction.annotation.Transactional;
@Transactional
<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> JpaDirectory <span class="hl-keyword">implements</span> Directory {
&#8230;
</pre><p>
</p><p>
Save the updated file triggering another successful refresh: <code class="literal">JpaDirectory</code> is now
transactional.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.applying-best-practices.exception-translation"></a>Enabling exception translation</h3></div></div></div><p>
When using JPA, the standard exceptions are somewhat out of keeping with Spring&#8217;s exception
model. Spring provides support for automatically translating these exceptions into Spring&#8217;s
<code class="literal">DataAccessException</code> hierarchy.
</p><p>
Open <code class="literal">module-context.xml</code> for <code class="literal">greenpages.jpa</code> again and add the
following bean definition to add the exception translator to the application context:
</p><pre class="programlisting"> &lt;<span class="hl-comment">!--
Post-processor to perform exception translation on @Repository classes
(from native exceptions such as JPA PersistenceExceptions to
Spring&amp;rsquo;s DataAccessException hierarchy).
--</span>&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"</span> /&gt;
</pre><p>
</p><p>
Save the updated file. The translation will only occur on classes that are annotated with
Spring&#8217;s <code class="literal">@Repository</code> stereotype annotation.
<code class="literal">JpaDirectory</code> needs to have this annotation added to it complete the
enabling of the exception translation.
</p><p>
Open <code class="literal">JpaDirectory.java</code> again, annotate the class with
<code class="literal">@Repository</code> and add an import for
<code class="literal">org.springframework.stereotype.Repository</code>:
</p><pre class="programlisting"><span class="hl-keyword">import</span> org.springframework.stereotype.Repository;
@Transactional
@Repository
<span class="hl-keyword">final</span> <span class="hl-keyword">class</span> JpaDirectory <span class="hl-keyword">implements</span> Directory {
</pre><p>
</p><p>
Save the updated file.
</p><p>
At this point the redeploy of the GreenPages application may fail with an error similar to this:
</p><pre class="programlisting">&lt;SPDE0100E&gt; The class with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor',
referenced by bean 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0',
could not be loaded by class loader 'ServerBundleClassLoader: [bundle=greenpages-1-greenpages.jpa_2.3.0]':
&#8230;
</pre><p>
which indicates that there is some package (<code class="code">org.springframework.dao.annotation</code>) which is not
available to the &#8220;<span class="quote"><code class="code">BundleClassLoader</code></span>&#8221; for bundle <code class="code">greenpages-1-greenpages.jpa_2.3.0</code>.
We should look in the <code class="literal">MANIFEST.MF</code> file for this bundle, and see that this package is not
imported (in the <code class="literal">Import-Package</code> header). Since Bundlor generated this file (controlled by the
template file <code class="literal">template.mf</code>) we should check that the manifest was re-generated on our last change.
</p><p>
Open <code class="literal">template.mf</code> in <code class="literal">greenpages.jpa</code> and,
in the <span class="emphasis"><em>Overview</em></span> pane, click on <span class="emphasis"><em>Update MANIFEST.MF</em></span>
in the <span class="emphasis"><em>Bundle Actions</em></span> section. The <code class="literal">MANIFEST.MF</code> file
is updated, and the application is redeployed, this time successfully. It might be worthwhile
checking the option <span class="emphasis"><em>Automatically update MANIFEST.MF in the background</em></span> on
the <code class="literal">template.mf</code> <span class="emphasis"><em>Overview</em></span> pane so that the <code class="literal">MANIFEST.MF
</code> is kept up to date as the project is changed.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.applying-best-practices.versioning-imports"></a>Versioning imports</h3></div></div></div><p>
By default, Bundlor generates <code class="literal">Import-Package</code> entries with no version range
specified. In the absence of a version range, the OSGi default of &#8220;<span class="quote">any version</span>&#8221; is used.
Whilst this is very flexible it&#8217;s generally a good idea to restrict an import by
specifying a narrower range. This can be achieved by providing Bundlor with some additional
information in the manifest template.
</p><p>
Open <code class="literal">template.mf</code> for <code class="literal">greenpages.jpa</code> and add the following
<code class="literal">Import-Template</code> header:
</p><pre class="programlisting">Import-Template: org.springframework.*;version="[3.0,3.1)",
greenpages;version="[2.0,2.1)",
javax.persistence;version="[1.0.0,1.0.0]"
</pre><p>
If there is already an <code class="literal">Import-Template</code> header in the template, extend it to include the
above package version range specifications.
</p><p>
This header tells Bundlor that all imports of <code class="literal">org.springframework</code> packages
should be in the range <code class="literal">3.0</code> inclusive to <code class="literal">3.1</code>
exclusive, that an import of the <code class="literal">greenpages</code> package should be in the
range <code class="literal">2.0</code> inclusive to <code class="literal">2.1</code> exclusive, and that an import of
<code class="literal">javax.persistence</code> should be at exactly version <code class="literal">1.0.0</code>.
</p><p>
Bundlor has also generated an import for the <code class="literal">javax.sql</code> package due to
the <code class="literal">greenpages.jpa</code> module&#8217;s use of <code class="literal">javax.sql.DataSource</code>.
This class is provided by the JRE and as such is generally considered to be unversioned, that is it
has the default OSGi version of zero. If version zero is <span class="emphasis"><em>precisely</em></span> what is required
then add the following to the <code class="literal">Import-Template</code> header:
</p><pre class="programlisting">,javax.sql;version="[0,0]"
</pre><p>
but if &#8220;<span class="quote">any</span>&#8221; version is acceptable add the following instead:
</p><pre class="programlisting">,javax.sql;version="0"
</pre><p>
Either of these will successfully allow GreenPages to deploy and work correctly. The difference
is in the level of flexibility allowed with the external dependency, something which is probably
irrelevant in this case, but with other package sources might be important.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="middle-tier.applying-best-practices.congratulations"></a>Congratulations!</h3></div></div></div><p>
The GreenPages middle tier is now complete and observes some &#8220;<span class="quote">best practice</span>&#8221;
development with Spring and OSGi.
</p></div></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="testing.greenpages"></a>6.&nbsp;Testing GreenPages</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="testing.greenpages.introduction"></a>6.1&nbsp;Introduction</h2></div></div></div><p>
Testing is one of the most important aspects of software development. Without testing it would be difficult
to determine if a piece of code worked properly, changes would have undetected consequences, and the quality
of products would generally be lower.
</p><p>
There are two major categories of testing generally recognised today: unit testing
and integration testing. In the context of the
GreenPages application, <span class="emphasis"><em>unit testing</em></span> means testing a single class in isolation from other application code.
This type of testing does not change at all when developing for Web Server.
</p><p>
In our application <span class="emphasis"><em>integration testing</em></span> means testing an application or
portion of an application with other code. This kind of testing does look a bit different when developing
for Web Server. In most cases Web Server applications are made up of small bundles that consume services through the
OSGi registry. In the following steps a single bundle and the entire GreenPages
application will be integration tested outside the container.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="testing.greenpages.single.bundle"></a>6.2&nbsp;Single bundle integration testing</h2></div></div></div><p>
One of the most common forms of integration testing is ensuring that the object relational mapping in an
application is working properly. This kind of testing typically uses a data access object to retrieve data
from a live database. In this step a test case for the <code class="classname">JpaDirectory</code>
class is created.
</p><p>
Before proceeding, stop any Web Server instance that was previously running.
</p><p>
Open the <code class="classname">greenpages.jpa.JpaDirectorySpringContextTests</code> class in the
<code class="filename">src/test/java</code> source folder of the <code class="literal">greenpages.jpa</code> project. This
class contains a method that uses <span class="emphasis"><em>JUnit</em></span> to test that a search completes
correctly. Rather than instantiate
this class directly in the test, the Spring Test Framework is used to instantiate and inject a
<code class="classname">JpaDirectory</code> based on the <code class="literal">META-INF/spring/module-context.xml</code> file.
</p><p>
Add Spring Test Framework declarations to the test class. These declarations run the test with the
<code class="classname">SpringJunit4ClassRunner</code> and configure the test with the
<code class="literal">classpath:/META-INF/spring/module-context.xml</code> file:
</p><pre class="programlisting">@RunWith(SpringJUnit4ClassRunner.<span class="hl-keyword">class</span>)
@ContextConfiguration(locations = <span class="hl-string">"classpath:/META-INF/spring/module-context.xml"</span>)
@TestExecutionListeners(value = DependencyInjectionTestExecutionListener.<span class="hl-keyword">class</span>)
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> JpaDirectorySpringContextTests {
&#8230;
</pre><p>
Use Eclipse to suggest the necessary imports until there are no errors.
</p><p>
When this configuration is complete, click on the <span class="emphasis"><em>Run</em></span> drop-down menu and select
<span class="emphasis"><em>Run Configurations&#8230;</em></span>. In the the dialog that opens select
<span class="guimenu">JUnit</span> &#8594; <span class="guimenuitem">JpaDirectorySpringContextTests</span>
and press <span class="emphasis"><em>Run</em></span>.
</p><div class="mediaobject" align="center"><img src="images/testing-greenpages/jpa-test-runner.png" align="middle"></div><p>
</p><p>
This test run will fail because there is no <code class="interfacename">DataSource</code> bean to be injected;
it is typically sourced from the OSGi service registry at runtime:
</p><pre class="programlisting">Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No bean named 'dataSource' is defined
</pre><p>
The next step will correct this error.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="testing.greenpages.contributing.osgi"></a>6.3&nbsp;Contributing OSGi sourced dependencies</h2></div></div></div><p>
In the previous step the <code class="classname">JpaDirectorySpringContextTests</code> test failed because it did
not have a <code class="interfacename">DataSource</code> to be injected. In this step, an
&#8220;<span class="quote">in-process</span>&#8221; database is instantiated and populated with data for testing.
</p><p>
Open the <code class="filename">test-context.xml</code> file in the
<code class="literal">src/test/resources</code> <code class="filename">META-INF/spring</code> folder.
In this file, define two beans; a
<code class="interfacename">DataSource</code> and a <code class="classname">TestDataPopulator</code>.
These two beans
will provide a test <code class="interfacename">DataSource</code> complete with test data.
</p><pre class="programlisting"> &lt;<span class="hl-tag">bean</span> <span class="hl-attribute">id</span>=<span class="hl-value">"dataSource"</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.apache.commons.dbcp.BasicDataSource"</span>
<span class="hl-attribute">p:driverClassName</span>=<span class="hl-value">"org.h2.Driver"</span> <span class="hl-attribute">p:url</span>=<span class="hl-value">"jdbc:h2:.~/greenpages-db/greenpages"</span>
<span class="hl-attribute">p:username</span>=<span class="hl-value">"greenpages"</span> <span class="hl-attribute">p:password</span>=<span class="hl-value">"pass"</span> <span class="hl-attribute">init-method</span>=<span class="hl-value">"createDataSource"</span>
<span class="hl-attribute">destroy-method</span>=<span class="hl-value">"close"</span> /&gt;
&lt;<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"greenpages.jpa.TestDataPopulator"</span> <span class="hl-attribute">init-method</span>=<span class="hl-value">"populate"</span>&gt;
&lt;<span class="hl-tag">constructor-arg</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"dataSource"</span> /&gt;
&lt;<span class="hl-tag">constructor-arg</span> <span class="hl-attribute">value</span>=<span class="hl-value">"file:../../db/db.sql"</span> /&gt;
&lt;<span class="hl-tag">/bean</span>&gt;
</pre><p>
</p><p>
Open the <code class="classname">JpaDirectorySpringContextTests</code> class and update the
<code class="interfacename">ContextConfiguration</code> annotation to point at both the
<code class="filename">module-context.xml</code> file and the <code class="filename">test-context.xml</code> file:
</p><pre class="programlisting">@ContextConfiguration(locations = {
<span class="hl-string">"classpath:/META-INF/spring/module-context.xml"</span>,
<span class="hl-string">"classpath:/META-INF/spring/test-context.xml"</span> })
</pre><p>
</p><p>
Once again use the <code class="literal">JpaDirectorySpringContextTests</code> JUnit profile to run the test class.
Now that there is a <code class="interfacename">DataSource</code> being contributed, the test will pass.
If the test fails, check that the H2 database server is still running in the background.
</p><p>
Proceed to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="testing.greenpages.application"></a>6.4&nbsp;Multi bundle integration testing</h2></div></div></div><p>
Earlier a single bundle was integration tested by providing a test implementation of its
<code class="interfacename">DataSource</code> dependency.
When integration testing it is often a good idea to
test the entire application outside of the container.
In this step a test case for the
entire GreenPages application is created, starting with the <code class="classname">GreenPagesController</code> class
and descending all the way to a database.
It would be sensible to create this in a separate test bundle
but as one of the bundles involved here is a web bundle the tests will have to go in there.
</p><p>
Since this project will be testing the GreenPages application as a whole, it needs to depend on the bundles
that make up the application.
Open the <code class="filename">pom.xml</code> file for the <code class="literal">greenpages.web</code>
project and add a dependency declaration for the <code class="literal">greenpages.jpa</code> bundle:
</p><pre class="programlisting"> &lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.jpa&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">scope</span>&gt;test&lt;<span class="hl-tag">/scope</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
noting that the scope is <code class="literal">test</code>.
</p><p>
Open the <code class="classname">GreenPagesSpringContextTests</code> class
and add the Spring Test Framework declarations.
These declarations should run the test with the
<code class="classname">SpringJunit4ClassRunner</code> and configure the test with the
<code class="literal">classpath*:/META-INF/spring/module-context.xml</code>,
<code class="literal">file:src/main/webapp/WEB-INF/greenpages-servlet.xml</code> and
<code class="literal">classpath:/META-INF/spring/test-context.xml</code> files. Note the use of
<code class="literal">classpath*:</code> with respect to the <code class="literal">module-context.xml</code> path.
This will
cause Spring to look for files that match that path in all of the bundles on the classpath meaning that all
the application beans will be instantiated.
Also, as we do not want the <code class="literal">WEB-INF</code> folder
on the classpath we must reference the servlet context for GreenPages with a full file path:
</p><pre class="programlisting">@RunWith(SpringJUnit4ClassRunner.<span class="hl-keyword">class</span>)
@ContextConfiguration(locations = {
<span class="hl-string">"classpath*:/META-INF/spring/module-context.xml"</span>,
<span class="hl-string">"file:src/main/webapp/WEB-INF/greenpages-servlet.xml"</span>,
<span class="hl-string">"classpath:/META-INF/spring/test-context.xml"</span> })
@TestExecutionListeners(value = DependencyInjectionTestExecutionListener.<span class="hl-keyword">class</span>)
<span class="hl-keyword">public</span> <span class="hl-keyword">class</span> GreenPagesSpringContextTests {
&#8230;
</pre><p>
It may be necessary to click on Update <code class="literal">MANIFEST.MF</code> on the template overview pane
and <span class="emphasis"><em>Update Dependencies</em></span> from the <span class="emphasis"><em>Maven</em></span> menu,
before Eclipse will suggest appropriate imports here.
</p><p>
When this configuration is complete, click on the <span class="emphasis"><em>Run</em></span> drop-down and select
<span class="emphasis"><em>Run Configurations&#8230;</em></span>.
In the the dialog that opens select
<span class="guimenu">JUnit</span> &#8594; <span class="guimenuitem">GreenPagesSpringContextTests</span>
and press <span class="emphasis"><em>Run</em></span>;
</p><div class="mediaobject" align="center"><img src="images/testing-greenpages/integration-test-runner.png" align="middle"></div><p>
</p><p>
When this test is run, Spring creates an <code class="interfacename">ApplicationContext</code> that is built
from the <code class="filename">module-context.xml</code> configuration files from all of the bundles.
Because of
this all of the internal dependencies are satisfied by the beans created directly by the bundles.
</p><p>
The test should pass. If it doesn't, try the usual Eclipse dance steps of opening and closing the project and doing a clean rebuild to clear the problem.
</p><p>
There are warnings output by this test concerning <code class="literal">log4j</code>:
</p><pre class="programlisting">log4j:WARN No appenders could be found for logger
(org.springframework.test.context.junit4.SpringJUnit4ClassRunner).
log4j:WARN Please initialize the log4j system properly.
</pre><p>
These warnings are benign, and do not influence the tests in any way.
</p><p>
The next chapter constructs an automated build system that might be used to build GreenPages
(and run its tests) outside of an interactive development environment.
</p></div></div><div class="chapter" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="automated.build"></a>7.&nbsp;Automated Build</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.introduction"></a>7.1&nbsp;Introduction</h2></div></div></div><p>
One of the most important components in application development is the automated build. This permits
application artifacts to be created outside of the developer&#8217;s IDE. The application can be
created and tested in a variety of environments including continuous integration.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.setup"></a>7.2&nbsp;Setting up for Automated Build</h2></div></div></div><p>
Before building and deploying from the command line, it is important to clean up the artifacts that Eclipse
has deployed. In this section the GreenPages application will be undeployed within Eclipse and all of
the GreenPages bundles built from the command line.
</p><p>
Right-click on the <code class="literal">greenpages</code> application in the <code class="literal">Servers</code> view and
select <span class="emphasis"><em>Remove</em></span>. Once this is complete close Eclipse: it is no longer needed.
</p><div class="mediaobject" align="center"><img src="images/automated-build/remove-application.png" align="middle"></div><p>
</p><p>
Run the following command from a command prompt with the <code class="filename">$GREENPAGES_HOME/start</code> as the current directory. This will build
the individual bundles that make up the GreenPages application:
</p><pre class="programlisting">mvn clean install</pre><p>
</p><p>
The first time this is run will cause Maven to download quite a few packages. It is likely also that
this does not build successfully on the first try, due to warnings from Bundlor. These warnings are due to
the lack of information regarding some of the packages required by <code class="literal">greenpages.db</code> and <code class="literal">greenpages.web</code>.
For example warnings like the following may be issued:
</p><pre class="programlisting">[WARNING] Bundlor Warnings:
[WARNING] &lt;SB0001W&gt;: The import of package javax.sql does not specify a version.
[WARNING] &lt;SB0001W&gt;: The import of package org.apache.commons.dbcp does not specify a version.
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Bundle transformer returned warnings.
Please fix manifest template at '/opt/greenpages-2.3.0.RELEASE/start/greenpages.db/template.mf'
and try again.
</pre><p>
which indicate that there is no information in the <code class="literal">template.mf</code> file in the <code class="literal">greenpages.db</code> project
to inform Bundlor what version of these packages to generate in the <code class="literal">MANIFEST.MF</code> for that bundle.
</p><p>
To correct these problems add the following lines to the <code class="literal">template.mf</code> file for
the <code class="literal">greenpages.db</code> bundle:
</p><pre class="programlisting">Import-Template: javax.sql;version="0",
org.apache.commons.dbcp;version="[1.2.2.osgi, 1.2.2.osgi]"
</pre><p>
and, if further warnings are issued, in the <code class="literal">template.mf</code> file of other bundles (for example, <code class="literal">greenpages.jpa</code>).
</p><p>
When the <code class="literal">mvn</code> command returns successfully, go to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.create.pom"></a>7.3&nbsp;Create POM</h2></div></div></div><p>
All of the projects except the PAR project have Maven POM files for building. In this step
an initial POM file for the PAR is created.
</p><p>
Using a text editor create a file called <code class="filename">$GREENPAGES_HOME/start/greenpages/pom.xml</code>.
Open this file and add the following skeleton to it:
</p><pre class="programlisting">&lt;<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>&gt;
&lt;<span class="hl-tag">project</span>
<span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://maven.apache.org/POM/4.0.0"</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://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"</span>&gt;
&lt;<span class="hl-tag">parent</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.parent&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;2.3.0.RELEASE&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">relativePath</span>&gt;../parent&lt;<span class="hl-tag">/relativePath</span>&gt;
&lt;<span class="hl-tag">/parent</span>&gt;
&lt;<span class="hl-tag">modelVersion</span>&gt;4.0.0&lt;<span class="hl-tag">/modelVersion</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">name</span>&gt;GreenPages PAR&lt;<span class="hl-tag">/name</span>&gt;
&lt;<span class="hl-tag">packaging</span>&gt;par&lt;<span class="hl-tag">/packaging</span>&gt;
&lt;<span class="hl-tag">dependencies</span>&gt;
&lt;<span class="hl-tag">/dependencies</span>&gt;
&lt;<span class="hl-tag">build</span>&gt;
&lt;<span class="hl-tag">plugins</span>&gt;
&lt;<span class="hl-tag">/plugins</span>&gt;
&lt;<span class="hl-tag">/build</span>&gt;
&lt;<span class="hl-tag">/project</span>&gt;
</pre><p>
ensuring that the version numbers are consistent
(for example, <code class="literal">2.3.0.RELEASE</code> might be <code class="literal">2.3.0</code>
depending on which version of <code class="literal">greenpages</code> being developed).
</p><p>
This skeleton defines a basic configuration with a parent POM. Notice that the <code class="literal">packaging</code>
type is <code class="literal">par</code>. After this file is created execute the following command from the
<code class="filename">$GREENPAGES_HOME/start/greenpages</code> directory.
</p><pre class="programlisting">mvn clean package</pre><p>
</p><p>
This command returns an error indicating that Maven does not know how to build a PAR:
</p><pre class="programlisting">[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] The plugin 'org.apache.maven.plugins:maven-par-plugin' does not exist
[INFO] or no valid version could be found
[INFO] ------------------------------------------------------------------------
</pre><p>
The next step will correct this.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.par.plugin"></a>7.4&nbsp;Adding the <code class="literal">par</code> plugin</h2></div></div></div><p>
Thorsten Maus contributed a Maven plugin to SpringSource (see <a class="xref" href="#further.resources.documentation" title="A.2&nbsp;Documentation">Section&nbsp;A.2, &#8220;Documentation&#8221;</a>)
that builds a PAR file from a list of dependencies. In this step the Maven <code class="literal">par</code> plugin is added
to properly build a PAR artifact type.
</p><p>
In the <code class="literal">&lt;build&gt;&lt;plugins&gt;&#8230;&lt;/plugins&gt;&lt;/build&gt;</code> section, add a plugin declaration for the
<code class="literal">par</code> plugin.
</p><pre class="programlisting">&lt;<span class="hl-tag">plugin</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.apache.maven.plugins&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;maven-par-plugin&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;1.0.0.RELEASE&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">configuration</span>&gt;
&lt;<span class="hl-tag">applicationSymbolicName</span>&gt;greenpages&lt;<span class="hl-tag">/applicationSymbolicName</span>&gt;
&lt;<span class="hl-tag">applicationDescription</span>&gt;GreenPages&lt;<span class="hl-tag">/applicationDescription</span>&gt;
&lt;<span class="hl-tag">/configuration</span>&gt;
&lt;<span class="hl-tag">/plugin</span>&gt;
</pre><p>
</p><p>
Declare the list of bundles to be packaged in the PAR as dependencies of the PAR project.
</p><pre class="programlisting">&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.app&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.jpa&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.db&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;com.springsource.dmserver&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;greenpages.web&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;${project.version}&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">type</span>&gt;war&lt;<span class="hl-tag">/type</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
</p><p>
Now, run the following command.
</p><pre class="programlisting">mvn clean package</pre><p>
</p><p>
This command will now complete successfully and build a PAR into <code class="filename">target/</code>:
</p><pre class="programlisting">[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building GreenPages PAR
[INFO] task-segment: [clean, package]
[INFO] ------------------------------------------------------------------------
[INFO] [clean:clean {execution: default-clean}]
[INFO] [resources:resources {execution: default-resources}]
[INFO] [par:par {execution: default-par}]
[INFO] Assembling Artifacts for PAR '&#8230;/start/greenpages/target/greenpages-2.3.0.RELEASE.par'
[INFO] Added 'greenpages.app.jar'
[INFO] Added 'greenpages.jpa.jar'
[INFO] Added 'greenpages.db.jar'
[INFO] Added 'greenpages.web.war'
[INFO] [com.springsource.bundlor.:transform {execution: bundlor}]
[INFO] Ignored project with non-bundle packaging: [par]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------</pre><p>
Proceed to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.dependency.plugin"></a>7.5&nbsp;Adding the <code class="literal">dependency</code> plugin</h2></div></div></div><p>
Maven now successfully builds the PAR for the application, however the dependencies of the PAR
are not apparent.
In this step the Maven <code class="literal">dependency</code> plugin is added to
collect the transitive dependency graph for the PAR.
</p><p>
In the <code class="literal">&lt;build&gt;&lt;plugins&gt;&#8230;&lt;/plugins&gt;&lt;/build&gt;</code> section
(after the <code class="literal">par</code> plugin
declaration), add a plugin declaration for the <code class="literal">dependency</code> plugin:
</p><pre class="programlisting">&lt;<span class="hl-tag">plugin</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.apache.maven.plugins&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;maven-dependency-plugin&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">executions</span>&gt;
&lt;<span class="hl-tag">execution</span>&gt;
&lt;<span class="hl-tag">id</span>&gt;copy-dependencies&lt;<span class="hl-tag">/id</span>&gt;
&lt;<span class="hl-tag">phase</span>&gt;package&lt;<span class="hl-tag">/phase</span>&gt;
&lt;<span class="hl-tag">goals</span>&gt;
&lt;<span class="hl-tag">goal</span>&gt;copy-dependencies&lt;<span class="hl-tag">/goal</span>&gt;
&lt;<span class="hl-tag">/goals</span>&gt;
&lt;<span class="hl-tag">configuration</span>&gt;
&lt;<span class="hl-tag">outputDirectory</span>&gt;${project.build.directory}/par-provided&lt;<span class="hl-tag">/outputDirectory</span>&gt;
&lt;<span class="hl-tag">overWriteIfNewer</span>&gt;true&lt;<span class="hl-tag">/overWriteIfNewer</span>&gt;
&lt;<span class="hl-tag">excludeGroupIds</span>&gt;com.springsource.dmserver,org.apache.log4j&lt;<span class="hl-tag">/excludeGroupIds</span>&gt;
&lt;<span class="hl-tag">/configuration</span>&gt;
&lt;<span class="hl-tag">/execution</span>&gt;
&lt;<span class="hl-tag">/executions</span>&gt;
&lt;<span class="hl-tag">/plugin</span>&gt;
</pre><p>
</p><p>
A dependency on Freemarker needs to be added to the other dependencies.
This is required to ensure the Web
bundle has the correct set of dependencies as well as the other bundles.
Normally they would simply be resolved
transitively from the bundle projects but the &#8216;war&#8217; project does not pass on its dependencies;
it expects
them to be contained in its &#8216;lib&#8217; directory.
For this reason its dependencies must be given explicitly.
</p><pre class="programlisting">&lt;<span class="hl-comment">!-- Required for the web bundle as dependencies are not propagated up from war build types --</span>&gt;
&lt;<span class="hl-tag">dependency</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.freemarker&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;com.springsource.freemarker&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">scope</span>&gt;provided&lt;<span class="hl-tag">/scope</span>&gt;
&lt;<span class="hl-tag">/dependency</span>&gt;
</pre><p>
</p><p>
The next step is to stop the Web bundle including its dependencies in a lib directory as they will be provided
by the runtime enviroment. Add the following build section to the <code class="literal">greenpages.web</code> POM file.
</p><pre class="programlisting">&lt;<span class="hl-tag">build</span>&gt;
&lt;<span class="hl-tag">plugins</span>&gt;
&lt;<span class="hl-tag">plugin</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;maven-war-plugin&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">version</span>&gt;2.1-beta-1&lt;<span class="hl-tag">/version</span>&gt;
&lt;<span class="hl-tag">configuration</span>&gt;
&lt;<span class="hl-tag">packagingExcludes</span>&gt;WEB-INF/lib/**&lt;<span class="hl-tag">/packagingExcludes</span>&gt;
&lt;<span class="hl-tag">/configuration</span>&gt;
&lt;<span class="hl-tag">/plugin</span>&gt;
&lt;<span class="hl-tag">/plugins</span>&gt;
&lt;<span class="hl-tag">/build</span>&gt;</pre><p>
</p><p>
Run the following command.
</p><pre class="programlisting">mvn clean package</pre><p>
</p><p>
When the command has completed, it will have copied all of the PAR&#8217;s dependencies into the
<code class="filename">target/par-provided</code> directory.
The output from Maven should include lines like these
</p><pre class="programlisting">[INFO] [par:par]
[INFO] Assembling Artifacts for PAR '/Users/chrisfrost/Repos/GIT/greenpages/solution/
greenpages/target/greenpages-solution-2.3.0.RELEASE.par'
[INFO] Added 'greenpages.app-solution.jar'
[INFO] Added 'greenpages.jpa-solution.jar'
[INFO] Added 'greenpages.db-solution.jar'
[INFO] Added 'greenpages.web-solution.war'
</pre><p>
If the dependencies are produced, proceed to the next step.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="running.tests"></a>7.6&nbsp;Automatically running the tests</h2></div></div></div><p>
Although the application is built, and dependencies produced for separate deployment, the tests
are not run as part of that build.
</p><p>
Add (or replace) the following plug-in entry in the <code class="literal">pom.xml</code> file in the <code class="literal">parent</code>
directory under <code class="literal">start</code>:
</p><pre class="programlisting">&lt;<span class="hl-tag">plugin</span>&gt;
&lt;<span class="hl-tag">groupId</span>&gt;org.apache.maven.plugins&lt;<span class="hl-tag">/groupId</span>&gt;
&lt;<span class="hl-tag">artifactId</span>&gt;maven-surefire-plugin&lt;<span class="hl-tag">/artifactId</span>&gt;
&lt;<span class="hl-tag">configuration</span>&gt;
&lt;<span class="hl-tag">includes</span>&gt;
&lt;<span class="hl-tag">include</span>&gt;**/*Tests.java&lt;<span class="hl-tag">/include</span>&gt;
&lt;<span class="hl-tag">/includes</span>&gt;
&lt;<span class="hl-tag">excludes</span>&gt;
&lt;<span class="hl-tag">exclude</span>&gt;**/Abstract*.java&lt;<span class="hl-tag">/exclude</span>&gt;
&lt;<span class="hl-tag">/excludes</span>&gt;
&lt;<span class="hl-tag">junitArtifactName</span>&gt;org.junit:com.springsource.org.junit&lt;<span class="hl-tag">/junitArtifactName</span>&gt;
&lt;<span class="hl-tag">argLine</span>&gt;-javaagent:${user.home}/.m2/repository/org/springframework/org.springframework.instrument/3.0.0.M3/org.springframework.instrument-3.0.0.M3.jar&lt;<span class="hl-tag">/argLine</span>&gt;
&lt;<span class="hl-tag">/configuration</span>&gt;
&lt;<span class="hl-tag">/plugin</span>&gt;</pre><p>
where the location of the user Maven repository is hard-coded.
</p><p>
Now run <code class="literal">mvn clean install</code> from the <code class="literal">start</code> directory.
Observe that the tests we constructed before are now run.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="automated.build.deploy.application"></a>7.7&nbsp;Deploying the application</h2></div></div></div><p>
Maven can now build both the PAR application and the collection of dependencies required for the
application. In this step the PAR and dependencies are copied to the Web Server and the PAR is started.
</p><p>
Change directory to <code class="literal">start/greenpages</code>.
</p><p>
Copy the JARs in the <code class="filename">target/par-provided</code> directory into the
<code class="filename">$VWS_HOME/repository/usr/</code> directory.
</p><p>
Copy the PAR (<code class="literal">greenpages-2.3.0.RELEASE.par</code>) in the <code class="filename">target/</code> directory
into the <code class="filename">$VWS_HOME/pickup</code> directory.
</p><p>
Start the Web Server and look for a message similar to:
</p><pre class="programlisting">&lt;DE0005I&gt; Started par 'greenpages' version '2.3.0.RELEASE'.
</pre><p>in the console output.
</p><p>
Once deployment of the GreenPages application has completed, navigate to
<a class="ulink" href="http://localhost:8080/greenpages" target="_top">http://localhost:8080/greenpages</a>.
</p><p>
The GreenPages application has been built from the command line,
with a complete dependency set generated for independent deployment.
</p><p>
The automated build and test procedure is to run <code class="literal">mvn clean install</code> from the
base directory, generating the component bundles, and then to run <code class="literal">mvn clean package</code> from
the <code class="literal">greenpages</code> directory to generate the PAR and produce all its dependencies.
</p></div></div><div class="appendix" lang="en"><div class="titlepage"><div><div><h2 class="title"><a name="further.resources"></a>Appendix&nbsp;A.&nbsp;Further Resources</h2></div></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="further.resources.projects"></a>A.1&nbsp;Projects</h2></div></div></div><div class="orderedlist"><ol type="a"><li><p>Virgo
(<a class="ulink" href="http://www.eclipse.org/virgo" target="_top">http://www.eclipse.org/virgo</a>) &#8212; homepage for Virgo.</p></li><li><p>SpringSource.org
(<a class="ulink" href="http://www.springsource.org" target="_top">http://www.springsource.org</a>) &#8212; homepage for Spring Framework.</p></li><li><p>OSGi
(<a class="ulink" href="http://www.osgi.org" target="_top">http://www.osgi.org</a>) &#8212; homepage for OSGi.</p></li><li><p>H2 Database
(<a class="ulink" href="http://www.h2database.com" target="_top">http://www.h2database.com</a> &#8212; homepage for the H2 database.</p></li><li><p>FreeMarker
(<a class="ulink" href="http://freemarker.sourceforge.net" target="_top">http://freemarker.sourceforge.net</a>) &#8212; homepage for FreeMarker templating
engine.</p></li><li><p>Commons DBCP
(<a class="ulink" href="http://commons.apache.org/dbcp" target="_top">http://commons.apache.org/dbcp</a>) &#8212; homepage for Commons DBCP.</p></li><li><p>Eclipse IDE
(<a class="ulink" href="http://www.eclipse.org/eclipse" target="_top">http://www.eclipse.org/eclipse</a>) &#8212; homepage for Eclipse IDE.</p></li><li><p>EclipseLink
(<a class="ulink" href="http://www.eclipse.org/eclipselink" target="_top">http://www.eclipse.org/eclipselink</a>) &#8212; homepage for EclipseLink JPA.</p></li></ol></div></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="further.resources.documentation"></a>A.2&nbsp;Documentation</h2></div></div></div><div class="orderedlist"><ol type="a"><li><p>Virgo Web Server Documentation
(<a class="ulink" href="http://www.eclipse.org/virgo/documentation" target="_top">http://www.eclipse.org/virgo/documentation</a>) &#8211; cover page for all Virgo documentation.
</p></li><li><p>Spring DM Reference Guide
(<a class="ulink" href="http://static.springsource.org/osgi/docs/1.2.0/reference/html/" target="_top">http://static.springsource.org/osgi/docs/1.2.0/reference/html/</a>).
</p></li><li><p>Spring Framework 3.0 documentation
(<a class="ulink" href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/" target="_top">http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/</a>).
</p></li><li><p>FreeMarker documentation
(<a class="ulink" href="http://freemarker.sourceforge.net/docs" target="_top">http://freemarker.sourceforge.net/docs</a>).</p></li><li><p>Eclipse IDE documentation
(<a class="ulink" href="http://www.eclipse.org/documentation" target="_top">http://www.eclipse.org/documentation</a>).</p></li><li><p>EclipseLink documentation wiki
(<a class="ulink" href="http://wiki.eclipse.org/EclipseLink/UserManual" target="_top">http://wiki.eclipse.org/EclipseLink/UserManual</a>).</p></li><li><p>Maven PAR plugin
(<a class="ulink" href="http://blog.springsource.com/2009/06/24/maven-par-plugin-100m1/" target="_top">http://blog.springsource.com/2009/06/24/maven-par-plugin-100m1/</a>).</p></li></ol></div></div></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--></body></html>