View Javadoc

1   package org.apache.myfaces.tobago.component;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  import javax.el.MethodExpression;
21  import javax.el.MethodInfo;
22  import javax.el.ELContext;
23  import javax.el.MethodNotFoundException;
24  import javax.el.ELException;
25  import javax.faces.component.StateHolder;
26  import javax.faces.el.MethodBinding;
27  import javax.faces.el.EvaluationException;
28  import javax.faces.context.FacesContext;
29  import javax.faces.FacesException;
30  
31  @SuppressWarnings("deprecation")
32  public class MethodBindingToMethodExpression extends MethodExpression implements StateHolder {
33    private MethodBinding methodBinding;
34  
35    private boolean transientFlag;
36  
37    private transient MethodInfo methodInfo;
38  
39    /**
40     * No-arg constructor used during restoreState
41     */
42    protected MethodBindingToMethodExpression() {
43    }
44  
45    /**
46     * Creates a new instance of MethodBindingToMethodExpression
47     */
48    public MethodBindingToMethodExpression(MethodBinding methodBinding) {
49      checkNullArgument(methodBinding, "methodBinding");
50      this.methodBinding = methodBinding;
51    }
52  
53    /**
54     * Return the wrapped MethodBinding.
55     */
56    public MethodBinding getMethodBinding() {
57      return methodBinding;
58    }
59  
60    void setMethodBinding(MethodBinding methodBinding) {
61      this.methodBinding = methodBinding;
62    }
63  
64    /**
65     * Note: MethodInfo.getParamTypes() may incorrectly return an empty class array if invoke() has not been called.
66     *
67     * @throws IllegalStateException if expected params types have not been determined.
68     */
69    public MethodInfo getMethodInfo(ELContext context) throws ELException {
70      checkNullArgument(context, "elcontext");
71      checkNullState(methodBinding, "methodBinding");
72  
73      if (methodInfo == null) {
74        final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
75        if (facesContext != null) {
76          methodInfo = invoke(new Invoker<MethodInfo>() {
77            public MethodInfo invoke() {
78              return new MethodInfo(null, methodBinding.getType(facesContext), null);
79            }
80          });
81        }
82      }
83      return methodInfo;
84    }
85  
86    public Object invoke(ELContext context, final Object[] params) throws ELException {
87      checkNullArgument(context, "elcontext");
88      checkNullState(methodBinding, "methodBinding");
89      final FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
90      if (facesContext != null) {
91        return invoke(new Invoker<Object>() {
92          public Object invoke() {
93            return methodBinding.invoke(facesContext, params);
94          }
95        });
96      }
97      return null;
98    }
99  
100   public boolean isLiteralText() {
101     if (methodBinding == null) {
102       throw new IllegalStateException("methodBinding is null");
103     }
104     String expr = methodBinding.getExpressionString();
105     return !(expr.startsWith("#{") && expr.endsWith("}"));
106   }
107 
108   public String getExpressionString() {
109     return methodBinding.getExpressionString();
110   }
111 
112   public Object saveState(FacesContext context) {
113     if (!isTransient()) {
114       if (methodBinding instanceof StateHolder) {
115         Object[] state = new Object[2];
116         state[0] = methodBinding.getClass().getName();
117         state[1] = ((StateHolder) methodBinding).saveState(context);
118         return state;
119       } else {
120         return methodBinding;
121       }
122     }
123     return null;
124   }
125 
126   public void restoreState(FacesContext context, Object state) {
127     if (state instanceof MethodBinding) {
128       methodBinding = (MethodBinding) state;
129       methodInfo = null;
130     } else if (state != null) {
131       Object[] values = (Object[]) state;
132       methodBinding = (MethodBinding) newInstance(values[0].toString());
133       ((StateHolder) methodBinding).restoreState(context, values[1]);
134       methodInfo = null;
135     }
136   }
137 
138   public void setTransient(boolean transientFlag) {
139     this.transientFlag = transientFlag;
140   }
141 
142   public boolean isTransient() {
143     return transientFlag;
144   }
145 
146   @Override
147   public int hashCode() {
148     final int prime = 31;
149     int result = 1;
150     result = prime * result + ((methodBinding == null) ? 0 : methodBinding.hashCode());
151     return result;
152   }
153 
154   @Override
155   public boolean equals(Object obj) {
156     if (this == obj) {
157       return true;
158     }
159     if (obj == null) {
160       return false;
161     }
162     if (getClass() != obj.getClass()) {
163       return false;
164     }
165     final MethodBindingToMethodExpression other = (MethodBindingToMethodExpression) obj;
166     if (methodBinding == null) {
167       if (other.methodBinding != null) {
168         return false;
169       }
170     } else if (!methodBinding.equals(other.methodBinding)) {
171       return false;
172     }
173     return true;
174   }
175 
176   private void checkNullState(Object notNullInstance, String instanceName) {
177     if (notNullInstance == null) {
178       throw new IllegalStateException(instanceName + " is null");
179     }
180   }
181 
182   private void checkNullArgument(Object notNullInstance, String instanceName) {
183     if (notNullInstance == null) {
184       throw new IllegalArgumentException(instanceName + " is null");
185     }
186   }
187 
188   private <T> T invoke(Invoker<T> invoker) {
189     try {
190       return invoker.invoke();
191     } catch (javax.faces.el.MethodNotFoundException e) {
192       throw new MethodNotFoundException(e.getMessage(), e);
193     } catch (EvaluationException e) {
194       throw new ELException(e.getMessage(), e);
195     }
196   }
197 
198   private interface Invoker<T> {
199     T invoke();
200   }
201 
202   private static Object newInstance(String type) {
203     if (type == null) {
204       throw new NullPointerException("type");
205     }
206     try {
207       try {
208         return Class.forName(type, false, Thread.currentThread().getContextClassLoader()).newInstance();
209       } catch (ClassNotFoundException e) {
210         // ignore
211         return Class.forName(type, false, MethodBindingToMethodExpression.class.getClassLoader()).newInstance();
212       }
213     } catch (ClassNotFoundException e) {
214       throw new FacesException(e);
215     } catch (NoClassDefFoundError e) {
216       throw new FacesException(e);
217     } catch (InstantiationException e) {
218       throw new FacesException(e);
219     } catch (IllegalAccessException e) {
220       throw new FacesException(e);
221     }
222   }
223 
224 }