Coverage Report - org.apache.myfaces.view.facelets.tag.jsf.core.AjaxHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
AjaxHandler
0%
0/118
0%
0/72
3.824
AjaxHandler$AjaxBehaviorListenerImpl
0%
0/22
0%
0/4
3.824
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one
 3  
  * or more contributor license agreements.  See the NOTICE file
 4  
  * distributed with this work for additional information
 5  
  * regarding copyright ownership.  The ASF licenses this file
 6  
  * to you under the Apache License, Version 2.0 (the
 7  
  * "License"); you may not use this file except in compliance
 8  
  * with the License.  You may obtain a copy of the License at
 9  
  *
 10  
  *   http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing,
 13  
  * software distributed under the License is distributed on an
 14  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 15  
  * KIND, either express or implied.  See the License for the
 16  
  * specific language governing permissions and limitations
 17  
  * under the License.
 18  
  */
 19  
 package org.apache.myfaces.view.facelets.tag.jsf.core;
 20  
 
 21  
 import java.io.IOException;
 22  
 import java.util.Collection;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 25  
 
 26  
 import javax.el.MethodExpression;
 27  
 import javax.faces.component.PartialStateHolder;
 28  
 import javax.faces.component.UIComponent;
 29  
 import javax.faces.component.UniqueIdVendor;
 30  
 import javax.faces.component.behavior.AjaxBehavior;
 31  
 import javax.faces.component.behavior.ClientBehavior;
 32  
 import javax.faces.component.behavior.ClientBehaviorHolder;
 33  
 import javax.faces.context.FacesContext;
 34  
 import javax.faces.event.AbortProcessingException;
 35  
 import javax.faces.event.AjaxBehaviorEvent;
 36  
 import javax.faces.event.AjaxBehaviorListener;
 37  
 import javax.faces.view.BehaviorHolderAttachedObjectHandler;
 38  
 import javax.faces.view.facelets.ComponentHandler;
 39  
 import javax.faces.view.facelets.FaceletContext;
 40  
 import javax.faces.view.facelets.FaceletHandler;
 41  
 import javax.faces.view.facelets.TagAttribute;
 42  
 import javax.faces.view.facelets.TagAttributeException;
 43  
 import javax.faces.view.facelets.TagConfig;
 44  
 import javax.faces.view.facelets.TagException;
 45  
 import javax.faces.view.facelets.TagHandler;
 46  
 
 47  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
 48  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
 49  
 import org.apache.myfaces.shared.renderkit.JSFAttr;
 50  
 import org.apache.myfaces.shared.renderkit.html.util.ResourceUtils;
 51  
 import org.apache.myfaces.view.facelets.AbstractFaceletContext;
 52  
 import org.apache.myfaces.view.facelets.FaceletCompositionContext;
 53  
 import org.apache.myfaces.view.facelets.tag.TagHandlerUtils;
 54  
 import org.apache.myfaces.view.facelets.tag.composite.InsertChildrenHandler;
 55  
 import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
 56  
 import org.apache.myfaces.view.facelets.tag.ui.DecorateHandler;
 57  
 import org.apache.myfaces.view.facelets.tag.ui.IncludeHandler;
 58  
 import org.apache.myfaces.view.facelets.tag.ui.InsertHandler;
 59  
 
 60  
 /**
 61  
  * This tag creates an instance of AjaxBehavior, and associates it with the nearest 
 62  
  * parent UIComponent that implements ClientBehaviorHolder interface. This tag can
 63  
  * be used on single or composite components.
 64  
  * <p>
 65  
  * Unless otherwise specified, all attributes accept static values or EL expressions.
 66  
  * </p>
 67  
  * <p>
 68  
  * According to the documentation, the tag handler implementing this tag should meet
 69  
  * the following conditions:  
 70  
  * </p>
 71  
  * <ul>
 72  
  * <li>Since this tag attach objects to UIComponent instances, and those instances 
 73  
  * implements Behavior interface, this component should implement 
 74  
  * BehaviorHolderAttachedObjectHandler interface.</li>
 75  
  * <li>f:ajax does not support binding property. In theory we should do something similar
 76  
  * to f:convertDateTime tag does: extends from ConverterHandler and override setAttributes
 77  
  * method, but in this case BehaviorTagHandlerDelegate has binding property defined, so
 78  
  * if we extend from BehaviorHandler we add binding support to f:ajax.</li>
 79  
  * <li>This tag works as a attached object handler, but note on the api there is no component
 80  
  * to define a target for a behavior. See comment inside apply() method.</li>
 81  
  * </ul>
 82  
  * @author Leonardo Uribe (latest modification by $Author$)
 83  
  * @version $Revision$ $Date$
 84  
  */
 85  
 @JSFFaceletTag(name = "f:ajax")
 86  
 public class AjaxHandler extends TagHandler implements
 87  
         BehaviorHolderAttachedObjectHandler
 88  
 {
 89  
 
 90  0
     public final static Class<?>[] AJAX_BEHAVIOR_LISTENER_SIG = new Class<?>[] { AjaxBehaviorEvent.class };
 91  
     
 92  
     /**
 93  
      * Constant used to check if in the current build view it has been rendered the standard jsf javascript
 94  
      * library. It is necessary to remove this key from facesContext attribute map after build, to keep
 95  
      * working this code for next views to be built.
 96  
      */
 97  
     public final static String STANDARD_JSF_AJAX_LIBRARY_LOADED
 98  
             = "org.apache.myfaces.STANDARD_JSF_AJAX_LIBRARY_LOADED";
 99  
 
 100  
     /**
 101  
      * 
 102  
      */
 103  
     @JSFFaceletAttribute(name = "disabled", className = "javax.el.ValueExpression",
 104  
                          deferredValueType = "java.lang.Boolean")
 105  
     private final TagAttribute _disabled;
 106  
 
 107  
     /**
 108  
      * 
 109  
      */
 110  
     @JSFFaceletAttribute(name = "event", className = "javax.el.ValueExpression",
 111  
                          deferredValueType = "java.lang.String")
 112  
     private final TagAttribute _event;
 113  
 
 114  
     /**
 115  
      * 
 116  
      */
 117  
     @JSFFaceletAttribute(name = "execute", className = "javax.el.ValueExpression",
 118  
                          deferredValueType = "java.lang.Object")
 119  
     private final TagAttribute _execute;
 120  
 
 121  
     /**
 122  
      * 
 123  
      */
 124  
     @JSFFaceletAttribute(name = "immediate", className = "javax.el.ValueExpression",
 125  
                          deferredValueType = "java.lang.Boolean")
 126  
     private final TagAttribute _immediate;
 127  
 
 128  
     /**
 129  
      * 
 130  
      */
 131  
     @JSFFaceletAttribute(name = "listener", className = "javax.el.MethodExpression",
 132  
             deferredMethodSignature = "public void m(javax.faces.event.AjaxBehaviorEvent evt) "
 133  
                                       + "throws javax.faces.event.AbortProcessingException")
 134  
     private final TagAttribute _listener;
 135  
 
 136  
     /**
 137  
      * 
 138  
      */
 139  
     @JSFFaceletAttribute(name = "onevent", className = "javax.el.ValueExpression",
 140  
                          deferredValueType = "java.lang.String")
 141  
     private final TagAttribute _onevent;
 142  
 
 143  
     /**
 144  
      * 
 145  
      */
 146  
     @JSFFaceletAttribute(name = "onerror", className = "javax.el.ValueExpression",
 147  
                          deferredValueType = "java.lang.String")
 148  
     private final TagAttribute _onerror;
 149  
 
 150  
     /**
 151  
      * 
 152  
      */
 153  
     @JSFFaceletAttribute(name = "render", className = "javax.el.ValueExpression",
 154  
                          deferredValueType = "java.lang.Object")
 155  
     private final TagAttribute _render;
 156  
     /**
 157  
      * 
 158  
      */
 159  
     @JSFFaceletAttribute(name = "delay", className = "javax.el.ValueExpression",
 160  
                          deferredValueType = "java.lang.String")
 161  
     private final TagAttribute _delay;
 162  
     
 163  
     @JSFFaceletAttribute(name = "resetValues", className = "javax.el.ValueExpression",
 164  
             deferredValueType = "java.lang.Boolean")
 165  
     private final TagAttribute _resetValues;
 166  
     
 167  
     private final boolean _wrapMode;
 168  
 
 169  
     public AjaxHandler(TagConfig config)
 170  
     {
 171  0
         super(config);
 172  0
         _disabled = getAttribute("disabled");
 173  0
         _event = getAttribute("event");
 174  0
         _execute = getAttribute("execute");
 175  0
         _immediate = getAttribute("immediate");
 176  0
         _listener = getAttribute("listener");
 177  0
         _onerror = getAttribute("onerror");
 178  0
         _onevent = getAttribute("onevent");
 179  0
         _render = getAttribute("render");
 180  0
         _delay = getAttribute("delay");
 181  0
         _resetValues = getAttribute("resetValues");
 182  
         // According to the spec, this tag works in two different ways:
 183  
         // 1. Apply an ajax behavior for a selected component in this way
 184  
         //    <x:component><f:ajax ..../></x:component>
 185  
         // 2. Apply an ajax behavior for a group of components inside it
 186  
         //   <f:ajax ....><x:componentA .../><x:componentB .../></f:ajax>
 187  
         //
 188  
         // The first problem is how to discriminate if f:ajax tag is on a
 189  
         // "leaf" or if contain other components.
 190  
         //
 191  
         // One option is use the same strategy to cache instance for 
 192  
         // <composite:interface> handler: traverse the tree for instances of 
 193  
         // ComponentHandler. If it is found, wrapMode is used otherwise
 194  
         // suppose f:ajax is the one wrapped by a component.
 195  0
         Collection<FaceletHandler> compHandlerList = 
 196  
             TagHandlerUtils.findNextByType(nextHandler, ComponentHandler.class, 
 197  
                     InsertChildrenHandler.class, InsertHandler.class, DecorateHandler.class, IncludeHandler.class);
 198  
         
 199  0
         _wrapMode = !compHandlerList.isEmpty();
 200  0
     }
 201  
 
 202  
     public void apply(FaceletContext ctx, UIComponent parent)
 203  
             throws IOException
 204  
     {
 205  
         //Apply only if we are creating a new component
 206  0
         if (!ComponentHandler.isNew(parent))
 207  
         {
 208  0
             if (_wrapMode)
 209  
             {
 210  0
                 AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 211  
                 // In this case it will be only applied to components inserted by 
 212  
                 // c:if or related tags, in other cases, ComponentTagHandlerDelegate should
 213  
                 // not reapply ajax tag.
 214  0
                 actx.pushAjaxHandlerToStack(this);
 215  0
                 nextHandler.apply(ctx, parent);
 216  0
                 actx.popAjaxHandlerToStack();
 217  
             }
 218  0
             return;
 219  
         }
 220  0
         if (_wrapMode)
 221  
         {
 222  0
             AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 223  
             // Push and pop this ajax handler to the stack, to delegate the
 224  
             // call to applyAttachedObject to ComponentTagHandlerDelegate
 225  
             // The default one proposed here is
 226  
             // use a different stack on DefaultFaceletContext.applyCompositeComponent,
 227  
             // so components inside composite:implementation tag will not be
 228  
             // affected by f:ajax outsider handlers.
 229  0
             actx.pushAjaxHandlerToStack(this);
 230  0
             nextHandler.apply(ctx, parent);
 231  0
             actx.popAjaxHandlerToStack();
 232  0
         }
 233  
         else
 234  
         {
 235  0
             if (parent instanceof ClientBehaviorHolder)
 236  
             {
 237  
                 //Apply this handler directly over the parent
 238  0
                 applyAttachedObject(ctx.getFacesContext(), parent);
 239  
             }
 240  0
             else if (UIComponent.isCompositeComponent(parent))
 241  
             {
 242  0
                 FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
 243  
                 // It is supposed that for composite components, this tag should
 244  
                 // add itself as a target, but note that on whole api does not exists
 245  
                 // some tag that expose client behaviors as targets for composite
 246  
                 // components. In RI, there exists a tag called composite:clientBehavior,
 247  
                 // but does not appear on spec or javadoc, maybe because this could be
 248  
                 // understand as an implementation detail, after all there exists a key
 249  
                 // called AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY that could be
 250  
                 // used to create a tag outside jsf implementation to attach targets.
 251  0
                 mctx.addAttachedObjectHandler(
 252  
                         parent, this);
 253  0
             }
 254  
             else
 255  
             {
 256  0
                 throw new TagException(this.tag,
 257  
                         "Parent is not composite component or of type ClientBehaviorHolder, type is: "
 258  
                                 + parent);
 259  
             }
 260  
         }
 261  
         
 262  0
         registerJsfAjaxDefaultResource(ctx, parent);
 263  0
     }
 264  
     
 265  
     public static void registerJsfAjaxDefaultResource(FaceletContext ctx, UIComponent parent)
 266  
     {
 267  
         // Register the standard ajax library on the current page in this way:
 268  
         //
 269  
         // <h:outputScript name="jsf.js" library="javax.faces" target="head"/>
 270  
         //
 271  
         // If no h:head component is in the page, we must anyway render the script inline,
 272  
         // so the only way to make sure we are doing this is add a outputScript component.
 273  
         // Note that call directly UIViewRoot.addComponentResource or use a listener 
 274  
         // does not work in this case, because check this condition will requires 
 275  
         // traverse the whole tree looking for h:head component.
 276  0
         FacesContext facesContext = ctx.getFacesContext();
 277  0
         if (!facesContext.getAttributes().containsKey(STANDARD_JSF_AJAX_LIBRARY_LOADED))
 278  
         {
 279  0
             UIComponent outputScript = facesContext.getApplication().
 280  
                 createComponent(facesContext, "javax.faces.Output", "javax.faces.resource.Script");
 281  0
             outputScript.getAttributes().put(JSFAttr.NAME_ATTR, ResourceUtils.JSF_JS_RESOURCE_NAME);
 282  0
             outputScript.getAttributes().put(JSFAttr.LIBRARY_ATTR, ResourceUtils.JAVAX_FACES_LIBRARY_NAME);
 283  0
             outputScript.getAttributes().put(JSFAttr.TARGET_ATTR, "head");
 284  
 
 285  
             //AbstractFaceletContext actx = (AbstractFaceletContext) ctx;
 286  
 
 287  
             // Since this component will be relocated, we need a generated clientId from the
 288  
             // viewRoot, so when this one is relocated, its parent will be this UIViewRoot instance
 289  
             // and prevent a duplicate id exception.
 290  0
             UniqueIdVendor uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
 291  
             // UIViewRoot implements UniqueIdVendor, so there is no need to cast to UIViewRoot
 292  
             // and call createUniqueId()
 293  0
             String uid = uniqueIdVendor.createUniqueId(ctx.getFacesContext(),null);
 294  0
             outputScript.setId(uid);
 295  
             
 296  0
             parent.getChildren().add(outputScript);
 297  
             
 298  0
             if (FaceletCompositionContext.getCurrentInstance(ctx).isMarkInitialState())
 299  
             {
 300  
                 //Call it only if we are using partial state saving
 301  0
                 outputScript.markInitialState();
 302  
             }            
 303  0
             facesContext.getAttributes().put(STANDARD_JSF_AJAX_LIBRARY_LOADED, Boolean.TRUE);
 304  
         }
 305  0
     }
 306  
 
 307  
     /**
 308  
      * ViewDeclarationLanguage.retargetAttachedObjects uses it to check
 309  
      * if the the target to be processed is applicable for this handler
 310  
      */
 311  
     public String getEventName()
 312  
     {
 313  0
         if (_event == null)
 314  
         {
 315  0
             return null;
 316  
         }
 317  
         else
 318  
         {
 319  0
             if (_event.isLiteral())
 320  
             {
 321  0
                 return _event.getValue();
 322  
             }
 323  
             else
 324  
             {
 325  0
                 FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().
 326  
                         getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
 327  0
                 return (String) _event.getValueExpression(faceletContext, String.class).getValue(faceletContext);
 328  
             }
 329  
         }
 330  
     }
 331  
 
 332  
     /**
 333  
      * This method should create an AjaxBehavior object and attach it to the
 334  
      * parent component.
 335  
      * 
 336  
      * Also, it should check if the parent can apply the selected AjaxBehavior
 337  
      * to the selected component through ClientBehaviorHolder.getEventNames() or
 338  
      * ClientBehaviorHolder.getDefaultEventName()
 339  
      */
 340  
     public void applyAttachedObject(FacesContext context, UIComponent parent)
 341  
     {
 342  
         // Retrieve the current FaceletContext from FacesContext object
 343  0
         FaceletContext faceletContext = (FaceletContext) context
 344  
                 .getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
 345  
 
 346  
         // cast to a ClientBehaviorHolder
 347  0
         ClientBehaviorHolder cvh = (ClientBehaviorHolder) parent;
 348  
         
 349  
         
 350  0
         String eventName = null;
 351  0
         if (_event != null)
 352  
         {
 353  0
             if (_event.isLiteral())
 354  
             {
 355  0
                 eventName = _event.getValue();
 356  
             }
 357  
             else
 358  
             {
 359  0
                 eventName = (String) _event.getValueExpression(faceletContext, String.class).getValue(faceletContext);
 360  
             }
 361  
         }
 362  0
         if (eventName == null)
 363  
         {
 364  0
             eventName = cvh.getDefaultEventName();
 365  0
             if (eventName == null)
 366  
             {
 367  0
                 if (_wrapMode)
 368  
                 {
 369  
                     // No eventName defined, we can't apply this tag to this component, because
 370  
                     // there is no event defined to attach it, but since we are in wrap mode
 371  
                     // we have here the case that the component could not be the target
 372  
                     // for this attached object.
 373  0
                     return;
 374  
                 }
 375  
                 else
 376  
                 {
 377  0
                     throw new TagAttributeException(_event,
 378  
                             "eventName could not be defined for f:ajax tag with no wrap mode.");
 379  
                 }
 380  
             }
 381  
         }
 382  0
         else if (!cvh.getEventNames().contains(eventName))
 383  
         {
 384  0
             if (_wrapMode)
 385  
             {
 386  
                 // The current component does not implement the event selected,
 387  
                 // this ajax behavior cannot be applied, but we can't throw any exception
 388  
                 // since we are in wrap mode and we have here the case that the 
 389  
                 // component could not be the target for this attached object.
 390  0
                 return;
 391  
             }
 392  
             else
 393  
             {
 394  0
                 throw new TagAttributeException(_event,
 395  
                         "event it is not a valid eventName defined for this component");
 396  
             }
 397  
         }
 398  
         
 399  0
         Map<String, List<ClientBehavior>> clientBehaviors = cvh.getClientBehaviors();
 400  
 
 401  0
         List<ClientBehavior> clientBehaviorList = clientBehaviors.get(eventName);
 402  0
         if (clientBehaviorList != null && !clientBehaviorList.isEmpty())
 403  
         {
 404  0
             for (ClientBehavior cb : clientBehaviorList)
 405  
             {
 406  0
                 if (cb instanceof AjaxBehavior)
 407  
                 {
 408  
                     // The most inner one has been applied, so according to 
 409  
                     // jsf 2.0 spec section 10.4.1.1 it is not necessary to apply
 410  
                     // this one, because the inner one has precendece over
 411  
                     // the outer one.
 412  0
                     return;
 413  
                 }
 414  0
             }
 415  
         }
 416  
 
 417  0
         AjaxBehavior ajaxBehavior = createBehavior(context);
 418  
 
 419  0
         if (_disabled != null)
 420  
         {
 421  0
             if (_disabled.isLiteral())
 422  
             {
 423  0
                 ajaxBehavior.setDisabled(_disabled.getBoolean(faceletContext));
 424  
             }
 425  
             else
 426  
             {
 427  0
                 ajaxBehavior.setValueExpression("disabled", _disabled
 428  
                         .getValueExpression(faceletContext, Boolean.class));
 429  
             }
 430  
         }
 431  0
         if (_execute != null)
 432  
         {
 433  0
             ajaxBehavior.setValueExpression("execute", _execute
 434  
                     .getValueExpression(faceletContext, Object.class));
 435  
         }
 436  0
         if (_immediate != null)
 437  
         {
 438  0
             if (_immediate.isLiteral())
 439  
             {
 440  0
                 ajaxBehavior
 441  
                         .setImmediate(_immediate.getBoolean(faceletContext));
 442  
             }
 443  
             else
 444  
             {
 445  0
                 ajaxBehavior.setValueExpression("immediate", _immediate
 446  
                         .getValueExpression(faceletContext, Boolean.class));
 447  
             }
 448  
         }
 449  0
         if (_listener != null)
 450  
         {
 451  0
             MethodExpression expr = _listener.getMethodExpression(
 452  
                     faceletContext, Void.TYPE, AJAX_BEHAVIOR_LISTENER_SIG);
 453  0
             AjaxBehaviorListener abl = new AjaxBehaviorListenerImpl(expr);
 454  0
             ajaxBehavior.addAjaxBehaviorListener(abl);
 455  
         }
 456  0
         if (_onerror != null)
 457  
         {
 458  0
             if (_onerror.isLiteral())
 459  
             {
 460  0
                 ajaxBehavior.setOnerror(_onerror.getValue(faceletContext));
 461  
             }
 462  
             else
 463  
             {
 464  0
                 ajaxBehavior.setValueExpression("onerror", _onerror
 465  
                         .getValueExpression(faceletContext, String.class));
 466  
             }
 467  
         }
 468  0
         if (_onevent != null)
 469  
         {
 470  0
             if (_onevent.isLiteral())
 471  
             {
 472  0
                 ajaxBehavior.setOnevent(_onevent.getValue(faceletContext));
 473  
             }
 474  
             else
 475  
             {
 476  0
                 ajaxBehavior.setValueExpression("onevent", _onevent
 477  
                         .getValueExpression(faceletContext, String.class));
 478  
             }
 479  
         }
 480  0
         if (_render != null)
 481  
         {
 482  0
             ajaxBehavior.setValueExpression("render", _render
 483  
                     .getValueExpression(faceletContext, Object.class));
 484  
         }
 485  0
         if (_delay != null)
 486  
         {
 487  0
             if (_delay.isLiteral())
 488  
             {
 489  0
                 ajaxBehavior.setDelay(_delay.getValue(faceletContext));
 490  
             }
 491  
             else
 492  
             {
 493  0
                 ajaxBehavior.setValueExpression("delay", _delay
 494  
                     .getValueExpression(faceletContext, String.class));
 495  
             }
 496  
         }
 497  0
        if (_resetValues != null)
 498  
         {
 499  0
             if (_resetValues.isLiteral())
 500  
             {
 501  0
                 ajaxBehavior
 502  
                         .setResetValues(_resetValues.getBoolean(faceletContext));
 503  
             }
 504  
             else
 505  
             {
 506  0
                 ajaxBehavior.setValueExpression("resetValues", _resetValues
 507  
                         .getValueExpression(faceletContext, Boolean.class));
 508  
             }
 509  
         }
 510  0
         cvh.addClientBehavior(eventName, ajaxBehavior);
 511  0
     }
 512  
 
 513  
     protected AjaxBehavior createBehavior(FacesContext context)
 514  
     {
 515  0
         return (AjaxBehavior) context.getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
 516  
     }
 517  
 
 518  
     /**
 519  
      * The documentation says this attribute should not be used since it is not
 520  
      * taken into account. Instead, getEventName is used on 
 521  
      * ViewDeclarationLanguage.retargetAttachedObjects.
 522  
      */
 523  
     public String getFor()
 524  
     {
 525  0
         return null;
 526  
     }
 527  
 
 528  
     /**
 529  
      * Wraps a method expression in a AjaxBehaviorListener
 530  
      */
 531  
     public final static class AjaxBehaviorListenerImpl implements
 532  
             AjaxBehaviorListener, PartialStateHolder
 533  
     {
 534  
         private MethodExpression _expr;
 535  
         private boolean _transient;
 536  
         private boolean _initialStateMarked;
 537  
         
 538  
         public AjaxBehaviorListenerImpl ()
 539  0
         {
 540  0
         }
 541  
         
 542  
         public AjaxBehaviorListenerImpl(MethodExpression expr)
 543  0
         {
 544  0
             _expr = expr;
 545  0
         }
 546  
 
 547  
         public void processAjaxBehavior(AjaxBehaviorEvent event)
 548  
                 throws AbortProcessingException
 549  
         {
 550  0
             _expr.invoke(FacesContext.getCurrentInstance().getELContext(),
 551  
                     new Object[] { event });
 552  0
         }
 553  
 
 554  
         public boolean isTransient()
 555  
         {
 556  0
             return _transient;
 557  
         }
 558  
 
 559  
         public void restoreState(FacesContext context, Object state)
 560  
         {
 561  0
             if (state == null)
 562  
             {
 563  0
                 return;
 564  
             }
 565  0
             _expr = (MethodExpression) state;
 566  0
         }
 567  
 
 568  
         public Object saveState(FacesContext context)
 569  
         {
 570  0
             if (initialStateMarked())
 571  
             {
 572  0
                 return null;
 573  
             }
 574  0
             return _expr;
 575  
         }
 576  
 
 577  
         public void setTransient(boolean newTransientValue)
 578  
         {
 579  0
             _transient = newTransientValue;
 580  0
         }
 581  
         
 582  
         public void clearInitialState()
 583  
         {
 584  0
             _initialStateMarked = false;
 585  0
         }
 586  
 
 587  
         public boolean initialStateMarked()
 588  
         {
 589  0
             return _initialStateMarked;
 590  
         }
 591  
 
 592  
         public void markInitialState()
 593  
         {
 594  0
             _initialStateMarked = true;
 595  0
         }
 596  
     }
 597  
 }