Here is the change bundle for spec issue 514, the addition of the
f:event tag for declarative event handling for page authors. The
changed and added files are attached. Below is the updated spec prose.
To make the new JSF 2 event model available to page authors, this
proposal will detail the addition of a new tag, f:event, which will
allow the page author to associate a method on a managed bean with a
specific event on a specific component.
Sections Added
==============
3.4.3.2 Named Events
To aid in the registration for Listeners for a custom event,
developers may annotate the class using the optional @NamedEvent
annotation. For example,
@NamedEvent(name="userLogin")
public class UserLoginEvent extends ComponentSystemEvent {
...
}
For each class with this annotation, the following logic will be
applied:
1. Get the unqualified class name (e.g., UserLoginEvent)
2. Strip off the trailing "Event", if present (e.g., UserLogin)
3. Convert the first character to lower-case (e.g., userLogin)
4. Prepend the package name to the lower-cased name
5. If the shortName attribute is specified, register the event by
that name as well.
In the event that two events specify the same name, a
FacesException will be thrown on the first use of the event name. The
Exception message should list, at a minimum, the event name and the
offending classes.
The following specification classes will be registered
automatically by the run-time using the logic above:
BeforeRenderEvent, AfterAddToParentEvent, and AfterAddToViewEvent,
using both the fully-qualifed name, and a short name, comprised of the
event's simple name only.
3.4.3.6 Declarative Listener Registration
Page authors can subscribe to events using the <f:event/> tag.
This tag will allow the application developer to specify the method to
be called when the specifed event fires for the component of which the
tag is a child. The tag usage is as follows:
<h:inputText value="#{myBean.text}">
<f:event type="beforeRender"
target="#{myBean.beforeTextRender}" />
</h:inputText>
The type specifies the type of event, and can be any of the
specification-defined events or one of any user-defined events, but
must be a ComponentSystemEvent, using either the short-hand name (see
section 3.4.3.2) for the event or the fully-qualified class name
(e.g., com.foo.app.event.CustomEvent). If the event can not be found,
a FacesException listing the offending event type will be thrown.
The method signature for the handling method must match the
following:
public void methodName (ComponentSystemEvent event);
Sections Modified
=================
Listener Classes (3.4.3.2) moved to 3.4.3.3
Listener Registrations (3.4.3.3) moved to 3.4.3.4
Listenter Registration by Annotation (3.4.3.4) moved to 3.4.3.5
Event Broadcasting (3.4.3.5) moved to 3.4.3.7
Classes Added
=============
javax.faces.event.NamedEvent:
/**
* <p class="changed_added_2_0">The presence of this annotation on a
* class automatically registers the class with the runtime as a {_at_link
* ComponentSystemEvent}. The value of the {_at_link #shortName}
attribute is taken to
* be the shor name for the {_at_link
javax.faces.event.ComponentSystemEvent}.
* The implementation must guarantee that for
* each class annotated with <code>NamedEvent</code>, found with the
* scanning algorithm at "<em><a target="_"
* href="../application/
FacesAnnotationHandler
.html
#configAnnotationScanningSpecification
">configAnnotationScanningSpecification</a></em>",
* the {_at_link javax.faces.event.ComponentSystemEvent} must registered
with the runtime.
* If the shortName has already been registered, the current class
must be added to a
* List of of duplicate Events for that name. If the event name is
then reference by an
* application, an Exception must thrown listing the shortName and
the offending classes.</p>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface NamedEvent {
/**
* <p class="changed_added_2_0">The value of this annotation
* attribute is taken to be the short name for the {_at_link
* javax.faces.event.ComponentSystemEvent}</p>
*/
String shortName() default "";
}
com.sun.faces.facelets.tag.jsf.core.EventHandler:
/**
* This is the TagHandler for the f:event tag.
*
* @author jasonlee
*/
public class EventHandler extends TagHandler {
protected final TagAttribute type;
protected final TagAttribute target;
public EventHandler(TagConfig config) {
super(config);
this.type = this.getRequiredAttribute("type");
this.target = this.getRequiredAttribute("target");
}
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, FaceletException, ELException {
Class<? extends SystemEvent> eventClass =
getEventClass(ctx);
if (eventClass != null) {
parent.subscribeToEvent(eventClass,
new
DeclarativeSystemEventListener(ctx.getFacesContext().getELContext(),
target.getMethodExpression(ctx, Object.class,
new Class[] { ComponentSystemEvent.class })));
}
}
protected Class<? extends SystemEvent>
getEventClass(FaceletContext ctx) {
Class<? extends SystemEvent> clazz = null;
String eventType = (String)
this.type.getValueExpression(ctx, String.class).getValue(ctx);
if (eventType == null) {
throw new FacesException("Attribute 'type' can not be
null");
}
ApplicationAssociate associate =
ApplicationAssociate
.getInstance(ctx.getFacesContext().getExternalContext());
NamedEventManager nem = associate.getNamedEventManager();
clazz = nem.getNamedEvent(eventType);
if (clazz == null) {
try {
clazz = Util.loadClass(eventType, this);
} catch (ClassNotFoundException ex) {
throw new FacesException ("An unknown event type
was specified: " + eventType);
}
}
return clazz;
}
}
class DeclarativeSystemEventListener implements
ComponentSystemEventListener {
private ELContext elContext;
private MethodExpression target;
public DeclarativeSystemEventListener(ELContext elContext,
MethodExpression target) {
this.elContext = elContext;
this.target = target;
}
public void processEvent(ComponentSystemEvent event) throws
AbortProcessingException {
target.invoke(elContext, new Object[]{event});
}
}
Jason Lee, SCJP
Senior Java Developer, Sun Microsystems
Mojarra and Mojarra Scales Dev Team
https://mojarra.dev.java.net
https://scales.dev.java.net
http://blogs.steeplesoft.com