| <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 © 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>™ 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>™ 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. 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 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 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 “<span class="quote">by name</span>” or “<span class="quote">by identifier</span>” (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 “<span class="quote">by identifier</span>” 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’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 “<span class="quote">refresh packages</span>” 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 1.1. 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>…implement the interface with a class <code class="literal">SomeImpl</code>: |
| |
| </p><pre class="programlisting">package org.bar.impl; |
| |
| class SomeImpl implements SomeInterface { |
| … |
| } |
| </pre><p> |
| </p><p>…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 “<span class="quote">refresh packages</span>” 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 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 (“<span class="quote"><code class="literal">.</code></span>”) 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 |
| “<span class="quote"><code class="literal">[</code></span>” or “<span class="quote"><code class="literal">]</code></span>” denotes |
| an <span class="emphasis"><em>inclusive</em></span> end of the range and a round bracket |
| “<span class="quote"><code class="literal">(</code></span>” or “<span class="quote"><code class="literal">)</code></span>” 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 “<span class="quote">strict</span>” 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 “<span class="quote">half-open</span>” 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 “<span class="quote">unbounded</span>” 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’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’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 Projects">the appendix Projects</a>.) |
| The bundle manifest’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 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’s <code class="literal">META-INF/spring</code> sub-directory.</p><p> |
| To publish a service, an <code class="literal"><osgi:service></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"><osgi:reference></code> tag is used and the |
| service may be passed into other Spring beans using Spring’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’s application contexts. |
| Web Server turns off damping of a service proxy while the proxy’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 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 “<span class="quote"><code class="literal">.par</code></span>”. 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 Documentation">Section A.2, “Documentation”</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 “<span class="quote">pickup</span>” |
| 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. 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 Pre-requisites</h2></div></div></div><p> |
| Before proceeding, ensure that a Java<span class="trademark"></span>™ 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 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>™ 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… |
| </p><pre class="programlisting">prompt> cd C:\ |
| prompt> "%JAVA_HOME%"\bin\jar xf <span class="emphasis"><em>\path\to\</em></span>virgo-web-server-2.1.0.RELEASE.zip |
| prompt> 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 <TC0000I> Starting Tomcat. |
| system-artifacts <TC0010I> Creating HTTP/1.1 connector with scheme http on port 8080. |
| system-artifacts <TC0010I> Creating HTTP/1.1 connector with scheme https on port 8443. |
| system-artifacts <TC0010I> Creating AJP/1.3 connector with scheme http on port 8009. |
| system-artifacts <TC0001I> Started Tomcat. |
| system-artifacts <DE0004I> Starting bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'. |
| system-artifacts <DE0004I> Starting bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'. |
| start-signalling-1 <DE0005I> Started bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'. |
| system-artifacts <DE0005I> Started bundle 'org.eclipse.virgo.web.tomcat' version '2.1.0.RELEASE'. |
| start-signalling-1 <DE0005I> Started bundle 'org.eclipse.gemini.web.tomcat' version '1.1.0.RELEASE'. |
| start-signalling-2 <DE0005I> Started bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'. |
| start-signalling-2 <DE0005I> Started plan 'org.eclipse.virgo.web' version '2.1.0'. |
| Thread-2 <UR0001I> 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>™ 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… |
| </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 <TC0000I> Starting Tomcat. |
| system-artifacts <TC0010I> Creating HTTP/1.1 connector with scheme http on port 8080. |
| system-artifacts <TC0010I> Creating HTTP/1.1 connector with scheme https on port 8443. |
| system-artifacts <TC0010I> Creating AJP/1.3 connector with scheme http on port 8009. |
| system-artifacts <TC0001I> Started Tomcat. |
| system-artifacts <DE0004I> Starting bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'. |
| system-artifacts <DE0004I> Starting bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'. |
| start-signalling-1 <DE0005I> Started bundle 'org.eclipse.virgo.web.dm' version '2.1.0.RELEASE'. |
| system-artifacts <DE0005I> Started bundle 'org.eclipse.virgo.web.tomcat' version '2.1.0.RELEASE'. |
| start-signalling-1 <DE0005I> Started bundle 'org.eclipse.gemini.web.tomcat' version '1.1.0.RELEASE'. |
| start-signalling-2 <DE0005I> Started bundle 'org.eclipse.virgo.web.core' version '2.1.0.RELEASE'. |
| start-signalling-2 <DE0005I> Started plan 'org.eclipse.virgo.web' version '2.1.0'. |
| Thread-2 <UR0001I> 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 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>™ 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> cd C:\ |
| prompt> "%JAVA_HOME%"\bin\jar xf \<span class="emphasis"><em>full…path…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>™ 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 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’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 …</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. 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 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 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> mkdir c:\springsource\samples |
| prompt> cd c:\springsource\samples |
| prompt> jar xf c:\path\to\greenpages-2.3.0.RELEASE.zip |
| prompt> 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. The Web Module">Chapter 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 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> cd %GREENPAGES_HOME%\solution\greenpages |
| prompt> 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> 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 &</pre><p>Press Return to continue.</p><p>On Windows, run the <code class="literal">run.bat</code> command:</p><pre class="programlisting">prompt> 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> 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> cd %VWS_HOME% |
| prompt> 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> "%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"><DE0005I> 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 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 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> → <span class="guimenuitem">Import</span>. |
| </p></li><li><p>From the Import Wizard select |
| <span class="guimenu">General</span> → <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…</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> → <span class="guisubmenu">Show View</span> → <span class="guimenuitem">Other…</span>.</p></li><li><p>In the <span class="emphasis"><em>Show View</em></span> dialog choose |
| <span class="guimenu">Server</span> → <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> → <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> → <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> → <span class="guimenuitem">Clean…</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 “<span class="quote">Eclipse dance</span>”.) |
| </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 ‘warm start’ 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 ‘Start server with -clean option’. |
| 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> cd %VWS_HOME%\pickup |
| prompt> 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…</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"><DE0005I> 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 “Installing dependencies into Web Server”</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. 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 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. Installation">Chapter 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. Installing and exploring GreenPages">Chapter 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 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> → <span class="guimenuitem">Server</span> → <span class="guimenuitem">Runtime Environments</span>. Select <span class="emphasis"><em>Add…</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 The controller</h2></div></div></div><p> |
| The Spring’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…</em></span> menu item. |
| In the dialog that opens, choose <span class="guimenuitem">General</span> → <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’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> → <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…</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 { |
| … |
| @RequestMapping(<span class="hl-string">"/home.htm"</span>) |
| <span class="hl-keyword">public</span> <span class="hl-keyword">void</span> home() { |
| } |
| … |
| </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’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"> <<span class="hl-comment">!-- enable classpath scanning --</span>> |
| <<span class="hl-tag">context:component-scan</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"greenpages.web"</span> /> |
| </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—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 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"><DE0005I> 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> → <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 “<span class="quote">404</span>” 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 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 ‘parent’ 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 The controller">Section 4.3, “The controller”</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 The controller">Section 4.3, “The controller”</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<Listing> 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< ></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’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> → <span class="guimenuitem">Project…</span>. In the dialog that opens select |
| <span class="guimenu">EclipseRT</span> → <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 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 “Creating web module metadata”</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—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"><dependencies></code> tags): |
| </p><pre class="programlisting"><<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.app<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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 “Creating web module metadata”</a>. |
| </p><pre class="programlisting">greenpages.*;version="[2.3, 2.4)"</pre><p> |
| Be careful to include the “<span class="quote"><code class="literal">.*</code></span>” 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…</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"><osgi:reference/></code> tag as follows: |
| </p><pre class="programlisting"><<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>/> |
| </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 “<span class="quote">time-out</span>” 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 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’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 { |
| … |
| </pre><p> |
| generating imports with Eclipse’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"><<span class="hl-tag">context:component-scan</span> <span class="hl-attribute">base-package</span>=<span class="hl-value">"greenpages.internal"</span>/> |
| </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"><osgi:service/></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"><<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>/> |
| </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 “<span class="quote">detailed</span>” 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 “<span class="quote">Andy Wilkinson</span>”. |
| </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. 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 Introduction</h2></div></div></div><p> |
| GreenPages’ 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 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’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> → <span class="guimenuitem">Project…</span>. In the resulting |
| dialog select <span class="guimenu">EclipseRT</span> → <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 “<span class="quote"><code class="literal">GreenPages DataSource</code></span>” to more accurately |
| describe the bundle’s purpose. An option to ‘Enable Bundle Classpath Container’ 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’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"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>> |
| <<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>> |
| |
| <<span class="hl-tag">parent</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.parent<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>2.3.0.RELEASE<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">relativePath</span>>../parent<<span class="hl-tag">/relativePath</span>> |
| <<span class="hl-tag">/parent</span>> |
| |
| <<span class="hl-tag">modelVersion</span>>4.0.0<<span class="hl-tag">/modelVersion</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.db<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">name</span>>greenpages.db<<span class="hl-tag">/name</span>> |
| <<span class="hl-tag">packaging</span>>jar<<span class="hl-tag">/packaging</span>> |
| |
| <<span class="hl-tag">dependencies</span>> |
| <<span class="hl-tag">/dependencies</span>> |
| |
| <<span class="hl-tag">/project</span>> |
| </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> → <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…</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’s main rô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’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’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> → <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"> <<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> /> |
| </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’s pom file. Open the pom file for <code class="literal">greenpages.db</code> and add |
| the following dependency between the <code class="literal"><dependencies></code> tags: |
| </p><pre class="programlisting"> <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>org.apache.commons<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>com.springsource.org.apache.commons.dbcp<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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> → <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"> <<span class="hl-comment">!-- |
| export the dataSource bean to the OSGi service registry under the |
| DataSource interface |
| --</span>> |
| <<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> /> |
| </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’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’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 “<span class="quote">Bundle Actions</span>” 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’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’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…</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’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 “Starting and configuring the database”</a> |
| in <a class="xref" href="#installing.greenpages" title="3. Installing and exploring GreenPages">Chapter 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 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’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"> <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>javax.persistence<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>com.springsource.javax.persistence<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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<Listing> 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"> <<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>> |
| <<span class="hl-tag">context:load-time-weaver</span> <span class="hl-attribute">aspectj-weaving</span>=<span class="hl-value">"on"</span> /> |
| |
| <<span class="hl-comment">!-- JPA EntityManagerFactory --</span>> |
| <<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>> |
| <<span class="hl-tag">property</span> <span class="hl-attribute">name</span>=<span class="hl-value">"jpaVendorAdapter"</span>> |
| <<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> /> |
| <<span class="hl-tag">/property</span>> |
| <<span class="hl-tag">/bean</span>> |
| |
| <<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>> |
| <<span class="hl-tag">context:annotation-config</span> /> |
| |
| <<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> /> |
| </pre><p> |
| </p><p> |
| The addition of the new beans to the context has introduced a new dependency upon Spring’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"> <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>org.springframework<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>org.springframework.spring-library<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">type</span>>libd<<span class="hl-tag">/type</span>> |
| <<span class="hl-tag">/dependency</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>org.eclipse.persistence<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>com.springsource.org.eclipse.persistence<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">/dependency</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>org.eclipse.persistence<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>com.springsource.org.eclipse.persistence.jpa<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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’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"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8" ?</span>> |
| <<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>> |
| |
| <<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>> |
| <<span class="hl-tag">class</span>>greenpages.jpa.JpaListing<<span class="hl-tag">/class</span>> |
| <<span class="hl-tag">/persistence-unit</span>> |
| |
| <<span class="hl-tag">/persistence</span>> |
| </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"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8" ?</span>> |
| <<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>> |
| <<span class="hl-tag">package</span>>greenpages.jpa<<span class="hl-tag">/package</span>> |
| <<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>> |
| <<span class="hl-tag">table</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LISTING"</span> /> |
| <<span class="hl-tag">attributes</span>> |
| <<span class="hl-tag">id</span> <span class="hl-attribute">name</span>=<span class="hl-value">"listingNumber"</span>> |
| <<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LISTING_NUMBER"</span> /> |
| <<span class="hl-tag">generated-value</span> <span class="hl-attribute">strategy</span>=<span class="hl-value">"TABLE"</span> /> |
| <<span class="hl-tag">/id</span>> |
| <<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"firstName"</span>> |
| <<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"FIRST_NAME"</span> /> |
| <<span class="hl-tag">/basic</span>> |
| <<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"lastName"</span>> |
| <<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"LAST_NAME"</span> /> |
| <<span class="hl-tag">/basic</span>> |
| <<span class="hl-tag">basic</span> <span class="hl-attribute">name</span>=<span class="hl-value">"emailAddress"</span>> |
| <<span class="hl-tag">column</span> <span class="hl-attribute">name</span>=<span class="hl-value">"EMAIL_ADDRESS"</span> /> |
| <<span class="hl-tag">/basic</span>> |
| <<span class="hl-tag">/attributes</span>> |
| <<span class="hl-tag">/entity</span>> |
| <<span class="hl-tag">/entity-mappings</span>> |
| </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"> <<span class="hl-comment">!-- import the DataSource from OSGi --</span>> |
| <<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> /> |
| </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’ |
| Web module it must be “<span class="quote">published</span>” 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"> <<span class="hl-comment">!-- export the directory bean to OSGi under the Directory interface --</span>> |
| <<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> /> |
| </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’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…</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’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 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"><!-- <osgi:service interface="greenpages.Directory" ref="directory"/> --> |
| </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’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 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’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’s <code class="literal">EntityManager</code>: |
| </p><pre class="programlisting"> <<span class="hl-comment">!-- |
| Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) |
| --</span>> |
| <<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> /> |
| </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"> <<span class="hl-comment">!-- |
| Instruct Spring to perform declarative transaction management |
| automatically on annotated classes. |
| --</span>> |
| <<span class="hl-tag">tx:annotation-driven</span> <span class="hl-attribute">mode</span>=<span class="hl-value">"aspectj"</span> /> |
| </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 { |
| … |
| </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’s exception |
| model. Spring provides support for automatically translating these exceptions into Spring’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"> <<span class="hl-comment">!-- |
| Post-processor to perform exception translation on @Repository classes |
| (from native exceptions such as JPA PersistenceExceptions to |
| Spring&rsquo;s DataAccessException hierarchy). |
| --</span>> |
| <<span class="hl-tag">bean</span> <span class="hl-attribute">class</span>=<span class="hl-value">"org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"</span> /> |
| </pre><p> |
| </p><p> |
| Save the updated file. The translation will only occur on classes that are annotated with |
| Spring’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"><SPDE0100E> 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]': |
| … |
| </pre><p> |
| which indicates that there is some package (<code class="code">org.springframework.dao.annotation</code>) which is not |
| available to the “<span class="quote"><code class="code">BundleClassLoader</code></span>” 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 “<span class="quote">any version</span>” is used. |
| Whilst this is very flexible it’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’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 “<span class="quote">any</span>” 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 “<span class="quote">best practice</span>” |
| 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. 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 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 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 { |
| … |
| </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…</em></span>. In the the dialog that opens select |
| <span class="guimenu">JUnit</span> → <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 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 |
| “<span class="quote">in-process</span>” 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"> <<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> /> |
| |
| <<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>> |
| <<span class="hl-tag">constructor-arg</span> <span class="hl-attribute">ref</span>=<span class="hl-value">"dataSource"</span> /> |
| <<span class="hl-tag">constructor-arg</span> <span class="hl-attribute">value</span>=<span class="hl-value">"file:../../db/db.sql"</span> /> |
| <<span class="hl-tag">/bean</span>> |
| </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 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"> <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.jpa<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">scope</span>>test<<span class="hl-tag">/scope</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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 { |
| … |
| </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…</em></span>. |
| In the the dialog that opens select |
| <span class="guimenu">JUnit</span> → <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. 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 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’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 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] <SB0001W>: The import of package javax.sql does not specify a version. |
| [WARNING] <SB0001W>: 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 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"><<span class="hl-tag">?xml version="1.0" encoding="UTF-8"?</span>> |
| <<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>> |
| |
| <<span class="hl-tag">parent</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.parent<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>2.3.0.RELEASE<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">relativePath</span>>../parent<<span class="hl-tag">/relativePath</span>> |
| <<span class="hl-tag">/parent</span>> |
| |
| <<span class="hl-tag">modelVersion</span>>4.0.0<<span class="hl-tag">/modelVersion</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">name</span>>GreenPages PAR<<span class="hl-tag">/name</span>> |
| <<span class="hl-tag">packaging</span>>par<<span class="hl-tag">/packaging</span>> |
| |
| <<span class="hl-tag">dependencies</span>> |
| <<span class="hl-tag">/dependencies</span>> |
| |
| <<span class="hl-tag">build</span>> |
| <<span class="hl-tag">plugins</span>> |
| <<span class="hl-tag">/plugins</span>> |
| <<span class="hl-tag">/build</span>> |
| |
| <<span class="hl-tag">/project</span>> |
| </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 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 Documentation">Section A.2, “Documentation”</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"><build><plugins>…</plugins></build></code> section, add a plugin declaration for the |
| <code class="literal">par</code> plugin. |
| </p><pre class="programlisting"><<span class="hl-tag">plugin</span>> |
| <<span class="hl-tag">groupId</span>>org.apache.maven.plugins<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>maven-par-plugin<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>1.0.0.RELEASE<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">configuration</span>> |
| <<span class="hl-tag">applicationSymbolicName</span>>greenpages<<span class="hl-tag">/applicationSymbolicName</span>> |
| <<span class="hl-tag">applicationDescription</span>>GreenPages<<span class="hl-tag">/applicationDescription</span>> |
| <<span class="hl-tag">/configuration</span>> |
| <<span class="hl-tag">/plugin</span>> |
| </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"><<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.app<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">/dependency</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.jpa<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">/dependency</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.db<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">/dependency</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>com.springsource.dmserver<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>greenpages.web<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>${project.version}<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">type</span>>war<<span class="hl-tag">/type</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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 '…/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 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"><build><plugins>…</plugins></build></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"><<span class="hl-tag">plugin</span>> |
| <<span class="hl-tag">groupId</span>>org.apache.maven.plugins<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>maven-dependency-plugin<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">executions</span>> |
| <<span class="hl-tag">execution</span>> |
| <<span class="hl-tag">id</span>>copy-dependencies<<span class="hl-tag">/id</span>> |
| <<span class="hl-tag">phase</span>>package<<span class="hl-tag">/phase</span>> |
| <<span class="hl-tag">goals</span>> |
| <<span class="hl-tag">goal</span>>copy-dependencies<<span class="hl-tag">/goal</span>> |
| <<span class="hl-tag">/goals</span>> |
| <<span class="hl-tag">configuration</span>> |
| <<span class="hl-tag">outputDirectory</span>>${project.build.directory}/par-provided<<span class="hl-tag">/outputDirectory</span>> |
| <<span class="hl-tag">overWriteIfNewer</span>>true<<span class="hl-tag">/overWriteIfNewer</span>> |
| <<span class="hl-tag">excludeGroupIds</span>>com.springsource.dmserver,org.apache.log4j<<span class="hl-tag">/excludeGroupIds</span>> |
| <<span class="hl-tag">/configuration</span>> |
| <<span class="hl-tag">/execution</span>> |
| <<span class="hl-tag">/executions</span>> |
| <<span class="hl-tag">/plugin</span>> |
| </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 ‘war’ project does not pass on its dependencies; |
| it expects |
| them to be contained in its ‘lib’ directory. |
| For this reason its dependencies must be given explicitly. |
| </p><pre class="programlisting"><<span class="hl-comment">!-- Required for the web bundle as dependencies are not propagated up from war build types --</span>> |
| <<span class="hl-tag">dependency</span>> |
| <<span class="hl-tag">groupId</span>>org.freemarker<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>com.springsource.freemarker<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">scope</span>>provided<<span class="hl-tag">/scope</span>> |
| <<span class="hl-tag">/dependency</span>> |
| </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"><<span class="hl-tag">build</span>> |
| <<span class="hl-tag">plugins</span>> |
| <<span class="hl-tag">plugin</span>> |
| <<span class="hl-tag">artifactId</span>>maven-war-plugin<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">version</span>>2.1-beta-1<<span class="hl-tag">/version</span>> |
| <<span class="hl-tag">configuration</span>> |
| <<span class="hl-tag">packagingExcludes</span>>WEB-INF/lib/**<<span class="hl-tag">/packagingExcludes</span>> |
| <<span class="hl-tag">/configuration</span>> |
| <<span class="hl-tag">/plugin</span>> |
| <<span class="hl-tag">/plugins</span>> |
| <<span class="hl-tag">/build</span>></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’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 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"><<span class="hl-tag">plugin</span>> |
| <<span class="hl-tag">groupId</span>>org.apache.maven.plugins<<span class="hl-tag">/groupId</span>> |
| <<span class="hl-tag">artifactId</span>>maven-surefire-plugin<<span class="hl-tag">/artifactId</span>> |
| <<span class="hl-tag">configuration</span>> |
| <<span class="hl-tag">includes</span>> |
| <<span class="hl-tag">include</span>>**/*Tests.java<<span class="hl-tag">/include</span>> |
| <<span class="hl-tag">/includes</span>> |
| <<span class="hl-tag">excludes</span>> |
| <<span class="hl-tag">exclude</span>>**/Abstract*.java<<span class="hl-tag">/exclude</span>> |
| <<span class="hl-tag">/excludes</span>> |
| <<span class="hl-tag">junitArtifactName</span>>org.junit:com.springsource.org.junit<<span class="hl-tag">/junitArtifactName</span>> |
| <<span class="hl-tag">argLine</span>>-javaagent:${user.home}/.m2/repository/org/springframework/org.springframework.instrument/3.0.0.M3/org.springframework.instrument-3.0.0.M3.jar<<span class="hl-tag">/argLine</span>> |
| <<span class="hl-tag">/configuration</span>> |
| <<span class="hl-tag">/plugin</span>></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 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"><DE0005I> 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 A. 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 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>) — homepage for Virgo.</p></li><li><p>SpringSource.org |
| (<a class="ulink" href="http://www.springsource.org" target="_top">http://www.springsource.org</a>) — homepage for Spring Framework.</p></li><li><p>OSGi |
| (<a class="ulink" href="http://www.osgi.org" target="_top">http://www.osgi.org</a>) — homepage for OSGi.</p></li><li><p>H2 Database |
| (<a class="ulink" href="http://www.h2database.com" target="_top">http://www.h2database.com</a> — 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>) — 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>) — 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>) — 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>) — 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 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>) – 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> |