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 javax.faces.component.behavior;
20  
21  import java.util.Arrays;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.EnumSet;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import javax.el.ValueExpression;
29  import javax.faces.component.StateHelper;
30  import javax.faces.context.FacesContext;
31  import javax.faces.event.AjaxBehaviorListener;
32  
33  /**
34   * @since 2.0
35   */
36  public class AjaxBehavior extends ClientBehaviorBase 
37  {
38  
39      /**
40       * not needed anymore but enforced by the spec
41       * theoretically a
42       * @FacesBehavior(value = "javax.faces.behavior.Ajax")
43       * could do it
44       */
45      public static final String BEHAVIOR_ID = "javax.faces.behavior.Ajax";
46  
47      private static final String ATTR_EXECUTE = "execute";
48      private static final String ATTR_ON_ERROR = "onerror";
49      private static final String ATTR_ON_EVENT = "onevent";
50      private static final String ATTR_RENDER = "render";
51      private static final String ATTR_DISABLED = "disabled";
52      private static final String ATTR_IMMEDIATE = "immediate";
53      private static final String ATTR_DELAY = "delay";
54      private static final String ATTR_RESET_VALUES = "resetValues";
55  
56      /**
57       * special render and execute targets
58       */
59      private static final String VAL_FORM = "@form";
60      private static final String VAL_ALL = "@all";
61      private static final String VAL_THIS = "@this";
62      private static final String VAL_NONE = "@none";
63  
64      private static final Collection<String> VAL_FORM_LIST = Collections.singletonList(VAL_FORM);
65      private static final Collection<String> VAL_ALL_LIST = Collections.singletonList(VAL_ALL);
66      private static final Collection<String> VAL_THIS_LIST = Collections.singletonList(VAL_THIS);
67      private static final Collection<String> VAL_NONE_LIST = Collections.singletonList(VAL_NONE);
68  
69      //To enable delta state saving we need this one
70      private _DeltaStateHelper<AjaxBehavior> _stateHelper = null;
71      
72      //private Map<String, ValueExpression> _valueExpressions 
73      //        = new HashMap<String, ValueExpression>();
74  
75      public AjaxBehavior() 
76      {
77          super();
78      }
79  
80      public void addAjaxBehaviorListener(AjaxBehaviorListener listener) 
81      {
82          super.addBehaviorListener(listener);
83      }
84      
85      public void removeAjaxBehaviorListener(AjaxBehaviorListener listener) 
86      {
87          removeBehaviorListener(listener);
88      }
89  
90      public Collection<String> getExecute() 
91      {
92          // we have to evaluate the real value in this method,
93          // because the value of the ValueExpression might
94          // change (almost sure it does!)
95          return evalForCollection(ATTR_EXECUTE);
96      }
97  
98      public void setExecute(Collection<String> execute) 
99      {
100         getStateHelper().put(ATTR_EXECUTE, execute);
101     }
102 
103     public String getOnerror() 
104     {
105         return (String) getStateHelper().eval(ATTR_ON_ERROR);
106     }
107 
108     public void setOnerror(String onError) 
109     {
110         getStateHelper().put(ATTR_ON_ERROR, onError);
111     }
112 
113     public String getOnevent() 
114     {
115         return (String) getStateHelper().eval(ATTR_ON_EVENT);
116     }
117 
118     public void setOnevent(String onEvent) 
119     {
120         getStateHelper().put(ATTR_ON_EVENT, onEvent);
121     }
122 
123     public Collection<String> getRender() 
124     {
125         // we have to evaluate the real value in this method,
126         // because the value of the ValueExpression might
127         // change (almost sure it does!)
128         return evalForCollection(ATTR_RENDER);
129     }
130 
131     public void setRender(Collection<String> render) 
132     {
133         getStateHelper().put(ATTR_RENDER, render);
134     }
135 
136     @SuppressWarnings("unchecked")
137     public ValueExpression getValueExpression(String name) 
138     {
139         //return getValueExpressionMap().get(name);
140         if (name == null)
141         {
142             throw new NullPointerException("name can not be null");
143         }
144         
145         Map<String,Object> bindings = (Map<String,Object>) getStateHelper().
146             get(PropertyKeys.bindings);
147         if (bindings != null)
148         {
149             return (ValueExpression) bindings.get(name);
150         }
151         else
152         {
153             return null;
154         }
155     }
156 
157     public void setValueExpression(String name, ValueExpression expression) 
158     {
159         /*
160         if (item == null) 
161         {
162             getValueExpressionMap().remove(name);
163             getStateHelper().remove(name);
164         } 
165         else 
166         {
167             getValueExpressionMap().put(name, item);
168         }
169         */
170         if (name == null)
171         {
172             throw new NullPointerException("name");
173         }
174 
175         if (expression == null)
176         {
177             getStateHelper().remove(PropertyKeys.bindings, name);
178         }
179         else
180         {
181             getStateHelper().put(PropertyKeys.bindings, name, expression);
182         }
183     }
184 
185     public boolean isDisabled() 
186     {
187         Boolean retVal = (Boolean) getStateHelper().eval(ATTR_DISABLED);
188         retVal = (retVal == null) ? false : retVal;
189         return retVal;
190     }
191 
192     public void setDisabled(boolean disabled) 
193     {
194         getStateHelper().put(ATTR_DISABLED, disabled);
195     }
196 
197     public boolean isImmediate() 
198     {
199         Boolean retVal = (Boolean) getStateHelper().eval(ATTR_IMMEDIATE);
200         retVal = (retVal == null) ? false : retVal;
201         return retVal;
202     }
203 
204     public void setImmediate(boolean immediate) 
205     {
206         getStateHelper().put(ATTR_IMMEDIATE, immediate);
207     }
208 
209     public boolean isImmediateSet() 
210     {
211         return (getStateHelper().get(ATTR_IMMEDIATE) != null) ||
212             (getValueExpression(ATTR_IMMEDIATE) != null);
213     }
214 
215     /**
216      * @since 2.2
217      */
218     public boolean isResetValues()
219     {
220         Boolean retVal = (Boolean) getStateHelper().eval(ATTR_RESET_VALUES);
221         retVal = (retVal == null) ? false : retVal;
222         return retVal;
223     }
224     
225     /**
226      * @since 2.2
227      */
228     public void setResetValues(boolean resetValues)
229     {
230         getStateHelper().put(ATTR_RESET_VALUES, resetValues);
231     }
232     
233     /**
234      * @since 2.2
235      */
236     public boolean isResetValuesSet()
237     {
238         return (getStateHelper().get(ATTR_RESET_VALUES) != null) ||
239             (getValueExpression(ATTR_RESET_VALUES) != null);
240     }
241     
242     /**
243      * @since 2.2
244      * @return 
245      */
246     public String getDelay()
247     {
248         return (String) getStateHelper().eval(ATTR_DELAY);
249     }
250 
251     /**
252      * @since 2.2
253      * @param delay 
254      */
255     public void setDelay(String delay)
256     {
257         getStateHelper().put(ATTR_DELAY, delay);
258     }
259 
260     @Override
261     public Set<ClientBehaviorHint> getHints() 
262     {
263         return EnumSet.of(ClientBehaviorHint.SUBMITTING);
264     }
265 
266     @Override
267     public String getRendererType() 
268     {
269         return BEHAVIOR_ID;
270     }
271 
272     @Override
273     public void restoreState(FacesContext facesContext, Object o)
274     {
275         if (o == null)
276         {
277             return;
278         }
279         Object[] values = (Object[]) o;
280         if (values[0] != null) 
281         {
282             super.restoreState(facesContext, values[0]);
283         }
284         getStateHelper().restoreState(facesContext, values[1]);
285     }
286 
287     private StateHelper getStateHelper()
288     {
289         return getStateHelper(true);
290     }
291 
292     /**
293      * returns a delta state saving enabled state helper
294      * for the current component
295      * @param create if true a state helper is created if not already existing
296      * @return an implementation of the StateHelper interface or null if none exists and create is set to false
297      */
298     private StateHelper getStateHelper(boolean create)
299     {
300         if(_stateHelper != null)
301         {
302             return _stateHelper;
303         }
304         if(create)
305         {
306             _stateHelper = new _DeltaStateHelper<AjaxBehavior>(this);
307         }
308         return _stateHelper;
309     }
310     
311     @Override
312     public Object saveState(FacesContext facesContext)
313     {
314         if (initialStateMarked())
315         {
316             Object parentSaved = super.saveState(facesContext);
317             Object stateHelperSaved = null;
318             StateHelper stateHelper = getStateHelper(false);
319             if (stateHelper != null)
320             {
321                 stateHelperSaved = stateHelper.saveState(facesContext);
322             }
323 
324             if (parentSaved == null && stateHelperSaved == null)
325             {
326                 //No values
327                 return null;
328             }   
329             return new Object[]{parentSaved, stateHelperSaved};
330         }
331         else
332         {
333             Object[] values = new Object[2];
334             values[0] = super.saveState(facesContext);
335             StateHelper stateHelper = getStateHelper(false);
336             if (stateHelper != null)
337             {
338                 values[1] = stateHelper.saveState(facesContext);
339             }
340             return values;
341         }
342     }
343 
344     //private Map<String, ValueExpression> getValueExpressionMap() 
345     //{
346     //    return _valueExpressions;
347     //}
348     
349     /**
350      * Invokes eval on the getStateHelper() and tries to get a
351      * Collection out of the result.
352      * @param attributeName
353      * @return
354      */
355     @SuppressWarnings("unchecked")
356     private Collection<String> evalForCollection(String attributeName)
357     {
358         Object value = getStateHelper().eval(attributeName);
359         if (value == null)
360         {
361             return Collections.<String>emptyList();
362         }
363         else if (value instanceof Collection)
364         {
365             return (Collection<String>) value;
366         }
367         else if (value instanceof String)
368         {
369             return getCollectionFromSpaceSplitString((String) value);
370         }
371         else
372         {
373             throw new IllegalArgumentException("Type " + value.getClass()
374                     + " not supported for attribute " + attributeName);
375         }
376     }
377     
378     /**
379      * Splits the String based on spaces and returns the 
380      * resulting Strings as Collection.
381      * @param stringValue
382      * @return
383      */
384     private Collection<String> getCollectionFromSpaceSplitString(String stringValue)
385     {
386         //@special handling for @all, @none, @form and @this
387         if (stringValue.equals(VAL_FORM)) 
388         {
389             return VAL_FORM_LIST;
390         } 
391         else if (stringValue.equals(VAL_ALL)) 
392         {
393             return VAL_ALL_LIST;
394         } 
395         else if (stringValue.equals(VAL_NONE)) 
396         {
397             return VAL_NONE_LIST;
398         } 
399         else if (stringValue.equals(VAL_THIS)) 
400         {
401             return VAL_THIS_LIST; 
402         }
403 
404         // not one of the "normal" values - split it and return the Collection
405         String[] arrValue = stringValue.split(" ");
406         return Arrays.asList(arrValue);
407     }
408  
409     private enum PropertyKeys
410     {
411         bindings,
412     }
413 }