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