Hibernate dynamic mapping and Dom4J enabled sessions

Hibernate from version 3.0? provide a very useful feature for people who develop application frameworks. Indeed this feature allows you to work directly with XML documents and elements which represent entities.
Imagine that you have an application or an SDK which help users to manipulate data from different RDBMSs. Hibernate provide rich configuration facilities which help you configure  Hibernate dynamically in term of adding mapping data or other configuration artifacts that usually stores in hibernate.cfg.xml or equal properties files.

As we are planning to use Hibernate dynamic mapping and Dom4J entity mode i am going to blog about it during my evaluation.
OK, Hibernate provide 3 kinds of entity mode

  • POJO
  • DOM4J
  • MAP

Default mode sets to be POJO as it is most commonly used mode. This modes tell session how it should handle entities. We can configure a session to use any of this modes when we need that mode, but we can configure it in hibernate configuration file for by adding a property like

 <property name="default_entity_mode">dom4j</property>

To hibernate.cfg.xml . but for our sample we will create a session with dom4j entity mode. you can find a complete sample for this blog entry here . Make sure that you read readme file in project folder before you go toward executing it. For this sample I used Netbeans 6.0 M6 (which really rules) and Hibernate 3.2.1 . I wont tell steps to create project, XML file or … but just actions and core required for hibernate side. you can see project structure in the following  image.

Hibernate dom4j session project structure

As you can see it is a basic ant based project.
Let me give you content of each file and explain about it as much as i could. First of all lets see what we have in hibernate.cfg.xml

 <?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration
 PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
 <hibernate-configuration>
     <session-factory >
         <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
         <property name="hibernate.connection.url">jdbc:mysql://localhost/hiberDynamic</property>
         <property name="hibernate.connection.username">root</property>
         <property name="hibernate.connection.password">root</property>
         <property name="hibernate.c3p0.min_size">5</property>
         <property name="hibernate.c3p0.max_size">20</property>
         <property name="hibernate.c3p0.timeout">300</property>
         <property name="hibernate.c3p0.max_statements">50</property>
         <property name="hibernate.c3p0.idle_test_period">3000</property>
         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
         <!--<property name="default_entity_mode">dom4j</property> -->
         <mapping resource="dynamic/Student.hbm.xml"/>
     </session-factory>
 </hibernate-configuration>


The configuration file is a simple and traditional hibernate configuration file with pooling enabled and  dialect sets to MySQL ones.
We have one mapping file which is named student.hbm.xml so we include it into the configuration file. If you do not have MySQL around then use Derby which is included into NetBeans 😉 .

 Log4J configuration is another traditional one, as you see
 log4j.appender.stdout=org.apache.log4j.FileAppender
 log4j.appender.stdout.File=messages_dynamic.log
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
 log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
 log4j.rootLogger=WARN, stdout
 

We used a file appender which send formatted log entry into a file named messages_dynamic.log in project root directory. next file which we are going to take a look is Student.hbm.xml  it is our mapping file, where we define the student as a dynamic entity.

 <?xml version="1.0"?>
 <!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

 <hibernate-mapping>
     <class  entity-name="Student" table="Student">
         <id name="id" column="STUDENT_ID" type="long">
             <generator class="native"/>
         </id>
         <property  name="name" type= "string"  column="STUDENT_NAME"/>
         <property name="lastName" type="string" column="STUDENT_LAST_NAME" />
     </class>
 </hibernate-mapping>

As you  can see there is just one change in  mapping file, we have entity-name attribute instead of class attribute. You should know that can have both class and entity-name attribute so an entity could be dynamic or mapped to a concrete class.

Next step is looking at our HibernateUtil which is known to the community for Hibernate booting and  hibernate instance management.
here is its code:


 package persistence;
 import org.hibernate.*;
 import org.hibernate.cfg.*;

 public class HibernateUtil {
   
     private static SessionFactory sessionFactory;
     static {
         try {
             sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
             throw new ExceptionInInitializerError(ex);
         }
     }
    
     public static SessionFactory getSessionFactory() {
         return sessionFactory;
     }
     public static void shutdown() {
        
         getSessionFactory().close();
     }
 }
 

Noting extra here. lets look at last part in which we try to use dom4j session to manipulate our data.

 package dynamic;
 import java.util.*;
 import org.hibernate.EntityMode;
 import org.hibernate.Query;
 import org.hibernate.Session;
 import org.hibernate.Transaction;
 import persistence.HibernateUtil;
 import org.dom4j.*;


 public class DynamicMapping {
    
     public static void main(String[] args) {
         Session session = HibernateUtil.getSessionFactory().openSession().getSession(EntityMode.DOM4J);
         Transaction tx = session.beginTransaction();
 Query deleteQuery = session.createQuery("delete from Student");
 deleteQuery.executeUpdate();
 tx.commit();

 tx = session.beginTransaction();
         //create some some student and save them
         {
             Element anStudent = DocumentHelper.createElement("Student");
             Element nameElement = DocumentHelper.createElement("name");
             nameElement.setText("Alice");
            
             Element lastNameElement = DocumentHelper.createElement("lastName");
             lastNameElement.setText("Cooper");
            
             anStudent.add(nameElement);
             anStudent.add(lastNameElement);
             session.save(anStudent);
         }
         {
             Element anStudent = DocumentHelper.createElement("Student");
             Element nameElement = DocumentHelper.createElement("name");
             nameElement.setText("Lea");
            
             Element lastNameElement = DocumentHelper.createElement("lastName");
             lastNameElement.setText("Connor");
            
             anStudent.add(nameElement);
             anStudent.add(lastNameElement);
             session.save(anStudent);
         }
        
         tx.commit();
         //List all student
         Query q = session.createQuery("from Student ");
        
         List students = q.list();
         org.dom4j.Element el = (org.dom4j.Element)students.get(0);
         System.out.println(el.getText());
         for (Iterator it = students.iterator(); it.hasNext();) {
             org.dom4j.Element student = (org.dom4j.Element)it.next();
            
            
             System.out.println("Printing an Student details: ");
            
             for ( Iterator i = student.elementIterator(); i.hasNext(); ) {
                 Element element = (Element) i.next();
                 System.out.println( element.getName()+":  "+ element.getText());
             }
         }
         //retrieve an student, update and save it
        
         q = session.createQuery("from Student where  name =:studentName ");
         q.setParameter("studentName", "Alice");
         Element alice = (Element) q.uniqueResult();
        
         alice.element("name").setText("No Alice any more");
         tx=session.beginTransaction();
         session.save(alice);
         tx.commit();
        
         session.close();
         HibernateUtil.shutdown();
     }
 }
 

