Cayenne ORM support for JPublish
We finally did it :) JPublish applications can now use a very nice ORM support through the beautiful Cayenne framework. I have to admit that initially I started to implement the Hibernate support but then I became more and more attracted by the vibrant community of Cayenne.
The implementation is very simple, a JPublish module and a lot of help from Cayenne's user list and Click's author generous support. Thank you all!
To enable Cayenne in a JPublish application you will have to configure the JPCayenneModule in your JPublish application. This is very simple. Edit the jpublish.xml file and add:
<!--JPublish Cayenne support -->(please verify that you have the JPCayenne.jar in your WEB-INF/lib folder. You can build it from our SVN or simply get it from our demo lib folder)
<module classname="org.jpublish.module.cayenne.JPCayenneModule">
<cayenne-config-path>/WEB-INF/cayenne</cayenne-config-path>
<auto-rollback>true</auto-rollback>
<session-scope>false</session-scope>
<shared-cache>true</shared-cache>
<!--
~ Http request paths using a per-request or a per-session Cayenne ObjectContext (OC),
~ the read-only paths will be interpreted first and will use a global OC one defined
~ per web app instance.
~ -->
<cayenne-enabled-urls>
<url path="/info/*" readonly="true"/>
<url path="/status/*" readonly="true"/>
<url path="/rss/*" readonly="true"/>
<url path="/users/*" readonly="false"/>
<url path="/companies/*"/> <!-- readonly="false" by default, if not defined -->
</cayenne-enabled-urls>
<debug>true</debug>
</module>
In the configuration above we demonstrate how one can enable ORM support for certain URLs. For example, any request for /rss/* will use a read-only Cayenne DataContext, while the requests coming for /companies/* will use a per-thread DataContext. The Cayenne's DataContext life-cycle is handled in a before/after advice style, so you don't have to worry about the internals :)
The Cayenne support is available in the JPublish context, Actions and Pages (Velocity, Freemarker or StringTemplate) being able to access the Cayenne service (JPCayenneModule.JPCAYENNE_SERVICE_NAME).
So for example in our simple demo TODOs app, any Beanshell action can access the Cayenne service like this (excerpt from actions/GetUsers.bsh):
jpCayenneService = context.get( JPCayenneModule.JPCAYENNE_SERVICE_NAME);
if( jpCayenneService!= null){
Expression qual = ExpressionFactory.likeIgnoreCaseExp("name", "%");
SelectQuery select = new SelectQuery(User.class, qual);
users = jpCayenneService.performQuery( select);
if( users != null)
context.put( "users", users);
}
You can find a very simple demo in our download section: jpcayenne.war, basically a simple TODO web application having the following model:
This demo is just scratching the Cayenne framework and I did it in less than three hours, so please be indulgent :) For learning Cayenne I kindly recommend you to visit Cayenne's web site for updated documentation and more examples.
I am now going to update our JPublish Wiki with more details about this implementation, so ... stay tuned and send us your feedback.
Give it a try and let us know how it goes.
Cheers,
