Coverage Report - javax.faces.component.UIViewAction
 
Classes in this File Line Coverage Branch Coverage Complexity
UIViewAction
0%
0/90
0%
0/46
2.154
UIViewAction$PropertyKeys
0%
0/7
N/A
2.154
UIViewAction$ViewActionFacesContextWrapper
0%
0/13
N/A
2.154
 
 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 javax.faces.component;
 20  
 
 21  
 import javax.el.MethodExpression;
 22  
 import javax.faces.context.FacesContext;
 23  
 import javax.faces.context.FacesContextWrapper;
 24  
 import javax.faces.el.MethodBinding;
 25  
 import javax.faces.event.AbortProcessingException;
 26  
 import javax.faces.event.ActionEvent;
 27  
 import javax.faces.event.ActionListener;
 28  
 import javax.faces.event.FacesEvent;
 29  
 import javax.faces.event.PhaseId;
 30  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
 31  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFListener;
 32  
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
 33  
 
 34  
 /**
 35  
  * @since 2.2
 36  
  */
 37  
 @JSFComponent(name = "f:viewAction")
 38  
 public class UIViewAction extends UIComponentBase implements ActionSource2
 39  
 {
 40  
     //private static final Logger log = Logger.getLogger(UIViewAction.class.getName());
 41  
     public static final String COMPONENT_FAMILY = "javax.faces.ViewAction";
 42  
     public static final String COMPONENT_TYPE = "javax.faces.ViewAction";
 43  
     
 44  
     /**
 45  
      * Key in facesContext attribute map to check if a viewAction broadcast is 
 46  
      * being processed. This is used to check when a JSF lifecycle restart is required
 47  
      * by the NavigationHandler implementation.
 48  
      */
 49  
     private static final String BROADCAST_PROCESSING_KEY = "oam.viewAction.broadcast";
 50  
     
 51  
     /**
 52  
      * Key in facesContext attribute map to count the number of viewAction events that 
 53  
      * remains to be processed.
 54  
      */
 55  
     private static final String EVENT_COUNT_KEY = "oam.viewAction.eventCount";
 56  
 
 57  
     public UIViewAction()
 58  0
     {
 59  0
         setRendererType(null);
 60  0
     }
 61  
 
 62  
     @Override
 63  
     public void broadcast(FacesEvent event) throws AbortProcessingException
 64  
     {
 65  0
         super.broadcast(event);
 66  
         
 67  0
         FacesContext context = getFacesContext();
 68  
         
 69  0
         if (context.getResponseComplete())
 70  
         {
 71  0
             return;
 72  
         }
 73  
         
 74  0
         UIComponent c = event.getComponent();
 75  0
         UIViewRoot sourceViewRoot = null;
 76  
         do
 77  
         {
 78  0
             if (c instanceof UIViewRoot)
 79  
             {
 80  0
                 sourceViewRoot = (UIViewRoot) c;
 81  0
                 break;
 82  
             }
 83  
             else
 84  
             {
 85  0
                 c = c.getParent();
 86  
             }
 87  0
         } while (c != null);
 88  
         
 89  0
         if (!context.getViewRoot().equals(sourceViewRoot))
 90  
         {
 91  0
             return;
 92  
         }
 93  
         
 94  0
         if (event instanceof ActionEvent)
 95  
         {
 96  0
             ActionListener defaultActionListener = context.getApplication().getActionListener();
 97  0
             if (defaultActionListener != null)
 98  
             {
 99  0
                 String  viewIdBeforeAction = context.getViewRoot().getViewId();
 100  0
                 Boolean oldBroadcastProcessing = (Boolean) context.getAttributes().
 101  
                     get(BROADCAST_PROCESSING_KEY);
 102  
                 try
 103  
                 {
 104  0
                     context.getAttributes().put(BROADCAST_PROCESSING_KEY, Boolean.TRUE);
 105  
 
 106  0
                     ViewActionFacesContextWrapper wrappedFacesContext = new ViewActionFacesContextWrapper(context);
 107  
 
 108  
                     try
 109  
                     {
 110  0
                         wrappedFacesContext.setWrapperAsCurrentFacesContext();
 111  
 
 112  0
                         MethodBinding mb = getActionListener();
 113  0
                         if (mb != null)
 114  
                         {
 115  0
                             mb.invoke(context, new Object[]
 116  
                             { event });
 117  
                         }
 118  
 
 119  0
                         if (defaultActionListener != null)
 120  
                         {
 121  0
                             defaultActionListener.processAction((ActionEvent) event);
 122  
                         }
 123  
                         
 124  
                         // Decrement count
 125  0
                         Integer count = (Integer) context.getAttributes().get(EVENT_COUNT_KEY);
 126  0
                         count = (count == null) ? 0 : count - 1;
 127  0
                         context.getAttributes().put(EVENT_COUNT_KEY, count);
 128  
                     }
 129  
                     finally
 130  
                     {
 131  0
                         wrappedFacesContext.restoreCurrentFacesContext();
 132  0
                     }
 133  
                 }
 134  
                 finally
 135  
                 {
 136  0
                     context.getAttributes().put(BROADCAST_PROCESSING_KEY, 
 137  
                         oldBroadcastProcessing == null ? Boolean.FALSE : oldBroadcastProcessing);
 138  0
                 }
 139  
 
 140  0
                 if (context.getResponseComplete())
 141  
                 {
 142  0
                     return;
 143  
                 }
 144  
                 else
 145  
                 {
 146  0
                     Integer count = (Integer) context.getAttributes().get(EVENT_COUNT_KEY);
 147  0
                     count = (count == null) ? 0 : count;
 148  0
                     String viewIdAfterAction = context.getViewRoot().getViewId();
 149  
 
 150  0
                     if (viewIdBeforeAction.equals(viewIdAfterAction) && count == 0)
 151  
                     {
 152  0
                         context.renderResponse();
 153  
                     }
 154  
                     // "... Otherwise, execute the lifecycle on the new UIViewRoot ..."
 155  
                     // Note these words are implemented in the NavigationHandler, but 
 156  
                     // the original proposal from seam s:viewAction did a trick here 
 157  
                     // to restart the JSF lifecycle.
 158  
                 }
 159  
             }
 160  
         }
 161  0
     }
 162  
 
 163  
     @Override
 164  
     public void decode(FacesContext context)
 165  
     {
 166  0
         super.decode(context);
 167  
         
 168  0
         if (context.isPostback() && !isOnPostback())
 169  
         {
 170  0
             return;
 171  
         }
 172  
         
 173  0
         if (!isRendered())
 174  
         {
 175  0
             return;
 176  
         }
 177  
         
 178  0
         ActionEvent evt = new ActionEvent(this);
 179  0
         String phase = getPhase();
 180  0
         PhaseId phaseId = (phase != null) ? PhaseId.phaseIdValueOf(phase) :
 181  
             isImmediate() ? PhaseId.APPLY_REQUEST_VALUES : PhaseId.INVOKE_APPLICATION;
 182  0
         evt.setPhaseId(phaseId);
 183  0
         this.queueEvent(evt);
 184  
         
 185  
         // "... Keep track of the number of events that are queued in this way 
 186  
         // on this run through the lifecycle. ...". The are two options:
 187  
         // 1. Use an attribute over FacesContext attribute map
 188  
         // 2. Use an attribute over the component
 189  
         // If the view is recreated again with the same viewId, the component 
 190  
         // state get lost, so the option 1 is preferred.
 191  0
         Integer count = (Integer) context.getAttributes().get(EVENT_COUNT_KEY);
 192  0
         count = (count == null) ? 1 : count + 1;
 193  0
         context.getAttributes().put(EVENT_COUNT_KEY, count);
 194  0
     }
 195  
 
 196  
     @Deprecated
 197  
     public MethodBinding getAction()
 198  
     {
 199  0
         MethodExpression actionExpression = getActionExpression();
 200  0
         if (actionExpression instanceof _MethodBindingToMethodExpression)
 201  
         {
 202  0
             return ((_MethodBindingToMethodExpression) actionExpression)
 203  
                     .getMethodBinding();
 204  
         }
 205  0
         if (actionExpression != null)
 206  
         {
 207  0
             return new _MethodExpressionToMethodBinding(actionExpression);
 208  
         }
 209  0
         return null;
 210  
     }
 211  
 
 212  
     /**
 213  
      * @deprecated Use setActionExpression instead.
 214  
      */
 215  
     @Deprecated
 216  
     public void setAction(MethodBinding action)
 217  
     {
 218  0
         if (action != null)
 219  
         {
 220  0
             setActionExpression(new _MethodBindingToMethodExpression(action));
 221  
         }
 222  
         else
 223  
         {
 224  0
             setActionExpression(null);
 225  
         }
 226  0
     }
 227  
 
 228  
     @JSFProperty
 229  
     public boolean isImmediate()
 230  
     {
 231  0
         return (Boolean) getStateHelper().eval(PropertyKeys.immediate, Boolean.FALSE);
 232  
     }
 233  
 
 234  
     public void setImmediate(boolean immediate)
 235  
     {
 236  0
         getStateHelper().put(PropertyKeys.immediate, immediate );
 237  0
     }
 238  
 
 239  
     @JSFProperty(stateHolder=true, returnSignature = "java.lang.Object", jspName = "action", clientEvent="action")
 240  
     public MethodExpression getActionExpression()
 241  
     {
 242  0
         return (MethodExpression) getStateHelper().eval(PropertyKeys.actionExpression);
 243  
     }
 244  
 
 245  
     public void setActionExpression(MethodExpression actionExpression)
 246  
     {
 247  0
         getStateHelper().put(PropertyKeys.actionExpression, actionExpression);
 248  0
     }
 249  
 
 250  
     @Deprecated
 251  
     @JSFProperty(stateHolder=true, returnSignature = "void", methodSignature = "javax.faces.event.ActionEvent")
 252  
     public MethodBinding getActionListener()
 253  
     {
 254  0
         return (MethodBinding) getStateHelper().eval(PropertyKeys.actionListener);
 255  
     }
 256  
 
 257  
     /**
 258  
      * @deprecated
 259  
      */
 260  
     @Deprecated
 261  
     @JSFProperty(returnSignature="void",methodSignature="javax.faces.event.ActionEvent")
 262  
     public void setActionListener(MethodBinding actionListener)
 263  
     {
 264  0
         getStateHelper().put(PropertyKeys.actionListener, actionListener);
 265  
         // Note f:viewAction does not have actionListener property defined.
 266  
         //throw new UnsupportedOperationException();
 267  0
     }
 268  
 
 269  
     public void addActionListener(ActionListener listener)
 270  
     {
 271  0
         addFacesListener(listener);
 272  0
     }
 273  
 
 274  
     public void removeActionListener(ActionListener listener)
 275  
     {
 276  0
         removeFacesListener(listener);
 277  0
     }
 278  
 
 279  
     @JSFListener(event="javax.faces.event.ActionEvent",
 280  
             phases="Invoke Application, Apply Request Values")
 281  
     public ActionListener[] getActionListeners()
 282  
     {
 283  0
         return (ActionListener[]) getFacesListeners(ActionListener.class);
 284  
     }
 285  
     
 286  
     @JSFProperty
 287  
     public String getPhase()
 288  
     {
 289  0
         return (String) getStateHelper().get(PropertyKeys.phase);
 290  
     }
 291  
     
 292  
     public void setPhase(String phase)
 293  
     {
 294  0
         getStateHelper().put(PropertyKeys.phase, phase);
 295  0
     }
 296  
     
 297  
     @JSFProperty
 298  
     public boolean isOnPostback()
 299  
     {
 300  0
         return (Boolean) getStateHelper().eval(PropertyKeys.onPostback, Boolean.FALSE);
 301  
     }
 302  
 
 303  
     public void setOnPostback(boolean onPostback)
 304  
     {
 305  0
         getStateHelper().put(PropertyKeys.onPostback, onPostback );
 306  0
     }    
 307  
     
 308  
     public static boolean isProcessingBroadcast(FacesContext context)
 309  
     {
 310  0
         return Boolean.TRUE.equals(context.getAttributes().get(BROADCAST_PROCESSING_KEY));
 311  
     }
 312  
 
 313  0
     enum PropertyKeys
 314  
     {
 315  0
          immediate
 316  0
         , value
 317  0
         , actionExpression
 318  0
         , actionListener
 319  0
         , phase
 320  0
         , onPostback
 321  
     }
 322  
 
 323  
     @Override
 324  
     public String getFamily()
 325  
     {
 326  0
         return COMPONENT_FAMILY;
 327  
     }
 328  
     
 329  0
     private static class ViewActionFacesContextWrapper extends FacesContextWrapper
 330  
     {
 331  
         private FacesContext delegate;
 332  
         private boolean renderResponseCalled;
 333  
 
 334  
         public ViewActionFacesContextWrapper(FacesContext delegate)
 335  0
         {
 336  0
             this.delegate = delegate;
 337  0
             this.renderResponseCalled = false;
 338  0
         }
 339  
 
 340  
         @Override
 341  
         public void renderResponse()
 342  
         {
 343  
             //Take no action
 344  0
             renderResponseCalled = true;
 345  0
         }
 346  
         
 347  
         public boolean isRenderResponseCalled()
 348  
         {
 349  0
             return renderResponseCalled;
 350  
         }
 351  
         
 352  
         @Override
 353  
         public FacesContext getWrapped()
 354  
         {
 355  0
             return delegate;
 356  
         }
 357  
         
 358  
         void setWrapperAsCurrentFacesContext()
 359  
         {
 360  0
             setCurrentInstance(this);
 361  0
         }
 362  
         
 363  
         void restoreCurrentFacesContext()
 364  
         {
 365  0
             setCurrentInstance(delegate);
 366  0
         }
 367  
     }
 368  
 }