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 ===