Smart Tech for a better Web
I have recently figured out how cool Apache Cayenne is. It is easy to use and has many benefits compared to the king of ORMs Hibernate. While I was setting up my Apache Wicket project I thought about the best way of integrating it. In short, the easiest solution is to use the Spring features of wicket and create a SpringBean with Cayennes data context. And here is the long version. My examples use the current Wicket trunk version which will be released as Wicket 1.5 somewhere in future.
First you'll need to activate the Spring features in Wicket. This is not necessary as you will see below, but it makes your life much more easier. This is shown in many tutorials out there, so I'll keep it short. In your applications init() do:
Then you'll need to create a applicationContext.xml file in your src/main/webapp/WEB-INF directory. This is used by Spring to create all your Spring-beans. I have already added the SpringBean for Cayenne:
For the sake of completeness, Wicket 1.5 uses Spring 2.5.6. Please refer to this docs if you need more instructions.
My connector class (feel free to give it a better name) connects to Cayenne. Make sure you have saved cayenne.xml, your cayenne map and your drivers xml in src/main/resources. Please don't forget to add your JDBC driver to your pom.xml and/or to your classpath.
As you can see, I have used a ObjectContext which is stored by thread. This is necessary in an multithreaded environment. You'll need to set this up as a new filter, which is provided by Cayenne.
NOTE: The original docs are not available no more.
Open your web.xml and write below the wicket filter:
The Spring bean can be injected into all other bean which need database access. Of course you can get rid of Spring and call the BaseContext.getThreadObjectContext(); yourself, but Dependency Injection is the better way to go.
Then you are ready - here is a sample DataProvider.
I would like to return all my stored users therefore the name is UserDataProvider. You'll need to tell Wicket to inject a SpringBean to this object - this can be done with the @SpringBean annotation.
Unfortunately you'll need to add the above call to the constructor. Wicket needs to know the classes to inject. I would be more cool if Wicket would look up all the SpringBean annotations by default. However, it works.
Here we go - i prepared a SelectQuery and used the paging values from Wicket. The connector returns the ObjectContext, the query is done and an Iterator on the results is returned. The SelectQuery could be used as a member variable to avoid multiple instances.
This is not very nice, but will do the trick. I need to return a Wicket Model filled with my User. I have choosen the LoadableDetachableModel. It's being filled at construction level. Therefore my load() method has nothing to do. You could do it in another way, for example you could move the complete Select-code into the load() method. This is the original intention. In my case this is enough and more flexible.
Please have in mind, Wicket will first call the size() method and cancel the process if the is 0 returned. I have created my own CountQuery to perform a SELECT COUNT(). This is one of the less "not so nice things" with Cayenne. You'll need to use the SQLTemplate and write a few lines code to create a count(). However, thanks to generics this has become trivial.
Thats it- with the model builder gui from Cayenne not only this integration is a trivial task. Modelling your application was never more fun.