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