You are viewing a plain text version of this content. The canonical link for it is here.
Posted to docs@cocoon.apache.org by do...@cocoon.apache.org on 2004/11/01 14:37:57 UTC

[Cocoon Wiki] Updated: CocoonAndHibernateTutorial

   Date: 2004-11-01T05:37:57
   Editor: JohannesTextor <jc...@gmx.de>
   Wiki: Cocoon Wiki
   Page: CocoonAndHibernateTutorial
   URL: http://wiki.apache.org/cocoon/CocoonAndHibernateTutorial

   no comment

Change Log:

------------------------------------------------------------------------------
@@ -23,18 +23,233 @@
 
 == Setting up ==
 
-I assume you have cocoon installed and running. You will also need a database
-connection set up in cocoon.xconf (more information regarding this can be 
-found in [DatabaseConnectionOverview]).
+First of all, you need an active database connection set up and configured in cocoon.xconf. 
+There are several wiki and documentation pages on how to do this. For instance, if you use
+MySQL have a look at [MySQL]. 
 
-The first thing we will do is to install Hibernate to WEB-INF/lib.
+For now, I will assume that your SQL datasource is named "test". 
 
- * Download Hibernate from [http://www.hibernate.org].
- * Copy hibernate2.jar to your WEB-INF/lib directory. 
+Now download hibernate from [http://www.hibernate.org]. I tried this with the current production
+release, 2.1.6. The following jars from the Hibernate distribution need to be copied to your 
+WEB-INF/lib directory:
 
-Now we will add an Avalon component to create Hibernate Sessions: 
+- hibernate2.jar
 
-{to be continued ..} 
+From the "lib" directory of the Hibernate distribution: 
+
+- dom4j-1.4.jar 
+- cglib-full-2.0.2.jar
+- jta.jar
+
+Now we will register Hibernate with Cocoon. If you are like me, you will 
+fire up Eclipse to accomplish the following part. 
+
+The first thing we'll do is create an interface {{{PersistenceFactory}}} that 
+extends the Component interface from Avalon: (Note: {{{PersistenceFactory}}} 
+and {{{HibernateFactory}}} originate from the Page CformsHibernateAndFlow!)
+
+{{{
+package org.test; // Put the name of the target package here. Using the default package is not recommended! 
+	
+import org.apache.avalon.framework.component.Component;
+	
+public interface PersistenceFactory extends Component {
+	String ROLE = PersistenceFactory.class.getName();
+	
+	public net.sf.hibernate.Session createSession();
+}
+}}} 
+
+As you can see the {{{PersistenceFactory}}} will be responsible for the creation 
+of Hibernate Sessions. This is the point where we'll have to decide how Hibernate will 
+connect to the database. My preffered solution is using the cocoon connection pool.
+
+However, most tutorials will tell you to create a file called hibernate.properties and 
+put your database access information in there. This will work, but Hibernate will use its
+own builtin connection pool, and the documentation states clearly that ''''the Hibernate 
+builtin connection pool is not for production use''''. 
+
+For example, when using MySQL, you will experience problems when leaving the webapp running
+overnight and coming back in the morning. MySQL connections die after 8 hours of idletime, and the 
+Hibernate builtin pool is not capable of dealing with this. So the first thing you will see
+is an error message. It goes away after reloading the page, but still it's unacceptable for
+production use. That's why I encourage you to spend the little extra effort and use Coccoon
+connection pooling right away. 
+
+Where we will do this is in the actual implementation of the {{{PersistenceFactory}}} interface, 
+in a class called {{{HibernateFactory}}} "(fellow Cocooners: is this good practice?)"
+
+{{{
+package org.test;
+
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.thread.ThreadSafe;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.excalibur.datasource.DataSourceComponent;
+import org.apache.avalon.framework.service.ServiceSelector;
+
+// import all classes from your package so you can later persist them  
+import org.test.*;
+
+public class HibernateFactory
+        extends AbstractLogEnabled
+        implements PersistenceFactory, Configurable, Serviceable, Initializable,
+            Disposable, ThreadSafe
+{
+
+    private boolean initialized = false;
+    private boolean disposed = false;
+    private ServiceManager manager = null;
+
+    // do not confuse with Avalon Configuration, Cocoon Session, etc.
+    net.sf.hibernate.cfg.Configuration cfg;
+    net.sf.hibernate.SessionFactory sf;
+
+    //for debugging: which instance am I using?
+    long time_start;
+
+    public HibernateFactory() {
+        System.out.println("Hibernate factory instance created");
+    }
+
+    public final void configure(Configuration conf) throws ConfigurationException {
+        if (initialized || disposed) {
+            throw new IllegalStateException ("Illegal call");
+        }
+        System.out.println("Hibernate configure called");
+    }
+
+    public final void service(ServiceManager smanager) throws ServiceException {
+        if (initialized || disposed) {
+            throw new IllegalStateException ("Illegal call");
+        }
+
+        if (null == this.manager) {
+            this.manager = smanager;
+        }
+        System.out.println("Hibernate service called");
+    }
+
+    public final void initialize() throws Exception {
+        if (null == this.manager) {
+            throw new IllegalStateException("Not Composed");
+        }
+
+        if (disposed) {
+            throw new IllegalStateException("Already disposed");
+        }
+
+        //  adapt:
+        //  build sessionfactory
+        //  map all classes we need
+        //  keep in sync with configuration file
+        //
+        try {
+              cfg = new net.sf.hibernate.cfg.Configuration();
+
+	      // classes to persist will be added here later 
+							
+              sf = cfg.buildSessionFactory();
+        }
+        catch ( Exception e) {
+              getLogger().error("Hibernate:" + e.getMessage());
+              return;
+        }
+        this.initialized = true;
+        System.out.println("Hibernate initialize called");
+    }
+
+    public final void dispose()  {
+        //
+        try {
+              sf.close();
+        }
+        catch ( Exception e) {
+              getLogger().error("Hibernate:" + e.getMessage());
+        }
+        finally {
+              sf = null;
+              cfg = null;
+        }
+        this.disposed = true;
+        this.manager = null;
+        System.out.println("Hibernate dispose called");
+    }
+
+
+
+    public net.sf.hibernate.Session createSession() {
+      net.sf.hibernate.Session hs;
+      DataSourceComponent datasource = null;
+      
+	// When creating a session, use a connection from 
+        // cocoon's connection pool 
+      try {			
+	// Select the DataSourceComponent named "test" 
+        // This is a normal SQL connection configured in cocoon.xconf 
+      	ServiceSelector dbselector =
+            (ServiceSelector) manager.lookup(DataSourceComponent.ROLE+"Selector");
+        datasource = (DataSourceComponent) dbselector.select("test"); 
+        	//name as defined in cocoon.xconf
+      	hs = sf.openSession(datasource.getConnection());
+      }
+      catch ( Exception e) {
+          getLogger().error("Hibernate: " + e.getMessage());
+          hs = null;
+      }
+      return hs;
+    }
+}
+}}}
+
+The crucial part is createSession(), where we tell Hibernate to use a connection from the 
+Cocoon pool. This connection is selected using the avalon framework API. 
+
+Compile these two files. I needed the following jars in my classpath: avalon-framework-api-4.1.5.jar, 
+excalibur-datasource-1.1.1.jar, and hibernate2.jar. All these should be in your WEB-INF/lib 
+folder anyway. When you're done, copy the .class files to a directory "org/test" (which obviously 
+depends on the package name you chose) in the "WEB-INF/classes/" folder of your cocoon installation.
+
+To register your {{{HibernateFactory}}} with Cocoon, put the following line in cocoon.xconf: 
+
+{{{
+	<component class="org.test.HibernateFactory" role="org.test.PersistenceFactory"/>
+}}}
+
+(Not sure whether it is actually important where you put this. There is a bunch of other component ... class ...
+statements in cocoon.xconf, so I just put mine above the Xalan XSLT processor component. Need some feedback here!) 
+
+Now, you need a hibernate.properties file in your "WEB-INF/classes" folder. A very basic config file I 
+use is the following: 
+
+{{{
+hibernate.cglib.use_reflection_optimizer = false
+hibernate.statement_cache.size=0
+hibernate.dialect = net.sf.hibernate.dialect.MySQLDialect
+}}}
+
+It basically tells hibernate to turn off the reflection optimizer (whatever that means? :) ) and the
+statement cache (although statement caching can boost performance, you should leave it turned off until you 
+are really sure how to use it). The most important line is where you tell Hibernate about the actual SQL 
+dialect you are using. If you do not supply this information, Hibernate won't be able to behave accordingly.
+For example, Hibernate will try to use subqueries which are not supported if you use MySQL.
+
+Now restart cocoon. If everything went right, you will see the following line in your servlet container log
+file (catalina.out if you are using Tomcat): 
+
+{{{ Hibernate initialize called }}}
+
+This means that Hibernate is ready for action, although it does not do anything so far. Read on for an example 
+on how to create a Java Class and store, retrieve or update objects using Hibernate.
+
+[To Be Continued] 
 
 
 === Test ===