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.