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.trinidad.bean.util;
20  
21  import java.util.Map;
22  
23  import java.util.Set;
24  
25  import javax.el.ValueExpression;
26  
27  import javax.faces.component.PartialStateHolder;
28  
29  import org.apache.myfaces.trinidad.bean.FacesBean;
30  import org.apache.myfaces.trinidad.bean.PropertyKey;
31  import org.apache.myfaces.trinidad.bean.PropertyMap;
32  import org.apache.myfaces.trinidad.util.ArrayMap;
33  
34  import javax.faces.context.FacesContext;
35  
36  public class PropertyArrayMap extends ArrayMap<PropertyKey,Object>
37                               implements PropertyMap
38  {
39    public PropertyArrayMap(
40      int initialCapacity)
41    {
42      super(initialCapacity);
43    }
44  
45    public PropertyArrayMap()
46    {
47      super();
48    }
49  
50    public Object get(
51      PropertyKey pKey)
52    {
53      if (pKey.getIndex() < 0)
54        return get(pKey);
55      return getByIdentity(pKey);
56    }
57  
58    @Override
59     public Object put(
60       PropertyKey key,
61       Object      value)
62     {
63       Object retValue = super.put(key, value);
64       if (_createDeltas())
65       {
66         if (key.getMutable().isAtLeastSometimesMutable() || !_equals(value, retValue))
67           _deltas.put(key, value);
68       }
69       else if (key.getMutable().isAtLeastSometimesMutable() && !(value instanceof ValueExpression))
70       {
71         _getMutableTracker(true).addProperty(key);
72       }
73  
74       if (key.isPartialStateHolder())
75       {
76         _getPartialStateHolderTracker(true).addProperty(key);
77       }
78  
79       return retValue;
80     }
81  
82    @Override
83     public Object remove(
84       Object key)
85     {
86       boolean useDeltas = _createDeltas();
87  
88       if (useDeltas)
89       {
90         if (!super.containsKey(key))
91           return null;
92  
93         // If this key is contained, it certainly must be a PropertyKey!
94         assert(key instanceof PropertyKey);
95         _deltas.put((PropertyKey) key, null);
96       }
97  
98       if (key instanceof PropertyKey)
99       {
100        PropertyKey propKey  = (PropertyKey)key;
101        if (propKey.isPartialStateHolder())
102        {
103          _getPartialStateHolderTracker(true).removeProperty(propKey);
104        }
105 
106        if (!useDeltas &&  propKey.getMutable().isAtLeastSometimesMutable())
107        {
108          PropertyTracker mutableTracker = _getMutableTracker(false);
109 
110          if (mutableTracker != null)
111            mutableTracker.removeProperty(propKey);
112        }
113      }
114 
115      return super.remove(key);
116    }
117 
118   @Override
119   public void putAll(Map<? extends PropertyKey, ? extends Object> t)
120   {
121     boolean useDeltas =_createDeltas();
122 
123     if (useDeltas)
124       _deltas.putAll(t);
125 
126     Set<? extends PropertyKey> keys = t.keySet();
127     for (PropertyKey key: keys)
128     {
129       if (key.isPartialStateHolder())
130       {
131         _getPartialStateHolderTracker(true).addProperty(key);
132       }
133 
134       if (!useDeltas && key.getMutable().isAtLeastSometimesMutable())
135       {
136         Object value = t.get(key);
137 
138         if (!(value instanceof ValueExpression))
139         {
140           _getMutableTracker(true).addProperty(key);
141         }
142       }
143 
144     }
145 
146     super.putAll(t);
147   }
148 
149   public Object saveState(FacesContext context)
150   {
151     if (_initialStateMarked)
152     {
153       if (_deltas == null)
154         return null;
155 
156       return StateUtils.saveState(_deltas, context, getUseStateHolder());
157     }
158     else
159     {
160       return StateUtils.saveState(this, context, getUseStateHolder());
161     }
162   }
163 
164   public void restoreState(
165     FacesContext context,
166     FacesBean.Type type,
167     Object state)
168   {
169     StateUtils.restoreState(this, context, type, state, getUseStateHolder());
170   }
171 
172   protected PropertyMap createDeltaPropertyMap()
173   {
174     PropertyArrayMap map = new PropertyArrayMap(2);
175     map.setUseStateHolder(getUseStateHolder());
176     map.setType(_type);
177 
178     PropertyTracker tracker = _getMutableTracker(false);
179 
180     if (tracker != null)
181     {
182       for (PropertyKey key: tracker)
183       {
184         Object val = get(key);
185 
186         if (val != null)
187         {
188           map.put(key, val);
189         }
190       }
191 
192       _mutableTracker = null;
193     }
194     return map;
195   }
196 
197 
198   public boolean getUseStateHolder()
199   {
200     return _useStateHolder;
201   }
202 
203   public void setUseStateHolder(boolean useStateHolder)
204   {
205     _useStateHolder = useStateHolder;
206   }
207 
208 
209 
210   // =-=AEW CLEAR?
211 
212   public void markInitialState()
213   {
214     _initialStateMarked = true;
215 
216     // PropertyTracker uses a bitmask to track properties
217     // We are tracking all properties that have CA_PARTIAL_STATE_HOLDER capability,
218     // so that we do not have to check every property here
219     PropertyTracker tracker = _getPartialStateHolderTracker(false);
220     if (tracker != null)
221     {
222       for (PropertyKey key: tracker)
223       {
224         Object val = get(key);
225         if (val != null)
226         {
227           ((PartialStateHolder)val).markInitialState();
228         }
229       }
230     }
231   }
232 
233 
234   public void clearInitialState()
235   {
236     _initialStateMarked = false;
237     _deltas = null;
238 
239     // PropertyTracker uses a bitmask to track properties
240     // We are tracking all properties that have CA_PARTIAL_STATE_HOLDER capability,
241     // so that we do not have to check every property here
242     PropertyTracker tracker = _getPartialStateHolderTracker(false);
243     if (tracker != null)
244     {
245       for (PropertyKey key: tracker)
246       {
247         Object val = get(key);
248         if (val != null)
249         {
250           ((PartialStateHolder)val).clearInitialState();
251         }
252       }
253     }
254   }
255 
256   public boolean initialStateMarked()
257   {
258     return _initialStateMarked;
259   }
260 
261   /**
262    * Sets the the FacesBean type used by this map's owner bean
263    * @param type FacesBean type
264    */
265   public void setType(FacesBean.Type type)
266   {
267     _type = type;
268   }
269 
270   private boolean _createDeltas()
271   {
272     if (_initialStateMarked)
273     {
274       if (_deltas == null)
275       {
276         _deltas = createDeltaPropertyMap();
277       }
278 
279       return true;
280     }
281 
282     return false;
283   }
284 
285   static private boolean _equals(Object a, Object b)
286   {
287     if (a == b)
288       return true;
289 
290     if (a == null)
291       return false;
292 
293     return a.equals(b);
294   }
295   
296   private PropertyTracker _getPartialStateHolderTracker(boolean create)
297   {
298     if (_tracker == null && create)
299     {
300       if (_type == null)
301       {
302         throw new IllegalStateException("FacesBean.TYPE is required to track properties");
303       }
304       _tracker = new PropertyTracker(_type);
305     }
306     return _tracker;
307   }
308 
309     private PropertyTracker _getMutableTracker(boolean create)
310     {
311       if (_mutableTracker == null && create)
312       {
313         if (_type == null)
314         {
315           throw new IllegalStateException("FacesBean.TYPE is required to track properties");
316         }
317         _mutableTracker = new PropertyTracker(_type);
318       }
319       return _mutableTracker;
320     }
321 
322 
323   private transient boolean _initialStateMarked;
324   private transient PropertyMap _deltas;
325   private boolean      _useStateHolder;
326   private FacesBean.Type _type;
327   private PropertyTracker _tracker;
328   private transient PropertyTracker _mutableTracker;
329 }