Wednesday, October 28, 2009

What to study next...

So many technologies I want to study further: JSF 2.0, GWT, ADF Faces Rich Client component library, deployment of Java EE apps to phones and pda's, Scala, Wicket, Tapestry, Facelets, et cetera ad nausium.

...so little time. I wish we could learn like they did on the matrix :-)

Monday, October 19, 2009

Oracle Open World Aftermath

I definitely owe a blog entry at this point!

Just came back from Open World, and boy: is my brain tired!! (ba-dum-CRASH)

Anyway. I had a request that I make some specific entries on my blog from someone in the audience that came up to visit after my presentation.

He wanted to know how to do two things that I mentioned:
1. how to use the phase listener to get resource files in a custom component, and
2. how to use a renderer to divide up functionality.

These are somewhat meaty topics but I will try to be concise.

I. PhaseListener "magic"
If you have Schalk and Burns's
JavaServer Faces: the complete reference then just (re)read Chapter 11.

If you do not...here comes the paraphrase. The general idea is that you need to add a phase listener to your application in the normal manner: by adding a few lines to your faces-config.xml file. Note that if you have a custom component in JSF, then your jar has in it in its META-INF directory a faces-config.xml file, where you can reference this phase listener. JSF guarentees that this will be read first before the one in your application, I believe, provided this jar is in your WEB-INF/lib directory of your application.

Anyway you take your added phase listener, and make it listen for the RESTORE_VIEW phase by overriding the getPhaseId() method, and returning PhaseId.RESTORE_VIEW constant.

So let us say for example that your component has a need to have javascript code, that you want to keep in a sepparate file...because there is too much code to render on the html page itself (or you are a "tidy" individual). So your component will encode/render a javascript "include" (i.e.,<script src="somename" type="text/JavaScript"></script>

). So you encode this line onto the page. Then when this page is "interpreted", and issued as a request, your phaseListener can be ready. Your phaseListener has knowledge that at some point after the RESTORE_VIEW phase is complete, the FacesContext.getViewRoot().getViewId() will contain "somename". At that point, the phase listener can use getClass().getResource("somename's filename"), to get a url. This url can be connected-to and read from, an inputStream, then an inputStreamReader, then a BufferedReader. Meanwhile you open the outputWriter from the response on the FacesContext's ExternalContext, create an outputStreamWriter, then do a while loop reading lines from the buffered reader and writing lines to the outputStreamWriter, until there are no more lines to write. By the way the FacesContext is available from the PhaseEvent that your receive as a parameter. And with this FacesContext, you finish with a call to its responseComplete() method.

II. Renderer.

This is easier. If you have a custom component that has no renderer you can move your encode*() methods and decode() method to the a custom Renderer class. The main changes you will need to make are because you now no longer say "this" when you need to reference your component. In your new renderer class (which BTW extends "Renderer") the encode*() and decode methods receive your component as a parameter, so you much change your "this" references to use this parameter.

You must also augment the faces-config.xml, to have a element with a sub-element which shows the family, type, and class of your renderer. Type can be anything, but whatever it is must now also be returned by getRendererType() overridden method in your tag handler class.

Also you will need to guard against receiving a null FacesContext or a null Component value for your parameters. This is in the spec so don't shoot me; I'm just the messenger.

Sir, I hope, whoever you said you were, that this blog entry, approaches meeting your custom-component writing needs or curiosities, or whatever drove your question. I bid you: good day!

I bid the same for the rest of you as well.