views:

3927

answers:

7

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). Although I'll gladly upvote those who give good explanations on that as well, since that could be helpful for others (and me down the line).

  1. 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?
  2. Read from the Value Binding - When do I read data from the valuebinding vs. reading it from submittedvalue and putting it into the valuebinding?
  3. 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.

Any help would be appreciated... thanks!

+3  A: 

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.

Peter Hilton
+5  A: 

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.

McDowell
A: 

@McDowell - Thanks for the information... I was able to figure out most of this in the morning by reading through MyFaces code, but you've added and clarified a number of details that are helpful.

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.

Honestly, I've struggled with whether to use JSF at all for exactly this reason. It is the only framework that I've ever used where component creation is a deep intricate process like this. None of the other web frameworks (whether in the .net world or not) make this so painful, which is completely inexplicable to me.

I've stuck with JSF largely for the promise that 2.0 will make it much less painful. The component is a composition of several inputtext (and other) base components, btw.

jsight
+1  A: 

It is the only framework that I've ever used where component creation is a deep intricate process like this. None of the other web frameworks (whether in the .net world or not) make this so painful, which is completely inexplicable to me.

Some of the design decisions behind JSF start to make a little more sense when you consider the goals. JSF was designed to be tooled - it exposes lots of metadata for IDEs. JSF is not a web framework - it is a MVP framework that can be used as a web framework. JSF is highly extensible and configurable - you can replace 90% of the implementation on a per-application basis.

Most of this stuff just makes your job more complicated if all you want to do is slip in an extra HTML control.

The component is a composition of several inputtext (and other) base components, btw.

I'm assuming JSP-includes/tooling-based page fragments don't meet your requirements.

I would consider using your UIComponentELTag.createComponent to create a composite control with a UIPanel base and creating all its children from existing implementations. (I'm assuming you're using JSPs/taglibs and making a few other guesses.) You'd probably want a custom renderer if none of the existing UIPanel renderers did the job, but renderers are easy.

McDowell
A: 

@McDowell:

Some of the design decisions behind JSF start to make a little more sense when you consider the goals. JSF was designed to be tooled - it exposes lots of metadata for IDEs. JSF is not a web framework - it is a MVP framework that can be used as a web framework. JSF is highly extensible and configurable - you can replace 90% of the implementation on a per-application basis.

Of that, I think the only part that I agree with is the "a little more sense". The metadata could have been exposed in other ways in JSF 1.2, and frankly, I have yet to see an IDE make decent use of it. Why can't an IDE give me a simple way to build a component?

I've used ASP.Net as well, and by comparison, JSF feels like it was written by a bunch of architecture astronauts led by a guy like the original Struts designer. Oh wait... :)

jsight
I so know what you're talking about! I've been learning and using both JSF and ASP.NET for the past 1.5 year. Both frameworks are sort of MVP implementations but the programmer's nightmare found in JSF (both from the usage and component creation point of view) is just like someone took a good idea and messed it up in any way possible.Go check out my blog at http://ihatejsf.com to see more about that.
Matthias Hryniszak
A: 

The best article I've found is Jsf Component Writing, as for 2 where do I read the value for a value binding in your component you have a getter that looks like this


public String getBar() {  
     if (null != this.bar) {  
         return this.bar ;  
     }  
     ValueBinding _vb = getValueBinding("bar");  
     return (_vb != null) ? (bar) _vb.getValue(getFacesContext()) : null;  
}
  

how did this get into the getValueBinding? In your tag class setProperties method

  if (bar!= null) {  
         if (isValueReference(bar)) {  
             ValueBinding vb = Util.getValueBinding(bar);  
             foo.setValueBinding("bar", vb);  
         } else {  
             throw new IllegalStateException("The value for 'bar' must be a ValueBinding.");  
         }  
     }
David Waters
A: 

Hi,

we've been struggling with the same thing and would like to know if you found a nicer solution to that. Thanks!

Matthias Hryniszak
Hi, welcome at SO. This isn't really a forum. This is more a blog. If you have a question, press `Ask Question` button. If you have an answer, then `Post Answer`. Do not post a question as an answer. Feel free to include links to topics you found but which didn't help much (and elaborate in detail why not). Good luck.
BalusC
The answers in here are pretty good, imo. Also, project woodstock has a pretty good (though very poorly documented) framework for generating a lot of the boilerplate code for you.
jsight
Woodstock is dead since two years and abandoned since january this year. Forget it. It's not only poorly documented but also very buggy and unmaintainable.
BalusC