In the begging we create a session with dom4j entity mode. so it will return Dom4J elements as our entities. in next two blocks i have create two students one is Alice Cooper and the other is John connor  (what does this name remind you? 😉 . we simply ask our session to save them as we do for usual POJO mode. Session know what to do with dom4j elements as it is configured as a DOM4J session.
In Second block we query our table and retrieve all entities into a list, but this list is not a list of Student POJOs instead it is a list of DOM4J elements. so we need to do some XML processing when we want to extract our entity properties. you can learn more about DOM4J at Here .

Next step we retrieve a single row, edit and save it into our database, Its all simple DOM4J operation which you should use over some elements to manipulate your data.

Build file that i used contains two target that we will use during this project. first one is hbm2ddl which will create our database structure and the second one is run target which will execute our main class. it is not required to include build file here  you can download the sample and check it yourself. make sure you look at readme file before digging into execution of application.

In next few days I will try to do a simple benchmark for some simple CRUD operation to have a basic clue about DOM4J entity mode in our environment.

overview of XML Parsing in java , different methods and libraries

what are different technologies and implementations to simply pars some XML files ?
What Java provide you to pars XML files ?
Iin this blog entry After answering the above questions , i will introduce (by name and method of parsing) some XML parser available in java land.we may talk more about each of them in next entries.
First lets see what are different methods to pars XML files. There are Two major XML parsing method , one of them is Old and Standard method using a DOM (Documet Object Model) and the other is Stream and Event Based Parsing.

  • In DOM metod we fetch entiere XML document into memory and create a Objective representation of it in the memory then we can traverse the document using a very rich set of methods which DOM interfaces defined. So wen can access the document tree in any time and change its elements or attributes on emand.
    But it will need a high amount of memory to store the Document Tree , so it is not suitable when you have resource (memory) limitation. as you know Current Browsers use this model, so we can easily use javaScript to access an elements and Change them in runtime base on our needs.Using DOM you can create and write XML files.

  • Other model Use Streaming and is event based, what does it means ? it means that it go trough the document from start to end , and as soon as it(the Streaming parser) sees some text nodes , attribute , Maleformed elements… it will trigger an Event which you are listening for , so it is a one way parsing which in , you can not change the elements or its attributes as you can do in DOM .In Streaming model you do not need a high amount of memory becasue you are not going to create a model of your document in memory.using Stream parsers you can create an XML file.

but we should notice that we have Another categorizing for XML parser refer to parser and client communication mechanism , there are two kind of communication mechanism between parsers and client that use those parsers , by this categorizing we have two kind of parses :

  • Push parser
  • Pull parser

Parsers that we have had before StAX are push parsers, which parser push XML data to client whether it needs those data or not or even it is ready to recieve data or not.
Pull Parsers which come along with StaX parsers provide another mechanism for letting Client to have the data . it give the ability of asking for XML data to client , so Client will recive Data when it asks for those Data.
Now you should know that DOM / SAX are both push parsers , and the only pull parser implementation that i used is StAX.
some features that make StAX a suitable parsing method when you need just to pars xml files while there is no need to create or update an XML file, you should know that StAX is one was parser as SAX parsers are.

  • With StAX you can write XML documents too , meanwhile with SAX you can not write XML documents.
  • using StAX as i will show you in next part is much easier than using SAX
  • In pull parsing your own code has the control of Parser client Thread becasue its you that engage with Parser MeanWhile in a push parser it is parse that is mainStream in your code becase it parse and give the parsed data back to you whether you ask for it or not
  • You can works with several XML Streams (parsing and processing them ) in pull parsing mode when your client code is one thread, meanwhile you can not do this in a push parsing mode

Now Lets see what XML parsers support which models:

Model / XML Parsing Library

Crimson
1.1.3

Xerces
1.4.4

JAXP
1.3

NekoPull1
0.2.4
   

Piccolo
1.04

StAX
1.2 RC

dom4j
1.6.1

Push Parsing

Yes

Yes

Yes

No

Yes

No

Yes

Pull Parsing

No

No

No

Yes

No

Yes

No

Stream Parsing  implementation (SAX)

Yes

Yes

Yes

Yes

Yes

Yes

Yes

DOM Parsing implementation

Yes

Yes

Yes

No

No

No

Yes

 

1- It Extends  XNI to provide pull parsing.