Documentation/Tutorials/Red5AndHibernate

Red5 and Hibernate

This document explains in details how to setup a derby database connection using  Hibernate and caching. This document assumes you are using Red5 0.8 and the latest Hibernate Release 3.3.1.

This update requires very latest Red5 svn trunk

Document below reference demo application  http://red5.electroteque.org/dev/demos/hibernateTest.zip.

Sources for this application is here  http://red5.electroteque.org/dev/demos/hibernateTest-src.zip

The demo application is built using the Red5Plugin, simply import the project into eclipse.

 http://www.hibernate.org/ DAO takes a similar approach to the Spring DAO JDBC setup but adds first and second level caching and example is described here [docs:Red5 and Spring JDBC Hibernate].

Required Libraries

  • aspectjweaver.jar - Found in Spring with dependancies distribution.
  • c3p0-0.9.1.2.jar
  • dom4j-1.6.1.jar - Hibernate dependancy, found in distribution
  • javassist-3.4.GA.jar - Hibernate dependancy, found in distribution
  • antlr-3.1.1.jar - Hibernate dependancy, found in distribution. Already included with Red5.
  • commons-collections-3.2.1.jar - Hibernate dependancy, found in distribution. Already included with Red5.
  • jta-1.1.jar - Hibernate dependancy, found in distribution. Already included with Red5.
  • slf4j-api-1.5.2.jar - Hibernate dependancy, found in distribution. Already included with Red5.
  • ehcache-1.6.0-beta1.jar - The latest ehcache which removes backport concurrent dependancy.
  • jsr107cache-1.0.jar - EHCache 1.6 dependancy.
  • derby-10.4.2.0.jar
  • hibernate3.jar - Get the latest which is 3.3.1.
  • spring-aop-2.5.5.jar - Already included with Red5.
  • spring-orm-2.5.5.jar - Already included with Red5.
  • spring-jdbc-2.5.5.jar - Found in spring distribution.
  • spring-tx-2.5.5.jar - Found in spring distribution.

There is still an issue getting aspectjweaver.jar to resolve in the classpath which is needed for the AOP style of the transaction setup therefore it is required to be included in the classpath to the Red5 startup script like so

export RED5_CLASSPATH="${RED5_HOME}/boot.jar${P}${RED5_HOME}/conf${P}${CLASSPATH}:webapps/hibernateTest/WEB-INF/lib/aspectjweaver.jar"

Configuration

The following configurations explain how to configure an existing Red5 application configuration files. To learn about creating the application first visit Create New Applications In Red5?.

