WARNING: This blog entry was imported from my old blog on blogs.sun.com (which used different blogging software), so formatting and links may not be correct.
As JSF is gaining popularity, more JSF components are being written. In fact
TopCoder
is running a competition on writing components. (Sun is a
sponsor.)
However, some of the components written work, but do not work well in tools
like Creator, or do not work well when used in conjunction with CSS. In this
blog entry I will provide some hints that will make sure your components do
not fall in that category.
How to actually write a JSF component is covered in many places; it's
not hard. You need to write 3-4 classes, plus write a .tld file and
a faces-config file with some information about your component.
Here's a document which takes you through this process.
However, there are some additional Rules You Should Follow when
you write your component.
These rules serve two purposes:
- They ensure that your component will work right when it is
sized and positioned using CSS properties. - They ensure that your component will work well at designtime
in a tool like Creator.
Here they are:
- First and foremost, you MUST use the
ResponseWriter'sstartElement
,endElement
andwriteAttribute
methods. Do NOT
write out markup by simply streaming out HTML bytes linearly using thewrite
method. There is one minor exception to this rule: some components
need to emit HTML provided by the user, such as theHtmlOutputText
component when itsEscape
property is set to false. In this limited
scenario you should usewrite
.
Always pass in a component reference to the startElement method on theResponseWriter
. E.g. if yourUIComponent
is a PanelGrid,
and you want to emit<table><tr><td>...
you would
use
writer.startElement("table", gridpanel);
writer.startElement("tr", gridpanel);
writer.startElement("td", gridpanel);
Every component should have astyle
property, which will render
to astyle
attribute on the rendered HTML markup.
This will allow tools like Creator to position and size the component (using CSS).
It is vital that you remember to replicate this style attribute on your top level
rendered HTML tag. However, there are some complications...- In the normal case, you render a single top level HTML element (possibly with
children) from the JSP tag. In this case, simply duplicate the value of the
JSP tag's style attribute to the top level HTML tag attribute. For example,
if you have<h:commandButton style="width: 100px"/>
in the
JSP, you would render<input type="submit" style="width: 100px"/>
If you need to render multiple top level HTML tags, but only one of them is visual,
duplicate the style attribute on the one visual tag. For example, your component
may want to render a<script>
tag before it renders its one visual
element,<table>
, and then perhaps another non visual element, an<input>
of typehidden
.
In this case, simply emit the<script>
, then emit the<table>
with the style property value from the JSF component,
and finally emit the hidden<input>
.
If you need to render more than one visual element as siblings at the top level, you
need to wrap these in a single container component, such as a<span>
or a<div>
. (Use span only if all the children being rendered are
inline elements.) The style property should be placed only on this outer, wrapping<span>
or<div>
.
- In the normal case, you render a single top level HTML element (possibly with
- Don't throw exceptions from your renderer! Even if for example
value
is a required
property, don't throw a configuration exception just because it's null when you're rendering!
If you really want your component to alert the user to the problem, I suppose it's okay to
throw an exception when the component is used at runtime, but at designtime, it's quite normal
for a component not to be correctly configured yet - after all, the user may just have dropped
the component and is about to configure it. If necessary, you can have code in your renderer which
checks if the component renderer is being used at designtime:
if (java.beans.Beans.isDesignTime()) {
// Designtime - better render error handling here
...
} else {
// Runtime - throw your exceptions if you must
...
}
One thing you might consider doing is having the component render exactly the problem message
to the user. As an example, in Creator, if you drop theMessage
component, it will
tell you if it is not bound to anything (since thefor
property is null, so the
component is not yet configured.)
Once you have written your component you should package it up such that it can easily be
imported into Creator and used out of the box by your users. That is also covered in
the component library article I linked to earlier.
Please let me know if you develop components that work well with Creator!
hi;
ReplyDeletei'm currently using jsf and develop some apps, my personal thought about JSF is its not easy as much as asp.net is. it needs some serious revisiotions, especially in backing bean development and design-time component behavior areas.
Actually my personal idea is JSF will never get such a popularity that asp.net had already gained.