Title: Introduction to Reasonable Server Faces
1Introduction to Reasonable Server Faces
- Aaron Zeckoski
- and
- Antranig Basman
2Why use RSF?
- Core RSF Values
- Completely pure HTML templating
- Roundtrip with designers without loss
- Preview behaviour as well as appearance from the
file system - Templates can be reloaded on a live server just
by dropping in files - IoC is built-in
- No need to "integrate with" Spring, RSF is built
from Spring - IoC in the request scope "refreshes the parts
other IoC cannot reach" (universal portability
without code changes)
3Why use RSF? (contd.)
- Core RSF Values
- Stateless design
- Lightweight EL system allows talk of data "in the
future" as well as via web services/AJAX - Request scope is completely flushed at the end of
the request - Sakai sessions can be gt 50Mb per user. RSF
encourages designs where session sizes are
minimized - Uses a more PHP-like "running off the DB" model
4A Sample RSF template
lt?xml version"1.0" encoding"UTF-8"
?gt lthtmlgtltheadgtlttitlegtRSF Itemslt/titlegtlt/headgtltbod
ygt Hello, ltspan rsfid"current-user-name"
gtCurrent Userlt/spangt ltform rsfid"listItemsForm"
method"post"gt lttable class"listHier"gt
lttr rsfid"item-row" gt lttd
class"firstColumn"gt ltspan
rsfid"item-title" gtNon updateable itemlt/spangt
lta rsfid"item-update"
href"AddItem.html?id1"gtNew item titlelt/agt
lt/tdgt lttd rsfid"item-dateCreated"
class"secondColumn"gt Oct 29, 2007 1026 AM
lt/tdgt lt/trgt lt/tablegt lt/formgt lt/bodygt
lt/htmlgt
5How to use this template?
- In RSF, there is a complete separation between
markup and render logic - Markup held in an XHTML template decorated with
rsfid markers - Logic held in a Spring-managed (Java) bean known
as a Producer - The job of a Producer is to produce a tree of
elementary ("primitive") UI components - To see how this all fits together, let's look at
the overall RSF app structure
6RSF structure and code
7RSF structure
- The template (always html) defines the interface
- The producer (java or xml) defines the view,
populates the template, and handles navigation - ViewParams define the values passed between views
(get) - The requestContext defines producer and backing
beans - The applicationContext defines app scope beans
and handles rsf app config (via spring) - Backing beans handle action processing
- Logic layer beans can be injected as defined in
the context xml files - Model is basic data POJO
Template (html)
ViewParams (java)
Producer (java)
requestContext (xml)
Backing Bean (java)
applicationContext (xml)
Logic Layer (rest of app)
model (java)
8RSF templates
Template (html)
- XHTML files
- Must be valid XML or runtime error will occur
- No custom tags used or needed
- Truly is a pure XHTML template
- Only uses one custom attribute
- rsfid - identifies this component for the
producer
9Sample template
lt?xml version"1.0" encoding"UTF-8"
?gt lthtmlgtltheadgtlttitlegtRSF Itemslt/titlegtlt/headgtltbod
ygt Hello, ltspan rsfid"current-user-name"
gtCurrent Userlt/spangt ltform rsfid"listItemsForm"
method"post"gt lttable class"listHier"gt
lttr rsfid"item-row" gt lttd
class"firstColumn"gt ltspan
rsfid"item-title" gtNon updateable itemlt/spangt
lta rsfid"item-update"
href"AddItem.html?id1"gtNew item titlelt/agt
lt/tdgt lttd rsfid"item-dateCreated"
class"secondColumn"gt Oct 29, 2007
1026 AM lt/tdgt lt/trgt
lt/tablegt lt/formgt lt/bodygtlt/htmlgt
10RSF producer
Producer (java)
- Controls displays logic and populates the
template with dynamic information - Defines a view uniquely
- By setting a ViewID
- Recommend you create a public static VIEW_ID
- Implements ViewComponentProducer
- Define start page by implementing DefaultView
- Implement NavigationCaseReporter to control
submit navigation - Implement ViewParamsReporter to receive query
parameters from http request
11Sample producer
public class ItemsProducer implements
ViewComponentProducer, DefaultView public
static final String VIEW_ID "Items" public
String getViewID() return VIEW_ID
private CrudPlusLogic logic public void
setLogic(CrudPlusLogic logic) this.logic
logic public void fillComponents(UICont
ainer tofill, ViewParameters viewparams,
ComponentChecker checker)
UIOutput.make(tofill, "current-user-name",
logic.getCurrentUserDisplayName()) UIForm
listform UIForm.make(tofill, "listItemsForm")
ListltCrudPlusItemgt l logic.getAllVisibleIte
ms() for (CrudPlusItem item l)
UIBranchContainer itemrow UIBranchContainer.make
(listform, "item-row") if
(logic.canWriteItem(item))
UIInternalLink.make(itemrow, "item-update",
item.getTitle(), new
AddItemViewParameters(AddItemProducer.VIEW_ID,
item.getId()) ) else
UIOutput.make(itemrow, "item-title",
item.getTitle() )
UIOutput.make(itemrow, "item-dateCreated",
item.getDateCreated() )
12RSF ViewParams
ViewParams (java)
- Controls the passing of data between page views
- Represents query parameters (GET) and URL trunk
in the abstract - extends SimpleViewParameters
- Should be used when data needs to be sent from
one view to another - Uses URLs in the RESTful way they were designed
- However, is abstract and typesafe
- Can be reused on multiple pages
13Sample ViewParams
- Is a "Pea" (uses fields rather than
getters/setters) - getParseSpec method is unnecessary unless you
want fine control over URL structure
14RSF requestContext
requestContext (xml)
- Request Scope Context
- Often called RSAC
- All RSAC beans are lazy by default
- Standard Spring bean definition file
- Uses the Spring file parser code
- Only includes a subset of the standard
functionality to increase speed - Location of this file is set in the web.xml
15Sample requestContext
lt?xml version"1.0" encoding"UTF-8"?gt lt!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http//www.springframework.org/dtd/spring-beans
.dtd"gt ltbeansgt lt!-- list the backing beans
here --gt ltbean id"itemsBean"
class"org.sakaiproject.crudplus.tool.ItemsBean"
init-method"init"gt ltproperty
name"logic" ref"org.sakaiproject.cru
dplus.logic.CrudPlusLogic" /gt lt/beangt
lt!-- list the producer beans here --gt ltbean
class"org.sakaiproject.crudplus.tool.producers.It
emsProducer"gt ltproperty name"logic"
ref"org.sakaiproject.crudplus.logic.CrudPl
usLogic" /gt lt/beangt ltbean
class"org.sakaiproject.crudplus.tool.producers.Ad
dItemProducer"gt ltproperty name"logic"
ref"org.sakaiproject.crudplus.logic.Crud
PlusLogic" /gt lt/beangt lt/beansgt
16RSF applicationContext
applicationContext (xml)
- A standard Spring bean definition file
- Puts the beans in the application context
- Mostly used for configuring RSF
- Define child of requestAddressibleParent to
specify beans which can be the target of EL - Define child of beanScopeParent to create a new
session scope for session beans - Define a child of CRITemplateResolverStrategy to
control the location of templates - Location of this file set in web.xml
17Sample applicationContext
lt?xml version"1.0" encoding"UTF-8"?gt lt!DOCTYPE
beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http//www.springframework.org/dtd/spring-beans
.dtd"gt ltbeansgt lt!-- For security purposes, only
beans listed in the comma separated value
list may be the target of EL operations coming
in over the request --gt ltbean parent"requestAddr
essibleParent"gt ltproperty name"value"
value"itemsBean, infoMessages"/gt lt/beangt lt!--
Put this backing bean in session scope --gt ltbean
id"messageBeanScope" parent"beanScopeParent"gt
ltproperty name"copyPreservingBeans"
value"infoMessages" /gt ltproperty
name"exclusive" value"true" /gt lt/beangt
lt/beansgt
18RSF Backing Bean
Backing Bean (java)
- Typical bean with methods to handle actions and
public properties - No RSF dependencies
- Store data needed for processing the user actions
using public properties - Control data model objects with public properties
(using EL from producer) - Process actions using methods
- Can interact with logic layer
- But so can the producers
- Created and destroyed in the request cycle by
default (recommended practice) - Can override this behavior
19Sample backing bean
public class ItemsBean public CrudPlusItem
newItem new CrudPlusItem() public Map
selectedIds new HashMap() ... private
CrudPlusLogic logic public void
setLogic(CrudPlusLogic logic)
this.logic logic ... public String
processActionAdd() if
(newItem.getHidden() null) //
null here means that the box was not checked
newItem.setHidden( DEFAULT_HIDDEN )
logic.saveItem(newItem)
return "added"
20Web app basics
- 4 key things you need to do in a webapp
- Output dynamic text
- Render data to the screen
- Loop structures
- Output collection or render tables
- Optional rendering of components
- Render some components based on state
- Trigger Actions
- User actions or data transmission
- In RSF, these all are done using one part in the
template and another in the producer (and maybe
the backing bean for an action method)
21Output dynamic text
1
Hello, ltspan rsfid"current-user-name"gtCurrent
Userlt/spangt
UIOutput.make(tofill, "current-user-name",
logic.getCurrentUserDisplayName())
- Uses an rsfid on an HTML entity to show where to
place the dynamic text - Does not have to be a span or div only!
- UIOutput will send the escaped string to the ID
location in the component tree - Non-escaped output using UIVerbatim
- Avoid this unless truly necessary
22Loop structure
2
Use UIBranchContainer and colon tags for looping
structures
ListltItemgt l logic.getAllVisibleItems() for
(Item item l) UIBranchContainer itemrow
UIBranchContainer.make(listform,
"item-row") if (logic.canWriteItem(item))
UIInternalLink.make(itemrow, "item-update",
item.getTitle(), new AddItemViewParameters(
AddItemProducer.VIEW_ID, item.getId()) )
else UIOutput.make(itemrow, "item-title",
item.getTitle() ) UIOutput.make(itemrow,
"item-dateCreated", item.getDateCreated() )
lttable class"listHier"gt lttr
rsfid"item-row"gt lttd
class"firstColumn"gt ltspan
rsfid"item-title"gtNon updateable itemlt/spangt
lta rsfid"item-update"
href"AddItem.html?id1"gtNew item titlelt/agt
lt/tdgt lttd rsfid"item-dateCreated"gtOc
t 29, 2007 1026 AMlt/tdgt lt/trgt lt/tablegt
23Optional rendering
3
if (item.getHidden().booleanValue())
UIOutput.make(itemrow, "item-title",
item.getTitle() )
ltspan rsfid"item-title"gtHidden item titlelt/spangt
- HTML entities are rendered if the component is
tied via the rsfid - If there is no UI component matching the id then
the renderer skips over it - A UIOutput can also peer with a tag in the
template with further component children, to swap
in or out a whole block of markup
24Trigger actions
4
ltinput rsfid"add-update-item" type"submit"
value"Add/Update Item" /gt
UICommand.make(addupdateitem, "add-update-item",
"itemsBean.processActionAdd")
public String processActionAdd()
logic.saveItem(updateItem) return "added"
- Use a normal submit button with an id
- Use UICommand to tie to an action method in a
backing bean using EL - NB "action methods" are considered an
old-fashioned form of programming try to use
BeanGuards instead (more later) - Return string ties to a navigation case in the
producer
25RSF in practice
26RSF experience
- RSF has a moderate learning curve
- Mostly unlearning poor practices
- UI components are comprehensive
- Cover all HTML entities, fairly flexible
- AJAX integration easy
- Designed to work well with AJAX and JS
- Works like a webapp should
- Normal REST, back button works
- Easy for UI designers to work with
27RSF EL
requestwriteablebean.property1.subproperty2
- A tiny subset of the functionality of JSF
Expression Language - No logic in the expression
- Sometimes called Value Language (VL)
- Works with any bean in the request or application
context - More info on the RSF EL page
URL http//www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?
pageEL
28OTP (One True Path)
ltinput rsfid"title-input" size"60"
name"title" type"text"/gt
UIInput.make(form, "title-input",
EntryLocator.1.title")
public class EntryLocator implements BeanLocator
ltbean id"EntryLocator" classuk.ac.cam.blogwow.
tool.otp.EntryLocator /gt
- Defines a single path (EL) to your data
- Points to a BeanLocator which allows you to tell
RSF where to find your data - Point it at your logic/dao layer
- RSF 0.7.2 has an automated "EntityBeanLocator"
which will map to most DAO APIs
29Internationalization (I18n)
ltb rsfidremove-item"gtAre you sure you want to
remove item (title)?lt/bgt
UIMessage.make(tofill, remove-item",
"remove.item.text", new Object
item.getTitle() )
remove.item.textAre you sure you want to remove
item (0)?
- Well supported with UIMessage concrete class
- Also MessageLocator
- Simple cases can be handled in the template with
rsfid"msgkey" - Takes advantage of the standard Java language
properties bundle handling - Uses the Spring MessageSource for resource
(properties file) loading - Configurable in applicationContext
URL http//www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?
pageI18N
30User feedback
ltdiv rsfid"message-for" class"alertMessage"gt
ltul style"margin0px"gtltligtMessage for user
herelt/ligtlt/ulgt lt/divgt
messages.addMessage( new TargettedMessage(user.me
ssage", new Object
item.getTitle() ,
TargettedMessage.SEVERITY_INFO))
user.messageNew item saved (0)
- Allows for messages generated in a previous
request to appear in the template - No code is required in the receiving template,
only the element with the rsfid - Format of the output messages is configurable
31Javascript and AJAX
- RSF does not use AJAX for its own purposes (not
embedded) so there are no issues with collisions - There are some widgets and helpers that are
included with RSF which use AJAX though - RSF includes a Javascript library to make it easy
to work with the RSF generated element ids - Can be tricky to work with because of the way the
branch nesting works
32RSF component trees
- Binds the markup to the model
- rsfid in the template
- EL in the producer
- Tree and components created and destroyed during
the request cycle - Short lived, frees up resources
- Rooted in a view and only kept around long enough
to render the view
URL http//www2.caret.cam.ac.uk/rsfwiki/Wiki.jsp?
pageComponent
33RSF structure revisit
- The template is pure XHTML
- Easy for UI designers
- The producer is simple and cleanly defines a view
- ViewParams abstract out the passing of values
- The requestContext and applicationContext are
pure spring config - Can be mixed up sometimes
- Backing beans are really just simple beans
Template (html)
ViewParams (java)
Producer (java)
requestContext (xml)
Backing Bean (java)
applicationContext (xml)
Logic Layer (rest of app)
model (java)
34RSF resources
- RSF Wiki (online documentation)
- http//www2.caret.cam.ac.uk/rsfwiki/
- RSF forums
- http//ponder.org.uk/rsf/
- RSF APIs
- http//saffron.caret.cam.ac.uk/projects/RSFUtil/ap
idocs/ - RSF SVN
- https//saffron.caret.cam.ac.uk/svn/
35Questions?
- RSF
- http//www2.caret.cam.ac.uk/rsfwiki/