RSF Programmers - CARET - University of Cambridge
Download
Report
Transcript RSF Programmers - CARET - University of Cambridge
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
TaskListServiceImpl.java
TaskListService.java
TaskBeanWrapper.java
TaskList.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
TaskListServiceImpl.java
TaskListService.java
TaskBeanWrapper.java
TaskList.java
TaskListManager.java
RSF Tasklist App Structure
TaskList.html
TaskListProducer.java
TaskListBean.java
TaskListManager.java
TaskList.java
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
TaskList.html
TaskListProducer.java
TaskListBean.java
TaskListManager.java
TaskList.java
“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!