There are a couple of things that I am having a difficult time understanding with regards to developing custom components in JSF. For the purposes of these questions, you can assume that all of the custom controls are using valuebindings/expressions (not literal bindings), but I'm interested in explanations on them as well.
- Where do I set the value for the valuebinding? Is this supposed to happen in decode? Or should decode do something else and then have the value set in encodeBegin?
- Read from the Value Binding - When do I read data from the valuebinding vs. reading it from submittedvalue and putting it into the valuebinding?
- When are action listeners on forms called in relation to all of this? The JSF lifecycle pages all mention events happening at various steps, but its not completely clear to me when just a simple listener for a commandbutton is being called
I've tried a few combinations, but always end up with hard to find bugs that I believe are coming from basic misunderstandings of the event lifecycle.
There is a pretty good diagram in the JSF specification that shows the request lifecycle - essential for understanding this stuff.
The steps are:
-
Restore View. The UIComponent tree is rebuilt.
-
Apply Request Values. Editable components should implement EditableValueHolder. This phase walks the component tree and calls the processDecodes methods. If the component isn't something complex like a UIData, it won't do much except call its own decode method. The decode method doesn't do much except find its renderer and invokes its decode method, passing itself as an argument. It is the renderer's job to get any submitted value and set it via setSubmittedValue.
-
Process Validations. This phase calls processValidators which will call validate. The validate method takes the submitted value, converts it with any converters, validates it with any validators and (assuming the data passes those tests) calls setValue. This will store the value as a local variable. While this local variable is not null, it will be returned and not the value from the value binding for any calls to getValue.
-
Update Model Values. This phase calls processUpdates. In an input component, this will call updateModel which will get the ValueExpression and invoke it to set the value on the model.
-
Invoke Application. Button event listeners and so on will be invoked here (as will navigation if memory serves).
-
Render Response. The tree is rendered via the renderers and the state saved.
- If any of these phases fail (e.g. a value is invalid), the lifecycle skips to Render Response.
- Various events can be fired after most of these phases, invoking listeners as appropriate (like value change listeners after Process Validations).
This is a somewhat simplified version of events. Refer to the specification for more details.
I would question why you are writing your own UIComponent. This is a non-trivial task and a deep understanding of the JSF architecture is required to get it right. If you need a custom control, it is better to create a concrete control that extends an exisiting UIComponent (like HtmlInputText does) with an equivalent renderer.
If contamination isn't an issue, there is an open-source JSF implementation in the form of Apache MyFaces.
Action listeners, such as for a CommandButton, are called during the Invoke Application phase, which is the last phase before the final Render Response phase. This is shown in The JSF Lifecycle - figure 1.