red5-hibernate.xml

  1. Create a config file called red5-hibernate.xml.
  2. Add the following code
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    
    <bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
                <property name="properties">
                        <props>
                                <prop key="hibernate.format_sql">true</prop>
                                <prop key="hibernate.use_sql_comments">true</prop>
                                <prop key="hibernate.generate_statistics">true</prop>
                                <prop key="hibernate.cache.use_structured_entries">true</prop>

                <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
               
                <!--  <prop key="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</prop>-->
                                <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
                                <prop key="hibernate.cache.provider_configuration_file_resource_path">hibernateTest-ehcache.xml</prop>
                                <prop key="hibernate.cache.use_query_cache">true</prop>
                                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                                <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
                                <prop key="connection.autocommit">true</prop>
                                <prop key="hibernate.show_sql">true</prop>
                                <prop key="hibernate.generate_statistics">true</prop>
                                <prop key="hibernate.hbm2ddl.auto">update</prop>
                                <prop key="hibernate.show_sql">true</prop>
                                <prop key="hibernate.c3p0.minPoolSize">5</prop>
                                <prop key="hibernate.c3p0.maxPoolSize">20</prop>
                                <prop key="hibernate.c3p0.timeout">600</prop>
                                <prop key="hibernate.c3p0.max_statement">50</prop>
                                <prop key="hibernate.c3p0.min_size">0</prop>
                                <prop key="hibernate.c3p0.max_size">20</prop>
                                <prop key="hibernate.c3p0.timeout">30</prop>
                                <prop key="hibernate.c3p0.testConnectionOnCheckout">false</prop>
                                <!--  <prop key="hibernate.query.substitutions">true 'T', false 'F'</prop>
                                <prop key="hibernate.hbm2ddl.auto">update</prop>
                                <prop key="hibernate.show_sql">true</prop>
                                <prop key="hibernate.c3p0.minPoolSize">5</prop>
                                <prop key="hibernate.c3p0.maxPoolSize">20</prop>
                                <prop key="hibernate.c3p0.timeout">600</prop>
                                <prop key="hibernate.c3p0.max_statement">50</prop>
                                <prop key="hibernate.c3p0.testConnectionOnCheckout">false</prop>-->
                        </props>
                </property>
        </bean>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${db.driver}"/>
        <property name="url" value="${db.jdbcurl}"/>
        <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
    </bean>  
    
    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                <property name="dataSource"><ref local="dataSource"/></property>
                <property name="hibernateProperties">
                        <ref bean="hibernateProperties" />
                </property>
                <!-- Must references all OR mapping files. -->
                <property name="mappingResources">
                        <list>
                        <value>org/red5/server/webapps/hibernateTest/dao/Users.hbm.xml</value>
                        </list>
                </property>
        </bean>
        

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
       <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    </bean>
    


        <bean id="usersDao" class="org.red5.server.webapps.hibernateTest.dao.UsersDaoImpl">
                <property name="sessionFactory"><ref local="sessionFactory"/></property>
        </bean>
        
        
        <bean id="usersService" class="org.red5.server.webapps.hibernateTest.dao.UsersServiceImpl">
                <property name="usersDao" ref="usersDao"/>
        </bean>

        <aop:config>
        <aop:pointcut id="usersServiceMethods" expression="execution(''' org.red5.server.webapps.hibernateTest.dao.*IUsersDao.'''(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="usersServiceMethods"/>
        </aop:config>
        
        <tx:advice id="txAdvice" transaction-manager="transactionManager">
            <tx:attributes>
              <tx:method name="get*" propagation="REQUIRED"/>
              <tx:method name="add*" propagation="REQUIRED"/>
              <tx:method name="delete*" propagation="REQUIRED"/>
            </tx:attributes>
         </tx:advice>

         
         <bean id="jmxExporter"
        class="org.springframework.jmx.export.MBeanExporter">
        <property name="beans">
            <map>
                <entry key="Hibernate:name=statistics">
                    <ref local="statisticsBean" />
                </entry>
            </map>
        </property>
    </bean> 

    <bean id="statisticsBean" class="org.hibernate.jmx.StatisticsService">
        <property name="statisticsEnabled">
            <value>true</value>
        </property>
        <property name="sessionFactory"><ref local="sessionFactory"/></property>
    </bean>
        
        
</beans>

If you don't want to use AOP and setup the Spring 1.0 way it is like

<bean id="usersService"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="target">
      <bean class="org.red5.server.webapps.hibernateTest.dao.UsersServiceImpl">
        <property name="usersDao" ref="usersDao"/>
      </bean>
    </property>
    <property name="transactionAttributes">
      <props>
        <prop key="get*">PROPAGATION_REQUIRED</prop>
        <prop key="add*">PROPAGATION_REQUIRES_NEW</prop>
        <prop key="delete*">PROPAGATION_REQUIRED</prop>
      </props>
    </property>
  </bean>

red5-web.xml

There is no need to import configs anymore into red5-web.xml assuming it is prefixed with red5-* in the name.

red5-web.properties

We setup the database connection properties in the red5-web.properties file

db.driver=org.apache.derby.jdbc.EmbeddedDriver
db.jdbcurl=jdbc:derby:/path/to/db/server
db.username=dbuser
db.password=dbpass

hibernateTest-ehcache.xml

This is needed to be placed into the classes directory to be loaded into the classpath

Add the following ehcache config to your classes location

<ehcache>       
        <diskStore path="webapps/hibernateTest/cache" />
        
        <defaultCache
                maxElementsInMemory="4"
                eternal="false"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                overflowToDisk="false"
                diskPersistent="false"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LFU"
        />
        
        <cache name="org.hibernate.cache.StandardQueryCache"
      maxElementsInMemory="100"
      eternal="false"
      timeToIdleSeconds="120"
      timeToLiveSeconds="120"
      overflowToDisk="false"/>
  
  <cache name="org.hibernate.cache.UpdateTimestampsCache"
      maxElementsInMemory="5000"
      timeToIdleSeconds="120"
      timeToLiveSeconds="120"
      eternal="true"/>
      
        <cache name="org.red5.server.webapps.hibernateTest.dao.Users" 
                maxElementsInMemory="1000"
                eternal="false"
                timeToIdleSeconds="120"
        timeToLiveSeconds="600"
                overflowToDisk="false" />
