h1

AOP and Compile-Time Weaving with Maven, Eclipse, and Spring 2.5

11/08/2010

It’s easy to become accustomed to Spring’s aspect-oriented magic, particularly dependency injection and transaction management. Should this method execute inside a transaction? Just add the @Transactional annotation and you’re done! You need that service there in the code? Just tell Spring to autowire it in with the @Autowire annotation!

The release of Java EE 6 has given the subject extra momentum with its @Inject and @TransactionAttribute annotations, effectively standardizing what was common practice anyway. (Note: These annotations are supported from Spring 3.0, which I’m not using yet because the latest Hibernate release is not fully compatible with it yet.)

Great, isn’t it? Well, unless you need those capabilities in objects that are not instantiated through Spring, like entity classes (instantiated by your JPA provider) or other objects instantiated somewhere by a framework you’re using. There, you need code weaving to make things work.

Code weaving comes in two flavors:

  • Load-time weaving: Aspect weaving is performed by the class loader when classes are first loaded.
  • Compile-time weaving: Aspects are weaved into the class files when they are compiled.

While at first load-time weaving sounds like a reasonable approach, in reality you will have to replace the class loader by including a special JAR file on the command line or by adding it to your servlet container and changing its class loader configuration. This makes execution environments hard to set up.

There’s very good tool support for compile-time weaving available for Maven and Eclipse, and it’s not so hard to set up. Once you have your build set up, you no longer need to worry about what is weaved when, things will just work. (With one caveat that I’ll discuss later.)

Assuming you already have Maven support installed in Eclipse, this is what you need:

In Eclipse

Install the AspectJ Developer Tools Plugin (AJDT).

In your pom.xml:

Add the Spring-Aspects and AspectJ dependencies:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-aspects</artifactId>
	<version>2.5.6</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjrt</artifactId>
	<version>1.6.7</version>
</dependency>

Configure the AspectJ plugin:

  <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>aspectj-maven-plugin</artifactId>
     <version>1.3</version>
     <configuration>
        <complianceLevel>1.6</complianceLevel>
        <encoding>UTF-8</encoding>
        <aspectLibraries>
           <aspectLibrary>
              <groupId>org.springframework</groupId>
              <artifactId>spring-aspects</artifactId>
           </aspectLibrary>
        </aspectLibraries>
     </configuration>
     <executions>
        <execution>
           <goals>
              <goal>compile</goal>
              <goal>test-compile</goal>
           </goals>
        </execution>
     </executions>
  </plugin>

Also configure the Eclipse plugin to configure the project to use the AJDT compiler:

<plugin>
	<artifactId>maven-eclipse-plugin</artifactId>
	<version>2.8</version>
	<configuration>
		<ajdtVersion>1.5</ajdtVersion>
	</configuration>
</plugin>

In your Spring context configuration:

<context:spring-configured />
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"
		mode="aspectj" />

These tags enable the use of, amongst others, the @Autowire, @Configurable, @Transactional and @PersistenceContext annotations in objects that may or not be managed by Spring.

For example, if you need access to a service and the entity manager inside an entity, that could look like this:

@Entity
@Table(name = "formatsettings_append_packet")
@Configurable(autowire = Autowire.BY_TYPE)
public class PacketAppendFormatSettings extends AbstractFormatSettings {

	@Transient
	private transient MyService myService;

	@PersistenceContext
	private transient EntityManager entityManager;

	public void myAction() {
		this.entityManager.find(...);
		this.myService.someMethod(...);
	}

	/*
	 * Setters for depenencies
	 */
	public void setMyService(MyService myService) {
		this.myService = myService;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}
}

Generally, AJDT and Maven work together quite well. The only caveat is that sometimes, Eclipse and AJDT forget to compile an aspect into one of your classes, and your code or test code fails with a NullPointerException. Cleaning and recompiling the project always fixes the problem, and because you use Maven to create builds, you will never miss any aspects when you create a JAR or WAR file for deployment.

h1

Prototype JS: Prevening the Default Action Without Stopping other Event Handlers

26/04/2010

