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.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.List;
24  
25  import javax.faces.component.PartialStateHolder;
26  import javax.faces.component.StateHolder;
27  import javax.faces.context.FacesContext;
28  import javax.faces.event.BehaviorEvent;
29  import javax.faces.event.BehaviorListener;
30  
31  /**
32   * 
33   * @author Simon Lessard (latest modification by $Author: lu4242 $)
34   * @version $Revision: 1297575 $ $Date: 2012-03-06 11:59:07 -0500 (Tue, 06 Mar 2012) $
35   *
36   * @since 2.0
37   */
38  public class BehaviorBase implements Behavior, PartialStateHolder
39  {
40      private _DeltaList<BehaviorListener> _behaviorListeners;
41      
42      private boolean _initialState;
43      
44      private transient boolean _transient;
45  
46      /**
47       * 
48       */
49      public BehaviorBase()
50      {
51      }
52      
53      //public abstract String getRendererType();
54      /**
55       * {@inheritDoc}
56       */
57      public void broadcast(BehaviorEvent event)
58      {
59          if (event == null)
60          {
61              throw new NullPointerException("event");
62          }
63          
64          if (_behaviorListeners != null)
65          {
66              // This code prevent listeners from unregistering themselves while processing the event.
67              // I believe it should always be alright in this case. However, the need rise, then it 
68              // should be possible to remove that limitation by using a clone for the looping
69              for (int i = 0; i < _behaviorListeners.size() ; i++)
70              {
71                  BehaviorListener listener = _behaviorListeners.get(i);
72                  if (event.isAppropriateListener(listener))
73                  {
74                      event.processListener(listener);
75                  }
76              }
77          }
78      }
79  
80      public void clearInitialState()
81      {
82          _initialState = false;
83          if (_behaviorListeners != null)
84          {
85              _behaviorListeners.clearInitialState();
86          }
87      }
88  
89      public boolean initialStateMarked()
90      {
91          return _initialState;
92      }
93  
94      public boolean isTransient()
95      {
96          return _transient;
97      }
98  
99      public void markInitialState()
100     {
101         _initialState = true;
102         if (_behaviorListeners != null)
103         {
104             _behaviorListeners.markInitialState();
105         }
106     }
107 
108     public void restoreState(FacesContext context, Object state)
109     {
110         if (state == null)
111         {
112             return;
113         }
114         else if (state instanceof _AttachedDeltaWrapper)
115         {
116             //Delta: check for null is not necessary since _behaviorListener field
117             //is only set once and never reset
118             //if (_behaviorListeners != null)
119             //{
120                 ((StateHolder)_behaviorListeners).restoreState(context,
121                         ((_AttachedDeltaWrapper) state).getWrappedStateObject());
122             //}
123         }
124         else
125         {
126             //Full
127             _behaviorListeners = (_DeltaList<BehaviorListener>)
128                 restoreAttachedState(context, state);
129         }
130     }
131 
132     public Object saveState(FacesContext context)
133     {
134         return saveBehaviorListenersList(context);
135     }
136     
137     private Object saveBehaviorListenersList(FacesContext facesContext)
138     {
139         PartialStateHolder holder = (PartialStateHolder) _behaviorListeners;
140         if (initialStateMarked() && _behaviorListeners != null && holder.initialStateMarked())
141         {                
142             Object attachedState = holder.saveState(facesContext);
143             if (attachedState != null)
144             {
145                 return new _AttachedDeltaWrapper(_behaviorListeners.getClass(),
146                         attachedState);
147             }
148             //_behaviorListeners instances once is created never changes, we can return null
149             return null;
150         }
151         else
152         {
153             return saveAttachedState(facesContext,_behaviorListeners);
154         }
155     }
156 
157     private static Object saveAttachedState(FacesContext context, Object attachedObject)
158     {
159         if (context == null)
160         {
161             throw new NullPointerException ("context");
162         }
163         
164         if (attachedObject == null)
165         {
166             return null;
167         }
168         // StateHolder interface should take precedence over
169         // List children
170         if (attachedObject instanceof StateHolder)
171         {
172             StateHolder holder = (StateHolder) attachedObject;
173             if (holder.isTransient())
174             {
175                 return null;
176             }
177 
178             return new _AttachedStateWrapper(attachedObject.getClass(), holder.saveState(context));
179         }        
180         else if (attachedObject instanceof List)
181         {
182             List<Object> lst = new ArrayList<Object>(((List<?>) attachedObject).size());
183             for (Object item : (List<?>) attachedObject)
184             {
185                 if (item != null)
186                 {
187                     lst.add(saveAttachedState(context, item));
188                 }
189             }
190 
191             return new _AttachedListStateWrapper(lst);
192         }
193         else if (attachedObject instanceof Serializable)
194         {
195             return attachedObject;
196         }
197         else
198         {
199             return new _AttachedStateWrapper(attachedObject.getClass(), null);
200         }
201     }
202 
203     private static Object restoreAttachedState(FacesContext context, Object stateObj) throws IllegalStateException
204     {
205         if (context == null)
206         {
207             throw new NullPointerException("context");
208         }
209         if (stateObj == null)
210         {
211             return null;
212         }
213         if (stateObj instanceof _AttachedListStateWrapper)
214         {
215             List<Object> lst = ((_AttachedListStateWrapper) stateObj).getWrappedStateList();
216             List<Object> restoredList = new ArrayList<Object>(lst.size());
217             for (Object item : lst)
218             {
219                 restoredList.add(restoreAttachedState(context, item));
220             }
221             return restoredList;
222         }
223         else if (stateObj instanceof _AttachedStateWrapper)
224         {
225             Class<?> clazz = ((_AttachedStateWrapper) stateObj).getClazz();
226             Object restoredObject;
227             try
228             {
229                 restoredObject = clazz.newInstance();
230             }
231             catch (InstantiationException e)
232             {
233                 throw new RuntimeException("Could not restore StateHolder of type " + clazz.getName()
234                         + " (missing no-args constructor?)", e);
235             }
236             catch (IllegalAccessException e)
237             {
238                 throw new RuntimeException(e);
239             }
240             if (restoredObject instanceof StateHolder)
241             {
242                 _AttachedStateWrapper wrapper = (_AttachedStateWrapper) stateObj;
243                 Object wrappedState = wrapper.getWrappedStateObject();
244 
245                 StateHolder holder = (StateHolder) restoredObject;
246                 holder.restoreState(context, wrappedState);
247             }
248             return restoredObject;
249         }
250         else
251         {
252             return stateObj;
253         }
254     }
255 
256     public void setTransient(boolean newTransientValue)
257     {
258         _transient = newTransientValue;
259     }
260     
261     protected void addBehaviorListener(BehaviorListener listener)
262     {
263         if (listener == null)
264         {
265             throw new NullPointerException("listener");
266         }
267         
268         if (_behaviorListeners == null)
269         {
270             // Lazy instanciation with size 1:
271             // the only posibility how to add listener is <f:ajax listener="" /> - there is no <f:ajaxListener/> tag 
272             _behaviorListeners = new _DeltaList<BehaviorListener>(new ArrayList<BehaviorListener>(1));
273         }
274         
275         _behaviorListeners.add(listener);
276     }
277     
278     protected void removeBehaviorListener(BehaviorListener listener)
279     {
280         if (listener == null)
281         {
282             throw new NullPointerException("listener");
283         }
284 
285         if (_behaviorListeners != null)
286         {
287             _behaviorListeners.remove(listener);
288         }
289     }
290 }