Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JSF Component Behaviors


Published on

JSF Summit 2009 presentation covering the JSF 2 component Behavior API.

Published in: Technology
  • Hi Andy,

    thank you for the link. Yesterday I found a solution that worked well. But I’m curious about how you solved it.
    Are you sure you want to  Yes  No
    Your message goes here
  • Hi Sebastian -

    I've been meaning to donate my suggest behavior code to one of the JSF open source projects, but haven't had time to do so. In the meantime, you can grab the code from here:

    You are welcome to use this code however you see fit, though keep in mind that it is really only demo quality code. :-)

    Take a look at SuggestBehavior.decode() to see how I am generating the response payload.

    Are you sure you want to  Yes  No
    Your message goes here
  • I solved the above problem by using a TagHandler, but now my problem is to return the suggestions to the client. In your presentation slide 74 and 75 are identically. Maybe slide 75 should cover that topic. Could you please give my a hint, how send the suggestions back?
    Are you sure you want to  Yes  No
    Your message goes here
  • I tryed to code your suggestion example but to assign my JS-code to multiple events, I had more than one occurence of the tag:

    <foo:suggest event='blur' suggester='#{suggester}' />

    <foo:suggest event='keyup' suggester='#{suggester}' />

    Is it possible to assign script code to multiple events without more than one tag and without to set the event-attribute?
    Are you sure you want to  Yes  No
    Your message goes here

