5.5 Applying best practices to the middle tier
Prev | 5. The Middle Tier | Next

## 5.5 Applying best practices to the middle tier

While the application middle tier now works as required, it does not observe a few Spring-related best practices.

### Using transactions

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.

Open `module-context.xml` in the `META-INF/spring` folder of `greenpages.jpa`. Add the following bean definition to create a transaction manager and associate it with the context’s `EntityManager`:

        <!--
            Transaction manager for a single JPA EntityManagerFactory (alternative to JTA)
        -->
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
            p:entityManagerFactory-ref="entityManagerFactory" />

(Save it, and the `greenpages.jpa` module will be refreshed.)

Next, Spring must be told to enable transaction management. In keeping with the use of annotation-based configuration for the `EntityManager`, annotation-based transaction configuration will also be used. Add the following to enable AspectJ-powered transaction demarcation for appropriately annotated beans:

        <!--
            Instruct Spring to perform declarative transaction management
            automatically on annotated classes.
        -->
        <tx:annotation-driven mode="aspectj" />

Save the updated file which will trigger (another) successful refresh of `greenpages.jpa`.

Lastly, `JpaDirectory` needs to be annotated so that it is identified as requiring Spring-based transaction management. Open `JpaDirectory.java` in `greenpages.jpa`. Annotate the class with `@Transactional` and add an import for `org.springframework.transaction.annotation.Transactional`, which Eclipse should suggest:

    import org.springframework.transaction.annotation.Transactional;

    @Transactional
    final class JpaDirectory implements Directory {
    …

Save the updated file triggering another successful refresh: `JpaDirectory` is now transactional.

### Enabling exception translation

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 `DataAccessException` hierarchy.

Open `module-context.xml` for `greenpages.jpa` again and add the following bean definition to add the exception translator to the application context:

        <!--
            Post-processor to perform exception translation on @Repository classes
            (from native exceptions such as JPA PersistenceExceptions to
            Spring&rsquo;s DataAccessException hierarchy).
        -->
        <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

Save the updated file. The translation will only occur on classes that are annotated with Spring’s `@Repository` stereotype annotation. `JpaDirectory` needs to have this annotation added to it complete the enabling of the exception translation.

Open `JpaDirectory.java` again, annotate the class with `@Repository` and add an import for `org.springframework.stereotype.Repository`:

    import org.springframework.stereotype.Repository;

    @Transactional
    @Repository
    final class JpaDirectory implements Directory {

Save the updated file.

At this point the redeploy of the GreenPages application may fail with an error similar to this:

    <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]':
    …

which indicates that there is some package (`org.springframework.dao.annotation`) which is not available to the “`BundleClassLoader`” for bundle `greenpages-1-greenpages.jpa_2.3.0`. We should look in the `MANIFEST.MF` file for this bundle, and see that this package is not imported (in the `Import-Package` header). Since Bundlor generated this file (controlled by the template file `template.mf`) we should check that the manifest was re-generated on our last change.

Open `template.mf` in `greenpages.jpa` and, in the Overview pane, click on Update MANIFEST.MF in the Bundle Actions section. The `MANIFEST.MF` file is updated, and the application is redeployed, this time successfully. It might be worthwhile checking the option Automatically update MANIFEST.MF in the background on the `template.mf` Overview pane so that the `MANIFEST.MF` is kept up to date as the project is changed.

### Versioning imports

By default, Bundlor generates `Import-Package` entries with no version range specified. In the absence of a version range, the OSGi default of “any version” 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.

Open `template.mf` for `greenpages.jpa` and add the following `Import-Template` header:

    Import-Template: org.springframework.*;version="[3.0,3.1)",
     greenpages;version="[2.0,2.1)",
     javax.persistence;version="[1.0.0,1.0.0]"

If there is already an `Import-Template` header in the template, extend it to include the above package version range specifications.

This header tells Bundlor that all imports of `org.springframework` packages should be in the range `3.0` inclusive to `3.1` exclusive, that an import of the `greenpages` package should be in the range `2.0` inclusive to `2.1` exclusive, and that an import of `javax.persistence` should be at exactly version `1.0.0`.

Bundlor has also generated an import for the `javax.sql` package due to the `greenpages.jpa` module’s use of `javax.sql.DataSource`. 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 precisely what is required then add the following to the `Import-Template` header:

    ,javax.sql;version="[0,0]"

but if “any” version is acceptable add the following instead:

    ,javax.sql;version="0"

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.

### Congratulations!

The GreenPages middle tier is now complete and observes some “best practice” development with Spring and OSGi.

Prev | Up | Next
5.4 Trying out the JPA middle tier | Home | 6. Testing GreenPages