You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/09/01 07:15:34 UTC

svn commit: r809818 - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf: BehaviorTagHandlerDelegate.java core/AjaxHandler.java core/CoreLibrary.java

Author: lu4242
Date: Tue Sep  1 05:15:33 2009
New Revision: 809818

URL: http://svn.apache.org/viewvc?rev=809818&view=rev
Log:
MYFACES-2323 Implement <f:ajax> tag handler 

Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/BehaviorTagHandlerDelegate.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/AjaxHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/BehaviorTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/BehaviorTagHandlerDelegate.java?rev=809818&r1=809817&r2=809818&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/BehaviorTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/BehaviorTagHandlerDelegate.java Tue Sep  1 05:15:33 2009
@@ -20,21 +20,31 @@
 
 import java.io.IOException;
 
+import javax.el.ValueExpression;
 import javax.faces.component.UIComponent;
+import javax.faces.component.behavior.Behavior;
+import javax.faces.component.behavior.ClientBehavior;
+import javax.faces.component.behavior.ClientBehaviorHolder;
 import javax.faces.context.FacesContext;
-import javax.faces.view.AttachedObjectHandler;
+import javax.faces.view.BehaviorHolderAttachedObjectHandler;
 import javax.faces.view.facelets.BehaviorHandler;
+import javax.faces.view.facelets.ComponentHandler;
 import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.MetaRuleset;
+import javax.faces.view.facelets.TagAttribute;
+import javax.faces.view.facelets.TagException;
 import javax.faces.view.facelets.TagHandlerDelegate;
 
+import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
+
 /**
  * @author Leonardo Uribe (latest modification by $Author$)
  * @version $Revision$ $Date$
  *
  * @since 2.0
  */
-public class BehaviorTagHandlerDelegate extends TagHandlerDelegate implements AttachedObjectHandler
+public class BehaviorTagHandlerDelegate extends TagHandlerDelegate implements BehaviorHolderAttachedObjectHandler
 {
 
     private BehaviorHandler _delegate;
@@ -45,31 +55,133 @@
     }
 
     @Override
-    public void apply(FaceletContext ctx, UIComponent comp) throws IOException
+    public void apply(FaceletContext ctx, UIComponent parent) throws IOException
     {
-        // TODO Auto-generated method stub
+        if (!ComponentHandler.isNew(parent))
+        {
+            return;
+        }
+        // Note that the only contract defined at this moment based on behavior api
+        // is client behavior, so it is enough to cast it here. In the future, new
+        // implementations should be added here.
+        if (parent instanceof ClientBehaviorHolder)
+        {
+            applyAttachedObject(ctx.getFacesContext(), parent);
+        }
+        else if (UIComponent.isCompositeComponent(parent))
+        {
+            // It is supposed that for composite components, this tag should
+            // add itself as a target, but note that on whole api does not exists
+            // some tag that expose client behaviors as targets for composite
+            // components. In RI, there exists a tag called composite:clientBehavior,
+            // but does not appear on spec or javadoc, maybe because this could be
+            // understand as an implementation detail, after all there exists a key
+            // called AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY that could be
+            // used to create a tag outside jsf implementation to attach targets.
+            CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, _delegate);
+        }
+        else
+        {
+            throw new TagException(_delegate.getTag(), "Parent not composite component or an instance of ClientBehaviorHolder: " + parent);
+        }
         
     }
+    
+    protected Behavior createBehavior(FaceletContext ctx)
+    {
+        if (_delegate.getBehaviorId() == null)
+        {
+            throw new TagException(
+                                   _delegate.getTag(),
+                                   "No behavior id defined");
+        }
+        return ctx.getFacesContext().getApplication().createBehavior(_delegate.getBehaviorId());
+    }
 
+    /**
+     * This tag call _delegate.setAttributes, so the returned MetaRuleset
+     * should ignore attributes that are not supposed to be there like
+     * "binding" and "event"
+     */
     @Override
     public MetaRuleset createMetaRuleset(Class<?> type)
     {
-        // TODO Auto-generated method stub
-        return null;
+        MetaRuleset ruleset = new MetaRulesetImpl(_delegate.getTag(), type);
+        ruleset.ignore("binding");
+        ruleset.ignore("event");
+        return ruleset;
     }
 
