par-tition your application

Posted by    |      

Packaging has always been a manual operation in ORM world. In Hibernate, you have to list the mapped entities either through the configuration API or through the hibernate.cfg.xml file. For a while now, JBoss AS has introduced the notion of .har, basically an archive scanned by the deployer to discover the Hibernate configuration and the hbm.xml files in it.

Packaging inside an EJB3 container

The EJB3 expert group has introduced the same notion in the EJB3 public draft. A PAR archive is basically a jar file having the .par extension. All you have to do is put all your annotated entities in the archive and the container has the responsibility to scan it and find all annotated entities. A PAR archive is a persistence unit definition that will be used to create an EntityManagerFactory (aka SessionFactory in the Hibernate world). You will then be able to use your persistence unit (by looking up or injecting an EntityManager or an EntityManagerFactory) named by the name of the PAR file without the extension (ie mypersistenceunit.par will be referred as mypersistenceunit).

Since you might want to customize your persistence unit configuration, a persistence.xml file can be added in the META-INF directory.

<?xml version="1.0" encoding="UTF-8"?>
<entity-manager>
   <name>FinancialPU</name>
   <provider>org.hibernate.ejb.HibernatePersistence</provider>
   <jta-data-source>jdbc/MyDB</jta-data-source>
   <class>com.acme.MyClass</class>
   <jar-file>externalEntities.jar</jar-file>
   <properties>
       <property name="hibernate.max_fetch_depth" value="4"/>
   </properties>
</entity-manager>

Let's analyze this small but comprehensive example.

The name element allows you to override the persistence unit name (defaulted to the PAR file name minor the .par suffix).

The provider element allows you to express the Entity Manager implementation you want to use for this persistence unit. The value is defaulted to Hibernate Entity Manager if none is specified. This is a interesting one, this basically means that you can use several Entity Manager implementations in the same application or use the Hibernate Entity Manager implementation in lieu of your vendor EJB3 persistence implementation in a standard way!

The jta-data-source aside with the non-jta-data-source let you specify the datasource the persistence unit will work onto.

The class element, allows you to add explicitly some entities to be mapped. These entities are typically outside of the PAR archive and the Entity Manager will search them in the EAR classpath. This is particularly convenient to be able to share the same entity definition across several persistence unit.

The jar-file element, allows you to ask the entity manager implementation to add all the entities contained in a particular JAR and include them in the configuration. In the case of the Hibernate Entity Manager, it will also look at the hbm.xml files. This is particularly convenient to share a certain amount of entities definitions across several persistence units.

There is also a mapping-file element currently not supported in Hibernate Entity Manager's implementation.

The properties elements is a way to provide some implementation specific properties to your entity manager. In the case of Hibernate you can add most of the hibernate.* properties. You can also define the second level cache informations using hibernate.ejb.classcache.* and hibernate.ejb.collectioncache.*, please refer to the reference documentation for more information.

This is good news for JBoss users, the .har archive is now standardized. The packaging that has always been a strong concept in J2EE is now extended to the ORM world in a very ease of use manner.

Packaging in J2SE environment

The very new point is that the PAR packaging simplicity works in the exact same manner in the J2SE world. The only difference is that you'll need to define your datasource not through the jta-data-source element but through the classic hibernate.* connection properties. The PAR archive is still scanned to find its contained entities and hbm.xml files. In order to let the Hibernate Entity Manager discover the PAR files, they need to have a persistence.xml file in the META-INF directory (Hibernate Entity Manager basically request any resources named META-INF/persistence.xml and deduces the PAR archive location from it).

Let's imagine the following acmedomainmodel.par archive structure

com/acme/model/Animal.class (an @Entity annotated class)
com/acme/model/Dog.class (an @Entity annotated class)
com/acme/model/Cat.class (an @Entity annotated class)
com/acme/model/Customer.class (a non annotated POJO)
com/acme/model/Customer.hbm.xml (the metadata definitions of Customer)
META-INF/persistence.xml

where persistence.xml is

<?xml version="1.0" encoding="UTF-8"?>
<entity-manager>
   <properties>
       <property name="hibernate.max_fetch_depth" value="4"/>
       <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
       <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
       <property name="hibernate.connection.username" value="emmanuel"/>
       <property name="hibernate.connection.password" value="secret"/>
       <property name="hibernate.connection.url" value="[=>jdbc:mysql:///test]"/>
       <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider"/>
   </properties>
</entity-manager>

My persistence unit named acmedomainmodel will then contains automatically Animal, Dog, Cat, Customer. Note that the Customer class don't really have to be in the PAR archive, it just need to be in the classpath as long as its hbm.xml definition itself is inside the PAR archive.

Note that you can tune the discovery mechanism through the hibernate.ejb.autodetection. The possible values are none (no auto detection), class (auto detection of the annotated entities), hbm (auto detection of the hbm files) and class,hbm (auto detection of both annotated entities and hbm files).

With a simple ant task you can then create a PAR archive which contains automatically your persistent domain model. No need to manually add the mapped entities inside the hibernate.cfg.xml file anymore.

Several persistent unit in my application

You can of course use several PARs archive in your application. The appropriate PAR archive will be processed based on the name your provide.

//create a keep the emf for later entity manager creations
EntityManagerFactory emf = Persistence.createEntityManagerFactory("acmedomainmodel");
...
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
em.persist(customer);
wolfy = em.find(Dog.class, wolfyId);
em.getTransaction().commit();
em.close();

Note that if there is only one PAR archive in your classpath, you don't have to pass the name to the createEntityManagerFactory() method, but is considered good practice however.

The PAR archive mechanism offers a very convenient and standard way to package your ORM persistent units. By its autodiscovery mechanism, the packaging setting up scales in a very elegant manner.


Back to top