miercuri, 10 decembrie 2014

OmniFaces Technique for Capturing/Suppressing the Original ResponseWriter

Usually the javax.faces.context.ResponseWriter is used in renderers of JSF components. When we write a custom component, typically we render the HTML markup by using the ResponseWriter in encodeXxx() methods. The main methods that are able to render markup code are startElement()writeText()writeAttribute(), writeURIAttribute () and endElement() methods. Per example, if we check the OmniFaces 2.0 code of GraphicImage component, you can see that encodeBegin() and encodeEnd() uses these methods:

@Override
public void encodeBegin(FacesContext context) throws IOException {
 ResponseWriter writer = context.getResponseWriter();
 writer.startElement("img", this);
 writer.writeURIAttribute("src", getSrc(context), "value");
 writeAttributes(writer, this, GraphicImage.ATTRIBUTE_NAMES);
}

@Override
public void encodeEnd(FacesContext context) throws IOException {
 ResponseWriter writer = context.getResponseWriter();
 writer.endElement("img");
}

Nothing fancy here! But, sometimes, when we write custom components that extends existent components, we need to capture (or supress) a chunk of markup rendered for the extended component. OmniFaces uses a three steps technique:

·         at first step, it clones the existing ResponseWriter, by using the ResponseWriter.cloneWithWriter() method. In order to accomplish this, it needs the "original" ResponseWriter, and a new ResponseWriter (e.g. StringWriter)

FacesContext context;
ResponseWriter originalResponseWriter = context.getResponseWriter();
StringWriter output = new StringWriter();
context.setResponseWriter(originalResponseWriter.cloneWithWriter(output));
...

·         further, OmniFaces calls a method that produce direct (or indirect) the markup that should be captured and/or suppressed (e.g. encodeBegin(), encodeChildren(), encodeEnd()). Any of these methods will write the markup in the OmniFaces response writer, instead of the "original" one.
·         at final step, OmniFaces "releases" the "original" ResponseWriter and process the captured content (the content of the output writer).

...
context.setResponseWriter(originalResponseWriter);


In the below figure you can see this technique used in the OmniFaces, Param component - I just cropped the code to reveal the technique, so don't try to understand the Param component itself from here:


This is a very cool technique that allows us to manipulate exitent markup in many ways. Is nice to have it in your arsenal!

Niciun comentariu:

Trimiteți un comentariu