After close to two weeks of struggling, I finally managed to deploy pure source to a CFML runtime (Railo, in this case), and get Groovy entities in and out of the database with Hibernate. No compliation, no IDE, no development-mode server, just my Groovy source along with a hacked up CF Groovy. This is very exciting for me, because while Groovy is cool and all, CF's dynamic nature has become a must have.
I don't have source to download yet, just a horribly hacky proof of concept, but here's what the user of the "framework" does. First, create your entity:
package com.barneyb import javax.persistence.* @Entity class Person { @Id @GeneratedValue Long id Long version String name Date dob def getAgeInSeconds() { (new Date().getTime() - dob.getTime()) / 1000 } def getAgeInDays() { ageInSeconds / 86400 } def getAgeInYears() { ageInDays / 365.249 } String toString() { "$name is $ageInYears years ($ageInDays days) old" } }
That's the same class as my initial CF Groovy demo used, except with the of JPA annotations added. Because I'm binding to Hibernate, you can use any Hibernate-supported annotations, but I opted to stick with vanilla JPA. Now we need our hibernate.cfg.xml, which is totally stock:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="current_session_context_class">thread</property> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <property name="show_sql">true</property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/dbname</property> <property name="hibernate.connection.username">username</property> <property name="hibernate.connection.password">password</property> <property name="hibernate.hbm2ddl.auto">update</property> <mapping class="com.barneyb.Person" /> </session-factory> </hibernate-configuration>
You could also map your classes manually with XML, if you wanted, but for the sake of simplicitly, I've done it all with annotations. You'll also notice the database connection information embedded directly in the file. This is far from ideal. I'm hoping to extract it from a CFML DSN, but that might only be possible on Adobe ColdFusion (via the Admin API). The last thing is the test script:
<g:script> import java.text.SimpleDateFormat import org.hibernate.* import org.hibernate.cfg.* import com.barneyb.Person sdf = new java.text.SimpleDateFormat("yyy/MM/dd") sdf.lenient = true def sf = new AnnotationConfiguration() .configure().buildSessionFactory() def sess = sf.openSession() def tx = sess.beginTransaction() sess.createQuery("delete Person").executeUpdate() sess.save(new Person( name: attributes.name ?: "Barney", dob: sdf.parse(attributes.dob ?: "1980/06/10") )) tx.commit() sess.close() sf.close() </g:script>
No need to compile anything, no need to drop JARs all over your server, nothing. Write, refresh, persist. That includes adding new entities, new properties to existing entities, etc.
It's not ready for public consumption at the moment, but that's my top "free time" priority. For the incredibly impatient, there's a branch in my SVN repository with the current source. Don't expect anything pretty. ;)
You can get a connection from a CF DSN like this:
var dataSource = "yourDSN";
var daFactory = CreateObject ("Java","coldfusion.server.ServiceFactory");
var daConnection = daFactory.getDataSourceService().getDatasource(dataSource).getConnection();
You can then use it for a hibernate session (with setConnection()).
I think JNDI is a better bet tho, as you can rock caching, and distribution, and whatnot.
Cool stuff man!
denny,
Yep, that's basically what I'm doing. Even better, it works the same way on Railo. However, seeding the SessionFactory with the data source itself, rather than individual sessions with a connection, makes things a lot simpler to deal with, so that's actually how I'm doing it. I had to use a thin wrapper around the datasource to provide to Hibernate, mostly to cover up the fact that Railo doesn't return a javax.sql.Datasource implementation like CF, but that's pretty irrelevant, and I'd expect that to be fixed up in the next release of Railo.
Right-o!
I wanted database reverse-engineering for my hibernate thingermuhbob, and HibernateTools only seems to take a configuration– can't pass in a datasource. At least last I tried.
So I started using JNDI. Seems like there's a lot of cool stuff you can do with it.
I haven't done any load-testing, but it would be interesting to see some stats, neh?
I really need to come up with some type of load-testing strategy. :-P
Anyways– it's good to know passing in the datasource itself basically works!