210 likes | 224 Views
Dive into the realm of RSF (Rapid Server Framework) as it offers pure HTML templating, zero server state processing, and Spring context-based development. Explore the power of ORM (Object-Relational Mapping) within the Sakai platform using RSF and Hibernate. Witness the seamless integration of Spring beans and RSF components to build a robust and scalable application. Understand the migration from JSF to RSF, leveraging RSF's elegant design principles and eliminating unnecessary complexities. Experience a hands-on approach in developing a Sakai TaskList app with RSF, RSAC, and Spring dependency injection.
E N D
RSF Programmers’ CaféandORM 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 TaskListServiceImpl.java TaskListBean.java TaskListService.java TaskListManager.java DataModel TaskBeanWrapper.java TaskList.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 TaskListServiceImpl.java TaskListBean.java TaskListService.java TaskListManager.java DataModel TaskBeanWrapper.java TaskList.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!