Coverage Report - javax.faces.event.MethodExpressionValueChangeListener
 
Classes in this File Line Coverage Branch Coverage Complexity
MethodExpressionValueChangeListener
65%
30/46
10%
1/10
1.818
 
 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.event;
 20  
 
 21  
 import javax.el.ELContext;
 22  
 import javax.el.ELException;
 23  
 import javax.el.ExpressionFactory;
 24  
 import javax.el.MethodExpression;
 25  
 import javax.el.MethodNotFoundException;
 26  
 import javax.faces.component.StateHolder;
 27  
 import javax.faces.context.FacesContext;
 28  
 
 29  
 /**
 30  
  * See Javadoc of <a href="https://javaserverfaces.dev.java.net/nonav/docs/2.0/javadocs/javax/faces/event/
 31  
  * MethodExpressionValueChangeListener.html">JSF Specification</a>
 32  
  */
 33  
 public class MethodExpressionValueChangeListener implements ValueChangeListener, StateHolder
 34  
 {
 35  
 
 36  2
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
 37  2
     private static final Object[] EMPTY_PARAMS = new Object[0];
 38  
     
 39  
     private MethodExpression methodExpressionOneArg;
 40  
     private MethodExpression methodExpressionZeroArg;
 41  14
     private boolean isTransient = false;
 42  
 
 43  
     /** Creates a new instance of MethodExpressionValueChangeListener */
 44  
     public MethodExpressionValueChangeListener()
 45  4
     {
 46  
         // constructor for state-saving 
 47  4
     }
 48  
 
 49  
     public MethodExpressionValueChangeListener(MethodExpression methodExpressionOneArg)
 50  4
     {
 51  4
         this.methodExpressionOneArg = methodExpressionOneArg;
 52  
         
 53  4
         _createZeroArgsMethodExpression(methodExpressionOneArg); 
 54  4
     }
 55  
 
 56  
     public MethodExpressionValueChangeListener(MethodExpression methodExpressionOneArg,
 57  
                                                MethodExpression methodExpressionZeroArg)
 58  6
     {
 59  6
         this.methodExpressionOneArg = methodExpressionOneArg;
 60  6
         if (methodExpressionZeroArg != null) 
 61  
         {
 62  6
             this.methodExpressionZeroArg = methodExpressionZeroArg;
 63  
         }
 64  
         else
 65  
         {
 66  0
             _createZeroArgsMethodExpression(methodExpressionOneArg);
 67  
         }
 68  6
     }
 69  
 
 70  
     public void processValueChange(ValueChangeEvent event) throws AbortProcessingException
 71  
     {
 72  
         try
 73  
         {
 74  
             try
 75  
             {
 76  
                 // call to the one argument MethodExpression
 77  4
                 Object[] params = new Object[] { event };
 78  4
                 methodExpressionOneArg.invoke(getElContext(), params);
 79  
             }
 80  2
             catch (MethodNotFoundException mnfe)
 81  
             {
 82  
                 // call to the zero argument MethodExpression
 83  2
                 methodExpressionZeroArg.invoke(getElContext(), EMPTY_PARAMS);
 84  2
             }
 85  
         }
 86  0
         catch (ELException e)
 87  
         {
 88  
             // "... If that fails for any reason, throw an AbortProcessingException,
 89  
             // including the cause of the failure ..."
 90  
             // -= Leonardo Uribe =- after discussing this topic on MYFACES-3199, the conclusion is the part is an advice
 91  
             // for the developer implementing a listener in a method expressions that could be wrapped by this class.
 92  
             // The spec wording is poor but, to keep this coherently with ExceptionHandler API,
 93  
             // the spec and code on UIViewRoot we need:
 94  
             // 2a) "exception is instance of APE or any of the causes of the exception are an APE, 
 95  
             // DON'T publish ExceptionQueuedEvent and terminate processing for current event".
 96  
             // 2b) for any other exception publish ExceptionQueuedEvent and continue broadcast processing.
 97  0
             Throwable cause = e.getCause();
 98  0
             AbortProcessingException ape = null;
 99  0
             if (cause != null)
 100  
             {
 101  
                 do
 102  
                 {
 103  0
                     if (cause instanceof AbortProcessingException)
 104  
                     {
 105  0
                         ape = (AbortProcessingException) cause;
 106  0
                         break;
 107  
                     }
 108  0
                     cause = cause.getCause();
 109  
                 }
 110  0
                 while (cause != null);
 111  
             }
 112  
             
 113  0
             if (ape != null)
 114  
             {
 115  
                 // 2a) "exception is instance of APE or any of the causes of the exception are an APE, 
 116  
                 // DON'T publish ExceptionQueuedEvent and terminate processing for current event".
 117  
                 // To do this throw an AbortProcessingException here, later on UIViewRoot.broadcastAll,
 118  
                 // this exception will be received and stored to handle later.
 119  0
                 throw ape;
 120  
             }
 121  
             //for any other exception publish ExceptionQueuedEvent and continue broadcast processing.
 122  0
             throw e;
 123  
             //Throwable cause = e.getCause();
 124  
             //if (cause == null)
 125  
             //{
 126  
             //    cause = e;
 127  
             //}
 128  
             //if (cause instanceof AbortProcessingException)
 129  
             //{
 130  
             //    throw (AbortProcessingException) cause;
 131  
             //}
 132  
             //else
 133  
             //{
 134  
             //    throw new AbortProcessingException(cause);
 135  
             //}
 136  4
         }
 137  4
     }
 138  
 
 139  
     public void restoreState(FacesContext context, Object state)
 140  
     {
 141  2
         methodExpressionOneArg = (MethodExpression) ((Object[]) state)[0];
 142  2
         methodExpressionZeroArg = (MethodExpression) ((Object[]) state)[1];
 143  2
     }
 144  
 
 145  
     public Object saveState(FacesContext context)
 146  
     {
 147  2
         return new Object[] {methodExpressionOneArg, methodExpressionZeroArg};
 148  
     }
 149  
 
 150  
     public void setTransient(boolean newTransientValue)
 151  
     {
 152  0
         isTransient = newTransientValue;
 153  0
     }
 154  
 
 155  
     public boolean isTransient()
 156  
     {
 157  0
         return isTransient;
 158  
     }
 159  
     
 160  
     private ELContext getElContext()
 161  
     {
 162  10
         return getFacesContext().getELContext();
 163  
     }
 164  
     
 165  
     private FacesContext getFacesContext()
 166  
     {
 167  14
         return FacesContext.getCurrentInstance();
 168  
     }
 169  
     
 170  
     /**
 171  
      * Creates a {@link MethodExpression} with no params and with the same Expression as 
 172  
      * param <code>methodExpression</code>
 173  
      * <b>WARNING!</b> This method creates new {@link MethodExpression} with expressionFactory.createMethodExpression.
 174  
      * That means is not decorating MethodExpression passed as parameter -
 175  
      * support for EL VariableMapper will not be available!
 176  
      * This is a problem when using facelets and <ui:decorate/> with EL params (see MYFACES-2541 for details).
 177  
      */
 178  
     private void _createZeroArgsMethodExpression(MethodExpression methodExpression)
 179  
     {
 180  4
         ExpressionFactory expressionFactory = getFacesContext().getApplication().getExpressionFactory();
 181  
 
 182  4
         this.methodExpressionZeroArg = expressionFactory.createMethodExpression(getElContext(), 
 183  
                   methodExpression.getExpressionString(), Void.class, EMPTY_CLASS_ARRAY);
 184  4
     }
 185  
 
 186  
 }