JSF Component Behaviors

  1. 1. JSF Component Behaviors Andy Schwartz | Oracle Corporation
  2. 2. Agenda <ul><li>History </li></ul><ul><li>Behavior API: Basics </li></ul><ul><li>A Simple Sample Behavior </li></ul><ul><li>Behavior API: Advanced Topics </li></ul><ul><li>Auto Suggest Sample Behavior </li></ul><ul><li>Future </li></ul>
  3. 3. <ul><li>History </li></ul>
  4. 4. First <ul><li>First, there was Ajax. </li></ul><ul><li>And it was good. </li></ul><ul><li>But it required JavaScript code. </li></ul>
  5. 5. Sample: Ajax JavaScript API <ul><li><h:outputScript name=&quot;jsf.js&quot; library=&quot;javax.faces&quot;/> </li></ul><ul><li><h:commandButton value=&quot;Do something Ajaxy&quot; </li></ul><ul><li>onclick=&quot;jsf.ajax.request(this, event, </li></ul><ul><li>{render: 'out'}); return false;&quot;/> </li></ul><ul><li><h:outputText id=”out” value=”Update me!”/> </li></ul>
  6. 6. Ajax JavaScript API <ul><li>The Good </li></ul><ul><ul><li>Standard </li></ul></ul><ul><ul><li>Flexible </li></ul></ul><ul><li>The Bad </li></ul><ul><ul><li>Verbose </li></ul></ul><ul><ul><li>Error-prone </li></ul></ul>
  7. 7. <ul><li>Time for a declarative Ajax API </li></ul>
  8. 8. Declarative Ajax, Take 1 <ul><li>New Components? </li></ul>
  9. 9. Sample: New Components? <h:commandButton value=“Not Ajax”/> <a:commandButton value=“Ajax!”/>
  10. 10. New Components? <ul><li>The Good </li></ul><ul><ul><li>Simple </li></ul></ul><ul><ul><li>Familiar </li></ul></ul><ul><li>The Bad </li></ul><ul><ul><li>Component explosion </li></ul></ul><ul><ul><li>Next feature: more components? </li></ul></ul>
  11. 11. Declarative Ajax, Take 2 <ul><li>New Attributes? </li></ul>
  12. 12. Sample: New Attributes? <h:commandButton ajax=“true”/>
  13. 13. New Attributes? <ul><li>The Good </li></ul><ul><ul><li>Simple </li></ul></ul><ul><ul><li>No new components </li></ul></ul><ul><li>The Bad </li></ul><ul><ul><li>Attribute explosion </li></ul></ul><ul><ul><li>Next feature: more attributes? </li></ul></ul>
  14. 14. Declarative Ajax, Take 3 <ul><li>Attached Objects? </li></ul><ul><li>Remember those? </li></ul>
  15. 15. What Are Attached Objects? <ul><li>Attached objects enhance components with functionality not anticipated by the original component author. </li></ul>
  16. 16. Some Existing Attached Objects <ul><li>Converters </li></ul><ul><ul><li>f:convertNumber </li></ul></ul><ul><ul><li>f:convertDateTime </li></ul></ul><ul><li>Validators </li></ul><ul><ul><li>f:validateLength </li></ul></ul><ul><ul><li>f:validateBean </li></ul></ul><ul><ul><li>f:validateRegex </li></ul></ul>
  17. 17. Ajax Attached Object? <!-- We already do this…--> <h:inputText> <f:convertNumber/> </h:inputText> <!-- Why not this? --> <h:commandButton> <f:ajax/> </h:commandButton>
  18. 18. Ajax Attached Object <ul><li>Yes! </li></ul>
  19. 19. Ajax Attached Object <ul><li>The Good </li></ul><ul><ul><li>Easy to use </li></ul></ul><ul><ul><li>Familiar pattern </li></ul></ul><ul><ul><li>No attribute explosion </li></ul></ul><ul><ul><li>No component explosion </li></ul></ul><ul><ul><li>Some precedent exists </li></ul></ul><ul><ul><ul><li>Think a4j:support as attached object instead of component </li></ul></ul></ul><ul><li>The Bad </li></ul><ul><ul><li>More verbose than component/attribute alternatives </li></ul></ul><ul><ul><li>Somebody needs to design the API! </li></ul></ul>
  20. 20. <ul><li>Behavior API: Basics </li></ul>
  21. 21. API Requirements <ul><li>Loose Coupling </li></ul><ul><li>Surprise? </li></ul>
  22. 22. Loose Coupling <ul><li>Components should not contain Ajax-specific code </li></ul><ul><li>Objects contribute scripts to component markup </li></ul><ul><li>Components know where to insert attached scripts </li></ul><ul><li>Objects may be attached to arbitrary components </li></ul><ul><li>Objects may implement arbitrary behaviors </li></ul><ul><ul><li>Not limited to Ajax </li></ul></ul>
  23. 23. Two New Contracts <ul><li>ClientBehavior </li></ul><ul><li>ClientBehaviorHolder </li></ul>
  24. 24. ClientBehavior Contract <ul><li>String getScript(ClientBehaviorContext) </li></ul>
  25. 25. ClientBehavior Scripts <ul><li>What can a ClientBehavior script do? </li></ul>
  26. 26. Say Hello // Some people *always* start with “Hello, World!” public String getScript(ClientBehaviorContext c) { return “alert(‘Hello, World!’)”; }
  27. 27. Ajax // Slightly more interesting public String getScript(ClientBehaviorContext c) { return “jsf.ajax.request(this, event)”; }
  28. 28. What Else? <ul><li>Client-side validation </li></ul><ul><li>DOM manipulation </li></ul><ul><li>Tooltips, hover content </li></ul><ul><li>Disclosures </li></ul><ul><li>Logging </li></ul><ul><li>Confirmation </li></ul><ul><li>Key handling </li></ul><ul><li>Auto-suggest </li></ul>
  29. 29. Who Calls getScript()? <ul><li>Components/Renderers call getScript() during rendering and insert scripts into the generated markup. </li></ul>
  30. 30. Standard ClientBehaviors <ul><li>Just one for now </li></ul><ul><ul><li>Java API: AjaxBehavior </li></ul></ul><ul><ul><li>Tag API: <f:ajax> </li></ul></ul>
  31. 31. Attaching ClientBehaviors <ul><li>Remember EditableValueHolder? </li></ul>
  32. 32. ClientBehaviorHolder Contract void addClientBehavior( String eventName, ClientBehavior behavior)
  33. 33. What Events? <ul><li>Components define available events/attach points </li></ul><ul><li>Behavior events can correspond to DOM events </li></ul><ul><li>Events can also be “logical” (component-level) </li></ul><ul><li>Some obvious events: </li></ul><ul><ul><li>h:commandButton: click </li></ul></ul><ul><ul><li>h:inputText: change </li></ul></ul><ul><li>Some less obvious events </li></ul><ul><ul><li>h:commandButton: focus, blur </li></ul></ul><ul><ul><li>h:inputText: keyup, keydown, keypress </li></ul></ul><ul><ul><li>h:panelGroup: mouseover, mouseout </li></ul></ul><ul><ul><li>foo: bar </li></ul></ul>
  34. 34. ClientBehaviorHolder Contract Collection<String> getEventNames();
  35. 35. Usage <h:commandButton> <f:ajax event=“focus”/> </h:commandButton> <h:inputText> <f:ajax event=“keypress”/> </h:inputText> <h:panelGroup> <foo:showHoverContent event=“mouseover”/> </h:panelGroup>
  36. 36. Logical Events <ul><li>Some components expose logical events </li></ul><ul><li>Command: action (not DOM click) </li></ul><ul><li>Input: valueChange (not DOM change) </li></ul><ul><li>Client-side event abstraction over DOM </li></ul><ul><li>Hides arbitrary DOM implementations </li></ul><ul><li>Matches server-side abstraction </li></ul><ul><li>Helpful in wrapping scenarios </li></ul>
  37. 37. Logical Events <!-- &quot;click&quot; event doesn't work if we want to target command components exclusively. --> <f:ajax event=&quot;click&quot;> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup> </f:ajax>
  38. 38. Logical Events <!-- Use logical &quot;action&quot; event instead. --> <f:ajax event=&quot;action&quot;> <h:panelGroup> <h:commandButton/> <h:inputText/> <h:commandButton/> </h:panelGroup> </f:ajax>
  39. 39. Default Events <ul><li>What happens if you do not specify an event? </li></ul>
  40. 40. ClientBehaviorHolder Contract String getDefaultEventName();
  41. 41. Default Event Usage <h:commandButton> <!-- Default event: action --> <f:ajax/> </h:commandButton> <h:inputText> <!-- Default event: value change --> <f:ajax/> </h:inputText> <h:panelGroup> <!-- No default event defined: Boom! --> <f:ajax/> </h:panelGroup>
  42. 42. More Event Fun: Chaining <h:commandButton> <foo:confirm/> <f:ajax/> </h:commandButton>
  43. 43. More Event Fun: Multiple Events <h:commandButton> <f:ajax/> <foo:showHoverContent event=“mouseover”/> <foo:hideHoverContent event=“mouseout”/> </h:commandButton>
  44. 44. Standard ClientBehaviorHolders <ul><li>All standard components implement ClientBehaviorHolder. </li></ul>
  45. 45. <ul><li>A Simple Sample Behavior </li></ul>
  46. 46. Our Simple Sample Behavior <ul><li>Confirm Behavior </li></ul>
  47. 47. Step 1: Implement the Behavior <ul><li>Extend ClientBehaviorBase </li></ul><ul><li>Implement getScript() </li></ul>
  48. 48. ConfirmBehavior public class ConfirmBehavior extends ClientBehaviorBase { @Override public String getScript( ClientBehaviorContext behaviorContext) { return &quot;return confirm('Are you sure?')&quot;; } }
  49. 49. Step 2: Register the Behavior <ul><li>Two ways to do this </li></ul><ul><ul><li>Old School: faces-config.xml </li></ul></ul><ul><ul><li>New School: annotations </li></ul></ul><ul><li>Both call Application.addBehavior(String, Class) </li></ul><ul><ul><li>Associates Behavior class with a behavior id. </li></ul></ul><ul><ul><li>Enables Application.createBehavior(String) </li></ul></ul>
  50. 50. Register Behavior: Old School <faces-config> <behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id> <behavior-class> org.jsf2foo.behavior.confirm.ConfirmBehavior </behavior-class> </behavior> </faces-config>
  51. 51. Register Behavior: New School @FacesBehavior(&quot;jsf2foo.behavior.Confirm”) public class ConfirmBehavior …
  52. 52. Step 3: Define the Tag <ul><li>Registering Behavior enables Application.createBehavior(String) </li></ul><ul><li>Still need a tag to expose to page authors </li></ul><ul><li>Facelets tags are defined in taglib.xml file </li></ul><ul><li>taglib.xml files live in WEB-INF or META-INF </li></ul>
  53. 53. Jsf2foo.taglib.xml <facelet-taglib> <namespace></namespace> <tag> <tag-name>confirm</tag-name> <behavior> <behavior-id>jsf2foo.behavior.Confirm</behavior-id> </behavior> </tag> </facelet-taglib>
  54. 54. Step 4: Ready To Go <ul><li>The Behavior is now available for use under namespace specified in the taglib.xml file </li></ul>
  55. 55. ConfirmBehavior Usage <html … xmlns:j2f=&quot;;> … <h:commandButton value=&quot;Submit&quot;> <j2f:confirm/> </h:commandButton>
  56. 56. What Gets Rendered? <input type=&quot;submit&quot; value=&quot;Submit&quot; onclick=&quot;return confirm('Are you sure?')&quot; />
  57. 57. <ul><li>Behavior API: Advanced Topics </li></ul>
  58. 58. ClientBehaviorContext <ul><li>Provides context for getScript() </li></ul><ul><ul><li>FacesContext </li></ul></ul><ul><ul><li>Component </li></ul></ul><ul><ul><li>Event name </li></ul></ul><ul><ul><li>Parameters </li></ul></ul><ul><ul><li>Source id </li></ul></ul>
  59. 59. ClientBehaviorHints <ul><li>Enum returned by ClientBehavior.getHints() </li></ul><ul><li>Provides hints to component/renderer </li></ul><ul><li>Currently only one hint: SUBMITTING </li></ul>
  60. 60. ClientBehavior Decoding <ul><li>ClientBehaviors also participate in decoding </li></ul><ul><ul><li>ClientBehavior.decode() </li></ul></ul><ul><li>Allows scripts to communicate back to server </li></ul><ul><li>What can ClientBehaviors do in decode? </li></ul><ul><ul><li>Queue an event </li></ul></ul><ul><ul><li>Send a response </li></ul></ul>
  61. 61. Server-Side Events <ul><li>ClientBehaviors can queue events </li></ul><ul><li>Events are queued on parent component </li></ul><ul><li>Leverage existing FacesEvent lifecycle </li></ul><ul><li>BehaviorEvent extends FacesEvent </li></ul><ul><li>BehaviorListener extends FacesListener </li></ul>
  62. 62. AjaxBehavior Event Sample <!-- Don't need a special event here --> <h:commandButton actionListener=&quot;#{foo.doIt}&quot;> <f:ajax/> </h:commandButton> <!-- But comes in handy here --> <h:panelGroup> <foo:showHoverContent event=“mouseover” listener=&quot;#{foo.hover}&quot;/> </h:panelGroup>
  63. 63. Behavior API <ul><li>So far we've been focusing on ClientBehavior API </li></ul><ul><li>There is more to the story: Behavior API </li></ul><ul><li>ClientBehavior extends Behavior </li></ul><ul><li>Base class for other possible non-client Behaviors </li></ul><ul><ul><li>Phased behavior </li></ul></ul><ul><li>Behavior defines event handling contract </li></ul><ul><ul><li>broadcast(BehaviorEvent) </li></ul></ul>
  64. 64. ClientBehaviorRenderer <ul><li>ClientBehaviors can delegate to RenderKit-specific ClientBehaviorRenderers </li></ul><ul><li>Similar to UIComponent/Renderer split </li></ul><ul><li>Allows RenderKit-specific script generation and decoding </li></ul><ul><li>Allows frameworks to plug in framework-specific functionality without replacing ClientBehavior implementations. </li></ul>
  65. 65. <ul><li>Auto Suggest Behavior </li></ul>
  66. 66. Goals/Assumptions <ul><li>Provide Google Auto Suggest-like functionality </li></ul><ul><li>Behavior attached to arbitrary input components </li></ul><ul><li>Assumption: Access to specific client events </li></ul><ul><li>Assumption: DOM input element </li></ul>
  67. 67. Contract <ul><li>We need an API for retrieving suggestions. </li></ul>
  68. 68. Contract: Suggester public interface Suggester { public Collection<String> suggest(String prefix); }
  69. 69. Contract <ul><li>We need a tag API. </li></ul>
  70. 70. Contract: Tag <!-- Attach to standard inputText --> <h:inputText id=&quot;search&quot;> <j2f:suggest suggester=&quot;#{suggester}&quot;/> </h:inputText> <!-- Attach to Trinidad inputText too --> <tr:inputText id=&quot;search&quot;> <j2f:suggest suggester=&quot;#{suggester}&quot;/> </tr:inputText>
  71. 71. Event Handling Behavior <ul><li>Key events: Retrieve suggestions, show list </li></ul><ul><li>Up/down arrow: Navigate suggestions list </li></ul><ul><li>Enter: Accept suggestion </li></ul><ul><li>Escape: Hide suggestions list </li></ul><ul><li>Blur: Hide suggestions list </li></ul>
  72. 72. Handler Implementation <ul><li>Typically the default BehaviorHandler is sufficient </li></ul><ul><li>We have special requirements </li></ul><ul><li>Single Behavior instance, multiple events </li></ul><ul><li>Solution: Need a custom BehaviorHandler </li></ul>
  73. 73. SuggestBehavior: getScript() <ul><li>Typically ClientBehaviors generate a single script </li></ul><ul><li>We have special requirements </li></ul><ul><li>SuggestBehavior generates event-specific scripts </li></ul><ul><li>Solution: ClientBehaviorContext.getEventName() </li></ul>
  74. 74. Requesting Suggestions <ul><li>Key up activity triggers suggestions list </li></ul><ul><li>Suggestions retrieved from server </li></ul><ul><li>Target the SuggestBehavior instance </li></ul><ul><li>Solution: Use jsf.ajax.request to implement fetch </li></ul>
  75. 75. Requesting Suggestions <ul><li>Key up activity triggers suggestions list </li></ul><ul><li>Suggestions retrieved from server </li></ul><ul><li>Target the SuggestBehavior instance </li></ul><ul><li>Solution: Use jsf.ajax.request to implement fetch </li></ul>
  76. 76. Selecting a Suggestion <ul><li>Handle key up for arrow key navigation </li></ul><ul><li>Enter key accepts current selection </li></ul><ul><li>However, enter key also submits form </li></ul><ul><li>Solution: cancel default enter key behavior </li></ul>
  77. 77. Resource Dependencies <ul><li>SuggestBehavior requires JavaScript, CSS </li></ul><ul><li>Dependencies should be transparent to application </li></ul><ul><li>Solution: Use new ResourceHandler mechanism </li></ul>
  78. 78. What's Left? <ul><li>State saving </li></ul><ul><li>Error handling </li></ul><ul><li>Request collapsing </li></ul><ul><li>Autocomplete </li></ul>
  79. 79. <ul><li>Future </li></ul>
  80. 80. Ideas <ul><li>Targeted postback paylaods </li></ul><ul><li>Ajax over GET </li></ul><ul><li>Out of band Ajax </li></ul><ul><li>Improved Ajax queueing/event collapsing </li></ul><ul><li>Pre-execute behavior processing </li></ul><ul><li>Alternate behavior contracts </li></ul><ul><li>Fallback behavior </li></ul><ul><li>Attached object value expression support </li></ul><ul><li>Attached object state saving </li></ul><ul><li>Initialization/DOM modifiers </li></ul>