Now on to the upgrade
Once we swapped out the underlying libraries, the only things breaking seemed to be some smaller issues such as annotations but nothing major. After some re-working of the META-INF/persistence.xml file and the spring declarations for the Entity Manager Factory and related classes, things looked okay. And once I updated the path from
-javaagent:/<PATH>/openjpa-1.2.2.jar
to
-javaagent:/<PATH>/openjpa-2.0.1.jar
our test cases ran perfectly inside of IntelliJ.
Since I don't get paid to just build running test cases, I had to get this up and running in Tomcat.
Enhancing OpenJPA 2 Entities in Tomcat
This proved to be a lot more difficult. In order to get the javaagent working, I added the open openjpa-2.0.1.jar to the /lib directory of the tomcat installation and updated our catalina.bat (yes this was on Windows) file to include the line
set JAVA_OPTS=%JAVA_OPTS% -javaagent:"%CATALINA_HOME%\lib\openjpa-2.0.1.jar"
This enables Runtime Enhancement for the OpenJPA2 Entities in our persistence.xml file. On startup I got a host of NoClassDefinedErrors and using maven, IntelliJ and Google realized I needed to add the following files into my tomcat /lib folder
commons-lang-2.4.jar
geronimo-jpa_2.0_spec-1.1.jar
geronimo-jta_1.1_spec-1.1.1.jar
serp-1.13.1.jar
log4j-1.2.14.jar
commons-collections-3.2.jar
And update the catalina.bat file again with:
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\commons-lang-2.4.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\geronimo-jpa_2.0_spec-1.1.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\geronimo-jta_1.1_spec-1.1.1.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\serp-1.13.1.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\log4j-1.2.14.jar
set CLASSPATH=%CLASSPATH%;%CATALINA_HOME%\lib\commons-collections-3.2.jar
The app started up, however the JPA entities weren't being enhanced at load time. OpenJPA essentially doesn't support unenhanced entites, so any attempt to access them failed.
Enabling Load Time Weaving
After a lot of digging without results, I decided to track down an error I saw in startup that hadn’t prevented OpenJPA 1 from working:
Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
I initially dismissed this error as it is caught and ignored by OpenJPA and doesn't prevent my test cases from running properly. Unfortunately, OpenJPA2 requires load time weaving to be enabled for it to work in an application server. I still haven’t found where this is documented outside of Spring’s ORM documentation but using that as a guide I went into my tomcat /conf/context.xml and added
<Loader loaderClass="org.springframework.instrument.
classloading.tomcat.TomcatInstrumentableClassLoader"/>
and moved the spring-instrument-tomcat-3.0.5.RELEASE.jar file into my tomcat /lib directory. This step adds a second ClassLoader to your Tomcat installation since the default Tomcat ClassLoader doesn’t support runtime proxying the way Spring and OpenJPA require.
With that, it all seemed to work... until we started our automated build process using Maven 3 and Junit 4.7 test cases.
Running OpenJPA 2 JUnit Tests in Maven 3
Tests were failing with the Runtime Enhancement errors we saw above. I edited the pom.xml file and updated the maven-surefire-plugin configuration to include
<argLine>-javaagent:"${user.home}/.m2/repository/org/apache/openjpa/openjpa/2.0.1/openjpa-2.0.1.jar"</argLine>
I re-ran our build and it failed, and with the LoadTimeWeaver issue. The solution to that is to use the Spring Agent jar as a javaagent. Thankfully, you can chain as many javaagents as you want onto the command line so I updated the argLine tag to
<argLine>-javaagent:"${user.home}/.m2/repository/org/springframework/spring-agent/2.5.6/spring-agent-2.5.6.jar" -javaagent:"${user.home}/.m2/repository/org/apache/openjpa/openjpa/2.0.1/openjpa-2.0.1.jar"</argLine>
and it ran fine locally.
Moving it to the Build Server
When I finally committed all of these changes, our build server kicked off a build… and it failed. Since the spring-agent-2.5.6.jar and openjpa-2.0.1.jar aren’t used in the application, they weren’t included in the pom.xml file and subsequently didn’t exist on the build server. To fix this I added
<dependency>
<groupId>org.apache.openjpa</groupId>
<artifactId>openjpa</artifactId>
<version>2.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-agent</artifactId>
<version>2.5.6</version>
<scope>test</scope>
</dependency>
to my pom.xml and everything worked perfectly. Now all I have to do is actually write the application that uses it.