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.

Tuesday, March 24, 2009

Create Spring beans dynamically

Spring XML declared beans can be wired building your business structure. The problem with this approach is that these beans are loaded on the start up, when the Spring Context is created, which does not leave much of playground to modify or change beans at run time. How ever Spring offers opportunity to load beans in the Spring context on run time when beans are needed, and populate them at need.
For doing this, we need the Spring Application context. For this to accomplish, one can declare one dedicated Spring context bean, which will implement the ApplicationContextAware and BeanFactoryPostProcessor interfaces. This should look something like this:


public class MyContextWrapper implements ApplicationContextAware,
BeanFactoryPostProcessor {

private ApplicationContext appContext;
private ConfigurableListableBeanFactory factory;

public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
throws BeansException {
this.factory = factory;
}
public void setApplicationContext(ApplicationContext c)
throws BeansException {
this.appContext = c;
}

//setters and getters

}



The postProcessBeanFactory will be executed after reading the configuration files of the spring context. Here one can do other configurations and bean loading, or save the factory for later use.
The Spring application context can be used for later dynamic bean retrieval or other purposes.

For this approach to work, one should let spring load this bean in to it's context by declaring the bean in the XML configuration file as follow:






Now this bean can be loaded in any other bean of the application via referencing it:








Now that we have the grip of the Spring context and it's factory, we can create beans dynamically. For this purpose, we can use the GenericBeanDefinition which allows to load bean definitions as follows:

BeanDefinitionRegistry registry = ((BeanDefinitionRegistry )factory);

GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(MyBeanClass.class);
beanDefinition.setLazyInit(false);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setScope("session");

registry.registerBeanDefinition("dynamicBean",beanDefinition);


As one can see, this bean is created in the session scope and will be stored in the session of the user. The property auto wire candidate tells spring if dependency's of the bean such as setter's or getter's or constructor argument's should be handled automatically by Spring. The property lay init tells Spring if this bean should be instantiated when needed.

To get a handle of Spring bean, one can use the Spring application context as follows:

Object bean=
getApplicationContext().getBean("dynamicBean");
if(bean instanceof MyBeanClass){
MyBeanClass myBean = (MyBeanClass) bean;

// do with the bean what ever you have to do.
}


As you can see, the dynamic bean creation in Spring is no big deal.It is easy to use, an certainly handy in many situations.

Thursday, March 19, 2009

JSR 286 IPC with JSF

In case you are portlets developer, you know what JSR 286 is. It is the holy grail for the portlets which should enable the portlets to communicate with each others. At least you would think it is the holy grail, until you read the specs and look upon the Suns minimalistic examples.
It seems to me, this spec is out for it's own sake, and forwards the developers in the ice age of pure html, which is unthinkable for someone who has got used to API's such as JSF or Struts. Vendors as JBoss or ICEFaces have yet to deliver a bridge which will support JSR 286 with an AJAX push.

The sad news is that JSR 286 works only with out AJAX push, and you have to do some work around to get the grips of it in JSF Portal environment.

The first thing to do is to define the event you want to publish. This is done in the portlet.xml. There are three declaration there:
  1. One Global declaration of your event
  2. Supported publishing event for your pulbishing portlet
  3. Supported processing event for our consumer portlet


The global event declaration looks as follow:



x:EventName
java.lang.String



In the Publishing portlet, put the following:



x:EventName



And atlast, in the consumer portlet:



x:EventName


Now that you have configured your event that it is only a simple String, you should set it. This can be done in two way's:

  1. Either extend javax.portlet.faces.GenericFacesPortlet and override the

    public void processAction(ActionRequest request, ActionResponse);
  2. Or set the event in one of your Faces action methods.
If you prefer the first way, than you have to think that your to pass your full class name in the portlet.xml for portlet instantiation which would look like this:


org.mycomp.IPCPublisher



If you prefer the JSF action method way, than your portlet.xml will look as usual:

javax.portlet.faces.GenericFacesPortlet



In you decide to override the method of the GenericFacesPortlet, than you will set the event similar to this:


public void processAction(ActionRequest request, ActionResponse response)
throws PortletException,IOException {

QName qname = new QName("http://www.mycomp.com/myevent" , "EventName");
response.setEvent(qname, "Hallo IPC Communication.");
}


If you decide you would like to publish this event from inside of your JSF action method, you can do that as follow:

public void publishIPCEvent(ActionEvent event){
Object response = FacesContext.getCurrentInstance()
.getExternalContext()
.getResponse();

if(response instanceof ActionResponse){
ActionResponse aResponse = (ActionResponse)response;
QName qname = new QName("http://www.mycomp.com/myevent" , "EventName");
aResponse.setEvent(qname, "Hallo IPC Communication.");
}
}



This method will be called as usual in JSF:








What is left is to read out this event in the Consumer portlet.
You should extend the Generic Faces Portlet and override the processEvent method. By doing that, don't forget to put the class definition in the portlet.xml as follow:

org.mycomp.IPCConsumer

Override the method as follow:

public void processEvent(EventRequest request, EventResponse response) {
Event event = request.getEvent();
if(event.getName().equals("EventName")){
String ipc = event.getValue();
response.getPortletSession().setAttribute("ipc",ipc);
}
}


As you can see, I read out the event and compare it's name if it is my event I want to handle. Than I read it's value and set it in the portlet session as attribute.

To get this value inside of JSF, you should do something like this:

Object ipc = FacesContext.getCurrentInstance()
.getExternalContext().getSession(false)
.getAttribute("ipc);



Some say that one can annotate the certain method, which should be responsible for processing the event. This should look something like this:

@ProcessEvent(qname="{http://www.mycomp.com/myevent}EventName")
public void myEventProcessingMethod(EventRequest request, EventResponse response){
Event event = request.getEvent();
if(event.getName().equals("EventName")){
String ipc = event.getValue();
response.getPortletSession().setAttribute("ipc",ipc);
}
}



But this method annotation did not work for me inside of JSF. The same should work with java.util.HashMap instead of java.lang.String as well.

Anyways, this IPC approach is not that straightforward as some would like it to be, but it fullfils it's purpose.