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