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