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
- Create a config file called red5-hibernate.xml.
- 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);
Links
- Hibernate - http://www.hibernate.org
- C3P0 - http://sourceforge.net/projects/c3p0
- AspectJ - http://www.eclipse.org/aspectj/
- Backport Util Concurrent - http://backport-jsr166.sourceforge.net/ (required by EHCache)
- EHCache - http://ehcache.sourceforge.net/
- Derby - http://db.apache.org/derby/
- Spring Framework - http://www.springframework.org/
- Hibernate Connection Pooling - http://www.informit.com/articles/article.aspx?p=353736&seqNum=4
- Hibernate C3P0 Connection Pooling - http://www.hibernate.org/214.html
- Hibernate Code Generator tools for eclipse and ant - http://docs.jboss.org/tools/2.1.0.Beta1/hibernatetools/html/
- Spring ORM - http://static.springframework.org/spring/docs/2.5.x/reference/orm.html
