JSF with Ajax, Phase Listener vs Servlet Comparison

When I first heard about Ajax, I thought the asynchronous call to the server can be handled by a servlet in a jsf application.At first sight the servlet idea was the only one that came up to my mind and I saw several examples that uses a servlet to embed ajax in jsf. After a while, I’ve observed another method to use AJAX with JSF; “phaselistener”. I’ve decided to write the same application with these techniques seperately in order to figure out the possible pros and cons of both. The example is simple, redirecting the request to response, the user clicks a button and an ajax request is sent to the server side.The response is sent back to the client as a string defining the technique being used and the string message is displayed in a simple textfield.

Here is the important part of the jsf page; A textfield to display the response and a button to send the request. The sndReq javascript function takes the technique name as an argument like ‘PhaseListener’ or ‘Servlet’;

        <inputText id=”text1″></h:inputText>
        <BUTTON onclick=”sndReq(‘Servlet or PhaseListener here’)”>Submit</BUTTON>

And here are the javascript functions to create the request and handle the response, the sending of the request is given seperately in the description of the techniques.

function createRequestObject() {
    var ro;
    var browser = navigator.appName;
    if(browser == “Microsoft Internet Explorer”){
        ro = new ActiveXObject(“Microsoft.XMLHTTP”);
    }else{
        ro = new XMLHttpRequest();
    }
    return ro;
}

var http = createRequestObject();

function handleResponse() {
    if(http.readyState == 4){
        var response = http.responseText;
        document.getElementById(‘form1:text1’).value = response;
    }
}
       

PhaseListener

Following is the javascript function to send the request to the server side.

function sndReq(requestString) {
    http.open(‘get’, ‘PROJECTNAME/faces/technique-comparison?technique=’+requestString);
    http.onreadystatechange = handleResponse;
    http.send(null);
}

And the PhaseListener to handle the Ajax request.

public class AjaxListener implements PhaseListener {

    private static final String AJAX_VIEW_ID = “technique-comparison”;

    public void afterPhase(PhaseEvent event) {
        String rootId = event.getFacesContext().getViewRoot().getViewId();
        if (rootId.indexOf(AJAX_VIEW_ID) != -1)
            handleAjaxRequest(event);
    }

    private void handleAjaxRequest(PhaseEvent event) {
        FacesContext context = event.getFacesContext();
        HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
        HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
        String name = request.getParameter(“technique”);
        try {
        response.getWriter().write(name);
        context.responseComplete();
        }catch(Exception exception) {
            exception.printStackTrace();
        }
    }

    public void beforePhase(PhaseEvent arg0) {
       
    }

    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }
}

The idea is exciting, when the request reaches the server, the phase listener takes the scene and after the restore view phase, it checks whether is an Ajax request or not. If it is, it creates a response and forces the life cycle to jump to the render response phase.

Servlet

Now the function is changed and the url target is a servlet;

function sndReq(requestString) {
    http.open(‘get’, ‘/PROJECTNAME/servlet/ResponseServlet?technique=’+requestString);
    http.onreadystatechange = handleResponse;
    http.send(null);
}

And the handling servlet;

public class ResponseServlet extends HttpServlet {   

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         String technique = request.getParameter(“technique”);
         response.getWriter().write(technique);
    }
}

As you see, servlet code is much shorter than the PhaseListener and looks simpler however we should consider the simplicity of the example. Servlet does not need to understand whether it is an ajax request or not because it is the servlet’s only job, however the phase listener must catch an ajax request. On the other hand the phase listener is a native solution but the servlet is in the external context. This gives the advantage to accss the stuff in context of faces easier. Also if you are writing a custom component that uses external sources like javascript files or css, phaselisteners can serve these for you from a single jar file which also contains your code.
Since I am a phaselistener fan I would suggest to use the phaselistener method whenever you try to add some ajax magic to your jsf application.

