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