Presentation is loading. Please wait.

Presentation is loading. Please wait.

Creative Commons Attribution- NonCommercial-ShareAlike 2.5 License Sakai Programmer's Café Saki PSaki PUK Idiomatic RSF – OTP, Messaging and BeanGuards.

Similar presentations


Presentation on theme: "Creative Commons Attribution- NonCommercial-ShareAlike 2.5 License Sakai Programmer's Café Saki PSaki PUK Idiomatic RSF – OTP, Messaging and BeanGuards."— Presentation transcript:

1 Creative Commons Attribution- NonCommercial-ShareAlike 2.5 License Sakai Programmer's Café Saki PSaki PUK Idiomatic RSF – OTP, Messaging and BeanGuards Antranig Basman, CARET, University of Cambridge

2 Recap of RSF Design Three main threads –On the design side, completely pure (X)HTML templates, previewability of appearance AND behaviour (IKAT renderer) –On the code side, a completely unintrusive binding to an application model (EL) Portability of applications assured through request- scope IoC (RSAC) – based on the Spring framework Statelessness and transparency of application behaviour through request cycle and ViewParameters –In between, a completely technology-neutral and behaviour-free representation of the *function* of a user interface (component tree)

3 Simple Rendering Sample Hello, Current User Uses an rsf:id 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 UIBranchContainer and colon tags allow complex looping and branching without polluting the template UIOutput.make(tofill, "current-user-name", logic.getCurrentUserDisplayName());

4 EL in RSF VERY lightweight Just a dot-separated path of bean names and properties (or 0-arg method for a method binding) Binds component tree to the model without polluting it No logic allowed Example from CRUD tool – an input field from AddItemProducer.java: UIInput.make(addupdateitem, "item-title", "#{itemsBean.newItem.title}", DEFAULT_TITLE ); Component class EL Reference Initial value

5 Quick recap of Spring A Spring bean has no framework dependencies (in Spring, as in RSF) Is configured in an XML file, which specifies bean class, bean properties and other dependencies (other beans) Here is the itemsBean we referred to earlier: <bean id="itemsBean" class="org.sakaiproject.crudplus.tool.ItemsBean" init-method="init"> <property name="logic" ref="org.sakaiproject.crudplus.logic.CrudPlusLogic" /> Bean name Injected Dependency

