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.0.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.0.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]"

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.