tag:blogger.com,1999:blog-9847594041115082972024-03-16T07:40:07.848-05:00WebSphere and Java PersistenceWith the recent introduction of the Java Persistence API (JPA), WebSphere is forging new trails with their JPA solution. Built on top of the <a href="http://openjpa.apache.org/">Apache OpenJPA</a>
project, the WebSphere JPA solution provides exceptional function, performance, and support. The postings on this site are our own and don’t necessarily represent IBM’s positions, strategies, or opinions.Kevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-984759404111508297.post-61695430927212403942013-04-03T16:53:00.001-05:002013-04-03T16:53:43.171-05:00Monitoring OpenJPA's Caches on the WebSphere Liberty ProfileOpenJPA provides several types of caches that can be used to improve the performance of many applications. Several of OpenJPA's caches collect statistics such as number of entries, hit count, and object type. These attributes can be helpful for monitoring the effectiveness of the cache. Analysis of these statistics can help you to make decisions about what to cache, how many objects to cache, or even whether to enable caching at all. An effective caching scheme can produce significant performance benefits, while an ineffective scheme may be a drag on performance and almost certainly increase the memory requirements of the application. A little tuning can normally go a long way.<br />
<br />
Initally, accessing OpenJPA's cache statistics required adding custom Java code to your application. You were required to call OpenJPA APIs to navigate through the configuration, get access to the caches, and then access their statistics. As of <a href="https://issues.apache.org/jira/browse/OPENJPA-1739">OPENJPA-1739</a> (OpenJPA 2.1), these caches are now JMX instrumented. This means that a application such as JConsole can be be used to monitor cache information out-of-band. This type of monitoring can be accomplished without changing the application code and with only minor changes to the configuration. For example, by adding set of properties to your persistence.xml, you can enable instrumentation of the data cache, query result cache, and SQL caches:<br />
<br />
<code>
<span style="font-size: x-small;"><property name="openjpa.Instrumentation<br />
value="jmx(Instrument='DataCache,QueryCache,QuerySQLCache')"/><br />
<property name="openjpa.DataCache"<br />
value="true(EnableStatistics=true)"/><br />
<property name="openjpa.QueryCache"<br />
value="true(EnableStatistics=true)"/><br />
<property name="openjpa.jdbc.QuerySQLCache"<br />
value="true(EnableStatistics=true)"/>
</span></code><br />
<br />
Using JConsole (provided with some 1.6 and later JDKs), you can attach to your Java program and use the MBeans provided by OpenJPA to view statistics for its caches. You can also invoke methods on the MBeans to get individual statistics about certain queries or cached object types. In addition to direct monitoring of the MBeans, the OpenJPA project provides a <a href="http://openjpa.apache.org/jconsole-datacache-plugin.html">data cache plugin for JConsole</a>. The data cache plugin provides a nice interface for monitoring the L2 data cache.<br />
<br />
As long as the environment supports JMX, applications running Java SE and Java EE environments can be monitored. The <a href="http://openjpa.apache.org/builds/2.1.1/apache-openjpa/docs/ref_guide_instrumentation.html">OpenJPA documentation</a> explains how to enable the JMX server in a Java SE environment. This blog contains some information for using <a href="http://wasdynacache.blogspot.com/2010/03/getting-jconsole-working-with-websphere.html">JConsole with WebSphere Application Server full profile</a>.<br/></br>
JPA applications deployed on the <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/entry/download_wlp">WebSphere Application Server Liberty Profile version 8.5 </a>and the Liberty <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/entry/download_wlp_eap">V.8.5.Next Beta </a> can also be monitored. Configuration is a piece of cake. You simply need to add the configuration above to your persistence.xml and enable the localConnector-1.0 feature in your Liberty Profile server.xml:<br />
<br />
<code>
<server description="Liberty Server"><br/>
<featureManager><br/>
<feature>jsp-2.2</feature><br/>
<feature>jpa-2.0</feature><br/>
<feature><strong>localConnector-1.0</strong></feature><br/>
</featureManager><br/>
... other configuration ...</br>
<server/><br/>
</code><br/>
Start the Liberty application server, and begin using your application. After performing a few operations that use JPA, start up JConsole with the <a href="http://openjpa.apache.org/jconsole-datacache-plugin.html">OpenJPA Data Cache plugin</a> and connect to the server. You can find the Liberty Server in the Local process list by searching for for ws-launch.jar followed by the name of your server.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTAQaQTFSSLBa1yTlgdg-ScGdeIfxqVK8droTyKPK6DxG4cBXdXLoY1gn9z_eutQ18hJ6GQrtBpPbaSOvFu9j6X8qCD6X-ahoyBrDQC94B6vy6q8TeUq3aC8xZ3nVH46CS36QKGk_yb4-M/s1600/JConsole1.jpg" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTAQaQTFSSLBa1yTlgdg-ScGdeIfxqVK8droTyKPK6DxG4cBXdXLoY1gn9z_eutQ18hJ6GQrtBpPbaSOvFu9j6X8qCD6X-ahoyBrDQC94B6vy6q8TeUq3aC8xZ3nVH46CS36QKGk_yb4-M/s320/JConsole1.jpg" /></a><br/></br>
JConsole will connect to the local process and the data cache plugin will discover the PUs available on the server. A tab will be created for each PU it discovers. This screen shows the DataCache statistics for the PollPU persistence unit.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgp9dEtvQfEZdrDoAvGg0odWu63Bhiw_MiJyc86RjRrWh2QX3ejpiTbfUsQF572_kmyFEdmuAd0M5d2GgNx6PwNZNQ8602r3vqg6ebTrRWZKJnsoCdKZqzSalmXcCMW0oOuRE-A8Fu_VyX/s1600/JConsole2.jpg" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgp9dEtvQfEZdrDoAvGg0odWu63Bhiw_MiJyc86RjRrWh2QX3ejpiTbfUsQF572_kmyFEdmuAd0M5d2GgNx6PwNZNQ8602r3vqg6ebTrRWZKJnsoCdKZqzSalmXcCMW0oOuRE-A8Fu_VyX/s320/JConsole2.jpg" /></a><br/></br>
You can also select the MBeans tab and browse through cache statistics of all the caches for the various persistence units in the server. The MBeans also allow you to reset cache statistics and query statistics for individual objects or queries on the fly.<br/><br/>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivDYujXDxvmEuCxBoDYsCpQYa1hd2TqLISLy9k6Nneo3fkFMdyCsLsub-xG6QhNI_iUgx0yqX9pMTnjP9K8fP7xgwx9SeZc2X77jo2jCHIxc1FDLP7_NMmMKMVNWROZqHHOWwYCpMVObUh/s1600/JConsole3.jpg" imageanchor="1" ><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivDYujXDxvmEuCxBoDYsCpQYa1hd2TqLISLy9k6Nneo3fkFMdyCsLsub-xG6QhNI_iUgx0yqX9pMTnjP9K8fP7xgwx9SeZc2X77jo2jCHIxc1FDLP7_NMmMKMVNWROZqHHOWwYCpMVObUh/s320/JConsole3.jpg" /></a><br/>
<br/>
-JeremyJeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com140tag:blogger.com,1999:blog-984759404111508297.post-69542165770981426072013-03-15T14:37:00.002-05:002013-03-15T14:39:58.672-05:00EJB Lite feature supports JPA in Liberty BetaThe WebSphere V8.5.Next Liberty Profile Alpha gave us a first look at a new EJB Lite (ejblite-3.1) feature for the WebSphere Liberty profile. If you use EJB session beans to drive your persistence layer you may have been disappointed since the EJB Lite capability in the Alpha didn't include support for JEE-style use of JPA with EJBs. Attempts at injecting or lookup of JPA entity managers and/or factories within an EJB resulted in an exception. The use of JPA with Java SE style bootstrapping (Persistence.createEntityManagerFactory()) may have worked if you happened to be using resource local transactions and connection properties (rather than server defined data sources). This was not an ideal or typical configuration in the application server environment.<br />
<br />
But, enough about the Alpha! I'm happy to report that the recent <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/entry/download_wlp_eap">WebSphere V8.5.Next Liberty Profile Beta</a> includes a <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/entry/article_newandnoteworthy_latest?lang=en">major bump in EJB Lite functionality</a>, including integration with JPA. This integration includes all you might expect, container managed persistence, enlistment in JTA transactions, and support for extended persistence contexts. The <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/entry/download_wdt_eap">WebSphere Development Tools for Eclipse Beta 9</a> on top of Eclipse WTP makes it a piece of cake to create new or modify existing EJB and JPA applications. To enable EJB and JPA in the <a href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/wasdev/resource/doc/liberty_v85next_beta.pdf">Liberty Beta</a> just add this feature set to your server.xml (include any other features you may require):
<br />
<pre> <featuremanager>
<feature>ejblite-3.1</feature>
<feature>jpa-2.0</feature>
</featuremanager>
</pre>
<br />
Check it out! <br />
<br />
-JeremyJeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com17tag:blogger.com,1999:blog-984759404111508297.post-72879891212900553132012-05-09T16:55:00.000-05:002012-05-09T16:55:37.647-05:00OpenBooks sample works with new WebSphere Liberty Profile!There is an exciting new feature in WebSphere Application Server v8.5 called the Liberty Profile. The Liberty Profile provides a new, sleek, highly-efficient application server environment both for development and production use. You can find out more details about Liberty on <a href="http://www.wasdev.net/" target="_blank">WASdev Home</a>.<br />
<br />
For those of you that joined me at Impact 2012 last week, I mentioned in my JPA presentation that I had attempted to deploy OpenBooks to a Liberty Profile server on the plane to Vegas. With just a couple of modifications to my configuration, I was able to get OpenBooks up and running in no time. But, I needed to update the OpenBooks instructions before going "public" with the information.<br />
<br />
I have now completed the updates to the<a href="http://openjpa.apache.org/building-and-running-openbooks.html" target="_blank"> OpenBooks sample and associated instructions</a>. In addition to making the necessary configuration updates to run the OpenBooks application on Liberty, I also updated a few other build, install, and execution issues. You can now build and execute the OpenBooks sample in JSE mode and two JEE environments -- WebSphere Application Server, and the new Liberty Profile. Enjoy!Kevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com2tag:blogger.com,1999:blog-984759404111508297.post-6602671052947870532011-03-28T09:14:00.046-05:002011-06-21T10:11:32.319-05:00Lightweight JPA testing in a JEE environment using the WebSphere Embeddable EJB Container<span style="font-size:85%;">Recognizing the importance of accelerated development and simplified testing, Enterprise JavaBeans took a page out of the JPA book by including JSE-friendly embeddable container within the EJB 3.1 specification. While the embeddable container doesn't support all the bells and whistles of a full blown container, it gives you plenty of features that can drastically speed up development and more importantly, provide a test environment that more closely resembles a JEE environment - in both configuration and behavior.<br /><br />The EJB 3.1 specification outlines these features for the embeddable container:<br /></span><ul><li><span style="font-size:85%;">Synchronous calling of local stateless, stateful, and singleton beans (singletons are new in EJB 3.1)</span></li><li><span style="font-size:85%;">Declarative and programmatic security</span></li><li><span style="font-size:85%;">Interceptors</span></li><li><span style="font-size:85%;">Use of annotations or XML deployment descriptors</span></li><li style="font-weight: bold;"><span style="font-size:85%;">Support for JPA 2.0</span></li></ul><span style="font-size:85%;">In addition to these features, the embeddable EJB container provided with <a href="http://www.ibm.com/software/webservers/appserv/was/features/">WebSphere Application Server V8</a> provides the ability to easily configure JDBC data sources. This is especially important when using JPA in container managed mode. WebSphere's embeddable container even supports the use of JTA component data sources within your persistence.xml. This allows you to use the same persistence.xml with the embeddable container as you use in your enterprise application.<br /></span><br /><span style="font-size:85%;">With the exception of an optional (but recommended) IDE such as Eclipse or <a href="http://www.ibm.com/software/awdtools/developer/application/">RAD 8.0.3</a>, </span><a href="http://www.ibm.com/software/webservers/appserv/was/features/"><span style="font-size:85%;">WebSphere Application Server V8</span></a><span style="font-size:85%;"> contains everything you need to get started - the Java SDK (depending on platform), the embeddable container, JPA client package, and the Derby database. When you install the beta be sure to install <span style="font-style: italic;">Stand-alone thin clients, resource adapters and embeddable containers.<br /><br /></span> </span><br /><span style="font-size:85%;"><span style="font-size:85%;"><span style="font-size:85%;"><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXZxrdCujrdWIW5DZUbEYwMcRa6sz2RolQw9XQA7Wp-SBgkdEAVrcRBcF3zpuvLNCzI1hXGZdk1rfazeU2_QpAbWbU6ag18N40wdpJbooxk-3VRnWDqaMuQ1Z5tbIDgupvXrTUSXLdyL-D/s1600/RequiredFeatures.jpg"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 98px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXZxrdCujrdWIW5DZUbEYwMcRa6sz2RolQw9XQA7Wp-SBgkdEAVrcRBcF3zpuvLNCzI1hXGZdk1rfazeU2_QpAbWbU6ag18N40wdpJbooxk-3VRnWDqaMuQ1Z5tbIDgupvXrTUSXLdyL-D/s320/RequiredFeatures.jpg" alt="" id="BLOGGER_PHOTO_ID_5594409258930954082" border="0" /></a></span></span><br />For the purposes of an example, let's say we have a simple EJB module that is used to manage personal contacts. The <span style="font-style: italic;">ContactModule</span> contains a simple annotated session bean named </span><span style="font-style: italic;font-size:85%;" >ContactBean<span style="font-weight: bold;"> </span></span><span style="font-size:85%;">which is primarly a transactional facade over JPA operations. The operations provided by the EJB allow you to find a contact by name, save a contact, and clear all contacts. The JPA operations operate on a persistent <span style="font-style: italic;">entity, Contact</span>. </span><span style="font-size:85%;">The</span><span style="font-style: italic;font-size:85%;" ><span style="font-style: italic;"> </span>ContactBean</span><span style="font-size:85%;"> is a session bean that implements a local interface </span><span style="font-style: italic;font-size:85%;" >Contac</span><span style="font-style: italic;font-size:85%;" >tLocal</span><span style="font-size:85%;">. While EJB 3.1 will now provide access to an bean without a Local interface, using interfaces is still a good practice. Interfaces provide a layer of abstraction from the base bean. They allow the bean to implement multiple specialized interfaces or allow the client to call a different EJB which implements the interface without modifying Java code. Here are our EJB and JPA classes and persistence.xml:</span><br /><br />ejbs/ContactBean.java<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;">package ejbs;<br /><br />import static javax.ejb.TransactionAttributeType.REQUIRED;<br />import static javax.ejb.TransactionAttributeType.SUPPORTS;<br /><br />import java.util.List;<br /><br />import javax.annotation.Resource;<br />import javax.annotation.Resources;<br />import javax.ejb.Stateless;<br />import javax.ejb.TransactionAttribute;<br />import javax.persistence.EntityManager;<br />import javax.persistence.PersistenceContext;<br />import javax.persistence.Query;<br />import javax.persistence.TypedQuery;<br />import javax.sql.DataSource;<br /><br />import entities.Contact;<br /><br />// Data source references for JPA<br />@Resources({<br />@Resource(name="jdbc/ContactDS", type=DataSource.class),<br />@Resource(name="jdbc/ContactNoTxDS", type=DataSource.class)<br />})<br />@Stateless<br />public class ContactBean implements ContactLocal {<br /><br />@PersistenceContext(unitName="ContactPU")<br />private EntityManager em;<br /><br />@TransactionAttribute(SUPPORTS)<br />public List<Contact> findContactsByLastName(String lastName) {<br /> TypedQuery<Contact> q = em.createNamedQuery("ByLastName", Contact.class);<br /> q.setParameter("lastName", lastName);<br /> return q.getResultList();<br />}<br /><br />@TransactionAttribute(REQUIRED)<br />public Contact saveContact(Contact c) {<br /> return em.merge(c);<br />}<br /><br />@TransactionAttribute(REQUIRED)<br />public void clearContacts() {<br /> Query q = em.createNamedQuery("DeleteAll");<br /> q.executeUpdate();<br />}<br />}</code></pre><br />ejbs/ContactLocal.java<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;">package ejbs;<br /><br />import java.util.List;<br />import javax.ejb.Local;<br />import entities.Contact;<br /><br />@Local<br />public interface ContactLocal {<br />public List<Contact> findContactsByLastName(String lastName);<br />public Contact saveContact(Contact c);<br />public void clearContacts();<br />}</code></pre><br />entities/Contact.java<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;">package entities;<br /><br />import javax.persistence.Entity;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.Id;<br />import javax.persistence.NamedQueries;<br />import javax.persistence.NamedQuery;<br /><br />@Entity<br />@NamedQueries( {<br />@NamedQuery(name="ByLastName",<br /> query="SELECT c FROM Contact c WHERE c.lastName = :lastName"),<br />@NamedQuery(name="DeleteAll", query="DELETE FROM Contact c")<br />})<br />public class Contact {<br /><br />@Id<br />@GeneratedValue<br />private Long id;<br /><br />private String firstName;<br />private String lastName;<br />private String phoneNumber;<br />private String emailAddress;<br /><br />public void setId(Long id) {<br /> this.id = id;<br />}<br /><br />public Long getId() {<br /> return id;<br />}<br /><br />public void setFirstName(String firstName) {<br /> this.firstName = firstName;<br />}<br /><br />public String getFirstName() {<br /> return firstName;<br />}<br /><br />public void setLastName(String lastName) {<br /> this.lastName = lastName;<br />}<br /><br />public String getLastName() {<br /> return lastName;<br />}<br /><br />public void setPhoneNumber(String phoneNumber) {<br /> this.phoneNumber = phoneNumber;<br />}<br /><br />public String getPhoneNumber() {<br /> return phoneNumber;<br />}<br /><br />public void setEmailAddress(String emailAddress) {<br /> this.emailAddress = emailAddress;<br />}<br /><br />public String getEmailAddress() {<br /> return emailAddress;<br />}<br />}</code></pre><br />META-INF/persistence.xml<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;"> <?xml version="1.0"?><br /><persistence xmlns="http://java.sun.com/xml/ns/persistence"<br />xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"<br />xsi:schemaLocation="http://java.sun.com/xml/ns/persistence<br />http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"><br /><persistence-unit name="ContactPU" transaction-type="JTA"><br /> <jta-data-source>java:comp/env/jdbc/ContactDS</jta-data-source><br /> <non-jta-data-source>java:comp/env/jdbc/ContactNoTxDS</non-jta-data-source><br /> <class>entities.Contact</class><br /> <exclude-unlisted-classes>true</exclude-unlisted-classes><br /> <properties><br /> <!-- Create the database tables on startup --><br /> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/><br /> </properties><br /></persistence-unit><br /></persistence><br /></code></pre><br /><span style="font-size:85%;">The simple EJB + JPA module looks like this when loaded as an Eclipse project:</span><br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTsJzrWzDUuIUR10O3n0JFpGFwdpxyOFwq3WXueKQ7BIze1Co5B5qRO4-3aM73CMTNM13LQL6HhCItS0wqfgz7drZpcRNhnHN09GIr3ZKSzh9MhCYpt1i08_cNI-6IL8q9hmUjw0kF8L4q/s1600/ContactModule.jpg"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 287px; height: 269px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTsJzrWzDUuIUR10O3n0JFpGFwdpxyOFwq3WXueKQ7BIze1Co5B5qRO4-3aM73CMTNM13LQL6HhCItS0wqfgz7drZpcRNhnHN09GIr3ZKSzh9MhCYpt1i08_cNI-6IL8q9hmUjw0kF8L4q/s320/ContactModule.jpg" alt="" id="BLOGGER_PHOTO_ID_5594428784993228434" border="0" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZOu69j2dHmMG43A1VhRbMKFwGbnfG9jnQcjE7OioOt_ILhLKDNMRlAmQMhP6q0fE9dfWIc9C-5nHvXxFL88VYg4_dt2FIvLDCrk5NfP6joGPUnDPxlZhyphenhyphen9BoRKdJKSO758qbI0f9j9Bzd/s1600/ContactModule.jpg"><br /></a><span style="font-size:85%;">Since <span style="font-style: italic;">ContactModule</span> uses only Java EE APIs, it only requires WAS_HOME\dev\JavaEE\j2ee.jar to compile. If you use WebSphere, OpenJPA, or other extensions you'll need to include additional jars in your build path. Remember, this is only to compile the EJB + JPA module. We'll need different jars to actually run the module in the Embeddable EJB Container.</span><br /><br /><span style="font-size:85%;">Now that the module is defined, we need to create an EJB jar file. As of EJB 3.0, a deployment descriptor (ejb-jar.xml) is not required. You can either use the "jar" command to create the jar or use the Eclipse Export... -> Java -> JAR file wizard. Export the jar to a location such as <span style="font-style: italic;">C:\ContactModule.jar</span>. The EJB jar file should contain:<br /><br /></span><ul><li><span style="font-size:85%;"><span style="font-weight: bold;">META-INF/MANIFEST.MF</span> </span></li><li><span style="font-size:85%;"><span style="font-weight: bold;">entities/Contact.class</span> </span></li><li><span style="font-size:85%;"><span style="font-weight: bold;">ejbs/ContactBean.class</span></span></li><li><span style="font-size:85%;"><span style="font-weight: bold;">ejbs/ContactLocal.class</span> </span></li><li><span style="font-size:85%;"><span style="font-weight: bold;">META-INF/persistence.xml</span> </span></li></ul><span style="font-size:85%;">We now have an EJB module. Traditionally, to test this module you'd write a web client, deploy it in the app server, and drive some http operations against it. Another option is to create a JEE client container app and then drive the EJB using launchClient. Or you may have used RAD's Universal Test Client to execute EJB operations. All of these options work, but they can be difficult to automate and some of them may require code modifications in order to work properly.<br /><br />Let's take a look at how the Embeddable EJB Container can be used to simplify this testing using the popular JUnit 4 test framework. Again, I used an Eclipse project, but provided that you have the necessary <a href="http://www.junit.org/">JUnit 4</a> libraries, you can also run the same tests from the command line. To test the basic functions of our <span style="font-style: italic;">ContactBean</span> session bean, we'll create a simple JUnit 4 annotated test class, <span style="font-style: italic;">TestContactBean</span>.<br /><br /></span>test/TestContactBean.java<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;">package test;<br /><br />import java.util.List;<br /><br />import javax.ejb.embeddable.EJBContainer;<br /><br />import org.junit.Assert;<br />import org.junit.Test;<br /><br />import ejbs.ContactLocal;<br />import entities.Contact;<br /><br />public class TestContactBean {<br /><br />@Test<br />public void testContactBean() {<br /><br /> // Create test data<br /> Contact c1 = new Contact();<br /> c1.setFirstName("John");<br /> c1.setLastName("Smith");<br /> c1.setPhoneNumber("555-555-5555");<br /> c1.setEmailAddress("john@someplace.org");<br /><br /> Contact c2 = new Contact();<br /> c2.setFirstName("Jane");<br /> c2.setLastName("Smith");<br /> c2.setPhoneNumber("555-555-5555");<br /> c2.setEmailAddress("jane@someplace.org");<br /><br /> // Create the embeddable container<br /> EJBContainer ec = EJBContainer.createEJBContainer();<br /><br /> try {<br /> // Use the embeddable container context to look up a bean<br /> ContactLocal contactBean = (ContactLocal) ec.getContext().lookup(<br /> "java:global/ContactModule/ContactBean!ejbs.ContactLocal");<br /><br /> // Clear existing contacts<br /> contactBean.clearContacts();<br /> <br /> // Save new contacts<br /> contactBean.saveContact(c1);<br /> contactBean.saveContact(c2);<br /><br /> // Query contacts and verify results<br /> List<contact> contacts = contactBean.findContactsByLastName("Smith");<br /> Assert.assertEquals(2, contacts.size());<br /> for (Contact c : contacts) {<br /> Assert.assertTrue(c.getLastName().equals("Smith"));<br /> }<br /> } catch (Throwable t) {<br /> Assert.fail("Caught unexpected exception: " + t.getMessage());<br /> } finally {<br /> ec.close();<br /> }<br />}<br />}</contact></code></pre><br /><span style="font-size:85%;">If you've used JPA in JSE-mode, the pattern looks pretty familiar, right? We use a static EJBContainer.createEJBContainer() method to create the embeddable container and then use a lookup to get an instance of the bean. Knowing what JNDI name to use can be a little tricky, but the new java:global namespace simplifies that as well. In general, you can use java:global/<module>module-name/bean-name<bean name="">[/!interface<interface>] to look up the bean. After you have a reference to the bean, you can call its EJB methods. Piece of cake. </interface></bean></module></span><span style="font-size:85%;">Well there is a little more to do. In order to get the code to compile and run you need to include <span style="font-style: italic;">ContactModule.jar</span>, <span style="font-style: italic;">WAS_HOME\runtimes\com.ibm.ws.ejb.embeddableContainer_8.0.0.jar</span>, <span style="font-style: italic;">WAS_HOME\runtimes\com.ibm.ws.jpa.thinclient_8.0.0.jar</span>, and the jUnit jars in your classpath.</span><br /><br /><span style="font-size:85%;">If we were simply testing EJBs we'd be all set. JPA has a few more requirements we need to take care of. First, since we'll be using Derby as our database, we need to add the Derby library to our classpath. It can be found at <span style="font-style: italic;">WAS_HOME\derby\lib\derby.jar</span>. Second, in an EE environment, JPA uses data sources to connect to a relational database. JPA typically requires both a transactional and non-transactional data source. WebSphere's embeddable container allows us to very easily configure data sources one of two ways. The most flexible of the two approaches is to configure them within a properties file. If a file named <span style="font-style: italic;">embeddable.properties </span>is found on the classpath the properties in this file will automatically get loaded by the embeddable container . The WebSphere Embeddable EJB Container also allows you to pass properties in via Map on the <span style="font-style: italic;">createEJBContainer </span>method. As a third option you can specify a system property to inform the embeddable container where its properties file resides. More information on the properties supported by the embeddable container can be found in the Information Center article <a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v8r0/topic/com.ibm.websphere.base.doc/info/aes/ae/rejb_emconproperties.html">Embeddable EJB container configuration properties</a>. You'll find that the embeddable container is extremely configurable. You can even configure settings such as cache size, security options, and logging.<br /><br /></span>embeddable.properties<br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;"># JPA Transactional data source definition<br />DataSource.ds1.name=jdbc/ContactDS<br />DataSource.ds1.className=org.apache.derby.jdbc.EmbeddedXADataSource<br />DataSource.ds1.createDatabase=create<br />DataSource.ds1.databaseName=ContactDB<br />DataSource.ds1.transactional=true<br /><br /># JPA non-Transactional data source definition<br />DataSource.ds2.name=jdbc/ContactNoTxDS<br />DataSource.ds2.className=org.apache.derby.jdbc.EmbeddedXADataSource<br />DataSource.ds2.createDatabase=create<br />DataSource.ds2.databaseName=ContactDB<br />DataSource.ds2.transactional=false<br /><br /># Definitions for global to component namespace bindings - required for @Resource defs<br />Bean.#ContactModule#ContactBean.ResourceRef.BindingName.jdbc/ContactDS=jdbc/ContactDS<br />Bean.#ContactModule#ContactBean.ResourceRef.BindingName.jdbc/ContactNoTxDS=jdbc/ContactNoTxDS<br /></code></pre> <span style="font-size:85%;"><br />Another approach is to define the data source using one or more @DataSourceDefinition(s) annotation(s) on the EJB. For example:<br /></span><br /><pre style="font-family: arial; font-size: 11px; border: 1px dashed rgb(204, 204, 204); width: 99%; height: auto; overflow: auto; background: none repeat scroll 0% 0% rgb(240, 240, 240); padding: 0px; color: rgb(0, 0, 0); text-align: left; line-height: 20px;"><code style="color: rgb(0, 0, 0); word-wrap: normal;">@DataSourceDefinitions({<br />@DataSourceDefinition(name="jdbc/ContactDS",<br /> className="org.apache.derby.jdbc.EmbeddedXADataSource",<br /> databaseName="JPAinEmbeddedContainer",<br /> transactional=true,<br /> properties={"createDatabase=create"}),<br />@DataSourceDefinition(name="jdbc/ContactNoTxDS",<br /> className="org.apache.derby.jdbc.EmbeddedXADataSource",<br /> databaseName="JPAinEmbeddedContainer",<br /> transactional=false,<br /> properties={"createDatabase=create"})<br />})<br />@Stateless<br />public class ContactBean implements ContactLocal {<br />...<br />}<br /></code></pre><span style="font-size:85%;"><br />As you can see, using @DataSourceDefinition is a very simple way to define data sources. There is no properties file or @Resource references to manage. The data sources automatically get registered into the<span style="font-style: italic;"> java:comp/env </span>namespace (take a look jta-data-source and non-jta-data-source definitions in the persistence.xml - as a best practice, component data sources are used). However, simplicity comes at the cost of flexibility. A change in the data source definition requires recompiling the application. </span><span style="font-size:85%;"><br /><br /></span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNpfKENIOGQbzqX3sVJtoc0jLYMXEA1C1lbdPc2y7D5YtXpIMlKS2YTkiOSpIs8IfJTCwFzzEFHvjirmILf0nZd5iTZNNoXyVu-JVhgbDE2q9aR9UAV4hAi3HjB_C0mu5fm8cNEUw5Cirn/s1600/Test_Project.jpg"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 208px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNpfKENIOGQbzqX3sVJtoc0jLYMXEA1C1lbdPc2y7D5YtXpIMlKS2YTkiOSpIs8IfJTCwFzzEFHvjirmILf0nZd5iTZNNoXyVu-JVhgbDE2q9aR9UAV4hAi3HjB_C0mu5fm8cNEUw5Cirn/s320/Test_Project.jpg" alt="" id="BLOGGER_PHOTO_ID_5594503737703086002" border="0" /></a><br /><span style="font-size:85%;">There's one more JPA-specific item we need to take care of before running the test. In the full application server, the container takes care of JPA entity enhancement. This does not occur in the embeddable container. Fortunately, you can either <a href="http://webspherepersistence.blogspot.com/2009/02/openjpa-enhancement.html">enhance the entities at build time</a> or the JPA agent-based enhancer can be used to perform the enhancement at runtime. Enabling the enhancer is as simple as specifying the JVM option <span style="font-style: italic;">-javaagent:C:\/"Program Files/"\IBM\WebSphere\AppServer\runtimes\com.ibm.ws.jpa.thinclient_8.0.0.jar</span></span><span style="font-size:85%;"> on the java or Eclipse jUnit invocation. If all goes well, you should see a result similar to this...<br /><br /><br /></span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4Hc2A4sn8I_ocLJAI-MFjxCdoR_KD_XcuV8ZqLUzV3MKRBfnljkwrhYle7eyX9KtTEXwAb4bi3Sa9wi0Wny8W0WGaIHo-nmsEYxwGCodoqavdDXMGeO70bRooGujsX-oVhaZ89AIxhn3r/s1600/jUnit_Exec.jpg"><img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 242px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4Hc2A4sn8I_ocLJAI-MFjxCdoR_KD_XcuV8ZqLUzV3MKRBfnljkwrhYle7eyX9KtTEXwAb4bi3Sa9wi0Wny8W0WGaIHo-nmsEYxwGCodoqavdDXMGeO70bRooGujsX-oVhaZ89AIxhn3r/s320/jUnit_Exec.jpg" alt="" id="BLOGGER_PHOTO_ID_5594495293520746498" border="0" /></a><br /><span style="font-size:85%;">More information about the <a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=%2Fcom.ibm.websphere.base.doc%2Finfo%2Faes%2Fae%2Ftejb_dvemcontainer.html">Embeddable EJB Container</a> is available in the <a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v8r0/index.jsp?topic=/com.ibm.websphere.base.doc/info/aes/ae/welcome_base.html">WebSphere Application Server V8 Information Center</a>. Happy testing!</span><br /><br /><span style="font-size:85%;">-Jeremy</span>Jeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com10tag:blogger.com,1999:blog-984759404111508297.post-29166460760786645002010-09-14T16:19:00.012-05:002010-09-16T11:54:35.392-05:00Type-safe JPQL query results with JPA 2.0If you use the <a href="http://www.eclipse.org/">Eclipse IDE</a> or <a href="http://www-01.ibm.com/software/awdtools/developer/application/">Rational Application Developer</a> (RAD) for your Java development, you probably make an effort to keep an eye out for warnings flagged in your code and spend some amount of time cleaning them up. That is why they are there, right? To help make sure your code is top notch. Warnings are even more prevalent if you have a large amount of pre-Java 5.0 code and have moved to Java 5 or Java 6. If you had a fairly warning-free code base and moved to Java 5 or newer you've probably encountered a barrage of new warnings in your workspace. The introduction of Java generics in Java 5.0 is one of the major culprits for all these new warnings. The use of collection classes (Collection, Set, List, etc.) that you happily used in your code are now all warning flagged as needing to be parameterized/typed.<br /><br />If you are a user of JPA, normal usage of some of the JPA APIs (primarly those from JPA 1.0) will add to your warning woes. For example, result list processing of JPQL queries returns an untyped result list that will get flagged as needing type information. Let's say you have some code that creates a JPQL query, executes it, and prints out the result.<br /><code><br /><font size="1"><strong>Query q = em.createQuery("SELECT e FROM Employee e");<br />List employees = q.getResultList();<br />if (employees != null) {<br /> for (int i = 0; i < employees.size(); i++) {<br /> Employee emp = (Employee)employees.get(i);<br /> System.out.println("Employee id=" + emp.getId() + ", name=" + e.getName());<br /> }<br />}</strong></font></code><br /><br />The Eclipse IDE will flag the 2nd line as a warning, telling you that you need to parameterize the List. A quick and dirty way to get rid of the warning is to wildcard the List definition, informing the compiler the list is untyped.<br /><code><br /><font size="1"><strong>List<?> employees = q.getResultList(); // Good-bye, warning!<br /></strong></font></code><br />This makes a dent in your warning count, but doesn't really buy you much. You are left with potentially unsafe type casts and result processing is still a bit messy. This is where a new feature/interface of JPA 2.0, <a href="http://download.oracle.com/javaee/6/api/javax/persistence/TypedQuery.html">TypedQuery</a> shines. The <a href="http://download.oracle.com/javaee/6/api/javax/persistence/TypedQuery.html">TypedQuery</a> interface provides the ability to operate on query results and parameters in a more type-safe manner. The <a href="http://download.oracle.com/javaee/6/api/javax/persistence/TypedQuery.html">TypedQuery</a> interface is actually geared more toward the new programmatic Criteria API, but provides benefits for JPQL queries as well. Here's an example of how one might write the original code using a TypedQuery.<br /><code><br /><font size="1"><strong>TypedQuery<Employee> tq = em.createQuery("SELECT e FROM Employee e", Employee.class);<br />for (Employee emp : tq.getResultList()) {<br /> System.out.println("Employee id=" + emp.getId() + ", name=" + e.getName());<br />}<br /></strong></font></code><br />The compile time warnings are gone, the casts are gone, and we are able to use the new iterator-based for loop to cleanly process the query result. Looks great, right? Well, there is a caveat. Currently, JPQL-based <a href="http://download.oracle.com/javaee/6/api/javax/persistence/TypedQuery.html">TypedQuery</a> does not support the use of the JPA 2.0 <a href="http://download.oracle.com/javaee/6/api/javax/persistence/Tuple.html">Tuple</a> to process multi-valued results (for example, returning multiple entity types in a single "row" of the result). However, the JPA 2.0 Criteria API does provide full Tuple support - along with all around true type-safety for query, query result, and query parameters. With any luck the ability to use <a href="http://download.oracle.com/javaee/6/api/javax/persistence/Tuple.html">Tuple</a> with JPQL may make its way in a future version of the JPA specification. But, if your JPQL queries primarily return a single value type, the TypedResult support for JPQL currently provided in JPA 2.0 could go a long way toward writing cleaner code.<br /><br />-JeremyJeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com0tag:blogger.com,1999:blog-984759404111508297.post-31132790106752897422010-07-07T12:53:00.020-05:002010-07-21T14:06:45.873-05:00Using Bean Validation with the OSGi/JPA 2.0 Feature Pack<span style="font-size:85%;">Do you have applications littered with layers of inconsistent validation logic or are writing a new application that will require data validation? Bean validation (</span><a href="http://jcp.org/en/jsr/detail?id=303"><span style="font-size:85%;">JSR-303</span></a><span style="font-size:85%;"> - part of the Java EE6 family of specifications) defines an API for providing runtime validation of data within Java beans. In addition, other EE6 specifications such as JPA 2.0, JSF, and JCA provide tight integration with bean validation, allowing runtime validation to occur seemlessly with your persistence, resource/connectivity, and UI logic.<br /><br />Using bean validation within the app server requires a JSR-303 spec API library, the bean validation provider library(ies), and any supporting libraries. If you'd like to test drive bean validation with JPA 2.0, the </span><a href="http://www-01.ibm.com/software/webservers/appserv/was/featurepacks/osgi/"><span style="font-size:85%;">WebSphere Application Server V7 Feature Pack for OSGi Applications and Java Persistence API 2.0</span></a><span style="font-size:85%;"> does not include a bean validation API or provider, but it does include a provision for wiring one in yourself. The wiring is pretty simple and is briefly explained in this IBM Infocenter document </span><a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.jpafep.multiplatform.doc/info/ae/ae/tejb_jpabeanval.html"><span style="font-size:85%;">Using Bean Validation with JPA</span></a><span style="font-size:85%;">. With the information provided in the <a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.jpafep.multiplatform.doc/info/ae/ae/tejb_jpabeanval.html">article</a>, I was able to configure WebSphere Application Server to use </span><a href="http://projects.apache.org/projects/bean_validation__incubating_.html"><span style="font-size:85%;">Apache's Bean Validation provider </span></a><span style="font-size:85%;">using these steps. </span><br /><ol><li><span style="font-size:85%;">Install WebSphere Application Server V7 with the Fixpack required for the feature pack (currently 7.0.0.9). There is a free </span><a href="http://www.ibm.com/developerworks/downloads/ws/wasdevelopers/index.html"><span style="font-size:85%;">Developer's Edition </span></a><span style="font-size:85%;">if you don't have the V7 test server for </span><a href="http://www.ibm.com/developerworks/downloads/r/rad/?S_TACT=105AGX28&S_CMP=TRIALS"><span style="font-size:85%;">RAD 7.5</span></a> <span style="font-size:85%;">or an extra license lying about. :-)</span></li><li><span style="font-size:85%;">Install the </span><a href="http://www-01.ibm.com/software/webservers/appserv/was/featurepacks/osgi/"><span style="font-size:85%;">WebSphere Application Server V7 Feature Pack for OSGi Applications and Java Persistence API 2.0</span></a><span style="font-size:85%;">.</span></li><li><span style="font-size:85%;">Download the </span><a href="https://repository.apache.org/content/groups/public/org/apache/geronimo/specs/geronimo-validation_1.0_spec/1.1/geronimo-validation_1.0_spec-1.1.jar"><span style="font-size:85%;">Apache Bean Validation Spec API jar</span></a><span style="font-size:85%;">. Save to a location such as:<br /><strong><em>/opt/apache/specs/geronimo-validation_1.0_spec-1.1.jar</em></strong></span></li><li><span style="font-size:85%;">Download the </span><a href="https://repository.apache.org/content/groups/public/org/apache/bval/bval-core/0.1-incubating/bval-core-0.1-incubating.jar"><span style="font-size:85%;">Apache Bean Validation Core jar</span></a><span style="font-size:85%;">. Save to a location such as:<br /><strong><em>/opt/apache/bval/bval-core-0.1-incubating.jar</em></strong></span></li><li><span style="font-size:85%;">Download the </span><a href="https://repository.apache.org/content/groups/public/org/apache/bval/bval-jsr303/0.1-incubating/bval-jsr303-0.1-incubating.jar"><span style="font-size:85%;">Apache Bean Valdation JSR-303 jar</span></a><span style="font-size:85%;">. Save to a location such as:<br /><strong><em>/opt/apache/bval/bval-jsr303-0.1-incubating.jar</em></strong></span></li><li><span style="font-size:85%;">Download </span><a href="http://commons.apache.org/beanutils/download_beanutils.cgi"><span style="font-size:85%;">Apache Commons Bean Utils</span></a><span style="font-size:85%;">. Extract the distribution and locate commons-beanutils-1.8.3.jar. Copy the jar to a location such as:<br /><strong><em>/opt/apache/commons/commons-beanutils-1.8.3.jar</em></strong></span></li><li><span style="font-size:85%;">Download </span><a href="http://archive.apache.org/dist/commons/lang/binaries/commons-lang-2.4-bin.zip"><span style="font-size:85%;">Apache Commons Lang 2.4</span></a><span style="font-size:85%;">. Extract the distribution and locate commons-lang-2.4.jar. Copy the jar to a location such as:<br /><strong><em>/opt/apache/commons/commons-lang-2.4.jar</em></strong></span></li><li><span style="font-size:85%;">Start the app server.</span></li><li><span style="font-size:85%;">Open the WebSphere Integrated Solutions Console in your browser (http://<server:port>/admin).</span></li><li><span style="font-size:85%;">In the navigation pane expand <strong>Servers</strong> -> <strong>Server Types</strong> and click on <strong>WebSphere application servers</strong>.</span></li><li><span style="font-size:85%;">Select the server profile to configure. Typically <strong>server1</strong> in a default single server environment.</span></li><li><span style="font-size:85%;">Under the <strong>Server Infrastructure</strong> section, select <strong>Process Definition</strong>.</span></li><li><span style="font-size:85%;">Under the <strong>Additional Properties</strong> section, select <strong>Java Virtual Machine</strong>.</span></li><li><span style="font-size:85%;">Under the <strong>Additional Properties</strong> section of the JVM settings, select <strong>Custom properties.</strong></span></li><li><span style="font-size:85%;">Click <strong>New</strong> and add a property named <strong><em>com.ibm.websphere.validation.api.jar.path</em></strong> and set the value to the location of the bean validation API jar. (ex. <strong><em>/opt/apache/specs/geronimo-validation_1.0_spec-1.1.jar</em></strong>) </span></li><li><span style="font-size:85%;">Restart the application server.</span></li></ol><p><span style="font-size:85%;">The application server is now configured to locate and load the bean validation spec API jar. The spec API classes are now available, but the application server (being an EE5 app server) does include a bean validation provider. You need to make a provider available to your application by either bundling it with your application archive (in the proper location within a war or ear) or via a </span><a href="http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/tcws_sharedlib.html"><span style="font-size:85%;">shared library</span></a><span style="font-size:85%;">. Include the bean validation core, bean validation jsr-303 component, commons bean utils, and commons lang 2.4 jars within the application or shared library and you'll be off to the races.</span></p><p><span style="font-size:85%;">That's all there is to configuring the application server. To actually build applications which take advantage of bean validation constraints, you'll need to specify the spec API library in the build path of your tooling. The examples in </span><a href="http://openjpa.apache.org/bean-validation-primer.html"><span style="font-size:85%;">Apache Bean Validation Primer </span></a><span style="font-size:85%;">will help you get started. The example in the primer is targeted for a JSE environment (I'm working on a JEE version -- no ETA), but the JPA entities, constraints, validators, and logic can be easily ported to an EE environment. One additional <span style="font-weight: bold;">very important</span> item to note is that your persistence.xml must be updated to version 2.0 in order for bean validation to be enabled by the JPA provider (OpenJPA). Since the 2.0 schema is backward compatible, it is typically a simple one line XML change. The JPA Integration section of the <a href="http://openjpa.apache.org/bean-validation-primer.html">primer</a> contains the rationale for this requirement and an example.<br /></span></p><p><span style="font-size:85%;">-Jeremy</span></p>Jeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com1tag:blogger.com,1999:blog-984759404111508297.post-67015562435300718962010-06-23T07:28:00.002-05:002010-06-23T10:40:14.206-05:00OpenJPA OpenBooks sample available for WebSphere Application Server<span style="font-size:85%;">A JEE version of OpenJPA's <a href="http://openjpa.apache.org/openbooks-featuring-jpa-20.html">OpenBooks sample</a> is now available for WebSphere Application Server with the <a href="http://www-01.ibm.com/software/webservers/appserv/was/featurepacks/osgi/">WebSphere Application Server V7 Feature Pack for OSGi Applications and Java Persistence API 2.0</a>. OpenBooks is a sample application that highlights many of the new features of <a href="http://jcp.org/en/jsr/detail?id=317">JPA 2.0</a>. The sample can be built from source obtained from the Apache's OpenJPA svn repository. If you are not familiar with <a href="http://subversion.apache.org/">svn</a>, don't let it deter you from getting the sample. Use of <a href="http://subversion.apache.org/">svn </a>for basic functions, like checking out a source tree, is a piece of cake. If you are in a single server environment, the OpenBooks build scripts (run with WebSphere's ws_ant) will compile, package, install, and configure OpenBooks. The OpenBooks <a href="http://openjpa.apache.org/building-and-running-openbooks.html">instructions</a> will help you get going. In particular, take a look at the section </span><span style="font-style: italic;font-size:85%;" >Deploy OpenBooks in an Application Server</span><span style="font-size:85%;">. This section contains some WebSphere-specific instructions.</span><br /><br /><span style="font-size:85%;">The build scripts are primarily targeted for a single server environment, but may work in an ND environment as well. By default, <a href="http://openjpa.apache.org/openbooks-featuring-jpa-20.html">OpenBooks</a> is installed to the default server and port and the script assumes admin security is disabled. If you need to target a specific server and/or have security enabled, there are command line variables you can use to specify these details. The script is currently all or nothing, so if you specify one, you must specify all. For example:</span><br /><br /><tt>$ /opt/WebSphere/AppServer/bin/ws_ant -Dbuild.mode=jee -Dappserver=was -Dwas.home=/opt/WebSphere/AppServer -Dwas.server=localhost -Dwas.port=8880 -Dwas.conntype=SOAP -Dwas.user=myuser -Dwas.password=mypassword</tt><br /><br /><span style="font-size:85%;">This invocation will install OpenBooks on the local machine with the profile serviced by SOAP admin port 8880 with the specified credentials. The script creates a new Derby data source (which is also configured to create a new database if it doesn't exist) by default, but if you are data source savvy you can easily configure the </span><span style="font-style: italic;font-size:85%;" >OpenBooks Data Source</span><span style="font-size:85%;"> and </span><span style="font-style: italic;font-size:85%;" >OpenBooks Non-transactional Data Source</span><span style="font-size:85%;"> to point at your own database. Assuming your build and install was successful, point your browser at <span style="font-style: italic;">http://</span><server:port><span style="font-style: italic;"><server>:<port>/OpenBooks</span> to run the sample. Enjoy!!<br /><br />-Jeremy<br /></server:port></span>Jeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com5tag:blogger.com,1999:blog-984759404111508297.post-48122316883421706652010-04-26T17:18:00.003-05:002010-04-26T17:25:53.067-05:00Apache OpenJPA 2.0.0 Now Available!I am proud to announce the availability of <a href="http://openjpa.apache.org/openjpa-200.html">Apache OpenJPA 2.0.0</a>!<br /><br />This distribution is based on the final <a href="http://jcp.org/en/jsr/detail?id=317" rel="nofollow"></a><a href="http://jcp.org/en/jsr/detail?id=317">JSR 317 Java Persistence API, Version 2.0 specification</a> and passes the JPA 2.0 TCK, while remaining backwards compatible with prior releases based on the Java Persistence API (JPA 1.0) part of Java Community Process JSR-220 (Enterprise JavaBeans 3.0).<br /><br />The WebSphere JPA solution is based on the Apache OpenJPA project.<br /><br />Check it out!<br /><br />KevinKevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com3tag:blogger.com,1999:blog-984759404111508297.post-74505348532360588502010-03-04T08:17:00.004-06:002010-03-04T08:40:47.391-06:00Beta 2 of Apache OpenJPA now available!As we continue to march towards a 2.0.0 release of OpenJPA, we recently announced a <a href="http://openjpa.apache.org/openjpa-200-beta-2.html">Beta 2 of the OpenJPA 2.0.0</a> deliverable. This release contains <a href="http://openjpa.apache.org/builds/2.0.0-beta2/apache-openjpa-2.0.0-beta2/RELEASE-NOTES.html">additional bug fixes and performance improvements</a> in addition to continuing our TCK compliance.<br /><br />Enjoy! Let us know your views and comments either via this forum or the OpenJPA mailing lists.<br /><br />Thanks,<br />KevinKevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com1tag:blogger.com,1999:blog-984759404111508297.post-79682013013035889852010-02-12T15:35:00.002-06:002010-02-12T16:07:46.990-06:00WebSphere V7 Feature Pack for OSGi Applications and Java Persistence API (JPA) 2.0 Open Beta now Available!I actually have two announcements to make. From a WebSphere perspective, I am pleased to announce the availability of the <a href="https://www14.software.ibm.com/iwm/web/cc/earlyprograms/websphere/wasfposgiajp/">IBM WebSphere Application Server V7 Feature Pack for OSGi Applications and Java Persistence API (JPA) 2.0 Open Beta</a>.<br /><br />I know that's a mouth full, but this announcement clearly demonstrates IBM's commitment to both the OSGi and JPA programming models. Each of these features can be individually installed on a WebSphere v7 system (specifically, 7.0.0.7). More details on the specifics can be found on the official announcement page above.<br /><br />The other item I would like to announce is the availability of the <a href="http://openjpa.apache.org/openjpa-200-beta.html">Apache OpenJPA 2.0.0-beta</a> release. This beta release is 100% compatible with the JPA 2.0 TCK, plus it contains several other improvements outlined on the announcement. This OpenJPA 2.0.0-beta has been available for a couple of weeks, but I was waiting to announce it in conjunction with the WebSphere Open Beta. (Apache OpenJPA provides the basis for the WebSphere JPA solution.)<br /><br />So, whether you are a WebSphere customer or just interested in experimenting with the latest JPA 2.0 feature set, one of these two offerings should fit the bill. Enjoy!Kevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com0tag:blogger.com,1999:blog-984759404111508297.post-57174875763104813352010-01-22T09:41:00.002-06:002010-01-22T10:00:58.850-06:00Basic tutorial for OpenJPA<span class="ul-threaded" style="margin: 0.5em 0pt 0pt -20px;"><span class="text-cell">Take a look at this <a href="http://bit.ly/JPATutorialOpen" target="_top" rel="nofollow" link="external">new tutorial</a> on the Apache site.<br /><br />Begin using OpenJPA - The Basics<br />This sample and tutorial steps through the requirements, setup, code and deployment of an OpenJPA implementation with a JSP web application on Geronimo. It is geared for those that are just beginning with OpenJPA. Users will be given detailed instructions for each part of the setup including the setup of Eclipse, Geronimo and the Derby database. For those developers that have been wanting to explore the power of OpenJPA, this is where you begin.<br /><br />This will get someone going in OpenJPA even if they are new to Geronimo, Derby and OpenJPA</span></span>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-984759404111508297.post-54690844024732819972009-11-18T15:06:00.003-06:002009-11-18T15:28:51.893-06:00OpenJPA tutorial for beginners availableWith the release of the IBM WebSphere OpenJPA V2.0 open Alpha, there will be a renewed interest in OpenJPA by those that have not yet learned it. For those that have been using OpenJPA, this release will provide new functions and features. For those that have never used JPA, the Open Alpha site has an excellent <a href="http://bit.ly/IBMWASOpenJPATutorial">getting-started tutorial</a>. This tutorial is a great place to learn the basics. This tutorial is labeled as part 1 and does not require the WebSphere Application Server. It uses J2SE, MySQL and Eclipse.<br />The tutorial steps through the parts of OpenJPA, including the way it uses annotations, the persistence.xml file and JPQL. To keep it simple and to allow the user maximum flexibility the complete working code is provided.<br /><br />You can download the tutorial here:<br /><a href="http://bit.ly/IBMWASOpenJPATutorial">IBM Websphere OpenJPA Tutorial Part 1</a><br /><span style="font-size:78%;">*free site registration required</span>Unknownnoreply@blogger.com2tag:blogger.com,1999:blog-984759404111508297.post-76409777975862827382009-10-29T14:47:00.005-05:002009-10-30T09:11:45.289-05:00WebSphere JPA 2.0 Open Alpha is now available!Hi,<br />The WebSphere JPA team is proud to announce the availability of the IBM WebSphere Application Server V7 Java Persistence API (JPA) 2.0 Open Alpha. Details can be found here...<br /><br /><a href="https://www14.software.ibm.com/iwm/web/cc/earlyprograms/websphere/wsasjpaoa/">https://www14.software.ibm.com/iwm/web/cc/earlyprograms/websphere/wsasjpaoa/</a><br /><br /><a href="http://www.blogger.com/Hi,%20The%20WebSphere%20JPA%20team%20is%20proud%20to%20announce%20the%20availability%20of%20the%20IBM%20WebSphere%20Application%20Server%20V7%20Java%20Persistence%20API%20%28JPA%29%202.0%20Open%20Alpha.%20Details%20can%20be%20found%20here...%20%20https://www14.software.ibm.com/iwm/web/cc/earlyprograms/websphere/wsasjpaoa/%20%20This%20JPA%202.0%20Open%20Alpha%20is%20based%20off%20the%20Public%20Final%20Draft%20#2%20of%20the%20JPA%202.0%20specification,%20which%20can%20be%20found%20here...%20%20http://jcp.org/en/jsr/detail?id=317%20%20If%20you%20are%20looking%20for%20something%20a%20bit%20more%20readable%20that%20highlights%20the%20new%20JPA%202.0%20features,%20you%20could%20also%20reference%20the%20following%20two%20articles...%20%20http://www.ibm.com/developerworks/websphere/techjournal/0909_col_sutter/0909_col_sutter.html%20http://www.ibm.com/developerworks/java/library/j-typesafejpa/%20%20Since%20the%20WebSphere%20JPA%20solution%20is%20built%20on%20top%20of%20the%20Apache%20OpenJPA%20project,%20you%20can%20always%20follow%20our%20progress%20via%20these%20URLs...%20%20http://openjpa.apache.org/%20http://openjpa.apache.org/jpa-20-roadmap.html%20%20Enjoy%21%20Kevin"></a>This JPA 2.0 Open Alpha is based off the Public Final Draft #2 of the JPA 2.0 specification, which can be found here...<br /><br /><a href="http://jcp.org/en/jsr/detail?id=317">http://jcp.org/en/jsr/detail?id=317</a><br /><br />If you are looking for something a bit more readable that highlights the new JPA 2.0 features, you could also reference the following two articles...<br /><br /><a href="http://www.ibm.com/developerworks/websphere/techjournal/0909_col_sutter/0909_col_sutter.html">http://www.ibm.com/developerworks/websphere/techjournal/0909_col_sutter/0909_col_sutter.html</a><br /><a href="http://www.ibm.com/developerworks/java/library/j-typesafejpa/">http://www.ibm.com/developerworks/java/library/j-typesafejpa/</a><br /><br />Since the WebSphere JPA solution is built on top of the Apache OpenJPA project, you can always follow our progress via these URLs...<br /><br /><a href="http://openjpa.apache.org/">http://openjpa.apache.org/</a><br /><a href="http://openjpa.apache.org/jpa-20-roadmap.html">http://openjpa.apache.org/jpa-20-roadmap.html</a><br /><br />Enjoy!<br />KevinKevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com2tag:blogger.com,1999:blog-984759404111508297.post-51858110002870330462009-06-25T10:50:00.003-05:002009-10-30T09:15:13.713-05:00OpenJPA with solidDBDonald Vines and myself recently published a DeveloperWorks article on how to use solidDB with OpenJPA. In a nutshell, since solidDB is a JDBC-compliant in-memory database, this configuration just worked out-of-the-box with the generic JDBC dictionary provided by OpenJPA. It still is on our <a href="https://issues.apache.org/jira/browse/OPENJPA-735">wish list</a> to create a specific dictionary for solidDB, but in the mean time, this article shows that the integration of solidDB and OpenJPA is possible today.<br /><br /><a href="http://www.ibm.com/developerworks/websphere/techjournal/0906_vines/0906_vines.html">http://www.ibm.com/developerworks/websphere/techjournal/0906_vines/0906_vines.html</a><br /><br />Enjoy!<br />KevinKevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com0tag:blogger.com,1999:blog-984759404111508297.post-15843115896095422292009-05-21T13:17:00.007-05:002009-07-28T08:05:20.299-05:00Intro to OpenJPA CachingIntro to OpenJPA Caching<br /><br />A part of the JPA 2.0 spec (JSR317) defines the javax.persistence.Cache Interface [1] which exposes a providers' second level(L2) cache. While exploring this new interface, I learned a few things about OpenJPA caching that were not entirely obvious to me at the time. Hopefully I can lay out some of what I've learned to save at least one person some pain.<br /><br />First off, I'm going to discuss the caching that wasn't obvious to me. Take a quick look through the semi-pseudo code that models the scenario I was running below.<br /><br /><div style="margin-left: 40px;">EntityManager em = EntityManagerFactory.createEntityManager()<br />Entity e = em.findEntity(Entity.class, Long.valueOf(1))<br />updateEntityViaJDBC(e.getId(), "new data")// a worker method to insert data using JDBC<br />e = em.findEntity(Entity.class, Long.valueOf(1))<br />if(e.getData().equals("new data")==false){<br />//Whoops, where did my updated data go!?!<br />}<br /></div><br />As you can see in the example above, I find an Entity from the database and then update the database using JDBC. Since my database was updated I figured I needed search again to update my Entity and finally I validated that the Entity was holding onto the data I *thought* it should. The last part of my logic is where I went astray.<br /><br />Once an Entity is loaded by OpenJPA, it is characterized as a managed Entity. When an Entity is managed by the JPA runtime, the spec says that "Synchronization to the database does not involve a refresh of any managed entities unless the refresh operation is explicitly invoked on those entities" [2]. The more I dug into this one, I found that OpenJPA tries to cache/optimize where ever the spec allows. If you were to create an EntityManager and then call em.find() on the same object 1000 times in a row, OpenJPA would only hit the DB once. I didn't expect that to happen, but I can swallow it now that I know that it is happening! This caching is sometimes referred to as the EntityManager L1 cache and it is scoped to the life of an EntityManager. In short, when an EntityManger falls out of scope or is closed, the L1 cache is cleared. I'm not going to lie, this stuff is complicated and I only discussed a small part of the entire picture. If you want/need more details, please see [3] for the entire description.<br /><br />One thing to note is that the previous paragraph talked <b>only</b> about the EntityManager L1 cache which is defined by the spec and it shouldn't be confused with the following paragraph which pertains to the L2 cache.<br /><br />The javax.persistence.Cache interface that is being introduced as part of JSR317 essentially exposes some of the functionality from org.apache.openjpa.persistence.StoreCache that has been in existence since the early days of OpenJPA. The interface itself is not that interesting, but the results from enabling the OpenJPA data cache are pretty impressive. The OpenJPA user manual states that "This cache is designed to significantly increase performance while remaining in full compliance with the JPA standard. This means that turning on the caching option can transparently increase the performance of your application, with no changes to your code." I hate to say this, but it is a case of where you can get something for free. Enabling the data cache is as simple as adding the following property to your persistence.xml.<br /><br />< name="openjpa.DataCache" value="true"><br /><br />For more information regarding the OpenJPA data cache see [4].<br /><pre class="programlisting">-Rick<br /></pre><div><br />http://jcp.org/aboutJava/communityprocess/pfd/jsr317/index.html --JSR317 download page.<br />[1] See 6.10 of JSR317.<br />[2] See 3.2.4 of JSR317.<br />[3] Chapter 6 of JSR317.<br />[4] http://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/ref_guide_caching.html<br /><br /></div>Rick Curtishttp://www.blogger.com/profile/10356648465322267003noreply@blogger.com10tag:blogger.com,1999:blog-984759404111508297.post-91515247646319300382009-04-28T08:52:00.011-05:002009-04-28T22:28:46.137-05:00Custom ORM with OpenJPA<span style="font-size:85%;"><br />While JPA provides a very rich set of mapping constructs, it doesn't offer much in terms of customization in situations where a domain model cannot be directly or easily mapped to the database using those constructs. This is more typically an issue when an existing application is being converted from some persistence mechanism such as a JDBC-based DAO to JPA and its domain classes cannot suffer more than minimal modifications.<br /><br />For example, let's say there is an application XYZ which has a domain class named User. The User class contains an email address field which is of type string. Application XYZ expects email addresses in the form user@domain. However, the database table backing the User class stores the components of an email address in separate columns, EMAIL_USER and EMAIL_DOMAIN. The persistence mechanism used in XYZ (for example, JDBC) performs the necessary transforms in a DAO layer to compose the database columns to a single string value of the expected format and vice versa.<br /><br />Converting this application to JPA would typically involve mapping the individual persistent fields for user and domain to the individual database columns and then wrappering them with the logic formerly provided by the DAO to do the transforms. While this is fairly straight forward, it requires modifications to the domain object and couples the transform logic to the entity. These types of changes can be invasive and undesirable in an existing application.<br /><br />OpenJPA has an elegant solution for handling these types of mappings: mapping strategies. Custom mapping strategies can be applied to persistent fields using OpenJPA’s @org.apache.openjpa.persistence.jdbc.Strategy annotation. Strategies are most simply created by subclassing the org.apache.openjpa.jdbc.meta.strats.AbstractValueHandler class. Although, for complex mappings you may decide to provide a full implementation class by implementing the org.apache.openjpa.jdbc.meta.ValueHandler interface. To implement a basic strategy you simply need to provide column mapping information and the methods to transform to and from a given type. The name of the custom strategy class is specified on the @Strategy annotation. At runtime, OpenJPA applies this strategy to the persistent field or property. This decouples the mapping and data transformation logic from the domain class. Below is a simple strategy for the multi-column email address mapping. It maps a single persistent field to two database columns and provides the transforms to get the data in the proper format to/from the domain model and database table.<br /><br /><strong>EmailAddressStrategy.java</strong></span><span style="font-size:85%;"><pre><br />package strategies;<br /><br />import org.apache.openjpa.jdbc.kernel.JDBCStore;<br />import org.apache.openjpa.jdbc.meta.ValueMapping;<br />import org.apache.openjpa.jdbc.meta.strats.AbstractValueHandler;<br />import org.apache.openjpa.jdbc.schema.Column;<br />import org.apache.openjpa.jdbc.schema.ColumnIO;<br />import org.apache.openjpa.meta.JavaTypes;<br /><br />public class EmailAddressStrategy extends AbstractValueHandler {<br /><br /> // Create the custom column mappings for this strategy<br /> public Column[] map(ValueMapping vm, String name, ColumnIO io,<br /> boolean adapt) {<br /><br /> Column user = new Column();<br /> user.setName("EMAIL_USER");<br /> user.setJavaType(JavaTypes.STRING);<br /><br /> Column domain = new Column();<br /> domain.setName("EMAIL_DOMAIN");<br /> domain.setJavaType(JavaTypes.STRING);<br /> return new Column[]{ user, domain };<br /> }<br /><br /> // Transform the email address value to its individual datastore column values.<br /> public Object toDataStoreValue(ValueMapping vm, Object val,<br /> JDBCStore store) {<br /> if (val == null)<br /> return null;<br /><br /> // Split the user and domain components into distinct values<br /> if (val instanceof String) {<br /> String strVal = (String)val;<br /> String user = strVal;<br /> String domain = null;<br /> int atIndex = user.indexOf('@');<br /> if (atIndex != -1) {<br /> user = strVal.substring(0, atIndex);<br /> domain = strVal.substring(atIndex+1);<br /> }<br /> return new Object[] { user, domain };<br /> }<br /> return val.toString();<br /> }<br /><br /> // Transform the separate datastore values to an email address.<br /> public Object toObjectValue(ValueMapping vm, Object val) {<br /> if (val == null)<br /> return null;<br /><br /> if (val instanceof Object[]) {<br /> String user = null;<br /> String domain = null;<br /> Object[] objArray = (Object[])val;<br /> if (objArray.length > 0)<br /> user = objArray[0].toString();<br /> if (objArray.length > 1)<br /> domain = objArray[1].toString();<br /> return user + "@" + domain;<br /> }<br /> return val.toString();<br /> }<br />}<br /></pre></span><br /><span style="font-size:85%;"><strong>User.java</strong></span><br /><span style="font-size:85%;"><pre><br />import javax.persistence.Entity;<br />import javax.persistence.GeneratedValue;<br />import javax.persistence.Id;<br /><br />import org.apache.openjpa.persistence.jdbc.Strategy;<br /><br />@Entity<br />public class User {<br /><br /> @Id<br /> @GeneratedValue<br /> private int id;<br /><br /> // Use email address strategy on this persistent field<br /> @Strategy("strategies.EmailAddressStrategy")<br /> private String emailAddress;<br /><br /> public void setEmailAddress(String emailAddress) {<br /> this.emailAddress = emailAddress;<br /> }<br /><br /> public String getEmailAddress() {<br /> return emailAddress;<br /> }<br />}<br /></pre><br /></span>In short, if you find that JPA's mapping constructs are not quite adequate for a particular mapping, creating your own mapping strategy may be just the ticket.<br /><br />-JeremyJeremy Bauerhttp://www.blogger.com/profile/05518443434830232764noreply@blogger.com0tag:blogger.com,1999:blog-984759404111508297.post-20199460459460929492009-04-19T00:47:00.001-05:002009-04-19T00:47:56.460-05:00What's in a word?<p>I wanted to understand what issues are important to the growing base of OpenJPA users. So I attempted a small experiment as follows:</p> <ul> <li>Extracted the headers from the users' postings in <a href="http://n2.nabble.com/OpenJPA-Users-f208411.html" target="_blank">OpenJPA Users' Mailing List</a>. </li> <li>The extraction process was a breeze with the help of <a href="http://htmlparser.sourceforge.net/" target="_blank">HTML Parser</a>. The program found a list of 1059 independent poster headers. </li> <li>Fed the headers to <a href="http://www.wordle.net/" target="_blank">Wordle</a> to create a <strong>Word Cloud</strong>. </li> </ul> <p>This is the Word Cloud after the first attempt </p> <p> </p> <img style="border-right: #ddd 1px solid; padding-right: 4px; border-top: #ddd 1px solid; padding-left: 4px; padding-bottom: 4px; border-left: #ddd 1px solid; padding-top: 4px; border-bottom: #ddd 1px solid" height="240" alt="Wordle: OpenJPASupportForum" src="http://www.wordle.net/thumb/wrdl/760415/OpenJPASupportForum" width="300" /> <p>The original Word Cloud is <a href="http://www.wordle.net/gallery/wrdl/760415/OpenJPASupportForum" target="_blank">here</a>  </p> Of course, "problem" is often what makes a user to post in the forum. To focus further and because did not like "problem" being so prominent in the Word Cloud, removed the following words for the input list of headers: "OpenJPA", "entity", "mapping", "error", "using", "Re:" <p> <img style="border-right: #ddd 1px solid; padding-right: 4px; border-top: #ddd 1px solid; padding-left: 4px; padding-bottom: 4px; border-left: #ddd 1px solid; padding-top: 4px; border-bottom: #ddd 1px solid" height="240" alt="Wordle: OpenJPA Word Cloud Iteration 2" src="http://www.wordle.net/thumb/wrdl/760468/OpenJPA_Word_Cloud_Iteration_2" width="300" /></a> <p>The original Word Cloud is <a title="Wordle: OpenJPA Word Cloud Iteration 2" href="http://www.wordle.net/gallery/wrdl/760468/OpenJPA_Word_Cloud_Iteration_2">here</a></p> Pinaki Poddarhttp://www.blogger.com/profile/16073196638530017268noreply@blogger.com0tag:blogger.com,1999:blog-984759404111508297.post-72543666170379859602009-04-14T10:30:00.003-05:002009-04-14T10:33:36.982-05:00OpenJPA Enhancement Eclipse BuilderAs I wrote about in a previous <a title="blog posts" target="_blank" href="http://webspherepersistence.blogspot.com/2009/02/openjpa-enhancement.html" id="gldb">blog post</a>, enhancement is HIGHLY recommended when developing an application that uses OpenJPA. The OpenJPA community has been vigilant about trying to cover every enhancement scenario, but after my last posting a reader brought up new somewhat uncovered situation. I say somewhat, because I'm sure the user could have enhanced using one of the existing methods, but it would not have been pretty. My understanding is that they are using Eclipse WTP to write and deploy their application, and orm.xml to map their Entities. We have the first two variants covered with an <a title="eclipse plugin" target="_blank" href="http://people.apache.org/%7Eppoddar/eclipse/index.html" id="i_.f">Eclipse plugin</a>, but the third is something that we have not addressed. I did some research and found that creating a custom Ant builder may be the perfect fit. This builder will be executed by Eclipse after compilation has completed. Below I've documented the steps required to create an Ant builder that will enhance your Entities after each compile.<br /><br />Please contact me with any questions/comments.<br /><br />-Rick<br /><br />For steps documented below, I have the following directory structure. <b>Note, these steps must be followed for each project that has Entities that need to be enhanced. </b><br /><div style="margin-left: 40px;">/<b>builder_project</b><br /> enhance.xml <- the OpenJPA builder.... download <a title="here" target="_blank" href="http://filebin.ca/zbfbg/enhance.xml" id="xkxr">here</a>.<br /> /<b>bin</b> <- Compile directory<br /> /src <- Source directory<br /> /<b>jpa_lib</b> <- OpenJPA binary and all jars from the lib dir of the binary download<br /> commons-collections-3.2.jar<br /> commons-lang-2.1.jar<br /> commons-pool-1.3.jar<br /> derby-10.2.2.0.jar<br /> geronimo-jpa_2.0_spec-1.0-EA-SNAPSHOT.jar<br /> geronimo-jta_1.1_spec-1.1.1.jar<br /> openjpa-2.0.0-SNAPSHOT.jar<br /> serp-1.13.1.jar<br /> /lib <- other libs<br /><br /></div><ol><li>After you add the enhance.xml file to your file system, make sure to refresh your Eclipse workspace so it knows about the newly added file. Make sure that the enhance.xml file is listed in the Navigator view.<br /></li><li>Right click on the Eclipse project that you want to enhance and click on properties.</li><li>Click on the builders filter, and create a new Ant builder.</li><li>Name your builder, then click on "Browse Workspace" in the buildfile box. If you downloaded the enhance.xml file and refreshed your workspace, it should be listed there. If not, go back to step 1 and make sure that Eclipse detects your enhance.xml file.<br /></li><li>In the "Base Directory" box, click on the variables button and select build_project. This <b>should</b> refer to the root of your project. In the directory structure above, it refers to "<b>builder_project</b>".<br /></li><li>In the "Arguments" box you need to add the following properties -Dopenjpa.libs and -Dbuild.dir. -Dopenjpa.libs is the path to the OpenJPA libs, relative to the root of the project. -Dbuild.dir is the path to the build directory, relative to the root of the project. In the directory structure above, openjpa.libs should be set to <b>jpa_lib</b> and build.dir should be set to <b>bin</b>.<br /></li><li>Click on the "Targets" tab along the top.</li><li>You need to set the enhance target to run as a part of "<b>Manual Build</b>" and "<b>Auto Build</b>".<br /></li></ol><br />Screenshots:<div id="vxhb" style="text-align: left;"><img style="width: 441px; height: 387px;" src="http://docs.google.com/File?id=dddf94sx_18djbbmnfm_b" /><br /><br /></div><div id="zcgd" style="text-align: left;"><img style="width: 600px; height: 491px;" src="http://docs.google.com/File?id=dddf94sx_16ctnkhqdm_b" /><br /><br /></div><div id="h59g" style="text-align: left;"><img style="width: 600px; height: 490px;" src="http://docs.google.com/File?id=dddf94sx_17d4tszjhf_b" /></div><br />Files:<br />[1]<a href="http://filebin.ca/zbfbg/enhance.xml">http://filebin.ca/zbfbg/enhance.xml</a> -- enhance.xml<br />[2]<a href="http://filebin.ca/aayeg/navigator.png">http://filebin.ca/aayeg/navigator.png</a> -- Navigator pane<br />[3]<a href="http://filebin.ca/cznvmv/main.png">http://filebin.ca/cznvmv/main.png</a> -- Edit builder configuration - main<br />[4]<a href="http://filebin.ca/fqnadv/targets.png">http://filebin.ca/fqnadv/targets.png</a> -- Edit builder configuration - targetsRick Curtishttp://www.blogger.com/profile/10356648465322267003noreply@blogger.com4tag:blogger.com,1999:blog-984759404111508297.post-21610108760427213932009-03-19T02:54:00.001-05:002009-03-19T02:54:43.708-05:00Jazz and Software Development<p>Jazz is said to be the fundamental rhythms of human life and man’s contemporary reassessment of his traditional values. The ancient beats and rhythms of Africa found a contemporary expression in the new world of New Orleans around early twentieth century. Often music historians spoke about undefinable quality of Jazz. Louis Armstrong -- one of the greatest Jazz musician ever - put is succinctly : "If you gotta ask, you’ll never know". The unscripted collaboration where every man plays his own tune but responds and respects others' -- is the core theme that gave rise to this uniquely American contribution to music. </p> <p>It is intriguing that the new software collaboration platform built on Eclipse from contributions by pioneers such as Erich Gamma is named Jazz. Naming is very important. Naming captures aspiration. A software engineer as great as Erich Gamma can foresee the evolution of software development practices or at least where he wants it to go. Building software is playing Jazz -- not Orchestra. </p> Pinaki Poddarhttp://www.blogger.com/profile/16073196638530017268noreply@blogger.com1tag:blogger.com,1999:blog-984759404111508297.post-38005485739578449842009-02-22T20:13:00.001-06:002009-02-22T20:13:30.047-06:00Dynamic Fetch Planning<p>Now I have heard this before:</p> <blockquote> <p>    <em> "Hibernate can do X, can your thing do X?"</em></p> </blockquote> <p>I mumble in a me-too manner. Because Hibernate, as the world knows, is 42 -- the answer to the eternal question. Also I have seen many postings in OpenJPA's own mailing list that can be paraphrased as: "We are migrating our Hibernate application to OpenJPA, but we could do X with Hibernate, OpenJPA does not seem to be able to do X". Or a slight variation on the theme: "This test fails with OpenJPA. But it passes with Hibernate". </p> <p>As a contributor to OpenJPA, this implied second-class status irks me at times (I also wonder: why are they migrating <em>away from</em> Hibernate anyway?). So when the following email from an unknown sender reached my mailbox -- I smiled. The mail says:</p> <blockquote> <p><em>"We are working in investment banking's IT sector. We have a requirement X that Hibernate can not support. Can OpenJPA do X?"</em></p> </blockquote> <p>Firstly, I was happy to note that OpenJPA can do X very well.</p> <p>Secondly, the proposal to include feature X to JPA 2.0 Specification was simply ignored. </p> <p>Thirdly, investment banking's IT is the bellwether of enterprise technology trends and demands. </p> <p>I must admit that I do not know Hibernate deep enough to ascertain that it can or can not do X -- I am just going by the sender's comments. </p> <p>So what is this feature X? It is called <strong>Dynamic FetchPlan</strong>. </p> <p>The conventional wisdom is to mix fetch plan with query. This wisdom is rooted in the history of SQL -- where projection and selection criteria appear together in an all-encompassing SQL statement (I have heard stories of a single SQL statement being 2000 lines long). JPA took the same route -- its query language JPQL introduced FETCH JOIN which lets you specify what instances (that are not directly part of the projected result) will be brought in the memory as a side-effect of query execution. </p> <p>While OpenJPA supports fetch join as per JPA specification -- OpenJPA prefers to separate these two concerns, namely: i) what is selected and ii) what is fetched. Because fetch plan is independently specified, you can issue a simple <font face="Courier New" size="2">EntityManager.find(Company.class, "acme.org") </font>-- and as a result the persistent context may either  be populated with a single Company instance or with all the Departments and all the Employees of those Departments with their Addresses and Spouses' names. It all depends on what fetch plan is active while you invoked <font face="Courier New" size="2">EntityManager.find()</font>. In one end of the spectrum, you can use basic default fetch plan which fetches the fields of primitive types but no relations. On the other end, you can be as creative as you wish to specify a sub-graph of the complete closure starting from a root Company instance. And you can specify these fetch plans during design, use them and edit them at runtime. </p> <p>But why should you care to carve out a sub-graph from a root entity? Why does OpenJPA use fetch plan as a pervasive notion throughout its internal design? Why even the question may be worth pondering?</p> <p>My take on it will take a separate post -- more importantly Oscar is starting in TV.... </p> Pinaki Poddarhttp://www.blogger.com/profile/16073196638530017268noreply@blogger.com6tag:blogger.com,1999:blog-984759404111508297.post-38346039794553458582009-02-12T16:58:00.005-06:002013-03-25T13:39:17.447-05:00OpenJPA Enhancement<span style="font-size: medium;"><b>What is Enhancement Anyway? </b></span><br />
<br />
I have cruised around the OpenJPA <a href="http://openjpa.208410.n2.nabble.com/" id="i-tp" target="_blank" title="forums">forums</a> enough to notice that numerous new developers have posted questions regarding enhancement. Since I'm new to OpenJPA myself, I figured I'd dive in to enhancement and see what all the fuss is about. This post is directed mainly at developers that are taking a first look at OpenJPA and having problems getting started. No worries for those of you deploying an application to run in a Java EE 5 compliant application server such as WebSphere Application Server because your Entities will be automatically enhanced at runtime. <strike></strike><span style="color: #351c75;"></span><br />
<br />
As I was exploring how to enhance, I started to wonder why do I need to enhance at all? As it turns out the JPA spec requires some type of monitoring of Entity objects, but the spec does not define how to implement this monitoring. Some JPA providers auto-generate new subclasses or proxy objects that front the user's Entity objects, while others like OpenJPA use byte-code weaving technologies to enhance the actual Entity class objects. Now that we've got that out of the way, lets get back to <b>how</b> to do the enhancement. I'm going to give runtime examples first, as I feel those are the easiest from a developers point of view.<br />
<br />
<b>Runtime enhancement-</b>When running in a JSE environment or in a non EE-5 compliant container, OpenJPA defaults to using <i>subclassing </i>enhancement. The <i><b>subclassing</b></i> enhancement support was added originally as a convenience to new developers to reduce the amount of work to get a 'HelloWorld-ish' OpenJPA application working out of the box. It was never meant to run in production. So you're probably thinking that this sounds great! OpenJPA handles enhancement automatically for me and I can stop reading this post. <b>Wrong!</b> Subclassing has two <b>major </b>drawbacks. First off, it isn't nearly as fast as byte-code enhancement and the second drawback is that there are some documented functional problems when using the subclassing support. <b>The moral of the story is, don't use this method of enhancement.</b> I'm not the only one making this recommendation as I've come across <a href="http://openjpa.markmail.org/thread/exzjoufkiqnwiuxj#query:+page:1+mid:bxpe66qvrs6gxue7+state:results" id="ec2l" target="_blank" title="form posts">form posts</a> about removing subclassing enhancement as the default OpenJPA behavior. Additional information regarding the subclassing enhancement can be found <a href="http://ci.apache.org/projects/openjpa/trunk/docbook/manual.html#ref_guide_pc_enhance_unenhanced_types" id="mrdn" target="_blank" title="here">here</a>. <br />
<br />
The second and <b>recommended </b>way get runtime enhancement is to provide a javaagent when launching the JVM that OpenJPA is going run in. This is the method that I use in most of my test environments because it is very painless. All that is required to get runtime enhancement in Eclipse is to specify the -javaagent:[open_jpa_jar_location] on the Run Configuration page. <b>That is it.</b><br />
<br />
Another simple way to get runtime enhancement is to specify the the -javaagent when launching an application from ant. Below is a snippet from my build.xml that shows how to pass the -javaagent when launching a JSE application that uses OpenJPA. <span style="background-color: yellow;"></span><br />
<blockquote>
<path id="jpa.enhancement.classpath"><br />
<pathelement location="bin"/><br />
<!-- lib contains all of the jars that came with the OpenJPA binary download --><br />
<fileset dir="lib"><br />
<include name="**/*.jar"/><br />
</fileset><br />
</path><br />
...<br />
<target name="drive" depends="clean, build"><br />
<echo message="Running test with run time enhancement."/><br />
<java classname="main.Driver" failonerror="true" fork="yes"><br />
<b><jvmarg value="-javaagent:${openJPA-jar}"/></b><br />
<classpath refid="jpa.enhancement.classpath"/><br />
</java><br />
</target><br />
<br /></blockquote>
<b>Buildtime enhancement -</b><br />
In this section I'm going to cover how to invoke the build time enhancer ant task that is packaged with OpenJPA through the use of ant and maven. Yes there are many different ways to buildtime enhancement bliss, but I'm only going to talk about using the ant task. Note that this entire section assumes you're running the ant/maven scripts from a command line. I can't say for certian how this works inside Eclipse. <b>Warning</b>: I'm not a maven wizard, so please be nice if I've commited some cardinal maven sin. :-)<br />
<br />
I'll start first by showing how to define a OpenJPA enhancer task and how to invoke the task in ant. I had to fumble a little to get it working, but overall it was pretty straight forward. First you'll need to compile the Entites. (Note: as a prereq to running the enhance task, I copied my persistence.xml file to my /build directory. You might not need to do this, but the persistence.xml has to be in the classpath.) Next you'll need to configure the enhancer task and a classpath where the task can be found.(Adding the classpath is the part that the OpenJPA manual missed.) The final step is to call the enhance task. A snippet is provided below.<b><span style="color: #351c75;"></span></b><br />
<blockquote>
<path id="jpa.enhancement.classpath"><br />
<pathelement location="bin"/><br />
<br />
<!-- lib contains all of the jars that came with the OpenJPA binary download --><br />
<fileset dir="lib"><br />
<include name="**/*.jar"/><br />
</fileset><br />
</path><br />
<br />
<br />
<target name="enhance" depends="build"><br />
<!-- This is a bit of a hack, but I needed to copy the persistence.xml file from my src dir<br />
to the build dir when we run enhancement --><br />
<copy includeemptydirs="false" todir="bin"><br />
<fileset dir="src" excludes="**/*.launch, **/*.java"/><br />
</copy><br />
<br />
<br />
<!-- define the openjpac task --><br />
<taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask"><br />
<classpath refid="jpa.enhancement.classpath"/><br />
</taskdef><br />
<br />
<!-- invoke enhancer the enhancer --><br />
<openjpac><br />
<classpath refid="jpa.enhancement.classpath"/><br />
</openjpac><br />
<echo message="Enhancing complete."/><br />
</target></blockquote>
The second(different) path to build time enhancement is to use the maven antrun plug-in to launch the OpenJPA enhancer task. Since I'm new to maven this road was pretty clunky, but the steps were nearly identical to running directly in ant. I'll include the parts from my pom.xml that took the most time to figure out. Again, I'm not sure if you will need to move the persistence.xml file to the build directory, but I did(I assume I'm not doing something right).<br />
<blockquote>
<build><br />
<!-- Copy the persistence.xml file to the build dir --><br />
<b style="color: black;"><!-- You can skip this step if you put the persistence.xml in src/main/resources/META-INF instead of src/main/java/META-INF --></b><br />
<resources><br />
<resource><br />
<directory> src/main/java </directory><br />
<includes><br />
<include> **/*.xml </include><br />
</includes><br />
</resource><br />
</resources><br />
<plugins><br />
..... <br />
<plugin><br />
<groupId>org.apache.maven.plugins</groupId><br />
<artifactId>maven-antrun-plugin</artifactId><br />
<version>1.2</version><br />
<executions><br />
<execution><br />
<phase>process-classes</phase><br />
<configuration><br />
<tasks><br />
<taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask" classpathref="maven.compile.classpath"/><br />
<openjpac><br />
<classpath refid="maven.compile.classpath"/><br />
</openjpac><br />
</tasks><br />
</configuration><br />
<goals><br />
<goal>run</goal><br />
</goals><br />
</execution><br />
</executions><br />
</plugin> <br />
</plugins><br />
....<br />
</build></blockquote>
Hopefully this helps someone out there! Feel free to contact me if you have any questions/comments/suggestions. <br />
<br />
-RickRick Curtishttp://www.blogger.com/profile/10356648465322267003noreply@blogger.com200tag:blogger.com,1999:blog-984759404111508297.post-36610224327928986122009-02-03T16:34:00.004-06:002009-02-03T16:52:11.338-06:00The problem with JPA and Java persistence in general...Hi,<br />I just came across another <a href="http://www.devwebsphere.com/devwebsphere/2009/02/the-problem-with-jpa-and-java-persistence-in-general.html">interesting article</a> from a colleague of mine (Billy Newport). Billy has a very active blog on lots of different topics related to Java Development (and a few items not related to programming in the least). But, this one caught my eye due to the title, "The problem with JPA and Java persistence in general..." Surprised by my attention? :-)<br /><br />I'm not going to try to steal Billy's thunder. If you are interested in debating Billy's viewpoints, you are more than welcome to do so via his blog. I just thought that the content may be of interest to the readers of this blog, so I thought I would cross-post it.<br /><br />But... I would like to comment that I think the Java EE community has made some great strides in the area of persistence. Not all of the attempts have been welcomed with open arms (ie. CMP Beans), but we really seem to be getting acceptance with the JPA approach. There are several fully-functional implementations of the JPA 1.0 specification, and the JPA 2.0 expert group is extremely active finalizing the next revision of the spec.<br /><br />So, let me just ask for general comments or suggestions for a Java persistence solution. Is JPA satisfying your persistence needs? What about WebSphere's JPA solution based on OpenJPA? If you are not using it, why not? And, what are you using instead? CMP beans? Straight JDBC? Hibernate? Something else?<br /><br />Thanks,<br />Kevin<br /><br /><br /><br /><span style="font-weight: bold;"></span>Kevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com4tag:blogger.com,1999:blog-984759404111508297.post-69015905242902654442009-02-02T14:58:00.006-06:002011-03-01T10:50:13.236-06:00OpenJPA and pureQueryThere's a hidden gem in WebSphere V7 that many of you may not know about. If you're looking for a way to improve performance of database-intensive applications that access DB2, you should probably take a look, especially if you're using z/OS and are looking to drive down CPU costs.<br /><br />In WebSphere Application Server V7, we deliver an enhanced Java Persistence API (JPA) implementation that supports static SQL access to DB2.. This may not mean much to you, but your DB2 DBAs will certainly understand the implications of this. In general, Java database access, whether through JDBC or OpenJPA is all dynamic SQL. From a security and performance perspective, static SQL can be better. For some applications, it can be significantly better.<br /><br />For those of you who have never heard of static SQL, Figure 1 says it all - static SQL is basically preprocessed so all the database access processing does not have to happen when real users are using the application. As well as reducing processing time, it also means that performance stays more consistent. There is no up and down of performance based on whether the query is in the SQL statement cache or not.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB_SrwsI6S4FwF41MBiwYaP6lJe5OREsepZwo73Fj7_vQogpwqX_86jhZaqUgBQEdl-ciGZpwF9LiJDaci6axFfCekJtLbjzcn9kaf5J8TT2Tb3eB31TM07oDmMSN2Je8oLovAG0IRXdY/s1600-h/StaticSQL.JPG"><img style="TEXT-ALIGN: center; MARGIN: 0px auto 10px; WIDTH: 400px; DISPLAY: block; HEIGHT: 280px; CURSOR: pointer" id="BLOGGER_PHOTO_ID_5298315050367657410" border="0" alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhB_SrwsI6S4FwF41MBiwYaP6lJe5OREsepZwo73Fj7_vQogpwqX_86jhZaqUgBQEdl-ciGZpwF9LiJDaci6axFfCekJtLbjzcn9kaf5J8TT2Tb3eB31TM07oDmMSN2Je8oLovAG0IRXdY/s400/StaticSQL.JPG" /></a>To take advantage of this feature, you don't need to change anything about your JPA application; however you do need to have the pureQuery Runtime. WebSphere AS provides the utility that generates the SQL from the persistence unit along and for any JPA named queries. For more on how to actually do this, see <a href="http://www.ibm.com/developerworks/websphere/techjournal/0812_wang/0812_wang.html">this article</a> in the WebSphere Tech journal.<br /><br />You can see some performance results of using static SQL with pureQuery in <a href="http://www.ibm.com/developerworks/data/library/dmmag/DBMag_2008_Issue2/pureQueryRuntime/index.html">this article</a>. More background material on Static SQL can also be found in <a href="http://www.ibm.com/developerworks/data/library/dmmag/DBMag_2008_Issue2/NoExcusesDB/index.html">this article</a>.<br /><br />To find out more about how pureQuery can work together with WebSphere to reduce costs and improve quality of service, be sure to tune in to <a href="http://www-01.ibm.com/software/os/systemz/telecon/feb4/?S_TACT=105AGX01&S_CMP=LP">this webcast</a>, presented by my colleague in pureQuery-land, Steve Brodsky. You can also read <a href="http://www.ibm.com/developerworks/blogs/page/datastudioteam?tag=jpa">his blog entry</a> on the pureQuery and OpenJPA integration.<br /><br />Enjoy,<br />KevinKevin Sutterhttp://www.blogger.com/profile/03501598040442845034noreply@blogger.com4tag:blogger.com,1999:blog-984759404111508297.post-25280105878306679532009-01-22T14:50:00.011-06:002012-07-19T14:19:26.821-05:00JPA Connection Pooling<span style="font-size: 100%;">OpenJPA does not use any kind of connection pooling out of the box, but no worries for those of you using openJPA on WebSphere. When running on WebSphere, the application server provides production-quality connection pooling. That is great if your application runs on WAS, not so great otherwise. Since I haven't found a *good* reason why anyone would run without connection pooling, it seems like a good topic for a first post.<br /><br />Modifying an existing application to use connection pooling couldn't be easier. To start, you're going to need to download the Apache Commons <a href="http://commons.apache.org/pool/">Pool </a> and <a href="http://commons.apache.org/dbcp/">DBCP </a> components and add them to your application classpath. Next you will need to update the application database connection properties. Below is an example openJPA configuration using DBCP. You will need to update the connection info where appropriate if using a different DB. Note that these properties are being set in the META-INF/persistence.xml file, but you can also set the JVM system properties directly.<br /><span style="font-size: 85%;"></span></span><br />
<blockquote>
<span style="font-size: 100%;"><span style="font-size: 85%;"><property name="openjpa.ConnectionDriverName" value="org.apache.commons.dbcp.BasicDataSource"/></span></span><br />
<span style="font-size: 100%;"><span style="font-size: 85%;"><property name="openjpa.ConnectionProperties" value="DriverClassName=com.mysql.jdbc.Driver,Url=jdbc:mysql://localhost/test,Username=root,Password=password"/></span></span></blockquote>
<span style="font-size: 100%;">Configuring openJPA to use connection pooling is as simple as that. I created a small JSE application for this post that uses both pooled and non-pooled connections to do 1000 selects on an empty table. Even though the example is very simple, the results are pretty impressive.</span><br />
<ul>
<li><span style="font-size: 100%;"> 1000 selects with no connection pooling took ~23.469 seconds.</span></li>
<li><span style="font-size: 100%;"> 1000 selects with connection pooling took ~1.234 seconds.</span></li>
</ul>
<span style="font-size: 100%;">-Rick</span>Rick Curtishttp://www.blogger.com/profile/10356648465322267003noreply@blogger.com5tag:blogger.com,1999:blog-984759404111508297.post-35907377285958190562009-01-13T01:35:00.002-06:002009-02-18T12:48:12.234-06:00Auditing with OpenJPA<p>A transactional application often requires to audit the persistent entities. In this brief example, I will present a small code example to outline how an application can audit changes via the life cycle callback methods. The JPA specification prescribes how an entity or a separate, stateless entity listener instance can receive callback notification during various life cycle state transition of an entity. Seven transition events are defined: PrePersist, PostPersist, PreRemove, PostRemove, PreUpdate, PostUpdate and PostLoad. To receive these callbacks either annotate certain methods a) of the entity class itself or b) of a separate entity listener class. The signature of the method in the entity class itself should be</p><pre class="csharpcode"><span class="kwrd">void</span> <METHOD>()</pre><style type="text/css">br /><br /><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: consolas, "Courier New", courier, monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br />.csharpcode pre { margin: 0em; }<br />.csharpcode .rem { color: #008000; }<br />.csharpcode .kwrd { color: #0000ff; }<br />.csharpcode .str { color: #006080; }<br />.csharpcode .op { color: #0000c0; }<br />.csharpcode .preproc { color: #cc6633; }<br />.csharpcode .asp { background-color: #ffff00; }<br />.csharpcode .html { color: #800000; }<br />.csharpcode .attr { color: #ff0000; }<br />.csharpcode .alt <br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br />.csharpcode .lnum { color: #606060; }</style>Whereas, callback methods defined on an entity listener class have the following signature<pre class="csharpcode"><span class="kwrd">void</span> <METHOD>(Object pc)</pre>In the later case, the managed entity is passed as an argument.<br /><p>Given this basic framework, how can we implement audit facility such that an application can track any update made on a persistent entity? Of course, to compute this change, the application must be able to access the entity state before and after the update. The central question is:</p><br /><center>how can an application access the <em>previous</em> state of an entity inside a callback method?</center><br /><p>The answer lies in the fact that OpenJPA can store the state of an entity as it enters the managed lifecycle. This internal copy is used by OpenJPA when a transaction is rolled back. The state of the entities participating in the failed transaction is restored to the original state i.e. as it were before the transaction started. The simple example presented here shows how to access that copy. Of course, a real audit facility has to figure out how to compute the difference between the current and previous state of an entity and where to record those differences. </p>Let us consider a simple persistent instance, audit.<code>PObject</code>.<br /><div class="csharpcode"><pre><span class="lnum"> 1: </span>package audit;<br /><span class="lnum"> 2: </span><br /> <span class="lnum"> 3: </span>import javax.persistence.Entity;<br /> <span class="lnum"> 4: </span>import javax.persistence.Id;<br /> <span class="lnum"> 5: </span>import javax.persistence.PostUpdate;<br /> <span class="lnum"> 6: </span><br /> <span class="lnum"> 7: </span>import org.apache.openjpa.enhance.PersistenceCapable;<br /> <span class="lnum"> 8: </span>import org.apache.openjpa.kernel.SaveFieldManager;<br /> <span class="lnum"> 9: </span>import org.apache.openjpa.kernel.StateManagerImpl;<br /><span class="lnum"> 10: </span><br /><span class="lnum"> 11: </span>@Entity<br /><span class="lnum"> 12: </span><span class="kwrd">public</span> <span class="kwrd">class</span> PObject {<br /><span class="lnum"> 13: </span> @Id<br /><span class="lnum"> 14: </span> <span class="kwrd">private</span> <span class="kwrd">long</span> id;<br /><span class="lnum"> 15: </span> <br /><span class="lnum"> 16: </span> <span class="kwrd">private</span> String name;<br /><span class="lnum"> 17: </span><br /><span class="lnum"> 18: </span> <span class="kwrd">public</span> <span class="kwrd">long</span> getId() {<br /><span class="lnum"> 19: </span> <span class="kwrd">return</span> id;<br /><span class="lnum"> 20: </span> }<br /><span class="lnum"> 21: </span><br /><span class="lnum"> 22: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> setId(<span class="kwrd">long</span> id) {<br /><span class="lnum"> 23: </span> <span class="kwrd">this</span>.id = id;<br /><span class="lnum"> 24: </span> }<br /><span class="lnum"> 25: </span><br /><span class="lnum"> 26: </span> <span class="kwrd">public</span> String getName() {<br /><span class="lnum"> 27: </span> <span class="kwrd">return</span> name;<br /><span class="lnum"> 28: </span> }<br /><span class="lnum"> 29: </span><br /><span class="lnum"> 30: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> setName(String name) {<br /><span class="lnum"> 31: </span> <span class="kwrd">this</span>.name = name;<br /><span class="lnum"> 32: </span> }<br /><span class="lnum"> 33: </span> <br /><span class="lnum"> 34: </span> @PostUpdate<br /><span class="lnum"> 35: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> audit() {<br /><span class="lnum"> 36: </span> PersistenceCapable currentState = (PersistenceCapable)<span class="kwrd">this</span>;<br /><span class="lnum"> 37: </span> StateManagerImpl sm = (StateManagerImpl)currentState.pcGetStateManager();<br /><span class="lnum"> 38: </span> SaveFieldManager sfm = sm.getSaveFieldManager();<br /><span class="lnum"> 39: </span> PersistenceCapable oldState = sfm.getState();<br /><span class="lnum"> 40: </span> PObject old = (PObject)oldState;<br /><span class="lnum"> 41: </span> <br /><span class="lnum"> 42: </span> System.err.println(<span class="str">"old : "</span> + old);<br /><span class="lnum"> 43: </span> System.err.println(<span class="str">"current : "</span> + <span class="kwrd">this</span>);<br /><span class="lnum"> 44: </span> }<br /><span class="lnum"> 45: </span> <br /><span class="lnum"> 46: </span> <span class="kwrd">public</span> String toString() {<br /><span class="lnum"> 47: </span> <span class="kwrd">return</span> <span class="kwrd">this</span>.getClass().getName()+<span class="str">"@"<br /></span><span class="lnum"> 48: </span> + Integer.toHexString(System.identityHashCode(<span class="kwrd">this</span>))<br /><span class="lnum"> 49: </span> + <span class="str">"["</span> + name +<span class="str">"]"</span>;<br /><span class="lnum"> 50: </span> }<br /><span class="lnum"> 51: </span>}</pre></div>The meat is in audit() method annotated with @PostUpdate to receive the callback notification. Now, within the method body, following steps are carried out to access the previous state of the instance.<br /><p>Line 36: Cast this instance to org.apache.openjpa.enhance.PersistenceCapable interface. The cast is safe. Because OpenJPA ensures that every persistent class implements PersistenceCapable. OpenJPA actually modifies original bytecode of audit.PObject class. This bytecode modification process is called enhancement and is described in detail in OpenJPA documentation. </p>Line 37: Get the StateManager. Every PersistenceCapable instance is managed by a StateManager. It is the StateManager who intercepts every access and mutation of entity state and calls the requisite underlying OpenJPA infrastructure to load or store the state of an entity which in turn may access the database via JDBC.<br /><p>Line 38: Get the SaveFieldManager. A StateManager may refer to a SaveFieldManager to which StateManager delegates the task of maintaining a copy of managed instance.</p>Line 39: Get the old state. The old state is maintained by the SaveFieldManager.<br /><p>Line 40: Cast is back to audit.PObject. This entity refers to the state of PObject as it entered a transaction.</p>At this point, a real audit application perhaps will do some sort of state comparison to determine what has changed between current and the previous state of this instance. I am just printing their values on the console.<br /><p>Now let us write a simple "Hellow JPA World" style application to check that the callback is received. I am omitting the scaffolding code to get a JPA EntityManagerFactory etcetera and just listing the transactional method.</p><br /><div class="csharpcode"><pre><span class="lnum"> 1: </span> <span class="kwrd">public</span> <span class="kwrd">void</span> testPostPersistCallabck() {<br /> <span class="lnum"> 2: </span> EntityManager em = emf.createEntityManager();<br /> <span class="lnum"> 3: </span> em.getTransaction().begin();<br /> <span class="lnum"> 4: </span> PObject pc = <span class="kwrd">new</span> PObject();<br /> <span class="lnum"> 5: </span> pc.setId(1001);<br /> <span class="lnum"> 6: </span> pc.setName(<span class="str">"X"</span>);<br /><span class="lnum"> 7: </span> em.persist(pc);<br /> <span class="lnum"> 8: </span> em.getTransaction().commit();<br /><span class="lnum"> 9: </span> Object pid = pc.getId();<br /><span class="lnum"> 10: </span> em.clear();<br /><span class="lnum"> 11: </span> <br /><span class="lnum"> 12: </span> em = emf.createEntityManager();<br /><span class="lnum"> 13: </span> em.getTransaction().begin();<br /><span class="lnum"> 14: </span> PObject audit = em.find(PObject.<span class="kwrd">class</span>, pid);<br /><span class="lnum"> 15: </span> audit.setName(<span class="str">"Y"</span>);<br /><span class="lnum"> 16: </span> em.getTransaction().commit();<br /><span class="lnum"> 17: </span> }</pre></div>When this code runs on my laptop against a MySQL database, that is what it prints out (hand-edited to show only the generated SQL and System.err.println() output)<pre class="csharpcode">203 test INFO [main] openjpa.jdbc.JDBC - Using dictionary <span class="kwrd">class</span> <span class="str">"org.apache.openjpa.jdbc.sql.MySQLDictionary"</span>.<br />1078 test TRACE [main] openjpa.jdbc.SQL - <t 21933769, conn 11875256> executing prepstmnt 7245716 INSERT INTO PObject (id, name) VALUES (?, ?) [<span class="kwrd">params</span>=(<span class="kwrd">long</span>) 1001, (String) X]<br />1156 test TRACE [main] openjpa.jdbc.SQL - <t 21933769, conn 23978087> executing prepstmnt 1440568 SELECT t0.name FROM PObject t0 WHERE t0.id = ? [<span class="kwrd">params</span>=(<span class="kwrd">long</span>) 1001]<br />1172 test TRACE [main] openjpa.jdbc.SQL - <t 21933769, conn 14837200> executing prepstmnt 30702379 UPDATE PObject SET name = ? WHERE id = ? [<span class="kwrd">params</span>=(String) Y, (<span class="kwrd">long</span>) 1001]<br /><br />old : audit.PObject@1581e80[X]<br />current : audit.PObject@3a9d95[Y]</pre><style type="text/css">r /><br /><br /><br /><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: consolas, "Courier New", courier, monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br />.csharpcode pre { margin: 0em; }<br />.csharpcode .rem { color: #008000; }<br />.csharpcode .kwrd { color: #0000ff; }<br />.csharpcode .str { color: #006080; }<br />.csharpcode .op { color: #0000c0; }<br />.csharpcode .preproc { color: #cc6633; }<br />.csharpcode .asp { background-color: #ffff00; }<br />.csharpcode .html { color: #800000; }<br />.csharpcode .attr { color: #ff0000; }<br />.csharpcode .alt <br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br />.csharpcode .lnum { color: #606060; }</style>As the last two lines of log output shows, the audit() callback has been invoked and the method had printed the state of the instance as it were before its name is changed from "X" to "Y". <pre class="csharpcode">The two critical points before we close.</pre><ul><li><pre class="csharpcode">This technique only works with build-time enhancement.<br /></pre></li><li><pre class="csharpcode">OpenJPA must be configured to record the state of persistent entities participating in a transaction. This is specified by the following property:</pre></li></ul><pre class="csharpcode"> <property name=<span class="str">"openjpa.RestoreState"</span> <span class="kwrd">value</span>=<span class="str">"all"</span>/></pre><pre class="csharpcode"> </pre><pre class="csharpcode"> </pre><br /><style type="text/css"><br /><br /><br /><br /><br />.csharpcode, .csharpcode pre<br />{<br /> font-size: small;<br /> color: black;<br /> font-family: consolas, "Courier New", courier, monospace;<br /> background-color: #ffffff;<br /> /*white-space: pre;*/<br />}<br />.csharpcode pre { margin: 0em; }<br />.csharpcode .rem { color: #008000; }<br />.csharpcode .kwrd { color: #0000ff; }<br />.csharpcode .str { color: #006080; }<br />.csharpcode .op { color: #0000c0; }<br />.csharpcode .preproc { color: #cc6633; }<br />.csharpcode .asp { background-color: #ffff00; }<br />.csharpcode .html { color: #800000; }<br />.csharpcode .attr { color: #ff0000; }<br />.csharpcode .alt <br />{<br /> background-color: #f4f4f4;<br /> width: 100%;<br /> margin: 0em;<br />}<br />.csharpcode .lnum { color: #606060; }</style>Pinaki Poddarhttp://www.blogger.com/profile/16073196638530017268noreply@blogger.com19