When re-using web components in Tapestry 5, I sometimes end up having multiple client-side classes observing the same events on the same objects. For example, I have a button in a modal dialog that requires two event listeners: One dismisses the modal dialog (this is written as a Tapestry Mixin to a button or link), and one that executes custom client-side code specific to the dialog. For things to work, they must both execute, but the default action (e.g. following a link or submitting a form) must not take place.

Now here’s the problem I had until a few minutes ago: In Prototype, I thougt the Event.stop() method was the only option — however, it does not only stop the default behaviour, but, as its name suggests, immediately stops the propagation of the event. If you have two event listeners bound to the same event type and they both call Event.stop(), only one of the event listeners will execute.

I just accidently (while debugging some JS) found out that there is a standard way to prevent the default behaviour only without stopping the event altogether. It’s called Event.preventDefault(), and it is not mentioned in the API docs because it’s a standard method. (Note: IE does not support preventDefault(), but Prototype emulates it for IE).

Now I call Event.preventDefault() and see all my event listeners execute happily.

h1

Custom Isolation Levels with JTA and Spring

15/12/2009

My current project involves multiple databases — MySQL and MS SQL Server. From the point of view of the application that I work on, there is one central MS SQL database, one additional MS SQL database for jBPM (the workflow/service orchestration framework we’re using), and a number of auxilliary databases interfacing with different component of the system, some of which run on MS SQL, some on MySQL.

The obvious choice for transaction management in such a setup is to use JTA. As the application is supposed to be deployed on a Tomcat 6 application server, and as I like to use Jetty during development, both of which do not come with a transaction manager, a JTA transaction manager had to be found. After a lot of experimenting, and after a lot of trouble with JOTM (which did not seem to rollback, ever) and Atomikos (which had problems with some of the XA datasources), I settled for the Bitronix Transaction Manager (BTM) because it was reasonably simple to set up and just worked.

MS SQL server needs a little tweaking to support XA transactions, but after that has been set up, they work as expected.

Using MS SQL server with some rather long-running transactions revealed a peculiar side of MS SQL server: By default, updates work through row locks, meaning that long transactions writing to the database block simultanious reads of the table (for display in a list, in our case), until they are committed. As we perform large inserts on multiple databases, we also have very long transactions, resulting in an unusable UI. I don’t know why this is the default setting for MS SQL, as most other databases (Oracle, MySQL/InnoDB) support concurrent read/write IO with such an ease that you rarely have to worry about locking issues.

Anyway, MS SQL has a per-schema switch to enable non-locking concurrency via row versioning: READ_COMMITTED_SNAPSHOT. I tried it, and it removed the locking instantly. However, it is either not implemented well in SQL Server 2008, or does not play with XA transactions: There is a time after a transaction is committed (i.e. the COMMIT command has executed) where subsequent reads from the database will result in stale data! When a lot of writing is done during a transaction, the timespan can be multiple seconds. This resulted in unexpected behaviour in our workflows, and we had to abandon READ_COMMITTED_SNAPSHOT.

Another option to ensure non-blocking reads is changing the isolation level to READ_UNCOMMITTED, which is acceptable for our UI. The problem is that JTA does not support setting custom isolation levels for individual transactions: You have to rely on proprietary features of the transaction manager to have access to such functionality. Spring has a couple of custom JtaTransactionManager implementations for various JTA implementations. BTM, however, does not have this feature.

The standards-compliant workaround is to set the isolation level directly on the JDBC connection. Luckily, the Spring framework has a couple of helper classes that do just that:

With that set up, custom isoltation levels work like a charm — using only standard JTA and JDBC.

The other, perfectly viable workaround is to use any other RDBMS than MS SQL. This is my first project where MS SQL holds the main database, and I can’t say I’m impressed.

Below are the relevant bits of the configuration to make this work.

This is the BTM configuration in jetty-env.xml:

<Call name="getConfiguration" class="bitronix.tm.TransactionManagerServices">
  <Set name="defaultTransactionTimeout">900</Set>
  <Set name="logPart1Filename">./target/work/btm1.tlog</Set>
  <Set name="logPart2Filename">./target/work/btm2.tlog</Set>