+    /**
+     * Create a ClientBehavior and attach it to the component
+     */
     @Override
     public void applyAttachedObject(FacesContext context, UIComponent parent)
     {
-        // TODO Auto-generated method stub
+        // Retrieve the current FaceletContext from FacesContext object
+        FaceletContext faceletContext = (FaceletContext) context.getAttributes().get(
+                FaceletContext.FACELET_CONTEXT_KEY);
+        
+        ValueExpression ve = null;
+        Behavior behavior = null;
+        if (_delegate.getBinding() != null)
+        {
+            ve = _delegate.getBinding().getValueExpression(faceletContext, Behavior.class);
+            behavior = (Behavior) ve.getValue(faceletContext);
+        }
+        if (behavior == null)
+        {
+            behavior = this.createBehavior(faceletContext);
+            if (ve != null)
+            {
+                ve.setValue(faceletContext, behavior);
+            }
+        }
+        if (behavior == null)
+        {
+            throw new TagException(_delegate.getTag(), "No Validator was created");
+        }
+        _delegate.setAttributes(faceletContext, behavior);
         
+        if (behavior instanceof ClientBehavior)
+        {
+            // cast to a ClientBehaviorHolder
+            ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
+            
+            // TODO: check if the behavior could be applied to the current parent
+            // For run tests it is not necessary, so we let this one pending.
+
+            // It is necessary to obtain a event name for add it, so we have to
+            // look first to the defined event name, otherwise take the default from
+            // the holder
+            String eventName = getEventName();
+            if (eventName == null)
+            {
+                eventName = cvh.getDefaultEventName();
+            }
+            cvh.addClientBehavior(eventName, (ClientBehavior) behavior);
+        }
     }
 
     @Override
     public String getFor()
     {
-        // TODO Auto-generated method stub
-        return null;
+        TagAttribute forAttribute = _delegate.getTagAttribute("for");
+        
+        if (forAttribute == null)
+        {
+            return null;
+        }
+        else
+        {
+            return forAttribute.getValue();
+        }
+    }
+
+    @Override
+    public String getEventName()
+    {
+        return _delegate.getEventName();
     }
 
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/AjaxHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/AjaxHandler.java?rev=809818&r1=809817&r2=809818&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/AjaxHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/AjaxHandler.java Tue Sep  1 05:15:33 2009
@@ -20,9 +20,14 @@
 
 import java.io.IOException;
 
+import javax.el.MethodExpression;
 import javax.faces.component.UIComponent;
+import javax.faces.component.behavior.AjaxBehavior;
 import javax.faces.component.behavior.ClientBehaviorHolder;
 import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
+import javax.faces.event.AjaxBehaviorEvent;
+import javax.faces.event.AjaxBehaviorListener;
 import javax.faces.view.BehaviorHolderAttachedObjectHandler;
 import javax.faces.view.facelets.ComponentHandler;
 import javax.faces.view.facelets.FaceletContext;
@@ -50,84 +55,71 @@
  * <li>Since this tag attach objects to UIComponent instances, and those instances 
  * implements Behavior interface, this component should implement 
  * BehaviorHolderAttachedObjectHandler interface.</li>
- * <li></li>
- * <li></li>
- * <li></li>
- * <li></li>
- * <li></li>
+ * <li>f:ajax does not support binding property. In theory we should do something similar
+ * to f:convertDateTime tag does: extends from ConverterHandler and override setAttributes
+ * method, but in this case BehaviorTagHandlerDelegate has binding property defined, so
+ * if we extend from BehaviorHandler we add binding support to f:ajax.</li>
+ * <li>This tag works as a attached object handler, but note on the api there is no component
+ * to define a target for a behavior. See comment inside apply() method.</li>
  * </ul>
  * @author Leonardo Uribe (latest modification by $Author$)
  * @version $Revision$ $Date$
  */
