Thursday, April 9, 2009

The facet thing

I have been looking for this in the Web my self, and could not find any real help.

Creating JSF components in dynamic way can bring you some troubles. Many JSF components, when using XHTML or JSP require Facets to render part of it's own body or content. Examples are Header of RichFaces panel or the like.

When creating dynamically a RichFaces panel for example, you will ran in to a problem if you want to create a header for your panel. To ilustrate this, let's look in to the way you create a RichFaces Panel when using the RichFaces tags:








As you may noticed, the problem one run on when creating this code in pure Java would be the Facet tag. If you look in to the JSF documentation, you will probably find the javax.faces.webapp.FacetTag which you might think of using it. But when creating a new instance of this class, you will certainly wonder how to use it, since this tag has nothing to do with JSF directly.
There is workaround for the following problem. Let us look in to the Java code on how to produce the same code from the above xml source:



HtmlPanel panel = (HtmlPanel)
FacesContext.getCurrentInstance().
getApplication().
createComponent(HtmlPanel.COMPONENT_TYPE);
HtmlOutputText text= (HtmlOutputText )
FacesContext.getCurrentInstance().
getApplication().
createComponent(HtmlOutputText .COMPONENT_TYPE);

text.setValue("My Header");

// now we will add the text to the panel's header

panel.getFacets().put("header",text);



As you see, that's all there it is to it. Every container component (correct me if I am wrong) in JSF has a Map of it's Facets. According to the JSF specification, the Facet (Tag) can contain only one UIComponent. So if you want more component's in your header, such as Text and Image at a time, you should wrap this components with one Html Panel Group instance and add it to your Facet Map.

Wednesday, April 1, 2009

Creating dynamic listener method binding

If you are JSF developer, you are most probably familiar with the following scenario:











The my bean instance should be created by the MyBean class which should include the following three methods:

public class MyBean{

public String action(){
// do something and return a string for the JSF navigation facility

return "navigateToPage2";
}

public void actionListener(ActionEvent event){

UIComponent component = event.getComponent();
// do something with or with out the component.
// the same view in JSF will be reloaded after
// this method returns.
}

public void valueChangeListener(ValueChangeEvent event){
UIComponent component = event.getComponent();
// do something with or with out the component.
// the same view in JSF will be reloaded after
// this method returns.
}
}


Sometimes, there are cases, where you have to do the binding for your self instead letting JSF bind your components with your listener methods via XML.

It these case, you should do, what JSF will do for you. From the JSF Context, you can get a handle to the Expression Language Factory or short referred as EL.

The expression language works similarly as the Reflection API of Sun Java SE. The main difference (at least for me) is that you can use the EL expression to bind your components to certain bean instances and methods.

To get a grip of the EL handle, you can use the following approach:


FacesContext ctx = FacesContext.getCurrentInstance();
Application app = ctx.getApplication();
ExpressionFactory el = app.getExpressionFactory();


Instead writing this code, you can use the inline call of the EL expression as follows:

ExpressionFactory el = FacesContext.getCurrentInstance().
getApplication().
getExpressionFactory();


In end effect, it is all the same for Java. It only saves you few lines of code.

Now that we have the grip of the handle for the EL, we can use it to create dynamic binding of component's and bean methods.

I will reproduce the same code from above with the command button and the text input. One should keep in mind that one can do this basically with every single JSF component.

public HtmlCommandButton createMyButton(){
HtmlCommandButton button = FacesContext.getCurrentInstance().getApplication().
createComponent(HtmlCommandButton.COMPONENT_TYPE );

//create the EL binding for the action method with return type String
MethodExpression action= FacesContext.getCurrentInstance().
getApplication().getExpressionFactory().
createMethodExpression(FacesContext.getCurrentInstance().getELContext(),
#{myBean.action}, String.class, new Class[]{});

//create the EL binding for the action listener method with return type void
// and argument of ActionEvent type
MethodExpression actionListener= FacesContext.getCurrentInstance().
getApplication().getExpressionFactory().
createMethodExpression(FacesContext.getCurrentInstance().getELContext(),
#{myBean.action}, null, new Class[]{ActionEvent.class});

//bind them to the button component.
button.setActionExpression(action);
// add the listener to the action
button.addActionListener(new MethodExpressionActionListener(actionListener));

return button;

}


What is important to notice, is that when creating the action method EL with return type String the createMethodExpression method of the EL factory takes four arguments:
  1. The faces context
  2. The String which represents the EL expression which should be used for binding
  3. The return type of String class
  4. The argument's of the method, which in this case are none to be passed.
The same goes for the creation of the action listener EL expression, where as the return type is set to null and the only argument passed is of type ActionEvent class.

The last thing to do is to save this method expressions expression in the map of the JSF component for later use. This goes only for the action method with return type of String. To add the EL expression for listener, you have to wrap the Method expression with the MethodExpressionActionListener class. In doing so, you add this expression to the component via UIComponent.addActionListener(ActionEvent); method.

The next thing to do is to create the text input component with it's value change listener binding.


public HtmlInputText createMyInput(){
HtmlInputText input = FacesContext.getCurrentInstance().getApplication().
createComponent(HtmlInputText.COMPONENT_TYPE );
// create the value change listener
MethodExpression valueChange=
FacesContext.getCurrentInstance().getApplication().getExpressionFactory().
createMethodExpression(FacesContext.getCurrentInstance().getELContext(),
#{myBean.valueChangeListener}, null, new Class[]{ValueChangeEvent.class});

//add the listener to the component
input.addValueChangeListener(new MethodExpressionValueChangeListener(valueChange));

}



As you can see, this procedure is the same as if you create action event. The only difference is the argument of the method,which is of type ValueChangeEvent class.