6 ItemsBean definition public class ItemsBean { public CrudPlusItem newItem = new CrudPlusItem(); public Map selectedIds = new HashMap(); private CrudPlusLogic logic; public void setLogic(CrudPlusLogic logic) { this.logic = logic; }... Initial section of ItemsBean –Recall that our EL was #{itemsBean.newItem.title} Classic example of the “captive entity pattern” –Halfway towards to OTP (which we will talk about NOW!)

7 Reworked CrudPlusItem sample Discuss the RSF inter-view messaging system based on TargettedMessageList Streamline code with more advanced RSF features –Validation is packaged as reusable POJOs through “BeanGuards” Also reworked to OTP (One True Path) ORM idiom –This idiom is less appropriate here than it would be in a completely “flat” model but still adds some value

8 I18N in RSF Since 0.7.1, done primarily through the UIMessage component –Use UIMessage directly rather than UIOutput to render a localised message –Use UIMessage as a nested component in UICommand, UILink and Decorators to render a localised label –Use setMessageKeys() on a UISelect component to interpret label String array as message keys UIMessage.make(tofill, "level-header", "modifytemplate.level.header", new String[] {currentLevel, new Integer(templateItemsList.size()).toString(), }); UIInternalLink.make(tofill, "modify_title_desc_link", UIMessage.make("modifytemplate.modify.title.desc.link"), new TemplateViewParameters(ModifyTemplateProducer.VIEW_ID, templateId));

9 Underlying I18N realities Messages are formatted as if by JDK’s standard MessageFormat (see Sun API) Next layer is a Spring standard MessageSource (by default ReloadableResourceBundleMessageSource) Top layer is RSF’s MessageLocator (application scope bean named messageLocator) which factorises off the dependence on the Locale and adds more convenience signatures Finally there is the UIMessage component which allows access to the message bundle without injecting anything String result = MessageFormat.format( "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.", arguments);

10 TargettedMessageList Functionality will not be fully rounded out until 0.8, but new in 0.7 is support for “info messages” The “errors” scope is a kind of mini-flow scope, and is targetted ONLY at the following view targettedMessageList is a request-scope (unreasonable) bean Inject it where you want (also has a standard proxy) Localisation, rendering, and formatting comes for free Messages appear in the template at the tag marked rsf:id=“message-for:*” Messages “widget” can be reskinned through messageTemplateContributor messages.addMessage(new TargettedMessage("item_updated", new Object[] {item.getTitle()}, TargettedMessage.SEVERITY_INFO));

11 More on scr= I SCRs are provided for HTML aggregation in reusable components –scr=contribute-script and scr=contribute-style mark CSS and JS declarations that need to be aggregated from components –scr=head-collect marks the place they should be collected (automatically inferred) –scr=portal-matter marks some material that is a placeholder for portal definitions and should be replaced (in progress)

12 More on scr= II Automatic inference of SCR tags is done by a TemplateParseInterceptor Any manual scr= declared in the template will block automatic inference public interface TemplateParseInterceptor { public void adjustAttributes (String tag, Map attributes); }

13 BeanGuards ™ for Validation A declarative strategy for attaching rules to modifications of the bean container Similar to, for example, Spring’s declarative transaction demarcation, or the Spring Acegi security framework Could also be seen as a kind of AOP –Although in this case the kind of AOP you can eat between meals without losing your appetite In any case, the key functionality is to provide guaranteed execution of logic without intruding either on the target, or on the validation code with framework code

14 BeanGuards Two main styles of BeanGuards –The Spring Validator interface is supported directly –Also supports pure POJO validators (preferred if Spring portability is no concern) Both of these are simply declared as beans (typically at application scope) * @author Rod Johnson public interface Validator { boolean supports(Class clazz); void validate(Object obj, Errors errors); }

15 Declaring a BeanGuard As well as declaring the Guard itself, you must declare WHAT it is meant to be guarding A Guard is targetted at a particular EL path within the container Many options for the “style” of the Guard, but typically one guards write access to the target path RSF contexts provide the helpful parent definition writeGuardParent For Spring Validator, you can use an inner bean for an all-in-one definition:

16 Using a POJO Validator For a POJO validator, the validator must be declared as a request scope bean Need to specify the property on the validator to receive the target object – can be combined with validator bean name to form an EL-like expression <bean id="CrudPlusItemValidator" class="org.sakaiproject.crudplus.tool.CrudPlusItemValidator" /> At request scope: In code: public class CrudPlusItemValidator { public void setItem(CrudPlusItem newItem) { if (newItem.getTitle() == null || newItem.getTitle().equals("")) { throw new IllegalArgumentException("title_required"); }

17 POJO Validators vs. Spring Validators Spring Validators –Are a somewhat recognised standard –Can be implemented in application scope –Cannot validate something which is null! POJO Validators –Can use the “sleaze” style of throwing a message key as exception text, and in that case be completely dependency free –Can be written without casts –Would need to inject TargettedMessageList if you wanted more complex message formatting

18 One True Path RSF ORM “idiom” rather than “library” OTP (= “One True Path”) assigns unique EL path to each entity of data model RSF “EL” is slimmed down so much (only elementary reads/writes permitted) that it is safe to address arbitrarily nasty “POJO” models, even those managed by Hibernate In some cases can lead to the abolition of “DAO”s Is an idea of more general power (come to “Helpers BOF”)

19 How does RSF OTP work? Assigns a unique EL path to each Entity managed by ORM, where read/write of the EL is *directly* bound to read/write of the model The EL path for the CrudPlusItem with ID of 5 is #{CrudPlusItem.5} Add new entities with the special id form #{CrudPlusItem.new 1} Following two points are part of “Full” OTP but are not used in the OTP version of CrudPlusTool 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. Not necessarily tied to any particular flavour or even use of ORM – EL paths are completely “generic”

20 How to set up OTP Again, a general concept rather than a specific library/implementation Using RSFHibernate exposes the entire entity set automatically via OTP SakaiRSF contains GenericDAOEntityBeanManager which will automatically convert entities managed by Aaron Zeckoski’s Generic DAO to OTP In general PonderUtilCore contains BasicObstinateEBL (implementing ObstinateEntityBeanLocator ) which will do most of the legwork in setting up an OTP mapping You can just do it yourself! (Can use plain Maps rather than BeanLocators)

21 How to use OTP In “pure” OTP, you can just emit bindings from the producer, and do without any kind of backing bean at all (see this style in OTP version of Vancouver’s TaskList app) In CrudPlusItem, only makes sense to operate OTP for “add/update” operations UIInput.make(newtask, "new-task-name", "#{Task.new 1.task}"); UICommand.make(newtask, "submit-new-task", null); newtask.parameters.add( new UIELBinding("#{Task.new 1.owner}", userId)); newtask.parameters.add( new UIELBinding("#{Task.new 1.siteId}", siteId));... deleteform.parameters.add(new UIDeletionBinding("#{Task}", new ELReference("#{deleteIds}"))); if (logic.canWriteItem(item)) { // check for current user and site UIBoundBoolean.make(itemrow, "select-item", "itemsBean.selectedIds." + item.getId(), Boolean.FALSE);

22 When to use OTP OTP comes into its own more and more in apps with larger schemas, with more anaemic models Is also much less trouble in single-ClassLoader environments Is particularly powerful for auto-generated apps (XML ViewProducers, hbm2java models) Since CRUDPlus has *some* logic (largely permissions checking) in its logic layer, requires more work Need to set up a “Front DAO” – CrudPlusLogicDAO I still think the cost is just about worth it in this case –“Changed value logic” is much clearer –With bigger entities would save more and more time

23 The Magic Ingredient What is this method in GenericDAO for? “Natural” OTP semantics are Spring transactional semantics –Request concludes normally == commit transaction –Exception is thrown == perform rollback RunnableInvoker is the greatest interface that was never in the JDK –In other languages (Javascript, Ruby, any of the functional family is not even necessary) public void invokeTransactionalAccess(Runnable toinvoke) { toinvoke.run(); }

24 The Great OSIV vs. DTO debate OSIV = Open Session In View DTO = Data Transfer Object Both are answers to the architectural risk posed by Hibernate OSIV costs are of leakage –Many believe that the view layer should be susceptible to raw persistence exceptions –In fact RSF has a coherent exception-handling strategy and this is not such a serious problem DTO costs are of redundancy –Is an absolute, rather than a relative architectural cost (i.e. is unconditionally bad! :) ) This debate is somewhat aligned to the Anaemic vs. Rich Domain model debate (backwards – a DTO is a fabricated Anaemic model) ONE purpose of invokeTransactionAccess is to enable OSIV

25 Why have I never seen this before? Is the natural completion of Sakai’s “poor man’s Enterprise Container” idiom Currently obscured by the fact that Sakai users are “happy” to have Hibernate as a global ClassLoader visible dependency Ultimately, both Spring and Hibernate will GO invokeTransactionalAccess in all frameworks enables OSIV –in RSF OSIV is considerably less messy and more controllable – can simply target the “alteration” cycle via a RunnableInvoker In RSF iTA also enables full OTP semantics, again since it properly only targets the alteration cycle public class GenericDAORunnableInvoker implements RunnableInvoker { private CoreGenericDao genericDAO; public void setGenericDAO(CoreGenericDao genericDAO) { this.genericDAO = genericDAO; } public void invokeRunnable(Runnable torun) { genericDAO.invokeTransactionalAccess(torun); }

26 A RunnableInvoker Conversation Nig: “Don’t you think people will be upset by the fact we don’t supply JTA like all the other containers? Thorton: “Actually I think all the other containers use JTA because they can’t think up RunnableInvoker” RIP Andrew Thornton, RSAC instigator and general RSF curmudgeon (No, he’s not really dead!) RunnableInvoker/iTA is the natural conclusion of Spring Transactional thinking, and allows transaction semantics to be exported out of an API into another ClassLoader with ZERO code intrusion Needs to be fleshed out with partners InvokeModifyingAccess and invokeReadOnlyAccess

27 RunnableInvoker put to more work AOP fanatics will recognise RunnableInvoker as the natural body of an “around” advice Can also be used as a BeanGuard with the AROUND timing –One use: converting exceptions thrown by JDK conversion methods into suitable “sleaze” forms – see uk.org.ponder.util.StaticExceptionConvertingRI Can also be used as the body of a BeanFetchBracketer –Like a BeanGuard only stronger – brackets the fetch of ANY RSAC bean –Example: RSF LogonTest sample, supplies a static declarative strategy for protecting pages from being viewed by a user who is not logged on

28 LogonTest App SecurityWrapper public class SecurityWrapper implements RunnableInvoker { private ViewParameters viewparams; private LogonBean logonbean; public void setViewParameters(ViewParameters viewparams) { this.viewparams = viewparams; } public void setLogonBean(LogonBean logonbean) { this.logonbean = logonbean; } public void invokeRunnable(Runnable towrap) { if (logonbean.name == null && !(LogonProducer.VIEW_ID.equals(viewparams.viewID))) { throw new SecurityException("Cannot view page " + viewparams.viewID + " while not logged on"); } towrap.run(); }


Download ppt "Creative Commons Attribution- NonCommercial-ShareAlike 2.5 License Sakai Programmer's Café Saki PSaki PUK Idiomatic RSF – OTP, Messaging and BeanGuards."

Similar presentations


Ads by Google