-@JSFFaceletTag(name="f:ajax")
-public class AjaxHandler extends TagHandler implements BehaviorHolderAttachedObjectHandler
+@JSFFaceletTag(name = "f:ajax")
+public class AjaxHandler extends TagHandler implements
+        BehaviorHolderAttachedObjectHandler
 {
 
+    public final static Class<?>[] AJAX_BEHAVIOR_LISTENER_SIG = new Class<?>[] { AjaxBehaviorEvent.class };
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="disabled",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.Boolean")
+    @JSFFaceletAttribute(name = "disabled", className = "javax.el.ValueExpression", deferredValueType = "java.lang.Boolean")
     private TagAttribute _disabled;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="event",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.String")
+    @JSFFaceletAttribute(name = "event", className = "javax.el.ValueExpression", deferredValueType = "java.lang.String")
     private TagAttribute _event;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="execute",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.Object")
+    @JSFFaceletAttribute(name = "execute", className = "javax.el.ValueExpression", deferredValueType = "java.lang.Object")
     private TagAttribute _execute;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="immediate",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.Boolean")
+    @JSFFaceletAttribute(name = "immediate", className = "javax.el.ValueExpression", deferredValueType = "java.lang.Boolean")
     private TagAttribute _immediate;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="listener",
-            className="javax.el.MethodExpression",
-            deferredMethodSignature=
-"public void m(javax.faces.event.AjaxBehaviorEvent evt) throws javax.faces.event.AbortProcessingException")
+    @JSFFaceletAttribute(name = "listener", className = "javax.el.MethodExpression", deferredMethodSignature = "public void m(javax.faces.event.AjaxBehaviorEvent evt) throws javax.faces.event.AbortProcessingException")
     private TagAttribute _listener;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="onevent",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.String")
+    @JSFFaceletAttribute(name = "onevent", className = "javax.el.ValueExpression", deferredValueType = "java.lang.String")
     private TagAttribute _onevent;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="onerror",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.String")
+    @JSFFaceletAttribute(name = "onerror", className = "javax.el.ValueExpression", deferredValueType = "java.lang.String")
     private TagAttribute _onerror;
-    
+
     /**
      * 
      */
-    @JSFFaceletAttribute(name="render",
-            className="javax.el.ValueExpression",
-            deferredValueType="java.lang.Object")
+    @JSFFaceletAttribute(name = "render", className = "javax.el.ValueExpression", deferredValueType = "java.lang.Object")
     private TagAttribute _render;
-    
+
     public AjaxHandler(TagConfig config)
     {
         super(config);
@@ -156,11 +148,22 @@
         }
         else if (UIComponent.isCompositeComponent(parent))
         {
-            CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, this);
+            // It is supposed that for composite components, this tag should
+            // add itself as a target, but note that on whole api does not exists
+            // some tag that expose client behaviors as targets for composite
+            // components. In RI, there exists a tag called composite:clientBehavior,
+            // but does not appear on spec or javadoc, maybe because this could be
+            // understand as an implementation detail, after all there exists a key
+            // called AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY that could be
+            // used to create a tag outside jsf implementation to attach targets.
+            CompositeComponentResourceTagHandler.addAttachedObjectHandler(
+                    parent, this);
         }
         else
         {
-            throw new TagException(this.tag, "Parent is not composite component or of type ClientBehaviorHolder, type is: " + parent);
+            throw new TagException(this.tag,
+                    "Parent is not composite component or of type ClientBehaviorHolder, type is: "
+                            + parent);
         }
     }
 