</Call>

<New class="org.mortbay.jetty.plus.naming.Resource">
  <Arg>javax.transaction.TransactionManager</Arg>
  <Arg>
    <Call name="getTransactionManager" class="bitronix.tm.TransactionManagerServices" />
  </Arg>
</New>

<New class="org.mortbay.jetty.plus.naming.Transaction">
  <Arg>
    <Call name="getTransactionManager" class="bitronix.tm.TransactionManagerServices" />
  </Arg>
</New>

<New id="obamaDatasource" class="org.mortbay.jetty.plus.naming.Resource">
  <Arg>
    <Ref id="wac" />
  </Arg>
  <Arg>jdbc/obamaDatasource</Arg>
  <Arg>
     <New class="bitronix.tm.resource.jdbc.PoolingDataSource">
      <Set name="className">com.microsoft.sqlserver.jdbc.SQLServerXADataSource</Set>
      <Set name="uniqueName">ds</Set>
      <Set name="allowLocalTransactions">true</Set>
      <Set name="minPoolSize">0</Set>
      <Set name="maxPoolSize">10</Set>
      <Get name="driverProperties">
        <Put name="URL">jdbc:sqlserver://xxxx;DatabaseName=yyyy</Put>
        <Put name="user">username</Put>
        <Put name="password">password</Put>
      </Get>
      <Call name="init" />
    </New>
  </Arg>
</New>

The relevant bits from web.xml:

<resource-ref>
  <description>UserTransaction</description>
  <res-ref-name>UserTransaction</res-ref-name>
  <res-type>javax.transaction.UserTransaction</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
  <description>TransactionManager</description>
  <res-ref-name>javax.transaction.TransactionManager</res-ref-name>
  <res-type>javax.transaction.TransactionManager</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

<resource-ref>
  <description>Obama DataSource</description>
  <res-ref-name>jdbc/obamaDatasource</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

And the relevant sections from the Spring configuration:

<!-- JTA transaction manager -->
<bean id="jtaTransactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="resourceRef" value="true" />
  <property name="jndiName" value="javax.transaction.TransactionManager" />
  <property name="expectedType" value="javax.transaction.TransactionManager" />
</bean>
<bean id="userTransaction" class="org.springframework.jndi.JndiObjectFactoryBean">
  <property name="resourceRef" value="true" />
  <property name="jndiName" value="UserTransaction" />
  <property name="expectedType" value="javax.transaction.UserTransaction" />
</bean>

<!-- Data source from the container via JNDI -->
<bean id="dataSource"
  class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc/obamaDatasource" />
  <property name="resourceRef" value="true" />
  <property name="expectedType" value="javax.sql.DataSource" />
</bean>

<!-- Transaction management -->
<bean id="transactionManager"
  class="org.springframework.transaction.jta.JtaTransactionManager">
  <property name="transactionManager" ref="jtaTransactionManager" />
  <property name="userTransaction" ref="userTransaction" />
  <property name="allowCustomIsolationLevels" value="true"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"
  mode="aspectj" />

<!--
JPA Entity manager configuration through Spring. See

http://static.springframework.org/spring/docs/2.5.x/reference/orm.html#orm-jpa-setup.

-->
<bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource">
    <!-- Workaround to allow custom isolation levels -->
    <bean class="org.springframework.jdbc.datasource.lookup.IsolationLevelDataSourceRouter" >
      <property name="defaultTargetDataSource" ref="dataSource" />
      <property name="targetDataSources">
        <map>
          <entry key="ISOLATION_READ_UNCOMMITTED">
            <bean class="org.springframework.jdbc.datasource.IsolationLevelDataSourceAdapter">
              <property name="targetDataSource" ref="dataSource" />
              <property name="isolationLevelName" value="ISOLATION_READ_UNCOMMITTED" />
            </bean>
          </entry>
        </map>
      </property>
    </bean>
  </property>
  <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
      <property name="showSql" value="false" />
      <property name="generateDdl" value="true" />
    </bean>
  </property>
  <property name="persistenceUnitName" value="My_PU" />
