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