Using Hibernate with ColdFusion, part 4

In 3 previous parts we have covered almost everything regarding using Hibernate with CFML. In this part we will finally expose Hibernate Session methods and transfer data from CFC to Java and from Java to CFC.

We are in situation when we can expose following methods:

  • delete
  • get
  • load
  • save
  • saveOrUpdate
  • update

to ColdFusion. All we need to do is add few methods to HibernateProxy.cfc. Here they are:

 <cffunction name="delete" access="public" output="false" returntype="void">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   sess.delete( clazz );
   sess.getTransaction().commit();
  </cfscript>
 </cffunction>

 <cffunction name="get" access="public" output="false" returntype="any">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfargument name="id" type="any" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfset var response = "" />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   response = sess.get( clazz.getClass(), arguments.id );
   sess.getTransaction().commit();
  </cfscript>
  <cftry>
   <cfset arguments.entity = createObject("component","CF2JAVA").mapBack( arguments.entity, response ) />
   <cfreturn arguments.entity />
   <cfcatch type="any">
    <cfreturn "" />
   </cfcatch>
  </cftry>
 </cffunction>

 <cffunction name="load" access="public" output="false" returntype="any">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfargument name="id" type="any" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfset var response = "" />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   response = sess.get( clazz.getClass(), arguments.id );
   sess.getTransaction().commit();
  </cfscript>
  <cftry>
   <cfset arguments.entity = createObject("component","CF2JAVA").mapBack( arguments.entity, response ) />
   <cfreturn arguments.entity />
   <cfcatch type="any">
    <cfreturn "" />
   </cfcatch>
  </cftry>
 </cffunction>

 <cffunction name="save" access="public" output="false" returntype="void">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   sess.save( clazz );
   sess.getTransaction().commit();
  </cfscript>
  <cfset arguments.entity = createObject("component","CF2JAVA").mapBack( arguments.entity, clazz ) />
 </cffunction>

 <cffunction name="saveOrUpdate" access="public" output="false" returntype="void">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   sess.saveOrUpdate( clazz );
   sess.getTransaction().commit();
  </cfscript>
  <cfset arguments.entity = createObject("component","CF2JAVA").mapBack( arguments.entity, clazz ) />
 </cffunction>

 <cffunction name="update" access="public" output="false" returntype="void">
  <cfargument name="entity" type="WEB-INF.cftags.component" required="true" />
  <cfset var clazz = ensureLoaded( arguments.entity ).newInstance() />
  <cfset var sess = getSession() />
  <cfscript>
   clazz = createObject("component","CF2JAVA").map( arguments.entity, clazz );
   sess.beginTransaction();
   sess.update( clazz );
   sess.getTransaction().commit();
  </cfscript>
 </cffunction>

As you can see each of these methods take at least instance of CFC. Each also calls ensureLoaded() method to make sure Java class is created and ready to use. Next step is get populated CFC or Java class instance based on passed CFC (delete, save, saveOrUpdate, update methods) or required DB entry (get, load methods).

Last component we are missing is CF2JAVA.cfc. This one is responsible for taking data from CFC and putting it into Java class and back. Here is CF2JAVA.cfc:

<cfcomponent>

 <cffunction name="map" access="public" returntype="any" output="false">
  <cfargument name="cfc" type="WEB-INF.cftags.component" required="true" />
  <cfargument name="clazz" type="any" required="true" />
  <cfset var jFields = arguments.clazz.getClass().getDeclaredFields() />
  <cfset var i = 0 />
  <cfloop from="1" to="#arrayLen( jFields )#" index="i">
   <cftry>
    <cfset evaluate("arguments.clazz.set"
                    & jFields[i].getName()
                    & "( arguments.cfc.get" & jFields[i].getName() & "() )") />
    <cfcatch type="any">
     <cfset evaluate("arguments.clazz.set" & jFields[i].getName()
                     & "( javaCast('null','') )") />
    </cfcatch>
   </cftry>
  </cfloop>
  <cfreturn arguments.clazz />
 </cffunction>

 <cffunction name="mapBack" access="public" returntype="any" output="false">
  <cfargument name="cfc" type="WEB-INF.cftags.component" required="true" />
  <cfargument name="clazz" type="any" required="true" />
  <cfset var jFields = arguments.clazz.getClass().getDeclaredFields() />
  <cfset var i = 0 />
  <cfloop from="1" to="#arrayLen( jFields )#" index="i">
   <cftry>
    <cfset evaluate("arguments.cfc.set"
                    & jFields[i].getName()
                    & "( arguments.clazz.get" & jFields[i].getName() & "() )") />
    <cfcatch type="any">
    </cfcatch>
   </cftry>
  </cfloop>
  <cfreturn arguments.cfc />
 </cffunction>

</cfcomponent>

map() method is used to take data from CFC and put it into Java class. mapBack() method takes data from Java class and asigns it to CFC.

This was last piece of HiberCF code. Because it is just prototype it is not bullet proof. It may select incorrect data type when creating Java source code or may throw exceptions while assigning data from CFC to Java or from Java to CFC. It does not handle arrays, structure and any relations. But presented code describes the idea of enabling Hibernate for CFML.

There is last part of this article presenting sample application. It covers configuration and deployment on ColdFusion server configuration installation. Full source code is also available for download.


About this entry