</bean>
h1

API design mistakes will haunt you forever

09/11/2009

The class org.apache.commons.net.ftp.FTPClient from the Apache Commons Net library is a good example of the use of inheritance where composition would have been more suitable.

The class builds on the low-level FTP support provided by its superclass, org.apache.commons.net.ftp.FTP. Its mission, as stated in the Javadocs, reads:

This class takes care of all low level details of interacting with an FTP server and provides a convenient higher level interface.

While that is certainly true, the use of inheritance makes the abstraction very leaky and confusing. When you autocomplete on an FTPClient object in your IDE, you will barely see all the methods starting with an “a”, because all the low-level FTP methods are also included, plus the socket-layer level methods inherited from org.apache.commons.net.SocketClient.

This is a classic mistake, probably resulting from coders loving inheritance trees a little too much in the 1990s, before discovering that inheritance makes sense only for “is-a” relationships, while “uses-a” or “has-a” relationships are much more adequately expressed through composition.

If you’re designing a library or framework for others to use, keep in mind that you will never ever be able to change anything that you have exposed as part of the public API. This is also the reason why many of Javas APIs seem a little dusty today: java.sql got the exception model totally wrong, and Java’s date support was designed before the benefits of immutability were widely accepted. Now, there is no way out without breaking everybody’s code.

This, obviously, also applies to some of the older Apache Commons libraries. The only thing you can do is provide a new, improved library, and wait until the old one falls into oblivion.

h1

Integration Testing with Spring and Maven

08/11/2009

Thanks to a Stack Overflow question, I recently stumbled over Spring’s integration test support (documentation here). In short, it provides a Spring context of your choice to your jUnit or TestNG classes and adds support for the @Transactional annotation.

However, contrary to the usual behaviour – comitting a transaction if no exception occurred, every transaction is instead rolled back by default, leaving the database unchanged.

All you have to do is to tell JUnit to use Spring’s test runner class, tell Spring which context files to load, and add the @Transactional annotation to your class or test methods.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/integrationTestContext.xml"})
@Transactional
public class MyIntegrationTest {

    @Test
    public void myTestMethod() {
        ...
    }

}

This is a rather elegant way of using the IoC pattern for integration testing. It even recycles the Spring container, should you use the same configuration in multiple test cases and/or classes.

However, if you also use Maven, you will have noticed that its opinion on integration testing seems to be “we’re not really doing that here”. While there is a “integration-test” phase, there is no distinct place to keep integration tests. While it seems that maybe, some day, there will be support for a “src/it/java” source folder to hold integration test classes, as of now we have some configuration work to do to run unit and integration tests separately.

In our pom.xml, we re-configure the Maven Surefire plugin as follows:

<plugin>
     <artifactId>maven-surefire-plugin</artifactId>
     <configuration>
         <excludes>
             <exclude>**/itest/**</exclude>
         </excludes>
     </configuration>
     <executions>
         <execution>
              <id>surefire-itest</id>
              <phase>integration-test</phase>
              <goals>
                   <goal>test</goal>
              </goals>
              <configuration>
                   <excludes>
                       <exclude>none</exclude>
                   </excludes>
                   <includes>
                       <include>**/itest/**</include>
                   </includes>
              </configuration>
          </execution>
    </executions>
</plugin>

The ugly bit here is that we’re forced to keep the integration tests in the same source folder as the unit tests, namely “src/test”. In this example, we exclude tests that have “itest” somewhere in their package name from unit testing, and bind the surefire plugin to the “integration-test” phase, running only tests with “itest” in their package name. I went for putting all integration tests into a root ”/itest” package, which makes them easy to tell apart, and run separately, from the unit tests.

With this layout, your test classes would, as previously, reside within the same package as the classes that they test, e.g. “my.package.MyClassTest”, while integration tests reside in their own package, e.g. “itest.my.package.MyClassIntegrationTest”.

We have now established a working distinction between fast-running unit tests and slower integration tests requiring a Spring container, and possibly additional resources. Certainly not ideal, but doable.

Follow

Get every new post delivered to your Inbox.