</ehcache>

StreamPoints.hbm.xml

This is the mapping file that hibernate will load to map objects to the database table.

<?xml version="1.0"?>

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

<hibernate-mapping>
    <class
        name="org.red5.server.webapps.hibernateTest.dao.Users"
        table="users"
        dynamic-update="false"
        dynamic-insert="false">
        
        <cache usage="read-write" />

        <id
            name="id"
            column="id"
            type="java.lang.Long"
            unsaved-value="-1">
                <generator class="increment" />
        </id>
        
        
        <property
            name="userName"
            type="string"
            update="false"
            insert="true"
            column="username"
            length="100"
            not-null="true"
           
        />
        

    </class>

     
</hibernate-mapping>

Hibernate DAO Classes

Users.java

public class Users implements Serializable {
        
    private String userName;
    private Long id;

    
        public Users()
        {               
        }
        
        public void setId(Long id)
        {
                this.id = id;
        }
         
        public Long getId() {
                return id;
        }
         
        public void setUserName(String value)
        {
                this.userName = value;
        }
         
         public String getUserName() {
                 return userName;
         }
        
}

IUsersDAO.java

package org.electroteque.dao;

import java.util.List;

public interface IStreamPointsDao {
        
        List getStreamPoints(); 
        StreamPoints getStreamPoint(StreamPoints streamPoint);
        void deleteStreamPoint(StreamPoints streamPoints);
        void addStreamPoint(StreamPoints streamPoints);
}

IStreamPointsService.java

package org.red5.server.webapps.hibernateTest.dao;

import java.util.List;


public interface IUsersDao {
        
        List getUsers(); 
        Users getUser(Users users);
        void deleteUser(Users users);
        void addUser(Users users);
}

UsersDaoImpl.java

package org.red5.server.webapps.hibernateTest.dao;

import java.util.List;


import org.hibernate.HibernateException;
import org.hibernate.Session;

import org.hibernate.criterion.Example;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;


public class UsersDaoImpl extends HibernateDaoSupport implements IUsersDao {
        

        public Users getUser(Users users) {
                Example example = Example.create(users);
                return (Users)this.getSessionFactory().getCurrentSession().createCriteria(Users.class)
                .add(example).list().iterator().next();
        }
        
        public List getUsers() {
                
                return this.getSessionFactory().getCurrentSession()
            .createQuery("FROM Users ORDER BY username")
            .list();
        }
               
            
        public void deleteUser(Users users)
        {
                this.getSessionFactory().getCurrentSession().delete(getUser(users));
        }
            
        public void addUser(Users users)
        {
                this.getSessionFactory().getCurrentSession().save(users);
        }
           
}

UsersServiceImpl.java

package org.red5.server.webapps.hibernateTest.dao;

import java.util.List;


public class UsersServiceImpl implements IUsersDao {
        

        private IUsersDao usersDao;

    public void setUsersDao(IUsersDao users) {
        this.usersDao = users;
    }
    
    public List getUsers() {
        return this.usersDao.getUsers();
    }
    
    public Users getUser(Users users) {
        return this.usersDao.getUser(users);
    }
            
        public Users getStreamPoint(Users users) {
                return this.usersDao.getUser(users);
        }
           
        public void deleteUser(Users users)
        {
                this.usersDao.deleteUser(users);
        }
            
        public void addUser(Users users)
        {
                this.usersDao.addUser(users);
        }
            
        
}

Usage

for (Iterator iter = this.usersService.getUsers().iterator(); iter.hasNext();) {
                        Users element = (Users) iter.next();
                        log.debug("User ID: {}, User Name: {}", new Object[]{element.getId(), element.getUserName()});
}

Users users = new Users();
users.setUserName("newuser");
this.usersService.addUser(users);
this.usersService.deleteUser(users);