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  package org.apache.myfaces.el.convert;
20  
21  import java.util.logging.Level;
22  import java.util.logging.Logger;
23  
24  import javax.el.ELContext;
25  import javax.el.ELException;
26  import javax.el.PropertyNotFoundException;
27  import javax.el.PropertyNotWritableException;
28  import javax.el.ValueExpression;
29  import javax.faces.component.StateHolder;
30  import javax.faces.context.FacesContext;
31  import javax.faces.el.EvaluationException;
32  import javax.faces.el.ValueBinding;
33  
34  import org.apache.myfaces.shared.util.ClassUtils;
35  
36  /**
37   * Wraps a ValueBinding inside a ValueExpression. Also allows access to the original ValueBinding object.
38   * 
39   * Although ValueExpression implements Serializable, this class implements StateHolder instead.
40   * 
41   * ATTENTION: If you make changes to this class, treat {@link ValueBindingToValueExpression} accordingly.
42   * 
43   * See javax.faces.component._ValueBindingToValueExpression
44   * 
45   * @author Stan Silvert
46   */
47  @SuppressWarnings("deprecation")
48  public class ValueBindingToValueExpression extends ValueExpression implements StateHolder
49  {
50      private static final long serialVersionUID = 8071429285360496554L;
51  
52      private static final Logger log = Logger.getLogger(ValueBindingToValueExpression.class.getName());
53  
54      private ValueBinding _valueBinding;
55  
56      private boolean _transient;
57  
58      /**
59       * No-arg constructor used during restoreState
60       */
61      public ValueBindingToValueExpression()
62      {
63      }
64  
65      private ValueBinding getNotNullValueBinding()
66      {
67          if (_valueBinding == null)
68          {
69              throw new IllegalStateException("value binding is null");
70          }
71          return _valueBinding;
72      }
73  
74      /** Creates a new instance of ValueBindingToValueExpression */
75      public ValueBindingToValueExpression(ValueBinding valueBinding)
76      {
77          if (valueBinding == null)
78          {
79              throw new IllegalArgumentException("value binding must not be null");
80          }
81          this._valueBinding = valueBinding;
82      }
83  
84      public ValueBinding getValueBinding()
85      {
86          return _valueBinding;
87      }
88  
89      @Override
90      public boolean isReadOnly(final ELContext context) throws NullPointerException, PropertyNotFoundException,
91              ELException
92      {
93          return invoke(new Invoker<Boolean>()
94          {
95              public Boolean invoke()
96              {
97                  return getNotNullValueBinding().isReadOnly(getFacesContext(context));
98              }
99          });
100     }
101 
102     @Override
103     public Object getValue(final ELContext context) throws NullPointerException, PropertyNotFoundException, ELException
104     {
105         return invoke(new Invoker<Object>()
106         {
107             public Object invoke()
108             {
109                 return getNotNullValueBinding().getValue(getFacesContext(context));
110             }
111         });
112     }
113 
114     @Override
115     public Class<?> getType(final ELContext context) throws NullPointerException, PropertyNotFoundException,
116             ELException
117     {
118         return invoke(new Invoker<Class<?>>()
119         {
120             public Class<?> invoke()
121             {
122                 return getNotNullValueBinding().getType(getFacesContext(context));
123             }
124         });
125     }
126 
127     @Override
128     public void setValue(final ELContext context, final Object value) throws NullPointerException,
129             PropertyNotFoundException, PropertyNotWritableException, ELException
130     {
131         invoke(new Invoker<Object>()
132         {
133             public Object invoke()
134             {
135                 getNotNullValueBinding().setValue(getFacesContext(context), value);
136                 return null;
137             }
138         });
139     }
140 
141     @Override
142     public int hashCode()
143     {
144         int result = 1;
145         result = 31 * result + (_transient ? 1231 : 1237);
146         result = 31 * result + ((_valueBinding == null) ? 0 : _valueBinding.hashCode());
147         return result;
148     }
149 
150     @Override
151     public boolean equals(Object obj)
152     {
153         if (this == obj)
154         {
155             return true;
156         }
157         if (obj == null)
158         {
159             return false;
160         }
161         if (getClass() != obj.getClass())
162         {
163             return false;
164         }
165         final ValueBindingToValueExpression other = (ValueBindingToValueExpression) obj;
166         if (_transient != other._transient)
167         {
168             return false;
169         }
170         if (_valueBinding == null)
171         {
172             if (other._valueBinding != null)
173             {
174                 return false;
175             }
176         }
177         else if (!_valueBinding.equals(other._valueBinding))
178         {
179             return false;
180         }
181         return true;
182     }
183 
184     @Override
185     public boolean isLiteralText()
186     {
187         return false;
188     }
189 
190     @Override
191     public String getExpressionString()
192     {
193         return getNotNullValueBinding().getExpressionString();
194     }
195 
196     @Override
197     public Class<?> getExpectedType()
198     {
199         if (_valueBinding != null)
200         {
201             try
202             {
203                 Object value = getNotNullValueBinding().getValue(FacesContext.getCurrentInstance());
204                 if (value != null)
205                 {
206                     return value.getClass();
207                 }
208             }
209             catch (Throwable e)
210             {
211                 log.log(Level.WARNING, "Could not determine expected type for '"
212                                        + _valueBinding.getExpressionString() + "': "
213                                        + e.getMessage(), e);
214             }
215         }
216         return null;
217     }
218 
219     public void restoreState(FacesContext context, Object state)
220     {
221         if (state instanceof ValueBinding)
222         {
223             _valueBinding = (ValueBinding) state;
224         }
225         else if (state != null)
226         {
227             Object[] stateArray = (Object[]) state;
228             _valueBinding = (ValueBinding) ClassUtils.newInstance((String) stateArray[0], ValueBinding.class);
229             ((StateHolder) _valueBinding).restoreState(context, stateArray[1]);
230         }
231     }
232 
233     public Object saveState(FacesContext context)
234     {
235         if (!_transient)
236         {
237             if (_valueBinding instanceof StateHolder)
238             {
239                 Object[] state = new Object[2];
240                 state[0] = _valueBinding.getClass().getName();
241                 state[1] = ((StateHolder) _valueBinding).saveState(context);
242                 return state;
243             }
244             return _valueBinding;
245         }
246         return null;
247     }
248 
249     public void setTransient(boolean newTransientValue)
250     {
251         _transient = newTransientValue;
252     }
253 
254     public boolean isTransient()
255     {
256         return _transient;
257     }
258 
259     private FacesContext getFacesContext(ELContext context)
260     {
261         if (context == null)
262         {
263             throw new IllegalArgumentException("el context must not be null.");
264         }
265         FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
266         if (facesContext == null)
267         {
268             throw new IllegalStateException("faces context not available in el context.");
269         }
270         return facesContext;
271     }
272 
273     private <T> T invoke(Invoker<T> invoker)
274     {
275         try
276         {
277             return invoker.invoke();
278         }
279         catch (javax.faces.el.PropertyNotFoundException e)
280         {
281             throw new PropertyNotFoundException(e.getMessage(), e);
282         }
283         catch (EvaluationException e)
284         {
285             throw new ELException(e.getMessage(), e);
286         }
287     }
288 
289     private interface Invoker<T>
290     {
291         T invoke();
292     }
293 }