Friday, June 29, 2012

Create A parameterized bean using request parameter for JSF

Suppose you have a page project.xhtml. If the request is project.xhtml?project=myproject, you retrieve the 'myproject' Project instance and let user to modify it. If the request is request.xhtml with no query parameter, you instantiate a new Project object and let user edit and add it. How can you do this in J2EE platform?

I used to do this using a PhaseListener. The PhaseListener will inspect the request parameter and create the bean directly or using BeanManager from CDI.  However, producer method in CDI provides a good alternative.


class ProjectEditor
{

@Inject @EdittableProject Project project;

@Produces 
@EdittableProject
@Dependent
Project getProject()
{
 Object tobj = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()
                .get("type");
        if (tobj==null)
        {
            return new Project();
        } else
        {
            return findedProject;
        }
}

public Project getProject()
{
 return project;
}
}

Here I use an qualifier @EdittableProject so that I make sure project from the producer method are used.

For the producer method, I give @Dependent scope explicitly to make sure there is  no client proxy wrapper around the return object.

After this I can reference the project in project.xhtml like this #{projectEditor.project}



Alternative to bean lookup from BeanManager from CDI

Suppose I have a utility object Util which is in application-scoped singleton. In traditional programming model, this object is constructed at application startup using its constructor. At any code location(bean or not bean), I can hold a reference through a static member like this Util.instance.

public class Util
{
  public static Util instance;
@Inject Field f1;
...
 }

In CDI, reference to Util has to be injected. To be injected, your code location should be a CDI bean.   You can not use Util constructor directly since some of its fields such as f1 need injecting from CDI. Its creation needs to be controlled by CDI. You can of course using BeanManager from CDI to look up the singleton instance. 

Here I give another easy solution not using BeanManager.

@ManagedBean(eager = true)
@ApplicationScoped
public class GlobalObjectFactory
{

   
@Inject Util util;
   
    @PostConstruct
    private void transferReference()
    {
        Util.instance=util;
    }
}


In this example, I have an application-scoped object GlobalObjectFactory which is created at the very beginning of application startup by CDI. Since it is created by CDI, you can ask CDI to inject other bean. Once you have a reference to the injected bean, you can pass the reference to a static member of other class. After this, the reference to the injected bean can be accessed through static member anywhere, bean or non-bean.



Sunday, June 24, 2012

Jboss arquillian: solution for J2EE Unit Test

Traditional test approach in J2EE 6 is tough. In J2EE 6, we have bean injection. The Bean by design is created by framework and not by tester.  Given the resource injection and persistence, a test setup can be difficulty and easy to break. At least, I tried two days with embedded EJBContainer and did not succeed. Finally, I got this absolutely wonderful test framework for J2EE: Jboss arquillian. Before you tweak anything, you have to check this out. 

Friday, June 22, 2012

simulate a4j:jsFunction in richfaces

a4j:jsFunction is very useful. It defines a javascript function you can make ajax call through script by invoking this function. How can you do the same thing without richfaces library?

First, define your action in a hidden command or inputtext field.

<h:commandButton id="mybutton" styleClass="myclass" style="display:none;" ...>
<f:ajax ...></f:ajax>
</h:commandButton>


javascript in YUI

myfunction =function()
{
  Y.one("input.myclass").simulate("click");
}

javascript in jQuery
myfucntion=function()
{
 jQuery("input.myclass").trigger("click");
}

After this you can use myfunction anywhere to trigger the ajax behavior.
 

Dynamically add data at client side for JSF:updated

In my last blog, I showed a method how dynamically add a client row/list entry at client side when JSF is used.   I used Richfaces a4j:region and a4j:jsFunction. However, I do not want to use richfaces for two reasons. First, richfaces loads all its component js files although I only uses two simple tags. Second, richfaces loads its stylesheet file I have no easy way to turn it off completely.

Here I give a solution without richfaces

The Bean File (same as it is in last blog)

@ManagedBean
class Bean
{
List<Integer> real=new ArrayList<Integer>();
List<Integer> buffer=new ArrayList<Integer>(10);

public List<Integer> getReal()
{
   return real;
}

public List<Integer> getBuffer()
{
   return buffer;
}

//ajax call AND form submission time.
public void transferBuffer()
{
  for(Integer i:buffer)
  {
    real.add(i);
  }
  buffer=new ArrayList<Integer>(10);
}
}


xhtml file

<style>
 ._bufferblock
{
display:none;
}
</style>
<ui:fragment>
<div id="#{component.clientId}" class="_buffercontainer">
<table >

<ui:repeat value="#{bean.real}" var="item">
<tr><td> <h:inputText value="#{item}"></inputText></td></tr>
</ui:repeat> 

<ui:repeat value="#{bean.buffer}" var="item">
<tr class="_bufferblock"><td> <h:inputText value="#{item}"></inputText></td></tr>
</ui:repeat>
 </table>

<h:commandButton value="Add" styleClass="_bufferbuttononclick="_displaybuffer(this, event); return false;" >
   <f:ajax listener="#{td.transferBuffer}" ></f:ajax>
</h:commandButton>
</div>
</ui:fragment>


Javascript using YUI

 _displaybuffer=function(button, event)
    {
        //do not submit the form, since we will make ajax call
        if (event!=null)
        {
            event.preventDefault();
            event.stopImmediatePropagation();
        }
        //event.
        var container=Y.one(button).ancestor("div._buffercontainer");
        var buffer=container.one("._bufferblock");
        if (buffer)
        {
            buffer.removeClass("_bufferblock");
        }  else
        {
            //collect execute id.
            var  names=[];
            container.all("input,select,textarea").each(function(node, index, list){
                names.push(node.get("name"));
            });
            //make the actual ajax call.
            options={
                    "javax.faces.behavior.event":"action", //a hack since the event in f:ajax does not work
                    onevent:function(data){
                        if (data.status=='success')
                        {
                           
                            //display one newly-loaded row.
                            //do not refer this button object since button will be replaced dynamically during reload
                            _displaybuffer("input[name='"+button.name+"']", null);
                        }
                    },
                    onerror:function(data)
                    {
                        window.alert(data.errorMessage);
                    },
                    render:container.get("id"),
                    execute:names.join(" ")
                   
                    };
            jsf.ajax.request(button, event, options);
        }
       
    };

Here I use code block for the onclick attribute of commandButton. This code will be called before the generated ajax flow from f:ajax. The generated ajax will not be called since the onclick code block always return false.  In the onclick code block, I use jsf.ajax.request to make explicit ajax call if no buffer is available.  JSF server does not distinguish whether the ajax call comes from manual javascript or the one generated. We still need the f:ajax tag so listener action can be invoked  in server side. 



Dynamically add data at client side for JSF

You have a list or a table. You want to add more items to the collection at client side. When user clicks a 'Add' button, a new row or list entry is available for user to enter new data.  The  list entry or row can be generated by manipulate DOM using JavaScript. However, the newly-added form elements in the row or list entry will be ignored by JSF server code since these elements are not in the JSF component tree.

Here I give a practical solution to this. The idea is like this: I have a real list and buffer list. The real list is visible at UI and the buffer list is hidden. When user clicks 'Add', an list entry from buffer list is displayed using JavaScript.
When the form is submitted, the real list and buffer list is combined.
If user repeatedly clicks 'Add' and buffer exhausts, Ajax call is made to server to reallocate buffer. If the buffer is reasonable large enough, there will not be any Ajax call in most time.

The Bean File

@ManagedBean
class Bean
{
List<Integer> real=new ArrayList<Integer>();
List<Integer> buffer=new ArrayList<Integer>(10);

public List<Integer> getReal()
{
   return real;
}

public List<Integer> getBuffer()
{
   return buffer;
}

//ajax call AND form submission time.
public void transferBuffer()
{
  for(Integer i:buffer)
  {
    real.add(i);
  }
  buffer=new ArrayList<Integer>(10);
}
 
}


xhtml file

<style>
 ._bufferblock
{
display:none;
}
</style>
<a4j:region>
<div class="_buffercontainer">
<table >

<ui:repeat value="#{bean.real}" var="item">
<tr><td> <h:inputText value="#{item}"></inputText></td></tr>
</ui:repeat> 

<ui:repeat value="#{bean.buffer}" var="item">
<tr class="_bufferblock"><td> <h:inputText value="#{item}"></inputText></td></tr>
</ui:repeat>
 </table>

<h:commandButton value="Add" styleClass="_bufferbutton" ></h:commandButton>
<a4j:jsFunction name="_reloadbuffer" render="@region" execute="@region"
                    actionListener="#{bean.transferBuffer}"></a4j:jsFunction>
</div>
 </a4j:region>

Javascript using jQuery

 jQuery(":button._bufferButton").live("click", function(event){
        event.preventDefault();
        var buffer=jQuery("._bufferblock:first", jQuery(this).closest("div._buffercontainer"));
        if (buffer.length>0)
        {
           //display it.
            buffer.removeClass("_bufferblock");
        } else
        {
            //reallocate buffer.
            _reloadbuffer();
        }
    });

NOTE

  • In JavaScript, I use live instead of click since the button is dynamically removed and added by JSF ajax call.

  • I use a4j and h:commandButton instead of f:ajax inside of h:commandButton. A f:ajax  will add onclick attribute to the generated button. The onclick javascript invokes JSF ajax call. Any other event listeners added later using javascript will be invoked after this. Right now, we have no way to invoke an event handler before the f:ajax client behaviour. So I separate them into two components to control the invocation flow as desired. 

  • a4j:region and a4j:jsFunction is from Jboss richfaces library .

 


rendered attribute in jsf

JSF has a very nice support for ajax. You can specify ajax behavior using f:ajax tag with any input or command components.  However, rendered attribute gives you surprise sometime.
Suppose you have a component in xhtml like this
<h:datatable ... rendered="#{empty configs}">
</h:datatable>
In you ajax tag, you'd like to refer to this table in render attribute.  Since your table could never be rendered, and not in the component tree, client code and server code will not be able to update it in ajax call.  You could use OutputPanel from richfaces library. However, there is a much simple soltuion: render your component in all time. Replace the rendered="false" case with something like style="display:none".
E.g:

<h:datatable ... styleClass="#{(empty configs)?'displayhidden':'displaytable'}">
</h:datatable>