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      public MethodInfo getMethodInfo(ELContext context) throws PropertyNotFoundException, MethodNotFoundException,
84              ELException
85      {
86          checkNullArgument(context, "elcontext");
87          checkNullState(methodBinding, "methodBinding");
88  
89          if (methodInfo == null)
90          {
91              final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
92              if (facesContext != null)
93              {
94                  methodInfo = invoke(new Invoker<MethodInfo>()
95                  {
96                      public MethodInfo invoke()
97                      {
98                          return new MethodInfo(null, methodBinding.getType(facesContext), null);
99                      }
100                 });
101             }
102         }
103         return methodInfo;
104     }
105 
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     public boolean isLiteralText()
126     {
127         if (methodBinding == null)
128             throw new IllegalStateException("methodBinding is null");
129         String expr = methodBinding.getExpressionString();
130         return !(expr.startsWith("#{") && expr.endsWith("}"));
131     }
132 
133     public String getExpressionString()
134     {
135         return methodBinding.getExpressionString();
136     }
137 
138     public Object saveState(FacesContext context)
139     {
140         if (!isTransient())
141         {
142             if (methodBinding instanceof StateHolder)
143             {
144                 Object[] state = new Object[2];
145                 state[0] = methodBinding.getClass().getName();
146                 state[1] = ((StateHolder) methodBinding).saveState(context);
147                 return state;
148             }
149             else
150             {
151                 return methodBinding;
152             }
153         }
154         return null;
155     }
156 
157     public void restoreState(FacesContext context, Object state)
158     {
159         if (state instanceof MethodBinding)
160         {
161             methodBinding = (MethodBinding) state;
162             methodInfo = null;
163         }
164         else if (state != null)
165         {
166             Object[] values = (Object[]) state;
167             methodBinding = (MethodBinding) _ClassUtils.newInstance(values[0].toString(), EXPECTED_TYPES);
168             ((StateHolder) methodBinding).restoreState(context, values[1]);
169             methodInfo = null;
170         }
171     }
172 
173     public void setTransient(boolean transientFlag)
174     {
175         _transientFlag = transientFlag;
176     }
177 
178     public boolean isTransient()
179     {
180         return _transientFlag;
181     }
182 
183     @Override
184     public int hashCode()
185     {
186         final int PRIME = 31;
187         int result = 1;
188         result = PRIME * result + ((methodBinding == null) ? 0 : methodBinding.hashCode());
189         return result;
190     }
191 
192     @Override
193     public boolean equals(Object obj)
194     {
195         if (this == obj)
196             return true;
197         if (obj == null)
198             return false;
199         if (getClass() != obj.getClass())
200             return false;
201         final _MethodBindingToMethodExpression other = (_MethodBindingToMethodExpression) obj;
202         if (methodBinding == null)
203         {
204             if (other.methodBinding != null)
205                 return false;
206         }
207         else if (!methodBinding.equals(other.methodBinding))
208             return false;
209         return true;
210     }
211 
212     private void checkNullState(Object notNullInstance, String instanceName)
213     {
214         if (notNullInstance == null)
215             throw new IllegalStateException(instanceName + " is null");
216     }
217 
218     private void checkNullArgument(Object notNullInstance, String instanceName)
219     {
220         if (notNullInstance == null)
221             throw new IllegalArgumentException(instanceName + " is null");
222     }
223 
224     private <T> T invoke(Invoker<T> invoker)
225     {
226         try
227         {
228             return invoker.invoke();
229         }
230         catch (javax.faces.el.MethodNotFoundException e)
231         {
232             throw new MethodNotFoundException(e.getMessage(), e);
233         }
234         catch (EvaluationException e)
235         {
236             throw new ELException(e.getMessage(), e);
237         }
238     }
239 
240     private interface Invoker<T>
241     {
242         T invoke();
243     }
244 }