1 package org.apache.myfaces.tobago.component;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }