Using Hibernate with ColdFusion, part 1
One of my last researching projects was using Hibernate ORM tool with ColdFusion. There is couple problems to solve in order to use ColdFusion components (CFCs) with Hibernate. First problem making Hibernate to use ColdFusion data source DB connection. Second problem is building Java classes based on CFCs and compiling them on the fly so they may be picked up by Hibernate. Third problem is echanging data between CFCs and created Java classes. This article is part 1 of series of articles describing prototype Hibernate proxy for ColdFusion. It does not handle any relations between CFCs and does not implement any of advanced types such as arrays and structs. It simply presents the idea of building Java classes based on CFCs and using them with get, save, saveOrUpdate, update and delete methods of Hibernate Session.
First of all Hibernate must be added to ColdFusion class path. When that is done we can start thinking of building Java classes. In order to expose CFC to Hibernate we must have following files for each entity:
- CFC file
- HBM file
- Java source file
- Java compiled class file
CFC and HBM file must be created by hand. Java builder uses them to create Java source file which is then compiled to class.
We can now think of getting Hibernate SessionFactory in CF. We can take advantage of Hibernate programmatic configuration to supply parameters such as dialect or cache options. My solution, called HiberCF, defines one file called hibercf.properties. This file contains two types of configuration settings. Lines starting with hibernate are passed to SessionFactory configuration and lines starting with hibercf are used by HiberCF. Sample file looks like following one:
hibernate.cache.use_query_cache=false hibernate.cache.use_second_level_cache=false hibernate.connection.aggressive_release=false hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider hibernate.current_session_context_class=thread hibernate.dialect=org.hibernate.dialect.SQLServerDialect hibernate.show_sql=false # hibercf settings: hibercf.application_root=D:/workspaces/monochrome/Proj-ColdFusion/ hibercf.delete_java_source=false hibercf.null_behavior=convertToAppropriate
As you can see there is not many settings for HIberCF itself. application_root defines where root of all packages starts. That is the directory where CFCs are stored. delete_java_source defines if Java files are deleted when compiled and null_behavior defines how null values are handled.
When using Hibernate from Java application it is almost always configured to obtain data base connection by setting following properties in hibernate.properties file:
- hibernate.connection.driver_class
- hibernate.connection.url
- hibernate.connection.username
- hibernate.connection.password
But in ColdFusion all of these are already defined in data source settings. Desired approach is not to make Hibernate create new DB connection but use the one defined by data source instead. So how to get that connection? Everything will be clear in a second. Take a look at following code which is first version of HibernateProxy.cfc:
<cfcomponent>
<cfset variables.___properties = arrayNew(1) />
<cfset variables.___configuration = "" />
<cfset variables.___connection = "" />
<cfset variables.___sessionFactory = "" />
<cfset variables.___cache = createObject("component","HibernateProxyCache") />
<cffunction name="configure" access="public"
returntype="HibernateProxy" output="false">
<cfargument name="dataSource" type="string" required="true" />
<cfargument name="path" type="string" required="true" />
<cfset var fcnt = "" />
<cfif setConnection( arguments.dataSource )>
<cffile action="read" file="#expandPath(arguments.path)#"
charset="utf-8" variable="fcnt" />
<cfset buildSessionFactory( listToArray(fcnt,chr(13)) ) />
<cfreturn this />
</cfif>
<cfthrow type="HibernateProxy.Connection"
message="Datasource '#arguments.dataSource#' could not be retrieved." />
</cffunction>
<cffunction name="getConnection" access="public" returntype="any" output="false">
<cfreturn variables.___connection />
</cffunction>
<cffunction name="setConnection" access="public"
returntype="boolean" output="false">
<cfargument name="dataSource" type="string" required="true" />
<cfscript>
var service = CreateObject(
"java", "coldfusion.server.ServiceFactory").DataSourceService;
try
{
variables.___connection = service.getDatasource(
arguments.dataSource ).getConnection();
return true;
}
catch (any e) {}
return false;
</cfscript>
</cffunction>
<cffunction name="buildSessionFactory" access="private"
output="false" returntype="void">
<cfargument name="properties" type="array" required="true" />
<cfset var i = 0 />
<cfset var key = "" />
<cfset var value = "" />
<cfset var f = createObject("java", "org.hibernate.cfg.Configuration").init() />
<cfset variables.___properties = arguments.properties />
<cfloop from="1" to="#arrayLen(arguments.properties)#" index="i">
<cfset key = listGetAt( trim(arguments.properties[i]), 1, "=" ) />
<cfset value = listGetAt( trim(arguments.properties[i]), 2, "=" ) />
<cfif key.startsWith( "hibernate." )>
<cfset f = f.setProperty( key, value ) />
</cfif>
</cfloop>
<cfset configureHiberCF( arguments.properties ) />
<cfset setConfiguration( f ) />
<cfset variables.___sessionFactory = getConfiguration().buildSessionFactory() />
</cffunction>
<cffunction name="rebuildSessionFactory" access="private"
output="false" returntype="void">
<cfset variables.___sessionFactory = getConfiguration().buildSessionFactory() />
</cffunction>
<cffunction name="configureHiberCF" access="private"
output="false" returntype="void">
<cfargument name="properties" type="array" required="true" />
<cfset var i = 0 />
<cfset var key = "" />
<cfset var value = "" />
<cfset var root_found = false />
<cfloop from="1" to="#arrayLen(arguments.properties)#" index="i">
<cfif not trim(arguments.properties[i]).startsWith("##")>
<cfset key = lCase( listGetAt( trim(arguments.properties[i]), 1, "=" ) ) />
<cfset value = listGetAt( trim(arguments.properties[i]), 2, "=" ) />
<cfif key eq "hibercf.application_root">
<!--- hibercf.application_root: --->
<cfset root_found = true />
<cfset variables.___applicationRoot = value />
<cfelseif key eq "hibercf.delete_java_source">
<!--- hibercf.delete_java_source: --->
<cfif value eq "true">
<cfset variables.___deleteJavaSource = true />
<cfelseif value eq "false">
<cfset variables.___deleteJavaSource = false />
<cfelse>
<cfthrow type="HibernateProxy.configureHiberCF"
message="Unknown value '#value#' for hibercf.delete_java_source." />
</cfif>
<cfelseif key eq "hibercf.custom_java_builder">
<cftry>
<cfset createObject(
"component",
"HibenateProxyUtils").verifyCustomJavaBuilder( value ) />
<cfset variables.___customJavaBuilder = value />
<cfset variables.___useCustomJavaBuilder = true />
<cfcatch type="HibernateProxy.Utils.customJavaBuilder">
<cftrace type="warning" text="#cfcatch.message#" />
</cfcatch>
</cftry>
</cfif>
</cfif>
</cfloop>
<cfif not root_found>
<cfthrow type="HibernateProxy.configureHiberCF"
message="Property hibercf.application_root must be explicitly
defined in hibercf.properties file." />
</cfif>
</cffunction>
<cffunction name="getApplicationRoot" access="public"
output="false" returntype="string">
<cfreturn variables.___applicationRoot />
</cffunction>
<cffunction name="isDeleteJavaSource" access="public"
output="false" returntype="boolean">
<cfreturn variables.___deleteJavaSource />
</cffunction>
<cffunction name="getCache" access="public"
output="false" returntype="HibernateProxyCache">
<cfreturn variables.___cache />
</cffunction>
<cffunction name="getProperties" access="private"
output="false" returntype="array">
<cfreturn variables.___properties />
</cffunction>
<cffunction name="getSession" access="public" output="false" returntype="any">
<cfreturn variables.___sessionFactory.openSession( getConnection() ) />
</cffunction>
<cffunction name="getConfiguration" access="public"
output="false" returntype="any">
<cfreturn variables.___configuration />
</cffunction>
<cffunction name="setConfiguration" access="public"
output="false" returntype="any">
<cfargument name="value" type="any" required="true" />
<cfset variables.___configuration = arguments.value />
</cffunction>
</cfcomponent>
At the very beginning we have configure() method which accepts two parameters: dataSource and path. Datasource is the name of DSN we want to use and path is full path to hibercf.properties file. Next we try to get connection to data base knowing DSN name. setConnection() method simply gets instance of ServiceFactory, then DataSourceService and connection by passed DSN name. If there is no error, method returns true.
Next configure() method reads configuration file and creates array of properties which is then passed to buildSessionFactory() method. Take a look at it now. It creates instance of org.hibernate.cfg.Configuration class, iterates over properties, finds those starting with hibernate and sets them on Hibernate Configuration. At this step we should be able to get instance of Session by calling getSession() method. That method uses SessionFactory which was created in buildSessionFactory().
Next step is create JavaBuilder.cfc which takes instance of CFC, creates Java class and compiles it. We focus on this task in 2nd part of this article.
About this entry
You’re currently reading “ Using Hibernate with ColdFusion, part 1 ,” an entry on ria:it
- Published:
- 6:47 pm on 25/05/2008
- Category:
- ColdFusion, Hibernate
No comments
Jump to comment form | comments rss [?] | trackback uri [?]