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.

2 comments:

edburns said...

I'm working on the second edition of the JSF book, exclusively focused on JSF 2.0, and I really hope you like the new chapter on custom components. JSF2.0 has a nice feature for this called "composite components".

Ed

Michael A. Fons said...

Ed! I am honored that you have read my blog! I love your book. I spent a couple hours reading it last night.

Could you please tell us more about your book? Have you decided on a title yet?

Were you at Oracle Open World? I was at the JSF 2.0 presentation. That presentation and the general move toward facelet-like technology is causing me to explore all kinds of things! I did my first facelets program this past weekend. I also just finished up Chapter 13 of your "complete reference"...on facelets. I am going to have to play with it more...because I don't yet have a grip on the way some of the facelet tags work.

If you give me the name of your book (should you know it yet), I will create an additional blog entry just to announce that.

FWIW I was so inspired by JSF 2.0 that I actually put in a request on the site to be a developer on the JSF project. I would definitely be a "gopher", but it would be great!