27 Responses to JSF with Ajax, Phase Listener vs Servlet Comparison

  1. Werner says:

    There are plus sides to phase listeners, you do not need to have an extra entry in the web.xml thus you can bundle them in a jar and just drop them in as JSF component pack, JSF takes care of the rest.

    However the main disadvantage is, that phase listeners follow a chain pattern and the entire chain is called at every request, while at servlet level the servlets are chosen upon pattern.
    Ok it does not make too much of a difference, but a difference between a theoretical log(n) and a fixed n in the calling order. Practically both methods probably cause the same performance hit.

  2. ivankov says:

    You cane much more with JSF, because it is a component framework.
    This is my idea:

    click

    ajax:request define a req javascript function which send an ajax request to the PhaseListener, with “divId” as parameter.
    ajax:request component decode the ajax request, and fire the action event.
    The testBean.getList method can affect the component.
    Now the the phaseListener start to play its role:
    substitute the current writer with an xml writer, and render the target component (the div modified by the managed bean).
    Now on the client side, the javascript function “req” handle the incoming xml and performa a DOM substitution of the div element, as described by the xml created by the phase listener.

    sources attribute of “ajax:request” can be used to build post parameters throught javascript. So you can have a very good integration between JSF and ajax.

    What do you think about this?

  3. Anthony says:

    I tried your example. It works but why response get in client side always duplicated my message.
    Say request msg “abc”, the return value from server is “abcabc”
    But from output of server side, its okay

  4. Jay says:

    I was trying to get the Phase Listener working, but I can’t seem to figure out where or how you’re mapping PROJECTNAME/faces/technique-comparison to the Phase Listener. I configured the phase listener as follows in faces-config.xml:

    src.ajaxtest.AjaxListener

    My question is how does JSF know that “technique-comparison” is mapped to ComparisonPhaseListener? Do we have to specify the mapping in another file?

    Thanks for the info.

  5. Cagatay says:

    Mapping is done programmatically;

    private static final String AJAX_VIEW_ID = “technique-comparison”;

    public void afterPhase(PhaseEvent event) {
    String rootId = event.getFacesContext().getViewRoot().getViewId();
    if (rootId.indexOf(AJAX_VIEW_ID) != -1)
    handleAjaxRequest(event);
    }

  6. Anonymous says:

    qrqrwr

  7. Hari says:

    I am running into the same problem that Anthony mentioned. The response is always duplicated. If the request message is “Phase”, the response text is “PhasePhase”. I noticed that afterPhase() and handleAjaxRequest() methods are called twice. What is fix for this problem.
    But from output of server side, its okay

  8. Hari says:

    I found the solution for the problem at http://wiki.apache.org/myfaces/FAQ#Twice

    The JSF specification requires any JSF implementation to automatically load /WEB-INF/faces-config.xml at startup. There is consequently no need for the following context parameter:

    javax.faces.CONFIG_FILES /WEB-INF/faces-config.xml

    Putting this context parameter in your deployment descriptor will force any JSF implementation to load the configuration twice, therefore registering each phase listener twice.

  9. Cagatay says:

    Yes, this is a well known and common mistake. There is no need to declare the default config file in web.xml.

  10. Timmi says:

    Hi,

    I have the same problem. The response is always duplicated. I already deleted the declaration of the config file in my web.xml, but the response is still duplicated. Any idea?

    Another question:
    When I use a Servlet for this example, how must I map this in web.xml?
    Because Faces-requests call the Faces-Servlet.

    Thanks for your help!

  11. Anonymous says:

    gggg

  12. Anonymous says:

    ss

  13. Anonymous says:

    123

  14. bansi says:

    Hi Cagatay

    Thanks for excellent article on http://www.jroller.com/page/cagataycivici?entry=jsf_with_ajax_phase_listener.

    Wondering how this works as i implemented your example and getting Null Pointer Exception in handleAjaxRequest method . Here is the snippet

    String name = request.getParameter(“technique”);

    System.out.println(“Name=”+name); // This prints Null

    try {

    response.getWriter().write(name);

    context.responseComplete();

    }catch(Exception exception) {

    exception.printStackTrace();

    }

    I can understand why its printing Null since the jsp page is not yet rendered and their is no request parameter yet. So in this case how your example works as the PhaseListener is always executed prior to rendering of jsp page and hence it always result in request parameter being NULL

    Regards

    Bansi

  15. Anonymous says:

    testing

  16. roopli says:

    JSF with Ajax

  17. evankstone says:

    Please forgive my ignorance here… but how would this work if one’s Faces Servlet mapping is “*.jsf” instead of “/faces/*”?

    The information in this post is *exactly* what I was looking for, since I’m trying to implement this type of Ajax call — but currently the project I’m working on has the Faces Servlet mapping set to “*.jsf”.

    So I added another mapping for “/jsf/*”, like so:


    Faces Servlet
    javax.faces.webapp.FacesServlet
    0


    Faces Servlet
    *.jsf


    Faces Servlet
    /jsf/*

    …and here’s the updated javascript i’m using to call the phase listener:

    function sndReq(requestString)
    {
    var url = “http://localhost:8080/ajaxphaselistener/jsf/technique-comparison?technique=” + requestString;
    http.open(‘get’, url );
    http.onreadystatechange = handleResponse;
    http.send(null);
    }

    Unfortunately, I’m getting an error 404, which says: “The requested resource (/ajaxphaselistener/technique-comparison) is not available.”

    Note that the “jsf” is missing from between ajaxphaselistener and technique-comparison. I don’t know if that’s significant or not, but I thought it was a bit strange – kind of like *something* was happening under the hood but maybe it was getting confused (perhaps due to the multiple Faces Servlet mappings?)

    Anyway, any insights or comments about how to get this working will be greatly appreciated…

    Thanks!

    ///eks

  18. evankstone says:

    OK… Thanks to Jay’s post earlier in this thread, I figured out my problem by putting both parts together to form a complete solution.

    I was missing the entry in my faces-config.xml to enable the phase listener (which I didn’t know I needed):

    com.blah.blah.AjaxListener

    After putting this entry in my config file, it came to life! w00t!!!

    Additionally, as a side note, I *am* using two mappings and it seems to be working fine (*.jsf and /jsf/*). Let me know if this is a bad idea or not…🙂

    Thanks again to Cagatay and Jay for their combined bits information which allowed me to solve this problem so quickly!!!

  19. Marek says:

    When I started to combine AJAX with my own JSF component I was sure that the encodeXXX() methods of UIInput class (in fact UIComponent) will be used to render an AJAX answer. And I’m surprise that I haven’t access to my component. It will be much simpler than rendering answer in PhaseListener.

    Let’s consider an example. encodeBegin() method renders a table with header, body and footer. If I want to render new body (table rows) using AJAX (let’s say user wanted to use filer) I have to code body rendering in PhaseListener once again.

    Am I right, or there is a possibility to use my component rendering methods?

    evankstone, specification allows you to create as many mapping as you want, so I think it is correct.

  20. Subramanian says:

    The duplicate output can be avoided by using the conditional check on the phase id.

  21. Sazeykkk says:

    interesting thank you…
    breast augmentation new york city san diego breast augmentation

  22. Xideqkkk says:

    very interesting
    account forex online trading broker canada forex online

%d bloggers like this: