You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mc...@apache.org on 2009/06/17 16:46:57 UTC
svn commit: r785633 - in
/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces: config/
config/annotation/ config/impl/digester/ config/impl/digester/elements/
view/facelets/tag/jsf/core/
Author: mconcini
Date: Wed Jun 17 14:46:57 2009
New Revision: 785633
URL: http://svn.apache.org/viewvc?rev=785633&view=rev
Log:
MYFACES-2253 - finish system event support
Added:
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/NamedEventManager.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/SystemEventListener.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java
Modified:
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/annotation/AnnotationConfigurator.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/Application.java
myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigDispenser.java Wed Jun 17 14:46:57 2009
@@ -27,6 +27,7 @@
import org.apache.myfaces.config.element.Renderer;
import org.apache.myfaces.config.impl.digester.elements.Converter;
import org.apache.myfaces.config.impl.digester.elements.ResourceBundle;
+import org.apache.myfaces.config.impl.digester.elements.SystemEventListener;
/**
* Subsumes several unmarshalled faces config objects and presents a simple interface
@@ -241,4 +242,9 @@
* @return Iterator over {@link ELResolver} implementation class names
*/
public Collection<String> getElResolvers();
+
+ /**
+ * @return Iterator over (@link SystemEventListener) implementation class names
+ */
+ public Collection<SystemEventListener> getSystemEventListeners();
}
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/FacesConfigurator.java Wed Jun 17 14:46:57 2009
@@ -60,6 +60,7 @@
import javax.faces.el.VariableResolver;
import javax.faces.event.ActionListener;
import javax.faces.event.PhaseListener;
+import javax.faces.event.SystemEvent;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.render.RenderKit;
@@ -81,6 +82,7 @@
import org.apache.myfaces.config.impl.digester.elements.FacesConfigNameSlot;
import org.apache.myfaces.config.impl.digester.elements.OrderSlot;
import org.apache.myfaces.config.impl.digester.elements.ResourceBundle;
+import org.apache.myfaces.config.impl.digester.elements.SystemEventListener;
import org.apache.myfaces.context.FacesContextFactoryImpl;
import org.apache.myfaces.context.PartialViewContextFactoryImpl;
import org.apache.myfaces.el.DefaultPropertyResolver;
@@ -1568,6 +1570,14 @@
dispenser.getViewHandlerIterator(),
application.getViewHandler()));
+ for (SystemEventListener systemEventListener : dispenser.getSystemEventListeners())
+ {
+
+ application.subscribeToEvent(
+ (Class<? extends SystemEvent>)ClassUtils.newInstance(systemEventListener.getSystemEventClass(),SystemEvent.class),
+ (Class<?>)ClassUtils.newInstance(systemEventListener.getSourceClass()),
+ (javax.faces.event.SystemEventListener)ClassUtils.newInstance(systemEventListener.getSystemEventClass(),javax.faces.event.SystemEventListener.class));
+ }
for (String componentType : dispenser.getComponentTypes())
{
Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/NamedEventManager.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/NamedEventManager.java?rev=785633&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/NamedEventManager.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/NamedEventManager.java Wed Jun 17 14:46:57 2009
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.config;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.PostAddToViewEvent;
+import javax.faces.event.PostValidateEvent;
+import javax.faces.event.PreRenderComponentEvent;
+import javax.faces.event.PreValidateEvent;
+
+/**
+ * The NamedEventManager class is used to keep map a short name to ComponentSystemEvent classes
+ * annotated with @NamedEvent.
+ */
+
+public class NamedEventManager {
+ private static final NamedEventManager instance = new NamedEventManager();
+
+ private HashMap<String, Collection<Class<? extends ComponentSystemEvent>>> events;
+
+ private NamedEventManager ()
+ {
+ events = new HashMap<String, Collection<Class<? extends ComponentSystemEvent>>>();
+
+ // Special spec-defined values.
+
+ addNamedEvent ("postAddToView", PostAddToViewEvent.class);
+ addNamedEvent ("preRenderComponent", PreRenderComponentEvent.class);
+ addNamedEvent ("preValidate", PreValidateEvent.class);
+ addNamedEvent ("postValidate", PostValidateEvent.class);
+ }
+
+ public static NamedEventManager getInstance ()
+ {
+ return instance;
+ }
+
+ /**
+ * Registers a named event.
+ *
+ * @param shortName a String containing the short name for the event, from the @NamedEvent.shortName()
+ * attribute.
+ * @param cls the event class to register.
+ */
+
+ public void addNamedEvent (String shortName, Class<? extends ComponentSystemEvent> cls)
+ {
+ String key = shortName;
+ Collection<Class<? extends ComponentSystemEvent>> eventList;
+
+ // Per the spec, if the short name is missing, generate one.
+
+ if (shortName == null) {
+ key = getFixedName (cls);
+ }
+
+ eventList = events.get (key);
+
+ if (eventList == null) {
+ // First event registered to this short name.
+
+ eventList = new LinkedList<Class<? extends ComponentSystemEvent>>();
+
+ events.put (key, eventList);
+ }
+
+ eventList.add (cls);
+ }
+
+ /**
+ * Retrieves a collection of system event classes based on their short name.
+ *
+ * @param shortName the short name to look up.
+ * @return a Collection of Class objects containing the system event classes registered to
+ * the given short name.
+ */
+
+ public Collection<Class<? extends ComponentSystemEvent>> getNamedEvent (String shortName)
+ {
+ return events.get (shortName);
+ }
+
+ /**
+ * Retrieves the short name for an event class, according to spec rules.
+ *
+ * @param cls the class to find the short name for.
+ * @return a String containing the short name for the given class.
+ */
+
+ private String getFixedName (Class<? extends ComponentSystemEvent> cls)
+ {
+ StringBuilder result = new StringBuilder();
+ String className;
+
+ // Get the unqualified class name.
+
+ className = cls.getSimpleName();
+
+ // Strip the trailing "event" off the class name if present.
+
+ if (className.toLowerCase().endsWith ("event")) {
+ className = className.substring (0, result.length() - 5);
+ }
+
+ // Prepend the package name.
+
+ if (cls.getPackage() != null) {
+ result.append (cls.getPackage().getName());
+ result.append ('.');
+ }
+
+ result.append (className);
+
+ return result.toString();
+ }
+}
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/annotation/AnnotationConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/annotation/AnnotationConfigurator.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/annotation/AnnotationConfigurator.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/annotation/AnnotationConfigurator.java Wed Jun 17 14:46:57 2009
@@ -48,6 +48,8 @@
import javax.faces.component.FacesComponent;
import javax.faces.context.ExternalContext;
import javax.faces.convert.FacesConverter;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.NamedEvent;
import javax.faces.render.FacesRenderer;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
@@ -57,6 +59,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.config.FacesConfigDispenser;
+import org.apache.myfaces.config.NamedEventManager;
import org.apache.myfaces.config.RuntimeConfig;
import org.apache.myfaces.config.impl.digester.elements.FacesConfig;
import org.apache.myfaces.shared_impl.util.ClassUtils;
@@ -851,6 +854,30 @@
runtimeConfig.addManagedBean(mbc.getManagedBeanName(), mbc);
}
+ NamedEvent namedEvent = (NamedEvent) clazz.getAnnotation (NamedEvent.class);
+
+ if (namedEvent != null) {
+ // Can only apply @NamedEvent to ComponentSystemEvent subclasses.
+
+ if (!ComponentSystemEvent.class.isAssignableFrom (clazz)) {
+ // Just log this. We'll catch it later in the runtime.
+
+ if (log.isWarnEnabled()) {
+ log.warn (clazz.getName() + " is annotated with @javax.faces.event.NamedEvent, but does " +
+ "not extend javax.faces.event.ComponentSystemEvent");
+ }
+
+ return;
+ }
+
+ // Have to register @NamedEvent annotations with the NamedEventManager class since
+ // we need to get access to this info later and can't from the dispenser (it's not a
+ // singleton).
+
+ NamedEventManager.getInstance().addNamedEvent (namedEvent.shortName(),
+ (Class<? extends ComponentSystemEvent>) clazz);
+ }
+
// TODO: All annotations scanned at startup must be configured here!
//FacesBehaviorRenderer
}
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigDispenserImpl.java Wed Jun 17 14:46:57 2009
@@ -39,6 +39,7 @@
import org.apache.myfaces.config.impl.digester.elements.LocaleConfig;
import org.apache.myfaces.config.impl.digester.elements.RenderKit;
import org.apache.myfaces.config.impl.digester.elements.ResourceBundle;
+import org.apache.myfaces.config.impl.digester.elements.SystemEventListener;
/**
* @author <a href="mailto:oliver@rossmueller.com">Oliver Rossmueller</a>
@@ -86,6 +87,8 @@
private List<NavigationRule> navigationRules = new ArrayList<NavigationRule>();
private List<ResourceBundle> resourceBundles = new ArrayList<ResourceBundle>();
+ private List<SystemEventListener> systemEventListeners = new ArrayList<SystemEventListener>();
+
/**
* Add another unmarshalled faces config object.
*
@@ -138,6 +141,7 @@
variableResolver.addAll(application.getVariableResolver());
resourceBundles.addAll(application.getResourceBundle());
elResolvers.addAll(application.getElResolver());
+ systemEventListeners.addAll(application.getSystemEventListener());
}
for (Converter converter : config.getConverters())
@@ -553,4 +557,10 @@
return elResolvers;
}
+ @Override
+ public Collection<SystemEventListener> getSystemEventListeners()
+ {
+ return systemEventListeners;
+ }
+
}
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/DigesterFacesConfigUnmarshallerImpl.java Wed Jun 17 14:46:57 2009
@@ -100,6 +100,11 @@
// 1.2 specific end
// 2.0 specific start
+ digester.addObjectCreate("faces-config/application/system-event-listener", SystemEventListener.class);
+ digester.addSetNext("faces-config/application/system-event-listener", "addSystemEventListener");
+ digester.addCallMethod("faces-config/application/system-event-listener/system-event-listener-class", "setSystemEventListenerClass",0);
+ digester.addCallMethod("faces-config/application/system-event-listener/system-event-class", "setSystemEventClass",0);
+ digester.addCallMethod("faces-config/application/system-event-listener/source-class", "setSourceClass",0);
digester.addCallMethod("faces-config/application/resource-handler", "addResourceHandler", 0);
digester.addCallMethod("faces-config/factory/exception-handler-factory", "addExceptionHandlerFactory", 0);
digester.addCallMethod("faces-config/factory/external-context-factory", "addExternalContextFactory", 0);
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/Application.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/Application.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/Application.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/Application.java Wed Jun 17 14:46:57 2009
@@ -39,7 +39,8 @@
private final List<LocaleConfig> localeConfig = new ArrayList<LocaleConfig>();
private final List<String> elResolver = new ArrayList<String>();
private final List<ResourceBundle> resourceBundle = new ArrayList<ResourceBundle>();
-
+ private final List<SystemEventListener> systemEventListener = new ArrayList<SystemEventListener>();
+
public void addActionListener(String listener)
{
actionListener.add(listener);
@@ -100,6 +101,11 @@
resourceBundle.add(bundle);
}
+ public void addSystemEventListener(SystemEventListener listener)
+ {
+ systemEventListener.add(listener);
+ }
+
public List<String> getActionListener()
{
return actionListener;
@@ -159,4 +165,9 @@
{
return resourceBundle;
}
+
+ public List<SystemEventListener> getSystemEventListener()
+ {
+ return systemEventListener;
+ }
}
Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/SystemEventListener.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/SystemEventListener.java?rev=785633&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/SystemEventListener.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/config/impl/digester/elements/SystemEventListener.java Wed Jun 17 14:46:57 2009
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.config.impl.digester.elements;
+
+public class SystemEventListener
+{
+ private String systemEventListenerClass;
+ private String systemEventClass;
+ private String sourceClass;
+
+ public void setSystemEventListenerClass(String listener)
+ {
+ systemEventListenerClass = listener;
+ }
+
+ public void setSystemEventClass(String event)
+ {
+ systemEventClass = event;
+ }
+
+ public void setSourceClass(String source)
+ {
+ sourceClass = source;
+ }
+
+ public String getSystemEventListenerClass()
+ {
+ return systemEventListenerClass;
+ }
+
+ public String getSystemEventClass()
+ {
+ return systemEventClass;
+ }
+
+ public String getSourceClass()
+ {
+ return sourceClass;
+ }
+}
Modified: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java?rev=785633&r1=785632&r2=785633&view=diff
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java (original)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java Wed Jun 17 14:46:57 2009
@@ -57,7 +57,9 @@
this.addConverter("convertNumber", NumberConverter.CONVERTER_ID, ConvertNumberHandler.class);
this.addConverter("converter", null, ConvertDelegateHandler.class);
-
+
+ this.addTagHandler ("event", EventHandler.class);
+
this.addTagHandler("facet", FacetHandler.class);
this.addTagHandler("loadBundle", LoadBundleHandler.class);
Added: myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java?rev=785633&view=auto
==============================================================================
--- myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java (added)
+++ myfaces/core/branches/2_0_0/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java Wed Jun 17 14:46:57 2009
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.view.facelets.tag.jsf.core;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+import javax.faces.FacesException;
+import javax.faces.component.UIComponent;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.view.facelets.FaceletContext;
+import javax.faces.view.facelets.FaceletException;
+import javax.faces.view.facelets.TagAttribute;
+import javax.faces.view.facelets.TagAttributeException;
+import javax.faces.view.facelets.TagConfig;
+import javax.faces.view.facelets.TagException;
+import javax.faces.view.facelets.TagHandler;
+
+import org.apache.myfaces.config.NamedEventManager;
+import org.apache.myfaces.view.facelets.util.ReflectionUtil;
+
+/**
+ * Registers a listener for a given system event class on the UIComponent associated with this tag.
+ */
+
+public final class EventHandler extends TagHandler {
+ private TagAttribute listener;
+ private TagAttribute name;
+ private TagAttribute type;
+
+ public EventHandler (TagConfig tagConfig)
+ {
+ super (tagConfig);
+
+ listener = getRequiredAttribute ("listener");
+ name = getAttribute ("name");
+ type = getAttribute ("type");
+
+ // TODO: is this right? The spec isn't entirely clear, but it seems to me that one or the other
+ // attribute must be defined, despite the fact that the docs say "name" is required.
+
+ if ((name == null) && (type == null)) {
+ throw new TagException (this.tag, "One of the 'name' or 'type' attributes must be defined");
+ }
+
+ else if ((name != null) && (type != null)) {
+ throw new TagException (this.tag, "Both the 'name' and 'type' attributes cannot be defined");
+ }
+ }
+
+ @Override
+ public void apply (FaceletContext ctx, UIComponent parent) throws ELException, FacesException, FaceletException, IOException
+ {
+ Class<? extends ComponentSystemEvent> eventClass = getEventClass (ctx);
+ MethodExpression methodExp = listener.getMethodExpression(ctx, void.class, new Class<?>[] {
+ ComponentSystemEvent.class });
+
+ // Simply register the event on the component.
+
+ parent.subscribeToEvent (eventClass, new Listener (ctx.getFacesContext().getELContext(), methodExp));
+ }
+
+ /**
+ * Gets the event class defined by the tag (either in the "name" or "type" attribute).
+ *
+ * @param context the Facelet context
+ * @return a Class containing the event class defined by the tag.
+ */
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends ComponentSystemEvent> getEventClass (FaceletContext context)
+ {
+ Class<?> eventClass = null;
+ ValueExpression valueExp = ((name != null) ? name.getValueExpression (context, String.class) :
+ type.getValueExpression (context, String.class));
+ String value = (String) valueExp.getValue (context.getFacesContext().getELContext());
+
+ if (name != null) {
+ Collection<Class<? extends ComponentSystemEvent>> events;
+
+ // We can look up the event class by name in the NamedEventManager.
+
+ events = NamedEventManager.getInstance().getNamedEvent (value);
+
+ if (events.size() > 1) {
+ StringBuilder classNames = new StringBuilder ("[");
+ Iterator<Class<? extends ComponentSystemEvent>> eventIterator = events.iterator();
+
+ // TODO: The spec is somewhat vague, but I think we're supposed to throw an exception
+ // here. The @NamedEvent javadocs say that if a short name is registered to more than one
+ // event class that we must throw an exception listing the short name and the classes in
+ // the list _when the application makes reference to it_. I believe processing this tag
+ // qualifies as the application "making reference" to the short name. Why the exception
+ // isn't thrown when processing the @NamedEvent annotation, I don't know. Perhaps follow
+ // up with the EG to see if this is correct.
+
+ while (eventIterator.hasNext()) {
+ classNames.append (eventIterator.next().getName());
+
+ if (eventIterator.hasNext()) {
+ classNames.append (", ");
+ }
+
+ else {
+ classNames.append ("]");
+ }
+ }
+
+ throw new FacesException ("The event name '" + value + "' is mapped to more than one " +
+ " event class: " + classNames.toString());
+ }
+
+ else {
+ eventClass = events.iterator().next();
+ }
+ }
+
+ else {
+ // Must have been defined via the "type" attribute, so instantiate the class.
+
+ try {
+ eventClass = ReflectionUtil.forName (value);
+ }
+
+ catch (Throwable e) {
+ throw new TagAttributeException ((name != null) ? name : type, "Couldn't create event class", e);
+ }
+ }
+
+ if (!ComponentSystemEvent.class.isAssignableFrom (eventClass)) {
+ throw new TagAttributeException ((name != null) ? name : type, "Event class " + eventClass.getName() +
+ " is not of type javax.faces.event.ComponentSystemEvent");
+ }
+
+ return (Class<? extends ComponentSystemEvent>) eventClass;
+ }
+
+ private class Listener implements ComponentSystemEventListener {
+ private ELContext elContext;
+ private MethodExpression methodExp;
+
+ private Listener (ELContext elContext, MethodExpression methodExp)
+ {
+ this.elContext = elContext;
+ this.methodExp = methodExp;
+ }
+
+ @Override
+ public void processEvent (ComponentSystemEvent event)
+ {
+ this.methodExp.invoke(elContext, new Object[] { event });
+ }
+ }
+}