1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.component;
20
21 import java.io.Externalizable;
22 import java.io.IOException;
23 import java.io.ObjectInput;
24 import java.io.ObjectOutput;
25 import java.io.Serializable;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31 import javax.faces.component.EditableValueHolder;
32 import javax.faces.component.UIComponent;
33 import javax.faces.context.FacesContext;
34
35 import org.apache.myfaces.trinidad.bean.FacesBean;
36 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
37
38
39
40
41 final class StampState implements Externalizable
42 {
43 public StampState()
44 {
45 _rows = Collections.emptyMap();
46 }
47
48
49
50
51
52
53 public void clear(Object skipCurrencyObj)
54 {
55 if (!_rows.isEmpty())
56 {
57 Iterator<DualKey> iter = _rows.keySet().iterator();
58 while(iter.hasNext())
59 {
60 DualKey dk = iter.next();
61 if (_eq(dk._key1, skipCurrencyObj))
62 continue;
63 iter.remove();
64 }
65 }
66 }
67
68 public void put(Object currencyObj, String key, Object value)
69 {
70 Map<DualKey, Object> comparant = Collections.emptyMap();
71 if (_rows == comparant)
72 {
73 if (value == null)
74 return;
75
76
77 _rows = new HashMap<DualKey, Object>(109);
78 }
79
80 DualKey dk = new DualKey(currencyObj, key);
81
82
83
84 if (value == null)
85 _rows.remove(dk);
86 else
87 _rows.put(dk, value);
88 }
89
90 public int size()
91 {
92 return _rows.size();
93 }
94
95 public Object get(Object currencyObj, String key)
96 {
97 DualKey dk = new DualKey(currencyObj, key);
98 return _rows.get(dk);
99 }
100
101
102
103
104 public static Object saveStampState(FacesContext context, UIComponent stamp)
105 {
106 RowState state = _createState(stamp);
107 return state;
108 }
109
110
111
112
113 public static void restoreStampState(FacesContext context, UIComponent stamp,
114 Object stampState)
115 {
116 if (stampState != null)
117 {
118 String stampId = stamp.getId();
119
120
121
122 stamp.setId(stampId);
123
124 RowState state = (RowState) stampState;
125 state.restoreRowState(stamp);
126 }
127 }
128
129
130
131
132
133 @SuppressWarnings("unchecked")
134 public static Object saveChildStampState(
135 FacesContext context,
136 UIComponent stamp,
137 UIXCollection table)
138 {
139 int childCount = stamp.getChildCount();
140
141
142 if (childCount == 0)
143 return null;
144
145 Object[] childStateArray = null;
146 List<UIComponent> children = stamp.getChildren();
147 boolean childStateIsEmpty = true;
148 for(int i=0; i < childCount; i++)
149 {
150 UIComponent child = children.get(i);
151 Object childState = table.saveStampState(context, child);
152
153
154
155
156
157
158
159
160
161
162 if (childStateArray == null)
163 {
164 if (childState == null)
165 continue;
166
167 childStateArray = new Object[childCount];
168 }
169
170
171
172
173 if ((childState != UIXCollection.Transient.TRUE) && (childState != null))
174 childStateIsEmpty = false;
175
176
177 assert(childStateArray != null);
178 childStateArray[i] = childState;
179 }
180
181
182
183 if (childStateIsEmpty)
184 return null;
185
186 return childStateArray;
187 }
188
189
190
191
192
193 @SuppressWarnings("unchecked")
194 public static void restoreChildStampState(
195 FacesContext context,
196 UIComponent stamp,
197 UIXCollection table,
198 Object stampState)
199 {
200 if (stampState == null)
201 return;
202
203 List<UIComponent> kids = stamp.getChildren();
204 Object[] state = (Object[]) stampState;
205
206 int childIndex = 0;
207 for(int i=0; i<state.length; i++)
208 {
209 Object childState = state[i];
210
211
212 if (childState != UIXCollection.Transient.TRUE)
213 {
214 while (childIndex < kids.size())
215 {
216 UIComponent kid = kids.get(childIndex);
217 childIndex++;
218
219 if (!kid.isTransient())
220 {
221 table.restoreStampState(context, kid, childState);
222 break;
223 }
224 }
225 }
226
227
228 else
229 {
230 if (childIndex < kids.size())
231 {
232 UIComponent child = kids.get(childIndex);
233
234
235
236 if (child.isTransient())
237 childIndex++;
238 }
239 }
240 }
241 }
242
243
244
245
246 public void writeExternal(ObjectOutput out) throws IOException
247 {
248 out.writeInt(_rows.size());
249
250 if (_rows.isEmpty())
251 return;
252
253 HashMap<DualKey, Object> map = new HashMap<DualKey, Object>(_rows.size());
254 map.putAll(_rows);
255
256 if (_LOG.isFinest())
257 {
258 for(Map.Entry<DualKey, Object> entry : map.entrySet())
259 {
260 _LOG.finest("Saving " + entry.getKey() + ", " + entry.getValue());
261 }
262 }
263
264 out.writeObject(map);
265 }
266
267 @SuppressWarnings("unchecked")
268 public void readExternal(ObjectInput in)
269 throws IOException, ClassNotFoundException
270 {
271 int size = in.readInt();
272
273 if (size > 0)
274 _rows = (Map<DualKey, Object>) in.readObject();
275
276 if (_LOG.isFinest())
277 {
278 for(Map.Entry<DualKey, Object> entry : _rows.entrySet())
279 {
280 _LOG.finest("Restoring " + entry.getKey() + ", " + entry.getValue());
281 }
282 }
283 }
284
285 private static RowState _createState(UIComponent child)
286 {
287 RowState state;
288 if (child instanceof EditableValueHolder)
289 {
290 state = new EVHState();
291 state.saveRowState(child);
292 }
293 else if (child instanceof UIXCollection)
294 {
295 state = new TableState();
296 state.saveRowState(child);
297 }
298 else if (child instanceof UIXShowDetail)
299 {
300 state = SDState.getState((UIXShowDetail) child);
301 }
302 else
303 {
304 state = null;
305 }
306
307 return state;
308 }
309
310 private static boolean _eq(Object k1, Object k2)
311 {
312 if (k1 == null)
313 return k2 == null;
314 return k1.equals(k2);
315 }
316
317
318 static private abstract class RowState implements Serializable
319 {
320
321 public RowState()
322 {
323 }
324
325 abstract public void saveRowState(UIComponent child);
326
327 abstract public void restoreRowState(UIComponent child);
328
329 abstract public boolean isNull();
330 }
331
332 static private final class SDState extends RowState
333 {
334
335
336
337 static public RowState getState(UIXShowDetail child)
338 {
339 FacesBean bean = child.getFacesBean();
340 Boolean disclosed = (Boolean)bean.getLocalProperty(UIXShowDetail.DISCLOSED_KEY);
341 if (disclosed == null)
342 return _NULL;
343 else if (disclosed)
344 return _TRUE;
345 else
346 return _FALSE;
347 }
348
349 public SDState()
350 {
351 }
352
353 private SDState(Boolean disclosed)
354 {
355 _disclosed = disclosed;
356 }
357
358 @Override
359 public void saveRowState(UIComponent child)
360 {
361 FacesBean bean = ((UIXShowDetail)child).getFacesBean();
362 _disclosed = (Boolean)bean.getLocalProperty(UIXShowDetail.DISCLOSED_KEY);
363 }
364
365 @Override
366 public void restoreRowState(UIComponent child)
367 {
368 FacesBean bean = ((UIXShowDetail)child).getFacesBean();
369 bean.setProperty(UIXShowDetail.DISCLOSED_KEY, _disclosed);
370 }
371
372 @Override
373 public boolean isNull()
374 {
375 return _disclosed == null;
376 }
377
378 @Override
379 public String toString()
380 {
381 return "SDState[disclosed=" + _disclosed + "]";
382 }
383
384
385
386 static private final SDState _TRUE = new SDState(true);
387 static private final SDState _FALSE = new SDState(false);
388 static private final SDState _NULL = new SDState(null);
389
390
391
392
393 private static final long serialVersionUID = -8605916495935317932L;
394
395 private Boolean _disclosed;
396 }
397
398 static private final class TableState extends RowState
399 {
400 public TableState()
401 {
402 }
403
404 @Override
405 public void saveRowState(UIComponent child)
406 {
407 _state = ((UIXCollection) child).__getMyStampState();
408 }
409
410 @Override
411 public void restoreRowState(UIComponent child)
412 {
413 ((UIXCollection) child).__setMyStampState(_state);
414 }
415
416 @Override
417 public boolean isNull()
418 {
419 return _state == null;
420 }
421
422 private Object _state = null;
423
424 private static final long serialVersionUID = 1L;
425 }
426
427 static private class EVHState extends RowState
428 {
429 public EVHState()
430 {
431 _valid = true;
432 }
433
434 @Override
435 public void saveRowState(UIComponent child)
436 {
437 assert _assertIsStampCorrect(child);
438
439 EditableValueHolder evh = (EditableValueHolder) child;
440 _submitted = evh.getSubmittedValue();
441 _localSet = evh.isLocalValueSet();
442 _local = evh.getLocalValue();
443 _valid = evh.isValid();
444 }
445
446 @Override
447 public void restoreRowState(UIComponent child)
448 {
449 assert _assertIsStampCorrect(child);
450
451 EditableValueHolder evh = (EditableValueHolder) child;
452 evh.setSubmittedValue(_submitted);
453 evh.setValue(_local);
454 evh.setLocalValueSet(_localSet);
455 evh.setValid(_valid);
456
457 assert _assertStampHonoursState(evh);
458 }
459
460 @Override
461 public boolean isNull()
462 {
463 return (_valid && (!_localSet) && (_submitted == null));
464 }
465
466
467 @Override
468 public String toString()
469 {
470 return "EVHState[value=" + _local + ",submitted=" + _submitted + "]";
471 }
472
473 private boolean _assertStampHonoursState(EditableValueHolder evh)
474 {
475 return (evh.getSubmittedValue() == _submitted) &&
476 (evh.getLocalValue() == _local) &&
477 (evh.isLocalValueSet() == _localSet) &&
478 (evh.isValid() == _valid);
479 }
480
481
482
483
484
485 private boolean _assertIsStampCorrect(UIComponent stamp)
486 {
487 if (_assertStamp != null)
488 {
489 String stampId = stamp.getId();
490 String assertStampId = _assertStamp.getId();
491 assert (((assertStampId == null) && (stampId == null)) ||
492 ((assertStampId != null) && assertStampId.equals(stampId))) :
493 "Current stamp:"+stamp+
494 " with id:"+stamp.getId()+
495 ". Previously stamp was:"+_assertStamp+
496 " with id:"+_assertStamp.getId();
497 }
498 else
499 {
500 _assertStamp = stamp;
501 }
502 return true;
503 }
504
505 private Object _submitted;
506 private Object _local;
507 private boolean _localSet;
508 private boolean _valid;
509 private transient UIComponent _assertStamp = null;
510
511 private static final long serialVersionUID = 1L;
512 }
513
514 private static final class DualKey implements Serializable
515 {
516 public DualKey(Object key1, Object key2)
517 {
518 _key1 = key1;
519 _key2 = key2;
520
521 _hash = _hash(key1) + _hash(key2);
522 }
523
524 @Override
525 public boolean equals(Object other)
526 {
527 if (other == this)
528 return true;
529 if (other instanceof DualKey)
530 {
531 DualKey otherKey = (DualKey) other;
532 if (hashCode() != otherKey.hashCode())
533 return false;
534
535 return _eq(_key1, otherKey._key1) && _eq(_key2, otherKey._key2);
536 }
537 return false;
538 }
539
540 @Override
541 public int hashCode()
542 {
543 return _hash;
544 }
545
546 @Override
547 public String toString()
548 {
549 return "<"+_key1+","+_key2+">";
550 }
551
552 private static int _hash(Object k)
553 {
554 return (k==null) ? 0 : k.hashCode();
555 }
556
557 private final Object _key1, _key2;
558 private final int _hash;
559
560 private static final long serialVersionUID = 1L;
561 }
562
563 private static final TrinidadLogger _LOG =
564 TrinidadLogger.createTrinidadLogger(StampState.class);
565
566 private Map<DualKey, Object> _rows;
567 private static final Object[] _EMPTY_ARRAY = new Object[0];
568 private static final long serialVersionUID = 1L;
569 }