Author: nbelaevski
Date: 2010-05-15 10:24:28 -0400 (Sat, 15 May 2010)
New Revision: 17062
Added:
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/ActionListenerHandler.java
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/TagHandlerUtils.java
root/ui/core/trunk/api/src/main/resources/META-INF/a4j_ext.taglib.xml
Modified:
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/AjaxHandler.java
Log:
https://jira.jboss.org/browse/RF-8444
Added:
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/ActionListenerHandler.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/ActionListenerHandler.java
(rev 0)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/ActionListenerHandler.java 2010-05-15
14:24:28 UTC (rev 17062)
@@ -0,0 +1,193 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.view.facelets.html;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.el.MethodExpression;
+import javax.el.ValueExpression;
+import javax.faces.component.ActionSource;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ActionEvent;
+import javax.faces.event.ActionListener;
+import javax.faces.event.MethodExpressionActionListener;
+import javax.faces.view.ActionSource2AttachedObjectHandler;
+import javax.faces.view.facelets.ComponentHandler;
+import javax.faces.view.facelets.FaceletContext;
+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;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ActionListenerHandler extends TagHandler implements
ActionSource2AttachedObjectHandler {
+
+ private TagAttribute binding;
+
+ private String listenerType;
+
+ private TagAttribute listenerMethod;
+
+ private static final class LazyActionListener implements ActionListener, Serializable
{
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 6303879250524609909L;
+
+ private final String type;
+
+ private final ValueExpression binding;
+
+ public LazyActionListener(String type, ValueExpression binding) {
+ this.type = type;
+ this.binding = binding;
+ }
+
+ public void processAction(ActionEvent event) throws AbortProcessingException {
+ ActionListener instance = null;
+ FacesContext faces = FacesContext.getCurrentInstance();
+ if (faces == null) {
+ return;
+ }
+
+ if (this.binding != null) {
+ instance = (ActionListener) binding.getValue(faces.getELContext());
+ }
+
+ if (instance == null && this.type != null) {
+ try {
+ instance = TagHandlerUtils.loadClass(this.type,
ActionListener.class).newInstance();
+ } catch (Exception e) {
+ throw new AbortProcessingException(
+ "Couldn't lazily instantiate ActionListener", e);
+ }
+
+ if (this.binding != null) {
+ binding.setValue(faces.getELContext(), instance);
+ }
+ }
+
+ if (instance != null) {
+ instance.processAction(event);
+ }
+ }
+ }
+
+ public ActionListenerHandler(TagConfig config) {
+ super(config);
+
+ this.binding = this.getAttribute("binding");
+
+ TagAttribute type = this.getAttribute("type");
+ if (type != null) {
+ if (!type.isLiteral()) {
+ throw new TagAttributeException(type, "Must be a literal class name
of type ActionListener");
+ } else {
+ // test it out
+ try {
+ TagHandlerUtils.loadClass(type.getValue(), ActionListener.class);
+ } catch (ClassNotFoundException e) {
+ throw new TagAttributeException(type,
+ "Couldn't qualify ActionListener", e);
+ } catch (ClassCastException e) {
+ throw new TagAttributeException(type,
+ "Qualified class is not ActionListener", e);
+ }
+ }
+
+ this.listenerType = type.getValue();
+ } else {
+ this.listenerType = null;
+ }
+
+ this.listenerMethod = this.getAttribute("listener");
+
+ if (this.listenerMethod != null && this.binding != null) {
+ throw new TagException(this.tag, "Attributes 'listener' and
'binding' cannot be used simultaneously");
+ }
+
+ if (this.listenerMethod != null && this.listenerType != null) {
+ throw new TagException(this.tag, "Attributes 'listener' and
'type' cannot be used simultaneously");
+ }
+ }
+
+ public void applyAttachedObject(FacesContext context, UIComponent parent) {
+ if (!(parent instanceof ActionSource)) {
+ throw new TagException(this.tag, "Parent is not of type ActionSource,
type is: " + parent);
+ }
+
+ ActionSource as = (ActionSource) parent;
+
+ FaceletContext ctx = (FaceletContext)
context.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
+
+ if (this.listenerMethod != null) {
+ MethodExpression listenerMethodExpression = this.listenerMethod.
+ getMethodExpression(ctx, Void.TYPE, new Class<?>[] {
ActionEvent.class });
+
+ as.addActionListener(new
MethodExpressionActionListener(listenerMethodExpression));
+ } else {
+ ValueExpression b = null;
+ if (this.binding != null) {
+ b = this.binding.getValueExpression(ctx, ActionListener.class);
+ }
+ ActionListener listener = new LazyActionListener(this.listenerType, b);
+ as.addActionListener(listener);
+ }
+ }
+
+ public String getFor() {
+ String result = null;
+ TagAttribute attr = this.getAttribute("for");
+
+ if (null != attr) {
+ result = attr.getValue();
+ }
+
+ return result;
+ }
+
+ public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
+ if (null == parent || !(ComponentHandler.isNew(parent))) {
+ return;
+ }
+
+ if (UIComponent.isCompositeComponent(parent)) {
+ if (null == getFor()) {
+ throw new TagException(this.tag,
+ "actionListener tags nested within composite components must
have a non-null 'for' attribute");
+ }
+
+ TagHandlerUtils.getOrCreateRetargetableHandlersList(parent).add(this);
+ } else {
+ applyAttachedObject(ctx.getFacesContext(), parent);
+ }
+ }
+
+}
Modified:
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/AjaxHandler.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/AjaxHandler.java 2010-05-15
12:28:52 UTC (rev 17061)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/AjaxHandler.java 2010-05-15
14:24:28 UTC (rev 17062)
@@ -26,10 +26,8 @@
import java.beans.BeanInfo;
import java.io.IOException;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import javax.el.ELContext;
import javax.el.MethodExpression;
@@ -41,7 +39,6 @@
import javax.faces.event.AbortProcessingException;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.event.AjaxBehaviorListener;
-import javax.faces.view.AttachedObjectHandler;
import javax.faces.view.AttachedObjectTarget;
import javax.faces.view.BehaviorHolderAttachedObjectHandler;
import javax.faces.view.BehaviorHolderAttachedObjectTarget;
@@ -59,8 +56,6 @@
//TODO nick - use TagHandlerDelegate
public class AjaxHandler extends TagHandler implements
BehaviorHolderAttachedObjectHandler {
- // TODO - is that implementation dependency?
- private static final String JAVAX_FACES_RETARGETABLE_HANDLERS =
"javax.faces.RetargetableHandlers";
private final TagAttribute disabled;
private final TagAttribute event;
private final TagAttribute execute;
@@ -137,20 +132,6 @@
}
}
- private static List<AttachedObjectHandler>
getOrCreateRetargetableHandlersList(UIComponent component) {
- Map<String, Object> attrs = component.getAttributes();
- @SuppressWarnings({
- "unchecked"}) List<AttachedObjectHandler> list =
- (List<AttachedObjectHandler>)
attrs.get(JAVAX_FACES_RETARGETABLE_HANDLERS);
-
- if (list == null) {
- list = new ArrayList<AttachedObjectHandler>();
- attrs.put(JAVAX_FACES_RETARGETABLE_HANDLERS, list);
- }
-
- return list;
- }
-
private void applyNested(FaceletContext ctx, UIComponent parent, AjaxBehavior
behavior) {
if (!ComponentHandler.isNew(parent)) {
return;
@@ -196,7 +177,7 @@
}
if (supportedEvent) {
- getOrCreateRetargetableHandlersList(parent).add(this);
+ TagHandlerUtils.getOrCreateRetargetableHandlersList(parent).add(this);
} else {
throw new TagException(tag, "Error: enclosing composite component
does not support event " + eventName);
}
Added:
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/TagHandlerUtils.java
===================================================================
---
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/TagHandlerUtils.java
(rev 0)
+++
root/ui/core/trunk/api/src/main/java/org/richfaces/view/facelets/html/TagHandlerUtils.java 2010-05-15
14:24:28 UTC (rev 17062)
@@ -0,0 +1,67 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.view.facelets.html;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.faces.component.UIComponent;
+import javax.faces.view.AttachedObjectHandler;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+final class TagHandlerUtils {
+
+ // TODO - is that implementation dependency?
+ private static final String JAVAX_FACES_RETARGETABLE_HANDLERS =
"javax.faces.RetargetableHandlers";
+
+ private TagHandlerUtils() {
+ //utility class constructor
+ }
+
+ static List<AttachedObjectHandler>
getOrCreateRetargetableHandlersList(UIComponent component) {
+ Map<String, Object> attrs = component.getAttributes();
+ @SuppressWarnings({
+ "unchecked"}) List<AttachedObjectHandler> list =
+ (List<AttachedObjectHandler>)
attrs.get(JAVAX_FACES_RETARGETABLE_HANDLERS);
+
+ if (list == null) {
+ list = new ArrayList<AttachedObjectHandler>();
+ attrs.put(JAVAX_FACES_RETARGETABLE_HANDLERS, list);
+ }
+
+ return list;
+ }
+
+ static <T> Class<? extends T> loadClass(String className, Class<T>
type)
+ throws ClassNotFoundException, ClassCastException {
+
+ ClassLoader ccl = Thread.currentThread().getContextClassLoader();
+ Class<?> loadedClass = Class.forName(className, false, ccl);
+
+ return loadedClass.asSubclass(type);
+ }
+
+}
Added: root/ui/core/trunk/api/src/main/resources/META-INF/a4j_ext.taglib.xml
===================================================================
--- root/ui/core/trunk/api/src/main/resources/META-INF/a4j_ext.taglib.xml
(rev 0)
+++ root/ui/core/trunk/api/src/main/resources/META-INF/a4j_ext.taglib.xml 2010-05-15
14:24:28 UTC (rev 17062)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<facelet-taglib
xmlns="http://java.sun.com/xml/ns/javaee"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
+ version="2.0" id="a4j_ext">
+ <
namespace>http://richfaces.org/a4j_ext</namespace>
+ <tag>
+ <tag-name>actionListener</tag-name>
+ <handler-class>org.richfaces.view.facelets.html.ActionListenerHandler</handler-class>
+ <attribute>
+ <description>
+ Value binding expression that evaluates to an object that implements
+ javax.faces.event.ActionListener.
+ </description>
+ <name>binding</name>
+ <type>javax.faces.event.ActionListener</type>
+ </attribute>
+ <attribute>
+ <description>
+ If present, this attribute refers to the value of one of the exposed attached objects
within
+ the composite component inside of which this tag is nested.
+ </description>
+ <name>for</name>
+ <type>java.lang.String</type>
+ </attribute>
+ <attribute>
+ <description>
+ Method expression referencing a method that will be called when an ActionEvent has
been broadcast
+ for the listener. Shouldn't be used simultaneously with 'binding' or
'type' attributes.
+ </description>
+ <name>listener</name>
+ <type>javax.el.MethodExpression</type>
+ </attribute>
+ <attribute>
+ <description>
+ Fully qualified Java class name of an ActionListener to be created and registered.
+ </description>
+ <name>type</name>
+ <type>java.lang.String</type>
+ </attribute>
+ </tag>
+</facelet-taglib>