View Javadoc

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.component;
20  
21  import javax.el.ELContext;
22  import javax.el.ELException;
23  import javax.el.MethodExpression;
24  import javax.el.MethodInfo;
25  import javax.el.MethodNotFoundException;
26  import javax.el.PropertyNotFoundException;
27  import javax.faces.component.StateHolder;
28  import javax.faces.context.FacesContext;
29  import javax.faces.el.EvaluationException;
30  import javax.faces.el.MethodBinding;
31  
32  import org.apache.myfaces.shared_tomahawk.util.ClassUtils;
33  
34  /**
35   * Converts a MethodBinding to a MethodExpression
36   * 
37   * TODO: find a way to share the implementation of class with impl.
38   * 
39   * This class could be moved or changed in the future
40   * 
41   * @since 1.1.7
42   * @author Stan Silvert
43   */
44  @SuppressWarnings("deprecation")
45  public class MethodBindingToMethodExpression extends MethodExpression implements StateHolder
46  {
47      private static final Class[] EXPECTED_TYPES = new Class[] { MethodBinding.class, StateHolder.class };
48  
49      private MethodBinding methodBinding;
50  
51      private boolean _transientFlag;
52  
53      private transient MethodInfo methodInfo;
54  
55      /**
56       * No-arg constructor used during restoreState
57       */
58      public MethodBindingToMethodExpression()
59      {
60      }
61  
62      /** Creates a new instance of MethodBindingToMethodExpression */
63      public MethodBindingToMethodExpression(MethodBinding methodBinding)
64      {
65          checkNullArgument(methodBinding, "methodBinding");
66          this.methodBinding = methodBinding;
67      }
68  
69      /**
70       * Return the wrapped MethodBinding.
71       */
72      public MethodBinding getMethodBinding()
73      {
74          return methodBinding;
75      }
76      
77      void setMethodBinding(MethodBinding methodBinding)
78      {
79          this.methodBinding = methodBinding;
80      }
81  
82      /**
83       * Note: MethodInfo.getParamTypes() may incorrectly return an empty class array if invoke() has not been called.
84       * 
85       * @throws IllegalStateException
86       *             if expected params types have not been determined.
87       */
88      public MethodInfo getMethodInfo(ELContext context) throws PropertyNotFoundException, MethodNotFoundException,
89              ELException
90      {
91          checkNullArgument(context, "elcontext");
92          checkNullState(methodBinding, "methodBinding");
93  
94          if (methodInfo == null)
95          {
96              final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
97              if (facesContext != null)
98              {
99                  methodInfo = invoke(new Invoker<MethodInfo>()
100                 {
101                     public MethodInfo invoke()
102                     {
103                         return new MethodInfo(null, methodBinding.getType(facesContext), null);
104                     }
105                 });
106             }
107         }
108         return methodInfo;
109     }
110 
111     public Object invoke(ELContext context, final Object[] params) throws PropertyNotFoundException,
112             MethodNotFoundException, ELException
113     {
114         checkNullArgument(context, "elcontext");
115         checkNullState(methodBinding, "methodBinding");
116         final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
117         if (facesContext != null)
118         {
119             return invoke(new Invoker<Object>()
120             {
121                 public Object invoke()
122                 {
123                     return methodBinding.invoke(facesContext, params);
124                 }
125             });
126         }
127         return null;
128     }
129 
130     public boolean isLiteralText()
131     {
132         if (methodBinding == null)
133             throw new IllegalStateException("methodBinding is null");
134         String expr = methodBinding.getExpressionString();
135         return !(expr.startsWith("#{") && expr.endsWith("}"));
136     }
137 
138     public String getExpressionString()
139     {
140         return methodBinding.getExpressionString();
141     }
142 
143     public Object saveState(FacesContext context)
144     {
145         if (!isTransient())
146         {
147             if (methodBinding instanceof StateHolder)
148             {
149                 Object[] state = new Object[2];
150                 state[0] = methodBinding.getClass().getName();
151                 state[1] = ((StateHolder) methodBinding).saveState(context);
152                 return state;
153             }
154             else
155             {
156                 return methodBinding;
157             }
158         }
159         return null;
160     }
161 
162     public void restoreState(FacesContext context, Object state)
163     {
164         if (state instanceof MethodBinding)
165         {
166             methodBinding = (MethodBinding) state;
167             methodInfo = null;
168         }
169         else if (state != null)
170         {
171             Object[] values = (Object[]) state;
172             methodBinding = (MethodBinding) ClassUtils.newInstance(values[0].toString(), EXPECTED_TYPES);
173             ((StateHolder) methodBinding).restoreState(context, values[1]);
174             methodInfo = null;
175         }
176     }
177 
178     public void setTransient(boolean transientFlag)
179     {
180         _transientFlag = transientFlag;
181     }
182 
183     public boolean isTransient()
184     {
185         return _transientFlag;
186     }
187 
188     @Override
189     public int hashCode()
190     {
191         final int PRIME = 31;
192         int result = 1;
193         result = PRIME * result + ((methodBinding == null) ? 0 : methodBinding.hashCode());
194         return result;
195     }
196 
197     @Override
198     public boolean equals(Object obj)
199     {
200         if (this == obj)
201             return true;
202         if (obj == null)
203             return false;
204         if (getClass() != obj.getClass())
205             return false;
206         final MethodBindingToMethodExpression other = (MethodBindingToMethodExpression) obj;
207         if (methodBinding == null)
208         {
209             if (other.methodBinding != null)
210                 return false;
211         }
212         else if (!methodBinding.equals(other.methodBinding))
213             return false;
214         return true;
215     }
216 
217     private void checkNullState(Object notNullInstance, String instanceName)
218     {
219         if (notNullInstance == null)
220             throw new IllegalStateException(instanceName + " is null");
221     }
222 
223     private void checkNullArgument(Object notNullInstance, String instanceName)
224     {
225         if (notNullInstance == null)
226             throw new IllegalArgumentException(instanceName + " is null");
227     }
228 
229     private <T> T invoke(Invoker<T> invoker)
230     {
231         try
232         {
233             return invoker.invoke();
234         }
235         catch (javax.faces.el.MethodNotFoundException e)
236         {
237             throw new MethodNotFoundException(e.getMessage(), e);
238         }
239         catch (EvaluationException e)
240         {
241             throw new ELException(e.getMessage(), e);
242         }
243     }
244 
245     private interface Invoker<T>
246     {
247         T invoke();
248     }
249 }