Phaselistener renders an image,no more Servlet

In my previous entry, I mentioned about the underestimated powers of jsf phase listeners and presented some cases demonstrating some of these in theory. The first two was well known ajax cases and the third one was a secret power:rendering an image. I had not tried the third solution when writing the entry but using the chart component as a test case I’ve done some coding and now I am presenting the results.

Well, the theory in practice worked fine, using a phaselistener instead of a seperate servlet, I was able to present the images in a page with no problem. In order to do it, I’ve done small changes, first of all I’ve deleted the servlet definition. That shows how much I believe in phaselistener approach:) Then created a phase listener and register it in the faces-config.xml. The last thing was to change the img source rendered by the component. Instead of a servlet request, a faces request is used now;

<img src=”/servlet/Chartlet?id=chart1″ />

<img src=”faces/chartlistener?id=chart1″ />

The new img src is handled by the faces servlet which initiates the jsf lifecycle, after restore view phase when the view id is set, chartlistener takes the scene and by changing the response type to image/png or image/jpg or whatever, responses an image.

So why using a phaselistener instead of a servlet is necessary in this case and why do I do that?
# I wondered the possibility actually, it seemed to be a cool idea instead of an old-school servlet solution.
# Now no need to declare a servlet, instead a component user needs only the jar file.(Plug and Play)
# Servlet does not allow the portlet integration, now it is possible.

Here is a general example of this approach, the image is in hex format and phaselistener renders it to the client.

 
    
    

    public class ImagePhaseListener implements PhaseListener {

    public final static String IMAGE_VIEW_ID = "hex_image";
   
    private final static Log log = LogFactory.getLog(ImagePhaseListener.class);

    public void afterPhase(PhaseEvent event) {
        FacesContext context = event.getFacesContext();
        String viewId = context.getViewRoot().getViewId();
        if (viewId.indexOf(IMAGE_VIEW_ID!= -1) {
            log.info("Handling image request");
            handleImageRequest(context);
        }
    }

    public void beforePhase(PhaseEvent event) {
            //Do nothing here...
    }

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

    private void handleImageRequest(FacesContext context) {
        HttpServletResponse response = (HttpServletResponsecontext.getExternalContext().getResponse();
        response.setContentType("image/jpeg");
        response.setContentLength(17);
        try {
            String hex = "SOMEHEXCODEHERE";
            byte [] bts = convertHexToByteArray(hex);
            response.getOutputStream().write(bts);
        catch (Exception exception) {
            log.error(exception.getMessage());
        }
        context.responseComplete();
    }
   
    private byte [] convertHexToByteArray(String hex) {
        byte[] bts = new byte[hex.length() 2];
        for (int i = 0; i < bts.length; i++) {
            bts[i(byteInteger.parseInt(hex.substring(2*i, 2*i+2)16);
        }
        return bts;
    }
}
      

In order to let the phaselistener to do it’s job we have to refer the source of the image as;

 <h:graphicImage value=”/hex_image.jsf” /> or  <h:graphicImage value=”faces/hex_image />

Phaselisteners can respone anything actually, this was an example of an image rendering, you just need to change the response type and send the output to the client. Anyway I will use this approach when dealing with the next release of the JSF Chart Creator since  the component is more pluggable this way. As Matthias commented to my previous entry: “PhaseListeners are great for developers, YES!”.

6 Responses to Phaselistener renders an image,no more Servlet

  1. Matthias Wessendorf says:

    yeah! cool, sounds great!🙂

    so… let’s get rid of non asf compliant licenses😉

  2. Cagatay says:

    Yes Matthias, I wish there a is way around, that license issue is really annoying.

  3. Udo Krass says:

    Hi,

    can you explain me your solution? I want to render an image with a Phase-Listener as you, but i didn’t found yur sourcecode. I have written a Phase-Listener and i have an Image-Hex-String. How can i render that Hex-String into an image with a Phase-Listener? It would be very nice if you can explain me that – i tried to implement that since 2 weeks…
    My Listener is invoked at RENDER_RESPONSE and it doens’t work…
    My afterPhase

    public void afterPhase(PhaseEvent e) {
    log.info(“AFTER ” + e.getPhaseId());
    FacesContext context = null;
    context = e.getFacesContext();
    byte[] bytes = “FFD8F…myHexString”.getBytes();
    ResponseStream rw = context.getResponseStream();
    try {
    rw.write(bytes,0,bytes.length);
    } catch (IOException er) {
    log.error(“Error while writing Image”);
    er.printStackTrace();
    }
    }

  4. Cagatay Civici says:

    I’ve updated the entry and demonstrate how to render an image in hex format.

  5. That’s brilliant. As I have the image in database, I have no need to convert from hex. The rest is exactly what I needed. Thanks for this article.

  6. newgaton says:

    good job!

    But I don’t know how to apply the PhaseListner class to only one page not looked by other page!

%d bloggers like this: