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   * @author Stan Silvert
44   * @see javax.faces.component._ValueBindingToValueExpression
45   */
46  @SuppressWarnings("deprecation")
47  public class ValueBindingToValueExpression extends ValueExpression implements StateHolder
48  {
49      private static final long serialVersionUID = 8071429285360496554L;
50  
51      //private static final Log logger = LogFactory.getLog(ValueBindingToValueExpression.class);
52      private static final Logger logger = 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             return true;
155         if (obj == null)
156             return false;
157         if (getClass() != obj.getClass())
158             return false;
159         final ValueBindingToValueExpression other = (ValueBindingToValueExpression) obj;
160         if (_transient != other._transient)
161             return false;
162         if (_valueBinding == null)
163         {
164             if (other._valueBinding != null)
165                 return false;
166         }
167         else if (!_valueBinding.equals(other._valueBinding))
168             return false;
169         return true;
170     }
171 
172     @Override
173     public boolean isLiteralText()
174     {
175         return false;
176     }
177 
178     @Override
179     public String getExpressionString()
180     {
181         return getNotNullValueBinding().getExpressionString();
182     }
183 
184     @Override
185     public Class<?> getExpectedType()
186     {
187         if (_valueBinding != null)
188         {
189             try
190             {
191                 Object value = getNotNullValueBinding().getValue(FacesContext.getCurrentInstance());
192                 if (value != null)
193                 {
194                     return value.getClass();
195                 }
196             }
197             catch (Throwable e)
198             {
199                 logger.log(Level.WARNING, "Could not determine expected type for '" + _valueBinding.getExpressionString() + "': "
200                         + e.getMessage(), e);
201             }
202         }
203         return null;
204     }
205 
206     public void restoreState(FacesContext context, Object state)
207     {
208         if (state instanceof ValueBinding)
209         {
210             _valueBinding = (ValueBinding) state;
211         }
212         else if (state != null)
213         {
214             Object[] stateArray = (Object[]) state;
215             _valueBinding = (ValueBinding) ClassUtils.newInstance((String) stateArray[0], ValueBinding.class);
216             ((StateHolder) _valueBinding).restoreState(context, stateArray[1]);
217         }
218     }
219 
220     public Object saveState(FacesContext context)
221     {
222         if (!_transient)
223         {
224             if (_valueBinding instanceof StateHolder)
225             {
226                 Object[] state = new Object[2];
227                 state[0] = _valueBinding.getClass().getName();
228                 state[1] = ((StateHolder) _valueBinding).saveState(context);
229                 return state;
230             }
231             return _valueBinding;
232         }
233         return null;
234     }
235 
236     public void setTransient(boolean newTransientValue)
237     {
238         _transient = newTransientValue;
239     }
240 
241     public boolean isTransient()
242     {
243         return _transient;
244     }
245 
246     private FacesContext getFacesContext(ELContext context)
247     {
248         if (context == null)
249         {
250             throw new IllegalArgumentException("el context must not be null.");
251         }
252         FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
253         if (facesContext == null)
254         {
255             throw new IllegalStateException("faces context not available in el context.");
256         }
257         return facesContext;
258     }
259 
260     private <T> T invoke(Invoker<T> invoker)
261     {
262         try
263         {
264             return invoker.invoke();
265         }
266         catch (javax.faces.el.PropertyNotFoundException e)
267         {
268             throw new PropertyNotFoundException(e.getMessage(), e);
269         }
270         catch (EvaluationException e)
271         {
272             throw new ELException(e.getMessage(), e);
273         }
274     }
275 
276     private interface Invoker<T>
277     {
278         T invoke();
279     }
280 }