@@ -192,7 +195,93 @@
     @Override
     public void applyAttachedObject(FacesContext context, UIComponent parent)
     {
-        // TODO Auto-generated method stub
+        // Retrieve the current FaceletContext from FacesContext object
+        FaceletContext faceletContext = (FaceletContext) context
+                .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
+
+        // cast to a ClientBehaviorHolder
+        ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
+        
+        // TODO: check if the behavior could be applied to the current parent
+        // For run tests it is not necessary, so we let this one pending.
+
+        AjaxBehavior ajaxBehavior = (AjaxBehavior) context.getApplication()
+                .createBehavior(AjaxBehavior.BEHAVIOR_ID);
+
+        if (_disabled != null)
+        {
+            if (_disabled.isLiteral())
+            {
+                ajaxBehavior.setDisabled(_disabled.getBoolean(faceletContext));
+            }
+            else
+            {
+                ajaxBehavior.setValueExpression("disabled", _disabled
+                        .getValueExpression(faceletContext, Boolean.class));
+            }
+        }
+        if (_execute != null)
+        {
+            ajaxBehavior.setValueExpression("execute", _execute
+                    .getValueExpression(faceletContext, Object.class));
+        }
+        if (_immediate != null)
+        {
+            if (_immediate.isLiteral())
+            {
+                ajaxBehavior
+                        .setImmediate(_immediate.getBoolean(faceletContext));
+            }
+            else
+            {
+                ajaxBehavior.setValueExpression("immediate", _immediate
+                        .getValueExpression(faceletContext, Boolean.class));
+            }
+        }
+        if (_listener != null)
+        {
+            MethodExpression expr = _listener.getMethodExpression(
+                    faceletContext, Void.TYPE, AJAX_BEHAVIOR_LISTENER_SIG);
+            AjaxBehaviorListener abl = new AjaxBehaviorListenerImpl(expr);
+            ajaxBehavior.addAjaxBehaviorListener(abl);
+        }
+        if (_onerror != null)
+        {
+            if (_onerror.isLiteral())
+            {
+                ajaxBehavior.setOnerror(_onerror.getValue(faceletContext));
+            }
+            else
+            {
+                ajaxBehavior.setValueExpression("onerror", _onerror
+                        .getValueExpression(faceletContext, String.class));
+            }
+        }
+        if (_onevent != null)
+        {
+            if (_onevent.isLiteral())
+            {
+                ajaxBehavior.setOnevent(_onevent.getValue(faceletContext));
+            }
+            else
+            {
+                ajaxBehavior.setValueExpression("onevent", _onevent
+                        .getValueExpression(faceletContext, String.class));
+            }
+        }
+        if (_render != null)
+        {
+            ajaxBehavior.setValueExpression("render", _render
+                    .getValueExpression(faceletContext, Object.class));
+        }
+
+        String eventName = getEventName();
+        if (eventName == null)
+        {
+            eventName = cvh.getDefaultEventName();
+        }
+
+        cvh.addClientBehavior(eventName, ajaxBehavior);
     }
 
     /**
@@ -205,4 +294,29 @@
     {
         return null;
     }
+
+    /**
+     * Wraps a method expression in a AjaxBehaviorListener 
+     * TODO: This instance should be StateHolder or Serializable,
+     * since ClientBehaviorBase implements PartialStateHolder
+     *
+     */
+    private final static class AjaxBehaviorListenerImpl implements
+            AjaxBehaviorListener
+    {
+        private final MethodExpression _expr;
+
+        public AjaxBehaviorListenerImpl(MethodExpression expr)
+        {
+            _expr = expr;
+        }
+
+        @Override
+        public void processAjaxBehavior(AjaxBehaviorEvent event)
+                throws AbortProcessingException
+        {
+            _expr.invoke(FacesContext.getCurrentInstance().getELContext(),
+                    new Object[] { event });
+        }
+    }
 }

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java?rev=809818&r1=809817&r2=809818&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/CoreLibrary.java Tue Sep  1 05:15:33 2009
@@ -50,6 +50,8 @@
 
         this.addTagHandler("actionListener", ActionListenerHandler.class);
 
+        this.addTagHandler("ajax", AjaxHandler.class);
+        
         this.addTagHandler("attribute", AttributeHandler.class);
 
         this.addConverter("convertDateTime", DateTimeConverter.CONVERTER_ID, ConvertDateTimeHandler.class);