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