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.custom.behavior;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Map;
25  
26  import javax.el.ValueExpression;
27  import javax.faces.component.StateHelper;
28  import javax.faces.component.StateHolder;
29  import javax.faces.context.FacesContext;
30  
31  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFClientBehavior;
32  import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
33  
34  /**
35   * Base behavior implementation for Apache MyFaces Tomahawk.
36   *
37   */
38  @JSFClientBehavior(
39          configExcluded = true,
40          evaluateELOnExecution = true,
41          tagHandler = "org.apache.myfaces.custom.behavior.ClientBehaviorBaseTagHandler")
42  public abstract class ClientBehaviorBase extends
43          javax.faces.component.behavior.ClientBehaviorBase
44  {
45  
46      private transient FacesContext _facesContext;
47      private StateHelper _stateHelper = null;
48  
49      /**
50       * @param context
51       */
52      @Override
53      public Object saveState(FacesContext facesContext)
54      {
55          if (initialStateMarked())
56          {
57              Object parentSaved = super.saveState(facesContext);
58              Object stateHelperSaved = null;
59              StateHelper stateHelper = getStateHelper(false);
60              if (stateHelper != null)
61              {
62                  stateHelperSaved = stateHelper.saveState(facesContext);
63              }
64  
65              if (parentSaved == null && stateHelperSaved == null)
66              {
67                  //No values
68                  return null;
69              }
70              return new Object[] { parentSaved, stateHelperSaved };
71          }
72          else
73          {
74              Object[] values = new Object[2];
75              values[0] = super.saveState(facesContext);
76              StateHelper stateHelper = getStateHelper(false);
77              if (stateHelper != null)
78              {
79                  values[1] = stateHelper.saveState(facesContext);
80              }
81              return values;
82          }
83      }
84  
85      @Override
86      public void restoreState(FacesContext facesContext, Object o)
87      {
88          if (o == null)
89          {
90              return;
91          }
92          Object[] values = (Object[]) o;
93          if (values[0] != null)
94          {
95              super.restoreState(facesContext, values[0]);
96          }
97          getStateHelper().restoreState(facesContext, values[1]);
98      }
99  
100     // --------------------- borrowed from UIComponentBase ------------
101 
102     @SuppressWarnings("unchecked")
103     public ValueExpression getValueExpression(String name)
104     {
105         if (name == null)
106             throw new NullPointerException("name");
107         StateHelper helper = getStateHelper(false);
108         if (helper == null)
109         {
110             return null;
111         }
112         Map<String, Object> bindings = (Map<String, Object>) helper
113                 .get(PropertyKeys.bindings);
114         if (bindings == null)
115         {
116             return null;
117         }
118         else
119         {
120             return (ValueExpression) bindings.get(name);
121         }
122     }
123 
124     public void setValueExpression(String name, ValueExpression expression)
125     {
126         if (name == null)
127             throw new NullPointerException("name");
128         if (expression == null)
129         {
130             getStateHelper().remove(PropertyKeys.bindings, name);
131         }
132         else
133         {
134             getStateHelper().put(PropertyKeys.bindings, name, expression);
135         }
136     }
137 
138     /**
139      * Serializes objects which are "attached" to this component but which are
140      * not UIComponent children of it. Examples are validator and listener
141      * objects. To be precise, it returns an object which implements
142      * java.io.Serializable, and which when serialized will persist the
143      * state of the provided object.
144      * <p>
145      * If the attachedObject is a List then every object in the list is saved
146      * via a call to this method, and the returned wrapper object contains
147      * a List object.
148      * <p>
149      * If the object implements StateHolder then the object's saveState is
150      * called immediately, and a wrapper is returned which contains both
151      * this saved state and the original class name. However in the case
152      * where the StateHolder.isTransient method returns true, null is
153      * returned instead.
154      * <p>
155      * If the object implements java.io.Serializable then the object is simply
156      * returned immediately; standard java serialization will later be used
157      * to store this object.
158      * <p>
159      * In all other cases, a wrapper is returned which simply stores the type
160      * of the provided object. When deserialized, a default instance of that
161      * type will be recreated.
162      */
163     public static Object saveAttachedState(FacesContext context,
164             Object attachedObject)
165     {
166         if (context == null)
167         {
168             throw new NullPointerException("context");
169         }
170 
171         if (attachedObject == null)
172             return null;
173         // StateHolder interface should take precedence over
174         // List children
175         if (attachedObject instanceof StateHolder)
176         {
177             StateHolder holder = (StateHolder) attachedObject;
178             if (holder.isTransient())
179             {
180                 return null;
181             }
182 
183             return new _AttachedStateWrapper(attachedObject.getClass(),
184                     holder.saveState(context));
185         }
186         else if (attachedObject instanceof List)
187         {
188             List<Object> lst = new ArrayList<Object>(
189                     ((List<?>) attachedObject).size());
190             for (Object item : (List<?>) attachedObject)
191             {
192                 if (item != null)
193                 {
194                     lst.add(saveAttachedState(context, item));
195                 }
196             }
197 
198             return new _AttachedListStateWrapper(lst);
199         }
200         else if (attachedObject instanceof Serializable)
201         {
202             return attachedObject;
203         }
204         else
205         {
206             return new _AttachedStateWrapper(attachedObject.getClass(), null);
207         }
208     }
209 
210     @SuppressWarnings("unchecked")
211     public static Object restoreAttachedState(FacesContext context,
212             Object stateObj) throws IllegalStateException
213     {
214         if (context == null)
215             throw new NullPointerException("context");
216         if (stateObj == null)
217             return null;
218         if (stateObj instanceof _AttachedListStateWrapper)
219         {
220             List<Object> lst = ((_AttachedListStateWrapper) stateObj)
221                     .getWrappedStateList();
222             List<Object> restoredList = new ArrayList<Object>(lst.size());
223             for (Object item : lst)
224             {
225                 restoredList.add(restoreAttachedState(context, item));
226             }
227             return restoredList;
228         }
229         else if (stateObj instanceof _AttachedStateWrapper)
230         {
231             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
232             Object restoredObject;
233             try
234             {
235                 restoredObject = clazz.newInstance();
236             }
237             catch (InstantiationException e)
238             {
239                 throw new RuntimeException(
240                         "Could not restore StateHolder of type "
241                                 + clazz.getName()
242                                 + " (missing no-args constructor?)", e);
243             }
244             catch (IllegalAccessException e)
245             {
246                 throw new RuntimeException(e);
247             }
248             if (restoredObject instanceof StateHolder)
249             {
250                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
251                 Object wrappedState = wrapper.getWrappedStateObject();
252 
253                 StateHolder holder = (StateHolder) restoredObject;
254                 holder.restoreState(context, wrappedState);
255             }
256             return restoredObject;
257         }
258         else
259         {
260             return stateObj;
261         }
262     }
263 
264     protected FacesContext getFacesContext()
265     {
266         if (_facesContext == null)
267         {
268             return FacesContext.getCurrentInstance();
269         }
270         else
271         {
272             return _facesContext;
273         }
274     }
275 
276     boolean isCachedFacesContext()
277     {
278         return _facesContext != null;
279     }
280 
281     void setCachedFacesContext(FacesContext facesContext)
282     {
283         _facesContext = facesContext;
284     }
285 
286     protected StateHelper getStateHelper()
287     {
288         return getStateHelper(true);
289     }
290 
291     /**
292      * returns a delta state saving enabled state helper
293      * for the current component
294      * @param create if true a state helper is created if not already existing
295      * @return an implementation of the StateHelper interface or null if none exists and create is set to false
296      */
297     protected StateHelper getStateHelper(boolean create)
298     {
299         if (_stateHelper != null)
300         {
301             return _stateHelper;
302         }
303         if (create)
304         {
305             _stateHelper = new _DeltaStateHelper(this);
306         }
307         return _stateHelper;
308     }
309     
310     /**
311      * The event that this client behavior should be attached.
312      * 
313      * @return
314      */
315     @JSFProperty
316     private String getEvent()
317     {
318         return null;
319     }
320 
321     enum PropertyKeys
322     {
323         bindings
324     }
325 }