1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.context.flash;
20
21 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
22 import org.apache.myfaces.shared.util.ExternalContextUtils;
23
24 import javax.faces.application.FacesMessage;
25 import javax.faces.context.ExternalContext;
26 import javax.faces.context.FacesContext;
27 import javax.faces.context.Flash;
28 import javax.faces.event.PhaseId;
29 import javax.servlet.ServletRequest;
30 import javax.servlet.http.Cookie;
31 import javax.servlet.http.HttpServletResponse;
32 import java.io.Serializable;
33 import java.math.BigInteger;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.SecureRandom;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.concurrent.atomic.AtomicLong;
43 import java.util.logging.Logger;
44
45
46
47
48
49
50
51
52 public class FlashImpl extends Flash
53 {
54
55
56
57 private static final Logger logger = Logger.getLogger(FlashImpl.class.getName());
58
59
60
61
62
63
64 @JSFWebConfigParam(defaultValue="false",since="2.0.5")
65 private static final String FLASH_SCOPE_DISABLED_PARAM = "org.apache.myfaces.FLASH_SCOPE_DISABLED";
66
67
68
69
70
71
72 private static final String FLASH_PREFIX = "oam.Flash";
73
74
75
76
77 static final String FLASH_INSTANCE = FLASH_PREFIX + ".INSTANCE";
78
79
80
81
82
83 static final String FLASH_REDIRECT = FLASH_PREFIX + ".REDIRECT";
84
85
86
87
88 static final String FLASH_PREVIOUS_REQUEST_REDIRECT
89 = FLASH_PREFIX + ".REDIRECT.PREVIOUSREQUEST";
90
91
92
93
94 static final String FLASH_KEEP_MESSAGES = FLASH_PREFIX + ".KEEP_MESSAGES";
95
96
97
98
99 static final String FLASH_KEEP_MESSAGES_LIST = "KEEPMESSAGESLIST";
100
101
102
103
104 static final String FLASH_SESSION_MAP_SUBKEY_PREFIX = FLASH_PREFIX + ".SCOPE";
105
106
107
108
109 static final String FLASH_RENDER_MAP = FLASH_PREFIX + ".RENDERMAP";
110
111
112
113
114 static final String FLASH_RENDER_MAP_TOKEN = FLASH_PREFIX + ".RENDERMAP.TOKEN";
115
116
117
118
119 static final String FLASH_EXECUTE_MAP = FLASH_PREFIX + ".EXECUTEMAP";
120
121
122
123
124 static final String FLASH_EXECUTE_MAP_TOKEN = FLASH_PREFIX + ".EXECUTEMAP.TOKEN";
125
126
127
128
129 static final char SEPARATOR_CHAR = '.';
130
131
132
133
134
135
136
137
138
139 public static Flash getCurrentInstance(ExternalContext context)
140 {
141 Map<String, Object> applicationMap = context.getApplicationMap();
142
143 Flash flash = (Flash) applicationMap.get(FLASH_INSTANCE);
144 if (flash == null)
145 {
146
147
148 synchronized (applicationMap)
149 {
150
151 flash = (Flash) applicationMap.get(FLASH_INSTANCE);
152 if (flash == null)
153 {
154 flash = new FlashImpl(context);
155 applicationMap.put(FLASH_INSTANCE, flash);
156 }
157 }
158 }
159
160 return flash;
161 }
162
163
164
165
166 private static long _getSeed()
167 {
168 SecureRandom rng;
169 try
170 {
171
172 rng = SecureRandom.getInstance("SHA1PRNG");
173 }
174 catch (NoSuchAlgorithmException e)
175 {
176
177
178 rng = new SecureRandom();
179 }
180
181
182 byte[] randomBytes = new byte[6];
183 rng.nextBytes(randomBytes);
184
185
186 return new BigInteger(randomBytes).longValue();
187 }
188
189
190
191
192 private final AtomicLong _count;
193 private boolean _flashScopeDisabled;
194
195 public FlashImpl(ExternalContext externalContext)
196 {
197 _count = new AtomicLong(_getSeed());
198
199
200 _flashScopeDisabled = "true".equalsIgnoreCase(externalContext.getInitParameter(FLASH_SCOPE_DISABLED_PARAM));
201 }
202
203
204
205
206
207
208
209
210 @Override
211 public void doPrePhaseActions(FacesContext facesContext)
212 {
213 if (!_flashScopeDisabled)
214 {
215 final PhaseId currentPhaseId = facesContext.getCurrentPhaseId();
216
217 if (PhaseId.RESTORE_VIEW.equals(currentPhaseId))
218 {
219
220
221
222 _restoreRedirectValue(facesContext);
223
224
225
226 _manageFlashMapTokens(facesContext);
227
228
229 _restoreMessages(facesContext);
230 }
231 }
232 }
233
234
235
236
237
238
239 @Override
240 public void doPostPhaseActions(FacesContext facesContext)
241 {
242 if (!_flashScopeDisabled)
243 {
244
245
246 if (_isLastPhaseInRequest(facesContext))
247 {
248 if (_isRedirectTrueOnThisRequest(facesContext))
249 {
250
251 Map<String, Object> renderMap = _getRenderFlashMap(facesContext);
252
253 for (Map.Entry<String, Object> entry
254 : _getExecuteFlashMap(facesContext).entrySet())
255 {
256 if (!renderMap.containsKey(entry.getKey()))
257 {
258 renderMap.put(entry.getKey(), entry.getValue());
259 }
260 }
261 }
262
263
264 _clearExecuteFlashMap(facesContext);
265
266
267
268
269
270 _saveMessages(facesContext);
271 }
272 }
273 }
274
275
276
277
278
279
280
281
282
283
284
285 @Override
286 public boolean isRedirect()
287 {
288 FacesContext facesContext = FacesContext.getCurrentInstance();
289 boolean thisRedirect = _isRedirectTrueOnThisRequest(facesContext);
290 boolean prevRedirect = _isRedirectTrueOnPreviousRequest(facesContext);
291 boolean executePhase = !PhaseId.RENDER_RESPONSE.equals(facesContext.getCurrentPhaseId());
292
293 return thisRedirect || (executePhase && prevRedirect);
294 }
295
296 @Override
297 public void setRedirect(boolean redirect)
298 {
299
300
301
302
303
304
305 FacesContext facesContext = FacesContext.getCurrentInstance();
306 ExternalContext externalContext = facesContext.getExternalContext();
307 Map<String, Object> requestMap = externalContext.getRequestMap();
308
309
310 Boolean alreadySet = (Boolean) requestMap.get(FLASH_REDIRECT);
311 alreadySet = (alreadySet == null ? Boolean.FALSE : Boolean.TRUE);
312
313
314 if (!alreadySet && redirect)
315 {
316 requestMap.put(FLASH_REDIRECT, Boolean.TRUE);
317
318
319 _saveRedirectValue(facesContext);
320 }
321 else
322 {
323 if (alreadySet)
324 {
325 logger.warning("Multiple call to setRedirect() ignored.");
326 }
327 else
328 {
329 logger.warning("Ignored call to setRedirect(false), because this "
330 + "should only be set to true by the NavigationHandler. "
331 + "No one else should change it.");
332 }
333 }
334 }
335
336
337
338
339
340
341 @Override
342 public void keep(String key)
343 {
344 _checkFlashScopeDisabled();
345 FacesContext facesContext = FacesContext.getCurrentInstance();
346 Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
347 Object value = requestMap.get(key);
348
349
350
351 if (value == null)
352 {
353 Map<String, Object> executeMap = _getExecuteFlashMap(facesContext);
354
355
356 if (executeMap != null)
357 {
358 value = executeMap.get(key);
359
360
361
362 requestMap.put(key, value);
363 }
364 }
365
366
367 _getRenderFlashMap(facesContext).put(key, value);
368 }
369
370
371
372
373 @Override
374 public void putNow(String key, Object value)
375 {
376 _checkFlashScopeDisabled();
377 FacesContext.getCurrentInstance().getExternalContext()
378 .getRequestMap().put(key, value);
379 }
380
381
382
383
384
385 @Override
386 public boolean isKeepMessages()
387 {
388 FacesContext facesContext = FacesContext.getCurrentInstance();
389 ExternalContext externalContext = facesContext.getExternalContext();
390 Map<String, Object> requestMap = externalContext.getRequestMap();
391 Boolean keepMessages = (Boolean) requestMap.get(FLASH_KEEP_MESSAGES);
392
393 return (keepMessages == null ? Boolean.FALSE : keepMessages);
394 }
395
396
397
398
399
400
401
402
403
404
405
406 @Override
407 public void setKeepMessages(boolean keepMessages)
408 {
409 FacesContext facesContext = FacesContext.getCurrentInstance();
410 ExternalContext externalContext = facesContext.getExternalContext();
411 Map<String, Object> requestMap = externalContext.getRequestMap();
412 requestMap.put(FLASH_KEEP_MESSAGES, keepMessages);
413 }
414
415
416
417
418
419
420 public void clear()
421 {
422 _checkFlashScopeDisabled();
423 _getFlashMapForWriting().clear();
424 }
425
426 public boolean containsKey(Object key)
427 {
428 _checkFlashScopeDisabled();
429 return _getFlashMapForReading().containsKey(key);
430 }
431
432 public boolean containsValue(Object value)
433 {
434 _checkFlashScopeDisabled();
435 return _getFlashMapForReading().containsValue(value);
436 }
437
438 public Set<java.util.Map.Entry<String, Object>> entrySet()
439 {
440 _checkFlashScopeDisabled();
441 return _getFlashMapForReading().entrySet();
442 }
443
444 public Object get(Object key)
445 {
446 _checkFlashScopeDisabled();
447 if (key == null)
448 {
449 return null;
450 }
451
452 if ("keepMessages".equals(key))
453 {
454 return isKeepMessages();
455 }
456 else if ("redirect".equals(key))
457 {
458 return isRedirect();
459 }
460
461 return _getFlashMapForReading().get(key);
462 }
463
464 public boolean isEmpty()
465 {
466 _checkFlashScopeDisabled();
467 return _getFlashMapForReading().isEmpty();
468 }
469
470 public Set<String> keySet()
471 {
472 _checkFlashScopeDisabled();
473 return _getFlashMapForReading().keySet();
474 }
475
476 public Object put(String key, Object value)
477 {
478 _checkFlashScopeDisabled();
479 if (key == null)
480 {
481 return null;
482 }
483
484 if ("keepMessages".equals(key))
485 {
486 Boolean booleanValue = _convertToBoolean(value);
487 this.setKeepMessages(booleanValue);
488 return booleanValue;
489 }
490 else if ("redirect".equals(key))
491 {
492 Boolean booleanValue = _convertToBoolean(value);
493 this.setRedirect(booleanValue);
494 return booleanValue;
495 }
496 else
497 {
498 return _getFlashMapForWriting().put(key, value);
499 }
500 }
501
502 public void putAll(Map<? extends String, ? extends Object> m)
503 {
504 _checkFlashScopeDisabled();
505 _getFlashMapForWriting().putAll(m);
506 }
507
508 public Object remove(Object key)
509 {
510 _checkFlashScopeDisabled();
511 return _getFlashMapForWriting().remove(key);
512 }
513
514 public int size()
515 {
516 _checkFlashScopeDisabled();
517 return _getFlashMapForReading().size();
518 }
519
520 public Collection<Object> values()
521 {
522 _checkFlashScopeDisabled();
523 return _getFlashMapForReading().values();
524 }
525
526
527
528
529
530
531
532
533
534
535
536 private boolean _isLastPhaseInRequest(FacesContext facesContext)
537 {
538 final PhaseId currentPhaseId = facesContext.getCurrentPhaseId();
539
540 boolean lastPhaseNormalRequest = PhaseId.RENDER_RESPONSE.equals(currentPhaseId);
541
542
543
544 boolean lastPhaseIfRedirect = facesContext.getResponseComplete()
545 && _isRedirectTrueOnThisRequest(facesContext);
546
547 return lastPhaseNormalRequest || lastPhaseIfRedirect;
548 }
549
550
551
552
553
554
555 private boolean _isRedirectTrueOnThisRequest(FacesContext facesContext)
556 {
557 ExternalContext externalContext = facesContext.getExternalContext();
558 Map<String, Object> requestMap = externalContext.getRequestMap();
559 Boolean redirect = (Boolean) requestMap.get(FLASH_REDIRECT);
560
561 return Boolean.TRUE.equals(redirect);
562 }
563
564
565
566
567
568
569
570 private boolean _isRedirectTrueOnPreviousRequest(FacesContext facesContext)
571 {
572 ExternalContext externalContext = facesContext.getExternalContext();
573 Map<String, Object> requestMap = externalContext.getRequestMap();
574 Boolean redirect = (Boolean) requestMap.get(FLASH_PREVIOUS_REQUEST_REDIRECT);
575
576 return Boolean.TRUE.equals(redirect);
577 }
578
579
580
581
582 private void _saveRedirectValue(FacesContext facesContext)
583 {
584 ExternalContext externalContext = facesContext.getExternalContext();
585
586
587
588
589
590
591
592 HttpServletResponse httpResponse = ExternalContextUtils
593 .getHttpServletResponse(externalContext);
594 if (httpResponse != null)
595 {
596 Cookie cookie = _createFlashCookie(FLASH_REDIRECT, "true", externalContext);
597 httpResponse.addCookie(cookie);
598 }
599 else
600 {
601 externalContext.getSessionMap().put(FLASH_REDIRECT, true);
602 }
603 }
604
605
606
607
608
609
610
611
612
613 private void _restoreRedirectValue(FacesContext facesContext)
614 {
615 ExternalContext externalContext = facesContext.getExternalContext();
616 HttpServletResponse httpResponse = ExternalContextUtils
617 .getHttpServletResponse(externalContext);
618 if (httpResponse != null)
619 {
620
621
622
623
624 Cookie cookie = (Cookie) externalContext
625 .getRequestCookieMap().get(FLASH_REDIRECT);
626 if (cookie != null)
627 {
628
629 externalContext.getRequestMap().put(
630 FLASH_PREVIOUS_REQUEST_REDIRECT, Boolean.TRUE);
631
632
633
634
635 cookie.setMaxAge(0);
636 cookie.setPath(_getCookiePath(externalContext));
637
638
639
640 httpResponse.addCookie(cookie);
641 }
642 }
643 else
644 {
645
646
647
648
649
650 Map<String, Object> sessionMap = externalContext.getSessionMap();
651
652
653 Boolean redirect = (Boolean) sessionMap.remove(FLASH_REDIRECT);
654
655
656 externalContext.getRequestMap().put(
657 FLASH_PREVIOUS_REQUEST_REDIRECT, redirect);
658 }
659 }
660
661
662
663
664
665
666
667 private void _saveMessages(FacesContext facesContext)
668 {
669 if (isKeepMessages())
670 {
671
672
673 List<MessageEntry> messageList = null;
674
675 Iterator<String> iterClientIds = facesContext.getClientIdsWithMessages();
676 while (iterClientIds.hasNext())
677 {
678 String clientId = (String) iterClientIds.next();
679 Iterator<FacesMessage> iterMessages = facesContext.getMessages(clientId);
680
681 while (iterMessages.hasNext())
682 {
683 FacesMessage message = iterMessages.next();
684
685 if (messageList == null)
686 {
687 messageList = new ArrayList<MessageEntry>();
688 }
689 messageList.add(new MessageEntry(clientId, message));
690 }
691 }
692
693 _getRenderFlashMap(facesContext).put(FLASH_KEEP_MESSAGES_LIST, messageList);
694 }
695 else
696 {
697
698 _getRenderFlashMap(facesContext).remove(FLASH_KEEP_MESSAGES_LIST);
699 }
700 }
701
702
703
704
705
706
707
708 @SuppressWarnings("unchecked")
709 private void _restoreMessages(FacesContext facesContext)
710 {
711 List<MessageEntry> messageList = (List<MessageEntry>)
712 _getExecuteFlashMap(facesContext).get(FLASH_KEEP_MESSAGES_LIST);
713
714 if (messageList != null)
715 {
716 Iterator<MessageEntry> iterMessages = messageList.iterator();
717
718 while (iterMessages.hasNext())
719 {
720 MessageEntry entry = iterMessages.next();
721 facesContext.addMessage(entry.clientId, entry.message);
722 }
723
724
725 _getExecuteFlashMap(facesContext).remove(FLASH_KEEP_MESSAGES_LIST);
726 }
727 }
728
729
730
731
732
733
734
735 private void _saveRenderFlashMapTokenForNextRequest(ExternalContext externalContext)
736 {
737 String tokenValue = (String) externalContext.getRequestMap().get(FLASH_RENDER_MAP_TOKEN);
738
739 HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
740 if (httpResponse != null)
741 {
742 Cookie cookie = _createFlashCookie(FLASH_RENDER_MAP_TOKEN, tokenValue, externalContext);
743 httpResponse.addCookie(cookie);
744 }
745 else
746 {
747
748 Map<String, Object> sessionMap = externalContext.getSessionMap();
749 sessionMap.put(FLASH_RENDER_MAP_TOKEN, tokenValue);
750 }
751 }
752
753
754
755
756
757
758
759
760
761 private String _getRenderFlashMapTokenFromPreviousRequest(ExternalContext externalContext)
762 {
763 String tokenValue = null;
764 HttpServletResponse httpResponse = ExternalContextUtils.getHttpServletResponse(externalContext);
765 if (httpResponse != null)
766 {
767
768 Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(FLASH_RENDER_MAP_TOKEN);
769 if (cookie != null)
770 {
771 tokenValue = cookie.getValue();
772 }
773 }
774 else
775 {
776
777 Map<String, Object> sessionMap = externalContext.getSessionMap();
778 tokenValue = (String) sessionMap.get(FLASH_RENDER_MAP_TOKEN);
779 }
780 return tokenValue;
781 }
782
783
784
785
786
787
788
789
790 private void _manageFlashMapTokens(FacesContext facesContext)
791 {
792 ExternalContext externalContext = facesContext.getExternalContext();
793 Map<String, Object> requestMap = externalContext.getRequestMap();
794
795 final String previousRenderToken
796 = _getRenderFlashMapTokenFromPreviousRequest(externalContext);
797 if (previousRenderToken != null)
798 {
799
800
801 requestMap.put(FLASH_EXECUTE_MAP_TOKEN, previousRenderToken);
802 }
803 else
804 {
805 if (facesContext.isPostback())
806 {
807
808 logger.warning("Identifier for execute FlashMap was lost on " +
809 "the postback, thus FlashScope information is gone.");
810 }
811
812
813
814 final String newExecuteToken = _getNextToken();
815 requestMap.put(FLASH_EXECUTE_MAP_TOKEN, newExecuteToken);
816 }
817
818
819 final String newRenderToken = _getNextToken();
820 requestMap.put(FLASH_RENDER_MAP_TOKEN, newRenderToken);
821
822
823
824 _saveRenderFlashMapTokenForNextRequest(externalContext);
825 }
826
827
828
829
830
831
832 private String _getNextToken()
833 {
834
835 long nextToken = _count.incrementAndGet();
836
837
838 return Long.toString(nextToken, 36);
839 }
840
841
842
843
844
845
846 private Map<String, Object> _createSubKeyMap(FacesContext context, String prefix)
847 {
848 ExternalContext external = context.getExternalContext();
849 Map<String, Object> sessionMap = external.getSessionMap();
850
851 return new SubKeyMap<Object>(sessionMap, prefix);
852 }
853
854
855
856
857
858
859
860
861
862
863
864
865 @SuppressWarnings("unchecked")
866 private Map<String, Object> _getRenderFlashMap(FacesContext context)
867 {
868
869
870
871
872 Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
873 Map<String, Object> map = (Map<String, Object>) requestMap.get(FLASH_RENDER_MAP);
874 if (map == null)
875 {
876 String token = (String) requestMap.get(FLASH_RENDER_MAP_TOKEN);
877 String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token;
878 map = _createSubKeyMap(context, fullToken);
879 requestMap.put(FLASH_RENDER_MAP, map);
880 }
881 return map;
882 }
883
884
885
886
887
888
889
890
891
892 @SuppressWarnings("unchecked")
893 private Map<String, Object> _getExecuteFlashMap(FacesContext context)
894 {
895
896
897
898
899 Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
900 Map<String, Object> map = (Map<String, Object>) requestMap.get(FLASH_EXECUTE_MAP);
901 if (map == null)
902 {
903 String token = (String) requestMap.get(FLASH_EXECUTE_MAP_TOKEN);
904 String fullToken = FLASH_SESSION_MAP_SUBKEY_PREFIX + SEPARATOR_CHAR + token;
905 map = _createSubKeyMap(context, fullToken);
906 requestMap.put(FLASH_EXECUTE_MAP, map);
907 }
908 return map;
909 }
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957 private Map<String, Object> _getActiveFlashMap()
958 {
959 FacesContext facesContext = FacesContext.getCurrentInstance();
960 if (PhaseId.RENDER_RESPONSE.equals(facesContext.getCurrentPhaseId())
961 || !facesContext.isPostback())
962 {
963 return _getRenderFlashMap(facesContext);
964 }
965 else
966 {
967 return _getExecuteFlashMap(facesContext);
968 }
969 }
970
971
972
973
974
975
976 private Map<String, Object> _getFlashMapForReading()
977 {
978 return _getExecuteFlashMap(FacesContext.getCurrentInstance());
979 }
980
981
982
983
984
985
986 private Map<String, Object> _getFlashMapForWriting()
987 {
988 return _getActiveFlashMap();
989 }
990
991
992
993
994
995 private void _clearExecuteFlashMap(FacesContext facesContext)
996 {
997 Map<String, Object> map = _getExecuteFlashMap(facesContext);
998
999
1000
1001
1002
1003
1004
1005
1006 map.clear();
1007 }
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018 private Cookie _createFlashCookie(String name, String value, ExternalContext externalContext)
1019 {
1020 Cookie cookie = new Cookie(name, value);
1021
1022 cookie.setMaxAge(-1);
1023 cookie.setPath(_getCookiePath(externalContext));
1024 cookie.setSecure(_isCurrentRequestSecure(externalContext));
1025
1026 return cookie;
1027 }
1028
1029
1030
1031
1032
1033
1034 private String _getCookiePath(ExternalContext externalContext)
1035 {
1036 String contextPath = externalContext.getRequestContextPath();
1037
1038 if (contextPath == null || "".equals(contextPath))
1039 {
1040 contextPath = "/";
1041 }
1042
1043 return contextPath;
1044 }
1045
1046
1047
1048
1049
1050
1051
1052 private boolean _isCurrentRequestSecure(ExternalContext externalContext)
1053 {
1054 boolean secure = false;
1055
1056
1057
1058 Object requestObject = externalContext.getRequest();
1059 if (requestObject instanceof ServletRequest)
1060 {
1061 secure = ((ServletRequest) requestObject).isSecure();
1062 }
1063
1064 return secure;
1065 }
1066
1067
1068
1069
1070
1071
1072 private Boolean _convertToBoolean(Object value)
1073 {
1074 Boolean booleanValue;
1075 if (value instanceof Boolean)
1076 {
1077 booleanValue = (Boolean) value;
1078 }
1079 else
1080 {
1081 booleanValue = Boolean.parseBoolean(value.toString());
1082 }
1083 return booleanValue;
1084 }
1085
1086
1087
1088
1089
1090 private void _checkFlashScopeDisabled()
1091 {
1092 if (_flashScopeDisabled) {
1093 throw new FlashScopeDisabledException("Flash scope was disabled by context param "
1094 + FLASH_SCOPE_DISABLED_PARAM + " but erroneously accessed");
1095 }
1096 }
1097
1098
1099
1100
1101
1102
1103 private static class MessageEntry implements Serializable
1104 {
1105 private static final long serialVersionUID = -690264660230199234L;
1106 private final String clientId;
1107 private final FacesMessage message;
1108
1109 public MessageEntry(String clientId, FacesMessage message)
1110 {
1111 this.clientId = clientId;
1112 this.message = message;
1113 }
1114 }
1115
1116 }