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             throw new IllegalStateException("methodBinding is null");
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         final 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             return true;
201         if (obj == null)
202             return false;
203         if (getClass() != obj.getClass())
204             return false;
205         final _MethodBindingToMethodExpression other = (_MethodBindingToMethodExpression)obj;
206         if (methodBinding == null)
207         {
208             if (other.methodBinding != null)
209                 return false;
210         }
211         else if (!methodBinding.equals(other.methodBinding))
212             return false;
213         return true;
214     }
215 
216     private void checkNullState(Object notNullInstance, String instanceName)
217     {
218         if (notNullInstance == null)
219             throw new IllegalStateException(instanceName + " is null");
220     }
221 
222     private void checkNullArgument(Object notNullInstance, String instanceName)
223     {
224         if (notNullInstance == null)
225             throw new IllegalArgumentException(instanceName + " is null");
226     }
227 
228     private <T> T invoke(Invoker<T> invoker)
229     {
230         try
231         {
232             return invoker.invoke();
233         }
234         catch (javax.faces.el.MethodNotFoundException e)
235         {
236             throw new MethodNotFoundException(e.getMessage(), e);
237         }
238         catch (EvaluationException e)
239         {
240             throw new ELException(e.getMessage(), e);
241         }
242     }
243 
244     private interface Invoker<T>
245     {
246         T invoke();
247     }
248 }