Thursday, December 15, 2011

Persistence Configuration

As with all configurations, the configuration depends on the environment you are running in. For this project I wanted to run with as few Hibernate dependencies as possible even though I am using Hiberate as the persistence provider. With that in mind, there is NO hibernate.cfg.xml file. Hibernate can conform to JPA 2.0 (JSR 371). In addition, since I used Netbeans as the development environment, it automatically created a glassfish-resources.xml file. Although you can use this file, it is redundant from the settings we did in the last exercise when we set up the connection pool and data source connection. So, there is no glassfish-resources.xml file. We use the persistence.xml file for configuration. As a side note: I have seen configurations that use both the persistence.xml file and the hibernate.cfg.xml file. So, no the persistence.xml file is not the same as hibernate.cfg.xml, but it can be used as a replacement, or as a primary configuration file. The properties in the two files are similar, but not the same. This setup was simply to demonstrate an environment that does not use the cfg file even though we are using Hibernate.

It is important where we place this file. The directory structure is: JSFDemoApp.war/WEB-INF/classes/META-INF/persistence.xml

This, of course, assumes you are using a war file. If you are not, then the name of the war file will simply be the name of the root directory of your app. i.e.: JSFDemoApp/WEB-INF/classes/META-INF/persistence.xml

Let me present the xml file, and then we will discuss the parts.
persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="JSFDemoPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>JSFDemoJNDI</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/jsfdemodb"/>
<property name="javax.persistence.jdbc.password" value="ItWorks!"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="JSFDemoUser"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup"/>
</properties>
</persistence-unit>
<persistence-unit name="localTestingPU" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.sample.OrderEntity</class>
<class>com.sample.OrderPartsEntity</class>
<class>com.sample.PartEntity</class>
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value="ItWorks!"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/jsfdemodb"/>
<property name="hibernate.connection.username" value="JSFDemoUser"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>


Discussion:

Now with a brief perusal of the file, we will notice there are several duplicated entries. That is because there are two persistence units being defined here. One will be used by the JEE server, and one will be used when we do local testing.

The top of the file defines it as a well formed xml file and declares the namespace as a persistence file so it can be validated. Notice the version is 2.0 and the persistence_2_0.xsd corresponds to that version.

Each unit is started by the tag '<persistence-unit>'. You must then supply the name and the transaction manager type. The name will by used by the EntityManagerFactory to create the persistence connection. Notice, we will not use the SessionManagerFactory which is a hibernate specific method. The JEE container will also call the EntityManagerFactory to create its connections. The name will be passed to the container to tell it which unit to use. When testing, I chose not to use the imbedded glassfish container to emulate running under the JEE server, but chose to inject our own entity manager that the testing unit managed. Therefore, we needed a unit that did not depend on the container for its connections. As a side note: there is nothing stopping us from using both persistence units when testing, we would just have to implement the glassfish embedded container to do the JTA management.

When using the JEE container, we will use container managed transactions. These transactions are known as JTA. So in the JSFDemoPU we set the transaction-type to "JTA". Since we are managing our own transaction in the LocalTestingPU, we set the transaction-type to "RESOURCE_LOCAL".

The next like defines the provider for the JPA Entity Manager. Since we are using hibernate, we define it as: org.hibernate.ejb.HibernatePersistence. It is interesting to note that some JEE's only support Hibernate as the JPA Entity Manager. I'm sure that will change over time, but you may need to check your JEE to determine what Entity Managers are supported. Also note: since we are not using a JEE container for testing, this line is not required in the LocalTestingPU, even though it is there. It does no harm, and when I copied and pasted the PU, I forgot to remove it. Leaving it there only serves to facilitate the discussion.

The next line defines the JTA data source. This is the name we supplied earlier when creating the datasource. If this does not match, nothing will work. Again, this line is only for the JEE container. Under the local PU, we must remove that line.

The next section defines the classes that are managed by the entity manager. With the JEE server, it will automatically scan the classes for the JPA annotations, if you do not wish to do this, you would set the exclude-unlisted-classes to true, and then list each class. Since all the classes marked in our project are to be managed, I simply set it to false, and it will find them all. For the local PU, we do not have a JEE server that will scan the classes. We could use hibernate to do it for us, but that is a hibernate extension and not a JPA standard, so instead we list each class.

The next section are the property definitions. These properties are read by the EntityManagerFactory when creating the connection. Notice the difference between the LocalTestingPU and the JSFDemoPU. The local PU uses the hibernate specific properties, whereas the JEE PU uses the JPA standard properties. The JEE will convert the standard properties into hibernate specific properties as it calls hibernate. In addition, there are a couple properties that we set for Hibernate itself. These properties are accessible to Hibernate even though we have no hibernate.cfg.xml file.

Properties in the JEE PU:
hibernate.hbm2ddl.auto : When hibernate starts, it can automatically set the database to the entities it is managing.  It can drop the database and create it from scratch, it can update the database with any changes, it can validate the database, and it can even drop the database when it is done.  The property values area: create, update, validate, create-drop.  Recall that we setup the user we are going to connect to to have all the privileges for the schema we are using.  This allows us to define this setting as update so that we will create and or modify the tables as our code changes.  Obviously this is a dangerous thing to do in a production environment, but it is a wonderful development tool.

hibernate.current_session_context_class  : Tells hibernate we are in a JTA environment.

hibernate.transaction.manager_lookup_class : Because we are using JTA, we have to tell hibernate how to find the transaction being managed.  Each JEE server will have its own class.  For Glassfish, we use: org.hibernate.transaction.SunONETransactionManagerLookup.

javax.persistence.jdbc.driver : JPA 2.0 standard property for defining the jbdc provider.

hibernate.dialect : Tells hibernate to use the MySQL dialect.  Each database has its own specific dialect.
javax.persistence.jdbc.url : JPA 2.0 standard property for defining the location of the database.  Note: if you were running the JEE server on a different machine then the database server, you would put the host name in place of localhost.


 javax.persistence.jdbc.user : The user the entity manager will connect to the database as.

javax.persistence.jdbc.password : The password for the above user.

The Local PU properties are mostly the same, but intead of javax.persistence.jdbc. they use hibernate.connection.  Also the name of the property slightly changes, but the correlation is obvious.  username=user, etc.

Okay, so now we have configured our environment.  Right?  Well, not so fast.  We have configured our persistence environment.  But we still have to define the entities, set up facelets, etc.  At this point, we cannot even test what we have done.  The most we can do is connect via mysql -u JSFDemoUser -pItWorks! to see that we can connect.  But this doesn't test the persistence units, transactions, etc.  We could create a JUnit test to exercise the local PU, but that still doesn't test the container.

We will continue until we get far enough that we can test the whole environment.

No comments:

Post a Comment