{"id":867,"date":"2010-01-08T21:30:08","date_gmt":"2010-01-08T21:30:08","guid":{"rendered":"http:\/\/salientsoft.co.uk\/?p=867"},"modified":"2011-11-17T13:52:56","modified_gmt":"2011-11-17T13:52:56","slug":"issues-propagating-jsf-1-2-events-from-custom-facelets-tags","status":"publish","type":"post","link":"https:\/\/salientsoft.co.uk\/?p=867","title":{"rendered":"JSF 1.2\/Facelets event &#038; state handling"},"content":{"rendered":"<p>The issue here came about when trying\u00a0to propagate click events from a child table pair tag to its parent\u00a0facelet page. The table pair contained buttons to move rows between the tables, and to reorder rows on the target table &#8211; a typical design pattern used in this case to assign roles and rights to a user. The table pair tag is responsible for all the buttons for this function &#8211; move row selection left\/right, move all left\/right, reorder\u00a0target row selection up, reorder target row selection down.<\/p>\n<p>My general design in this situation is for the backing bean structure to mirror the objects on the page. There is therefore an overall page bean which has\u00a0a child table pair bean for the table pair facelet\u00a0tag, which in turn has 2 child table beans for its subsidiary facelet table tags. Whilst the parent facelet page does not need to know about the above button logic (it just pulls the result rows\u00a0out of the child beans e.g. when a save is done), it does need to know when the child table pair has caused the page to be dirty, i.e. to have unsaved changes, which comes about when one of the above buttons is clicked.<\/p>\n<p>My ideal solution to this would be to add an additional action listener on the table pair buttons &#8211; the main one is handled by the table pair bean, and an additional one on each button calls a single method on the overall page bean to notify that the page has changed. The parent does not need to know which button was clicked or why, but merely to know that a change has occurred. However this idea is scuppered in JSF 1.2 by the fact that a secondary <strong>f:actionListener<\/strong> tag on a button does <strong>not<\/strong> accept a method binding like the primary <strong>actionListener<\/strong>, but takes a fully qualified class name which must implement the <strong>ActionListener<\/strong> interface. This is a right pain as it is a <strong>class<\/strong> and not even an <strong>instance<\/strong> &#8211; you cannot tie the event to a particular bean.<\/p>\n<p>My next attempt was to simply inject\u00a0a parent reference in the TablePair bean in <strong>faces-config.xml,<\/strong> however this fails because JSF does not allow cyclic references in <strong>faces-config.<\/strong><\/p>\n<p>My final solution was therefore to pass a value binding\u00a0for\u00a0my own\u00a0<strong>ChangeListener<\/strong> interface\u00a0on the parent bean\u00a0to the TablePair tag as a parameter, and declare this on each button using <strong>f:attribute.<\/strong> The TablePair bean then fetches the bean reference from the\u00a0attribute when its <strong>actionListener<\/strong> is fired and calls the <strong>notify<\/strong> method on the reference&#8217;s <strong>Change Listener<\/strong> implementation. (I could also have used <strong>setPropertyActionListener <\/strong>to simplify this but an ICEfaces bug prevented this working &#8211; <strong>setPropertyActionListener <\/strong>was being called after the <strong>actionListener<\/strong> so the latter only ever saw a null value). The following code fragment illustrates what was used to pull the reference out of the attribute (note that this is incomplete and imports etc. are missing) :-<\/p>\n<pre>\/\/ Calling code\r\n  private static final String CHANGE_LISTENER_ATTRIBUTE = \"changeListener\";\r\n  ...\r\n  ChangeListener changeListener =\r\n    JSFUtil.fetchComponentAttribute(actionEvent, CHANGE_LISTENER_ATTRIBUTE);\r\n\u00a0\u00a0if (changeListener != null)\r\n\u00a0\u00a0\u00a0 changeListener.notify(this);\r\n...\r\n\/\/ Utility Class\r\npublic class JSFUtil {\r\n\u00a0 public static&lt;F&gt; F fetchComponentAttribute(ActionEvent actionEvent, String attribute) {\r\n\u00a0\u00a0  UIComponent component = actionEvent.getComponent();\r\n\u00a0\u00a0  Map&lt;String, Object&gt; attributes = component.getAttributes();\r\n\u00a0\u00a0  return (F)(attributes.get(attribute));\r\n\u00a0 }\r\n}<\/pre>\n<p>When propagating changes like this, it is important that the design does not cause recursive notifications, for example where a change gets passed up from one child to a parent, back down from the parent to all its children, who send it back up and so on. To this end, I therefore distinguish between the following concepts to avoid this happening:-<\/p>\n<ol>\n<li><strong>Action Notification Events<\/strong> are <strong>only<\/strong> propagated upwards from children to parents, and are <strong>only<\/strong> raised in respect of <strong>external actions<\/strong>, \u00a0for example when a button click in a child tag causes a change which the parent needs to know about. ActionNotifications are <strong>never<\/strong> raised as a result of a property change on a component which\u00a0could have been initiated by a parent.\u00a0For clarity,\u00a0if an external action causes a property change and needs to\u00a0propagate this upwards,<strong> it is the fact that an external action occurred which is being propagated, and not the fact that a property has changed, i.e. in JSF terms it is the result of an action event and not a value change event.<\/strong> This means that\u00a0whilst such an external action will pass an event up as well as changing a property,\u00a0if a parent directly changes the same property,\u00a0no event will be propagated up.\u00a0\u00a0A child cannot directly change properties in its parent so it needs this mechanism to tell the parent &#8220;something external such as a button or link click has happened in me which you need to be aware of&#8221;. Typically this will be because a click action on the child has made the whole page dirty and the parent therefore needs to change component state throughout the page to reflect this (for example to enable the save and discard\u00a0buttons and disable navigation from the page). As notifications only travel upwards, recursive notifications cannot therefore occur.<\/li>\n<li><strong>Property Changes<\/strong> are <strong>only<\/strong> performed by a component on itself or on its child components. On itself, it can change any of its internal properties. On a child component, it can change any of the publically changeable properties of the child. As stated above, such changes will <strong>never<\/strong> give rise to action notification\u00a0event propagation. However, property changes can certainly propagate downwards as required.<\/li>\n<\/ol>\n<p>The state determination\u00a0of a JSF page or a custom component can become complex when a number of components need to be, for example, selectively enabled and disabled depending on various property combinations. If the logic to determine the state is scattered throughout the component&#8217;s managed bean, or even worse, is coded in value expressions on a JSF page, it is hard to make sense of the state determination logic, easy to miss logic that is required, and easy to break the state determination when the code is changed. Therefore, I always use a private <strong>changeState<\/strong> method on a bean to perform <strong>all<\/strong> the state determination and changes. Typically this will involve a ladder of\u00a0<strong>if..else <\/strong>based logic which checks properties on the bean, and then for example sets or clears various enable\/disable properties for the JSF components. In State Machine terms, the various properties of the bean are <strong>inputs<\/strong> to the <strong>changeState<\/strong> method, and the method uses these inputs to determine a new state for the bean, setting various properties for the new state. I am not fussy about the precise implementation of this &#8211; in complex cases, it may be worth using a state machine\/state table driven approach to determine state, and maintain a &#8216;current state&#8217; for the bean which is independant of the beans properties,\u00a0but for most normal cases this is overkill. What is important is to use an implementation which is clear, correct and easy to maintain, and where the mechanism is easy to understand and flows naturally from the state change requirements. This method\u00a0should\u00a0be\u00a0called whenever a change happens to\u00a0any of the <strong>inputs<\/strong> which the method uses to determine state, and therefore will normally be called many times throughout the bean. If AOP is in use, this might be a good candidate for using a pointcut and advice to dynamically insert the calls, for example on\u00a0various property changes. In\u00a0typical cases, I end up with a <strong>dirty<\/strong> flag on the bean which indicates that something has changed, and the <strong>changeState<\/strong> method checks the flag and sets various enable\/disable properties as required. It is therefore often worth having an overloaded version of <strong>changeState<\/strong> which allows new values of such inputs to be passed in and set, and then the state change logic performed, in a single call.<\/p>\n<p>As mentioned earlier, I specifically <strong>do not<\/strong> perform any such logic on a JSF page. The presence of logic in value expressions on a JSF page is a warning bell as it may indicate that either MVC controller logic or worse, \u00a0business logic has been placed on the page. As an example, my TablePair bean allows the &#8216;move selected rows to destination&#8217; button to be clicked if any rows have been selected in the source table &#8211; otherwise the button is disabled. It would be possible to code an &#8216;anyRowsSelected&#8217; property on the bean, and call this property directly from the <strong>disable<\/strong> attribute on the JSF page. Whilst this is a simple example, I would contend that this effectively places a controller logic decision in the MVC view. The correct way would be for the <strong>disable<\/strong> property on the button to directly refer to an enable\/disable flag on the bean, and for the <strong>changeState<\/strong> method in the bean to call anyRowsSelected as a method, and set the enable\/disable flag as required. This removes all evidence of the logic from the view, and also means that if the logic changes, for example if other conditions can occur on the bean which affect the button state, the change is made in the correct place &#8211; only in the <strong>changeState<\/strong> method on the bean. The JSF page would not need to be touched and has no knowledge of this.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The issue here came about when trying\u00a0to propagate click events from a child table pair tag to its parent\u00a0facelet page. The table pair contained buttons to move rows between the tables, and to reorder rows on the target table &#8211; a typical design pattern used in this case to assign roles and rights to a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[22],"tags":[76,40,184,16],"_links":{"self":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/867"}],"collection":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=867"}],"version-history":[{"count":11,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/867\/revisions"}],"predecessor-version":[{"id":872,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/867\/revisions\/872"}],"wp:attachment":[{"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=867"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=867"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/salientsoft.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=867"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}