Upload
gerald-mark
View
215
Download
1
Tags:
Embed Size (px)
Citation preview
RSF Programmers’ Caféand
ORM in Sakai with RSF and Hibernate
Antranig Basman,
CARET, University of Cambridge
Quick Recap of RSF Points
• The key RSF features are:– Pure (REALLY pure) HTML templating– Zero server state processing– Built ENTIRELY of a set of Spring contexts,
rather than merely “integrating” with Spring– Request-scope IoC container, RSAC
RSF compared to JSF• RSF preserves all the “key value points” of JSF
– Abstract “component tree” isolates you from view technology
– EL bindings system isolates the data model from the view layer
– Abstract dispatching procedure isolates you from the hosting environment (Servlets, Portlets, Sakai – IChannel?)
• But delivers on all its promises and more– Free of “model” classes coupling you to the framework
– “Speak like a native” approach to HTML – anything is possible
– Output is GUARANTEED valid XML
– IoC throughout the framework means application fragility does not increase with size, testability &c.
Café “TaskList” app• The simplest app that could be useful• Demonstrates most of the key requirements
on a Sakai app– ORM using standard Sakai SessionFactory (as
well as other approaches, abstracted behind a DAO interface)
– Rendering compliant with Sakai Style Guide– Exposing a Sakai-wide service API
• Written in JSF– Easily the most problematic aspect of the whole
tool
JSF Tasklist App Structure
TaskList.jsp
TaskListBean.java
DataModel
TaskBeanWrapper.java
TaskList.java
TaskListServiceImpl.java
TaskListService.java TaskListManager.java
Thinking• Looking at the TaskListService API in detail, it becomes clear that
it only really has value *within* the app• This API was created because it is awkward to deliver enough of
the Sakai and other Spring dependencies to a JSF-managed bean• This API and Impl can be destroyed completely in the RSF version• We know that in the RSF version, the view logic in the JSP will be
placed into a ViewProducer, TaskListProducer• The ViewProducer is *already* a Spring-configured bean, so the
dependencies which used to be delivered to TaskListServiceImpl will be transferred onto TaskListProducer
• Since the Producer is normal Java code which has full access to the application state, the “Wrapper” class is also unnecessary.
• The presence of the DataModel in what should be the business layer of the app was an unconditional excrescence.
JSF Tasklist App Structure 2
TaskList.jsp
TaskListBean.java
DataModel
TaskBeanWrapper.java
TaskList.java
TaskListServiceImpl.java
TaskListService.java TaskListManager.java
RSF Tasklist App Structure
TaskListBean.java
TaskList.java
TaskListManager.java
TaskListProducer.javaTaskList.html
Timeline 1
• Run the JSF app, and save the HTML it produces (take a look at this as TaskList-originalJSF.html)
• Clean up the HTML (considerably) and annotate with rsf:id
• Take faces-config.xml and convert into the equivalent Spring declarations– Message bundle -> Spring MessageSource (remember
to convert . to / in path)
– TaskListBean.java -> RSAC requestContext.xml
– NavigationCase -> return from TaskListProducer
Timeline 2
• Deal with web.xml– Spring listener declaration is unchanged– FacesServlet -> ReasonableSakaiServlet– Remove JSF context params– Add RSF context param “resourceurlbase”
= context name– Alter Sakai Request Filter mapping to ONLY
apply to path faces/ (no flexibility here with current SakaiRSF – but who cares – noone should see tool URLs anyway)
Timeline 3
• Deal with project.xml– A mess, as with all Maven stuff– Basically, remove JSF dependencies (JSF and
commons-X stuff) and add RSF dependencies (Spring, CGLib, XPP, ServletUtil and PonderUtilCore)
• NB this project does not use Sakai master project but has hard-coded version numbers
Timeline 4
• Write the ViewProducer!– In this case, virtually all the logic ended up in this file. – Made more sense to inject most “leaf” dependencies
into the TaskListBean (e.g. siteId)– This isn’t quite the “expected” effect, since all this code
actually has framework dependence– But there is much less of it in total, and what there is is
more straightforward– And in truth this actually *is* view logic. There is just
a lot less “business” logic in this app than appears at first sight.
– Talk about LocaleGetter
ORM with RSF (OTP style)
• This app used Hibernate ORM, but did not use the RSFHibernate integration library
• Demonstrates the “broad church” approach of RSF
• Basically, if it a Spring bean already, you can just use it in RSF without any problems
• RSF ORM enables us to destroy yet more code from this app.
RSF Tasklist App Structure with OTP
TaskListBean.java
TaskList.java
TaskListManager.java
TaskListProducer.javaTaskList.html
“Nearly”
• Actually “TaskListManager” is serving a dual purpose in our refactored RSF app
• Not only is it the app’s interface to its storage, it is also Sakai’s interface to the app
• This only happens because the app is essentially just a CRUD app. For more complex apps these interfaces would diverge.
• RSF only lets you get rid of internal APIs, not external ones!
• So in fact we would need to preserve TaskListManager for this app for its external function
Transit Beans
• Also, this app does indeed contain one line of actual business logic.
if (newtask.getTask() == null || newtask.getTask().equals("")) { return "error"; }
• This is essentially validation logic. In RSF, this belongs in “Transit Beans”
• A POJO with a setter, and a getter, which throws an exception if value is invalid.
• Use request-scope IoC to wire it into the setter chain
How does RSF OTP work?• Assigns a unique EL path to each Entity managed
by ORM• This is why returning a Map from the RSF version
of TaskListManager is the beginning of OTP• The EL path for the TaskList with Id of 5 is
#{TaskList.5}• Add new entities with the special id form
#{TaskList.new 1}• Issue special binding type (UIDeletionBinding) to
“unlink” or “delete” an existing entity• If the request concludes normally, commit – if any
kind of exception propagates out, rollback
OTP result
• The TaskListBean disappears entirely!!
• TaskListManager disappears entirely (except for external function)
• Issue: We can’t do this in RSF right now, since there is no deletion binding form for issuing multiple deletes
• Will be fixed in RSF 0.6.4
Working example: HibernateCookbook• Look at “javacategory” version at
http://www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?page=HibernateCookBook_4
• Syntax for a Command link operating a deletion binding:
UICommand destroy = UICommand.make(reciperow, "recipe-destroy"); destroy.parameters.add( new UIDeletionBinding("#{Recipe." + id +"}"));
• Isn’t this cool?• Brings Java that much closer to the “convention
over configuration” scriptaculous scumbag crowd
What OTP requires• If you have your own SessionFactory, just point
RSF at it and it will manage all the entities in it• By default, just define a bean called
“sessionFactory”• If you are sharing a SessionFactory (e.g. Sakai
GlobalSessionFactory), need to list the entities you want managed
• You don’t have to use Hibernate to use OTP – All that’s required is:– An “AlterationWrapper” to enclose the action logic
which needs to be transactional– A set of “BeanLocators” which expose the entities at
their root paths
Takehome Message
• There will always need to be external APIs• But internally you can do away with boring DAOs
and action beans, for all basic CRUD functionality• For some apps, the external API is as wide as the
data model, so this is not so much benefit• OTP is just another RSF design option, the first
version of the app worked just fine and was probably quite enough of an improvement on the JSF version.
• If you are still dealing with Hibernate under the covers, you still need to watch out!