REVIEW REQUESTED: Proposed change for Spec Issue 514

From: Jason Lee <>
Date: Wed, 17 Dec 2008 16:57:20 -0600

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
============== 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,

    public class UserLoginEvent extends ComponentSystemEvent {

    For each class with this annotation, the following logic will be

        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. 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}" />

    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 for the event or the fully-qualified class name
(e.g., 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

    public void methodName (ComponentSystemEvent event);

Sections Modified

    Listener Classes ( moved to
    Listener Registrations ( moved to
    Listenter Registration by Annotation ( moved to
    Event Broadcasting ( moved to

Classes Added

  * <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
  * The implementation must guarantee that for
  * each class annotated with <code>NamedEvent</code>, found with the
  * scanning algorithm at "<em><a target="_"
  * href="../application/
  * 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>

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 "";

     * 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) {
            this.type = this.getRequiredAttribute("type");
   = this.getRequiredAttribute("target");

        public void apply(FaceletContext ctx, UIComponent parent)
throws IOException, FacesException, FaceletException, ELException {
            Class<? extends SystemEvent> eventClass =
            if (eventClass != null) {
                        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
            ApplicationAssociate associate =
            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;
   = 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