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