1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.application.jsp;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.ByteArrayOutputStream;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.ObjectInputStream;
26 import java.io.ObjectOutputStream;
27 import java.io.OutputStream;
28 import java.io.Serializable;
29 import java.lang.reflect.Method;
30 import java.security.AccessController;
31 import java.security.PrivilegedActionException;
32 import java.security.PrivilegedExceptionAction;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 import java.util.zip.GZIPInputStream;
44 import java.util.zip.GZIPOutputStream;
45
46 import javax.faces.FactoryFinder;
47 import javax.faces.application.StateManager;
48 import javax.faces.component.NamingContainer;
49 import javax.faces.component.UIComponent;
50 import javax.faces.component.UIViewRoot;
51 import javax.faces.context.ExternalContext;
52 import javax.faces.context.FacesContext;
53 import javax.faces.render.RenderKit;
54 import javax.faces.render.RenderKitFactory;
55 import javax.faces.render.ResponseStateManager;
56 import javax.faces.view.StateManagementStrategy;
57 import javax.faces.view.ViewDeclarationLanguage;
58
59 import org.apache.commons.collections.map.AbstractReferenceMap;
60 import org.apache.commons.collections.map.ReferenceMap;
61 import org.apache.myfaces.application.MyfacesStateManager;
62 import org.apache.myfaces.application.TreeStructureManager;
63 import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
64 import org.apache.myfaces.shared.renderkit.RendererUtils;
65 import org.apache.myfaces.shared.util.MyFacesObjectInputStream;
66
67
68
69
70
71
72
73
74
75 public class JspStateManagerImpl extends MyfacesStateManager
76 {
77
78 private static final Logger log = Logger.getLogger(JspStateManagerImpl.class.getName());
79
80 private static final String SERIALIZED_VIEW_SESSION_ATTR=
81 JspStateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
82
83 private static final String SERIALIZED_VIEW_REQUEST_ATTR =
84 JspStateManagerImpl.class.getName() + ".SERIALIZED_VIEW";
85
86 private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR =
87 JspStateManagerImpl.class.getName() + ".RESTORED_SERIALIZED_VIEW";
88
89
90
91
92
93 private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
94
95
96
97
98 private static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
99
100
101
102
103
104
105 private static final String SERIALIZE_STATE_IN_SESSION_PARAM = "org.apache.myfaces.SERIALIZE_STATE_IN_SESSION";
106
107
108
109
110
111
112
113 private static final String COMPRESS_SERVER_STATE_PARAM = "org.apache.myfaces.COMPRESS_STATE_IN_SESSION";
114
115
116
117
118 private static final boolean DEFAULT_COMPRESS_SERVER_STATE_PARAM = true;
119
120
121
122
123 private static final boolean DEFAULT_SERIALIZE_STATE_IN_SESSION = true;
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE = "org.apache.myfaces.CACHE_OLD_VIEWS_IN_SESSION_MODE";
149
150
151
152
153
154
155 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT = "hard-soft";
156
157 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT = "soft";
158
159 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK = "soft-weak";
160
161 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK = "weak";
162
163 private static final String CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF = "off";
164
165 private static final int UNCOMPRESSED_FLAG = 0;
166 private static final int COMPRESSED_FLAG = 1;
167
168 private static final int JSF_SEQUENCE_INDEX = 0;
169
170 private RenderKitFactory _renderKitFactory = null;
171
172 public JspStateManagerImpl()
173 {
174 if (log.isLoggable(Level.FINEST))
175 {
176 log.finest("New JspStateManagerImpl instance created");
177 }
178 }
179
180 @Override
181 protected Object getComponentStateToSave(FacesContext facesContext)
182 {
183 if (log.isLoggable(Level.FINEST))
184 {
185 log.finest("Entering getComponentStateToSave");
186 }
187
188 UIViewRoot viewRoot = facesContext.getViewRoot();
189 if (viewRoot.isTransient())
190 {
191 return null;
192 }
193
194 Object serializedComponentStates = viewRoot.processSaveState(facesContext);
195
196 if (log.isLoggable(Level.FINEST))
197 {
198 log.finest("Exiting getComponentStateToSave");
199 }
200 return serializedComponentStates;
201 }
202
203
204
205
206
207
208
209 @Override
210 protected Object getTreeStructureToSave(FacesContext facesContext)
211 {
212 if (log.isLoggable(Level.FINEST))
213 {
214 log.finest("Entering getTreeStructureToSave");
215 }
216 UIViewRoot viewRoot = facesContext.getViewRoot();
217 if (viewRoot.isTransient())
218 {
219 return null;
220 }
221 TreeStructureManager tsm = new TreeStructureManager();
222 Object retVal = tsm.buildTreeStructureToSave(viewRoot);
223 if (log.isLoggable(Level.FINEST))
224 {
225 log.finest("Exiting getTreeStructureToSave");
226 }
227 return retVal;
228 }
229
230
231
232
233
234
235
236 @Override
237 protected void restoreComponentState(FacesContext facesContext,
238 UIViewRoot uiViewRoot,
239 String renderKitId)
240 {
241 if (log.isLoggable(Level.FINEST))
242 {
243 log.finest("Entering restoreComponentState");
244 }
245
246
247
248
249
250 RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
251 ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
252
253 Object serializedComponentStates;
254 if (isSavingStateInClient(facesContext))
255 {
256 if (isLegacyResponseStateManager(responseStateManager))
257 {
258 serializedComponentStates = responseStateManager.getComponentStateToRestore(facesContext);
259 }
260 else
261 {
262 serializedComponentStates = responseStateManager.getState(facesContext, uiViewRoot.getViewId());
263 }
264 if (serializedComponentStates == null)
265 {
266 log.severe("No serialized component state found in client request!");
267
268 uiViewRoot.setViewId(null);
269 return;
270 }
271 }
272 else
273 {
274 Integer serverStateId = getServerStateId((Object[])
275 responseStateManager.getState(facesContext, uiViewRoot.getViewId()));
276
277 Object[] stateObj = (Object[])( (serverStateId == null)
278 ? null
279 : getSerializedViewFromServletSession(facesContext, uiViewRoot.getViewId(), serverStateId) );
280
281 if (stateObj == null)
282 {
283 log.severe("No serialized view found in server session!");
284
285 uiViewRoot.setViewId(null);
286 return;
287 }
288 SerializedView serializedView = new SerializedView(stateObj[0], stateObj[1]);
289 serializedComponentStates = serializedView.getState();
290 if (serializedComponentStates == null)
291 {
292 log.severe("No serialized component state found in server session!");
293 return;
294 }
295 }
296
297 if (uiViewRoot.getRenderKitId() == null)
298 {
299
300 uiViewRoot.setRenderKitId(renderKitId);
301 }
302
303
304 uiViewRoot.processRestoreState(facesContext, serializedComponentStates);
305
306 if (log.isLoggable(Level.FINEST))
307 {
308 log.finest("Exiting restoreComponentState");
309 }
310 }
311
312 protected Integer getServerStateId(Object[] state)
313 {
314 if (state != null)
315 {
316 Object serverStateId = state[JSF_SEQUENCE_INDEX];
317 if (serverStateId != null)
318 {
319 return Integer.valueOf((String) serverStateId, Character.MAX_RADIX);
320 }
321 }
322 return null;
323 }
324
325
326
327
328 @Override
329 protected UIViewRoot restoreTreeStructure(FacesContext facesContext,
330 String viewId,
331 String renderKitId)
332 {
333 if (log.isLoggable(Level.FINEST))
334 {
335 log.finest("Entering restoreTreeStructure");
336 }
337
338 RenderKit rk = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
339 ResponseStateManager responseStateManager = rk.getResponseStateManager();
340
341 UIViewRoot uiViewRoot;
342 if (isSavingStateInClient(facesContext))
343 {
344
345 Object treeStructure = responseStateManager.getTreeStructureToRestore(facesContext, viewId);
346 if (treeStructure == null)
347 {
348 if (log.isLoggable(Level.FINE))
349 {
350 log.fine("Exiting restoreTreeStructure - No tree structure state found in client request");
351 }
352 return null;
353 }
354
355 TreeStructureManager tsm = new TreeStructureManager();
356 uiViewRoot = tsm.restoreTreeStructure(treeStructure);
357 if (log.isLoggable(Level.FINEST))
358 {
359 log.finest("Tree structure restored from client request");
360 }
361 }
362 else
363 {
364
365 Integer serverStateId = getServerStateId((Object[]) responseStateManager.getState(facesContext, viewId));
366
367 Object[] stateObj = (Object[])( (serverStateId == null)
368 ? null
369 : getSerializedViewFromServletSession(facesContext, viewId, serverStateId) );
370
371 if (stateObj == null)
372 {
373 if (log.isLoggable(Level.FINE))
374 {
375 log.fine("Exiting restoreTreeStructure - No serialized view found in server session!");
376 }
377 return null;
378 }
379
380 SerializedView serializedView = new SerializedView(stateObj[0], stateObj[1]);
381 Object treeStructure = serializedView.getStructure();
382 if (treeStructure == null)
383 {
384 if (log.isLoggable(Level.FINE))
385 {
386 log.fine("Exiting restoreTreeStructure - No tree structure state found "
387 + "in server session, former UIViewRoot must have been transient");
388 }
389 return null;
390 }
391
392 TreeStructureManager tsm = new TreeStructureManager();
393 uiViewRoot = tsm.restoreTreeStructure(serializedView.getStructure());
394 if (log.isLoggable(Level.FINEST))
395 {
396 log.finest("Tree structure restored from server session");
397 }
398 }
399
400 if (log.isLoggable(Level.FINEST))
401 {
402 log.finest("Exiting restoreTreeStructure");
403 }
404 return uiViewRoot;
405 }
406
407 @Override
408 public UIViewRoot restoreView(FacesContext facesContext, String viewId, String renderKitId)
409 {
410 if (log.isLoggable(Level.FINEST))
411 {
412 log.finest("Entering restoreView - viewId: " + viewId + " ; renderKitId: " + renderKitId);
413 }
414
415 UIViewRoot uiViewRoot = null;
416
417 ViewDeclarationLanguage vdl = facesContext.getApplication().
418 getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
419 StateManagementStrategy sms = null;
420 if (vdl != null)
421 {
422 sms = vdl.getStateManagementStrategy(facesContext, viewId);
423 }
424
425 if (sms != null)
426 {
427 if (log.isLoggable(Level.FINEST))
428 {
429 log.finest("Redirect to StateManagementStrategy: " + sms.getClass().getName());
430 }
431
432 uiViewRoot = sms.restoreView(facesContext, viewId, renderKitId);
433 }
434 else
435 {
436 RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, renderKitId);
437 ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
438
439 Object state;
440 if (isSavingStateInClient(facesContext))
441 {
442 if (log.isLoggable(Level.FINEST))
443 {
444 log.finest("Restoring view from client");
445 }
446
447 state = responseStateManager.getState(facesContext, viewId);
448 }
449 else
450 {
451 if (log.isLoggable(Level.FINEST))
452 {
453 log.finest("Restoring view from session");
454 }
455
456 Integer serverStateId
457 = getServerStateId((Object[]) responseStateManager.getState(facesContext, viewId));
458
459 state = (serverStateId == null)
460 ? null
461 : getSerializedViewFromServletSession(facesContext, viewId, serverStateId);
462 }
463
464 if (state != null)
465 {
466 Object[] stateArray = (Object[])state;
467 TreeStructureManager tsm = new TreeStructureManager();
468 uiViewRoot = tsm.restoreTreeStructure(stateArray[0]);
469
470 if (uiViewRoot != null)
471 {
472 facesContext.setViewRoot (uiViewRoot);
473 uiViewRoot.processRestoreState(facesContext, stateArray[1]);
474 }
475 }
476 }
477 if (log.isLoggable(Level.FINEST))
478 {
479 log.finest("Exiting restoreView - " + viewId);
480 }
481
482 return uiViewRoot;
483 }
484
485
486
487
488
489 @Override
490 public Object saveView(FacesContext facesContext)
491 {
492 UIViewRoot uiViewRoot = facesContext.getViewRoot();
493
494 String viewId = uiViewRoot.getViewId();
495 ViewDeclarationLanguage vdl = facesContext.getApplication().
496 getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
497 try
498 {
499 facesContext.getAttributes().put(StateManager.IS_SAVING_STATE, Boolean.TRUE);
500 if (vdl != null)
501 {
502 StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
503
504 if (sms != null)
505 {
506 if (log.isLoggable(Level.FINEST))
507 {
508 log.finest("Calling saveView of StateManagementStrategy: " + sms.getClass().getName());
509 }
510
511 return sms.saveView(facesContext);
512 }
513 }
514
515
516
517
518
519 if (uiViewRoot.isTransient())
520 {
521 return null;
522 }
523
524 return super.saveView(facesContext);
525 }
526 finally
527 {
528 facesContext.getAttributes().remove(StateManager.IS_SAVING_STATE);
529 }
530 }
531
532 @Override
533 public SerializedView saveSerializedView(FacesContext facesContext) throws IllegalStateException
534 {
535 if (log.isLoggable(Level.FINEST))
536 {
537 log.finest("Entering saveSerializedView");
538 }
539
540 checkForDuplicateIds(facesContext, facesContext.getViewRoot(), new HashSet<String>());
541
542 if (log.isLoggable(Level.FINEST))
543 {
544 log.finest("Processing saveSerializedView - Checked for duplicate Ids");
545 }
546
547 ExternalContext externalContext = facesContext.getExternalContext();
548
549
550 Object serializedView = externalContext.getRequestMap()
551 .get(SERIALIZED_VIEW_REQUEST_ATTR);
552 if (serializedView == null)
553 {
554 if (log.isLoggable(Level.FINEST))
555 {
556 log.finest("Processing saveSerializedView - create new serialized view");
557 }
558
559
560 Object treeStruct = getTreeStructureToSave(facesContext);
561 Object compStates = getComponentStateToSave(facesContext);
562 serializedView = new Object[] {treeStruct, compStates};
563 externalContext.getRequestMap().put(SERIALIZED_VIEW_REQUEST_ATTR,
564 serializedView);
565
566 if (log.isLoggable(Level.FINEST))
567 {
568 log.finest("Processing saveSerializedView - new serialized view created");
569 }
570 }
571
572 Object[] serializedViewArray = (Object[]) serializedView;
573
574 if (!isSavingStateInClient(facesContext))
575 {
576 if (log.isLoggable(Level.FINEST))
577 {
578 log.finest("Processing saveSerializedView - server-side state saving - save state");
579 }
580
581 saveSerializedViewInServletSession(facesContext, serializedView);
582
583 if (log.isLoggable(Level.FINEST))
584 {
585 log.finest("Exiting saveSerializedView - server-side state saving - saved state");
586 }
587 return new SerializedView(serializedViewArray[0], new Object[0]);
588 }
589
590 if (log.isLoggable(Level.FINEST))
591 {
592 log.finest("Exiting saveSerializedView - client-side state saving");
593 }
594
595 return new SerializedView(serializedViewArray[0], serializedViewArray[1]);
596 }
597
598 private static void checkForDuplicateIds(FacesContext context,
599 UIComponent component,
600 Set<String> ids)
601 {
602 String id = component.getId();
603 if (id != null && !ids.add(id))
604 {
605 throw new IllegalStateException("Client-id : " + id +
606 " is duplicated in the faces tree. Component : " +
607 component.getClientId(context)+", path: " +
608 getPathToComponent(component));
609 }
610
611 if (component instanceof NamingContainer)
612 {
613 ids = new HashSet<String>();
614 }
615
616 Iterator<UIComponent> it = component.getFacetsAndChildren();
617 while (it.hasNext())
618 {
619 UIComponent kid = it.next();
620 checkForDuplicateIds(context, kid, ids);
621 }
622 }
623
624 private static String getPathToComponent(UIComponent component)
625 {
626 StringBuffer buf = new StringBuffer();
627
628 if(component == null)
629 {
630 buf.append("{Component-Path : ");
631 buf.append("[null]}");
632 return buf.toString();
633 }
634
635 getPathToComponent(component,buf);
636
637 buf.insert(0,"{Component-Path : ");
638 buf.append("}");
639
640 return buf.toString();
641 }
642
643 private static void getPathToComponent(UIComponent component, StringBuffer buf)
644 {
645 if(component == null)
646 {
647 return;
648 }
649
650 StringBuffer intBuf = new StringBuffer();
651
652 intBuf.append("[Class: ");
653 intBuf.append(component.getClass().getName());
654 if(component instanceof UIViewRoot)
655 {
656 intBuf.append(",ViewId: ");
657 intBuf.append(((UIViewRoot) component).getViewId());
658 }
659 else
660 {
661 intBuf.append(",Id: ");
662 intBuf.append(component.getId());
663 }
664 intBuf.append("]");
665
666 buf.insert(0,intBuf.toString());
667
668 getPathToComponent(component.getParent(),buf);
669 }
670
671 @Override
672 public void writeState(FacesContext facesContext,
673 SerializedView serializedView) throws IOException
674 {
675 if (log.isLoggable(Level.FINEST))
676 {
677 log.finest("Entering writeState");
678 }
679
680 UIViewRoot uiViewRoot = facesContext.getViewRoot();
681
682 RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, uiViewRoot.getRenderKitId());
683 ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
684
685 if (isLegacyResponseStateManager(responseStateManager))
686 {
687 responseStateManager.writeState(facesContext, serializedView);
688 }
689 else if (!isSavingStateInClient(facesContext))
690 {
691 Object[] state = new Object[2];
692 state[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
693 responseStateManager.writeState(facesContext, state);
694 }
695 else
696 {
697 Object[] state = new Object[2];
698 state[0] = serializedView.getStructure();
699 state[1] = serializedView.getState();
700 responseStateManager.writeState(facesContext, state);
701 }
702
703 if (log.isLoggable(Level.FINEST))
704 {
705 log.finest("Exiting writeState");
706 }
707
708 }
709
710 @Override
711 public String getViewState(FacesContext facesContext)
712 {
713 UIViewRoot uiViewRoot = facesContext.getViewRoot();
714 String viewId = uiViewRoot.getViewId();
715 ViewDeclarationLanguage vdl
716 = facesContext.getApplication().getViewHandler().getViewDeclarationLanguage(facesContext,viewId);
717 if (vdl != null)
718 {
719 StateManagementStrategy sms = vdl.getStateManagementStrategy(facesContext, viewId);
720
721 if (sms != null)
722 {
723 if (log.isLoggable(Level.FINEST))
724 {
725 log.finest("Calling saveView of StateManagementStrategy from getViewState: "
726 + sms.getClass().getName());
727 }
728
729 return facesContext.getRenderKit().getResponseStateManager().
730 getViewState(facesContext, saveView(facesContext));
731 }
732 }
733 Object[] savedState = (Object[]) saveView(facesContext);
734
735 if (!isSavingStateInClient(facesContext))
736 {
737 Object[] state = new Object[2];
738 state[JSF_SEQUENCE_INDEX] = Integer.toString(getNextViewSequence(facesContext), Character.MAX_RADIX);
739 return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, state);
740 }
741 else
742 {
743 return facesContext.getRenderKit().getResponseStateManager().getViewState(facesContext, savedState);
744 }
745 }
746
747
748
749
750
751
752
753 @Override
754 public void writeStateAsUrlParams(FacesContext facesContext,
755 SerializedView serializedView) throws IOException
756 {
757 if (log.isLoggable(Level.FINEST))
758 {
759 log.finest("Entering writeStateAsUrlParams");
760 }
761
762 if (isSavingStateInClient(facesContext))
763 {
764 if (log.isLoggable(Level.FINEST))
765 {
766 log.finest("Processing writeStateAsUrlParams - client-side state saving writing state");
767 }
768
769 UIViewRoot uiViewRoot = facesContext.getViewRoot();
770
771 RenderKit renderKit = getRenderKitFactory().getRenderKit(facesContext, uiViewRoot.getRenderKitId());
772 ResponseStateManager responseStateManager = renderKit.getResponseStateManager();
773 if (responseStateManager instanceof MyfacesResponseStateManager)
774 {
775 ((MyfacesResponseStateManager)responseStateManager).writeStateAsUrlParams(facesContext,
776 serializedView);
777 }
778 else
779 {
780 log.severe("ResponseStateManager of render kit " + uiViewRoot.getRenderKitId()
781 + " is no MyfacesResponseStateManager and does not support saving state in url parameters.");
782 }
783 }
784
785 if (log.isLoggable(Level.FINEST))
786 {
787 log.finest("Exiting writeStateAsUrlParams");
788 }
789 }
790
791
792
793 protected RenderKitFactory getRenderKitFactory()
794 {
795 if (_renderKitFactory == null)
796 {
797 _renderKitFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
798 }
799 return _renderKitFactory;
800 }
801
802 protected void saveSerializedViewInServletSession(FacesContext context,
803 Object serializedView)
804 {
805 Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
806 SerializedViewCollection viewCollection = (SerializedViewCollection) sessionMap
807 .get(SERIALIZED_VIEW_SESSION_ATTR);
808 if (viewCollection == null)
809 {
810 viewCollection = new SerializedViewCollection();
811 sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
812 }
813 viewCollection.add(context, serializeView(context, serializedView));
814
815 sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
816 }
817
818 protected Object getSerializedViewFromServletSession(FacesContext context, String viewId, Integer sequence)
819 {
820 ExternalContext externalContext = context.getExternalContext();
821 Map<String, Object> requestMap = externalContext.getRequestMap();
822 Object serializedView = null;
823 if (requestMap.containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR))
824 {
825 serializedView = requestMap.get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
826 }
827 else
828 {
829 SerializedViewCollection viewCollection = (SerializedViewCollection) externalContext
830 .getSessionMap().get(SERIALIZED_VIEW_SESSION_ATTR);
831 if (viewCollection != null)
832 {
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848 if (sequence != null)
849 {
850 Object state = viewCollection.get(sequence, viewId);
851 if (state != null)
852 {
853 serializedView = deserializeView(state);
854 }
855 }
856 }
857 requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
858 nextViewSequence(context);
859 }
860 return serializedView;
861 }
862
863 protected int getNextViewSequence(FacesContext context)
864 {
865 ExternalContext externalContext = context.getExternalContext();
866
867 if (!externalContext.getRequestMap().containsKey(RendererUtils.SEQUENCE_PARAM))
868 {
869 nextViewSequence(context);
870 }
871
872 Integer sequence = (Integer) externalContext.getRequestMap().get(RendererUtils.SEQUENCE_PARAM);
873 return sequence.intValue();
874 }
875
876 protected void nextViewSequence(FacesContext facescontext)
877 {
878 ExternalContext externalContext = facescontext.getExternalContext();
879 Object sessionObj = externalContext.getSession(true);
880 synchronized(sessionObj)
881
882 {
883 Map<String, Object> map = externalContext.getSessionMap();
884 Integer sequence = (Integer) map.get(RendererUtils.SEQUENCE_PARAM);
885 if(sequence == null || sequence.intValue() == Integer.MAX_VALUE)
886 {
887 sequence = Integer.valueOf(1);
888 }
889 else
890 {
891 sequence = Integer.valueOf(sequence.intValue() + 1);
892 }
893 map.put(RendererUtils.SEQUENCE_PARAM, sequence);
894 externalContext.getRequestMap().put(RendererUtils.SEQUENCE_PARAM, sequence);
895 }
896 }
897
898 protected Object serializeView(FacesContext context, Object serializedView)
899 {
900 if (log.isLoggable(Level.FINEST))
901 {
902 log.finest("Entering serializeView");
903 }
904
905 if(isSerializeStateInSession(context))
906 {
907 if (log.isLoggable(Level.FINEST))
908 {
909 log.finest("Processing serializeView - serialize state in session");
910 }
911
912 ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
913 try
914 {
915 OutputStream os = baos;
916 if(isCompressStateInSession(context))
917 {
918 if (log.isLoggable(Level.FINEST))
919 {
920 log.finest("Processing serializeView - serialize compressed");
921 }
922
923 os.write(COMPRESSED_FLAG);
924 os = new GZIPOutputStream(os, 1024);
925 }
926 else
927 {
928 if (log.isLoggable(Level.FINEST))
929 {
930 log.finest("Processing serializeView - serialize uncompressed");
931 }
932
933 os.write(UNCOMPRESSED_FLAG);
934 }
935
936 Object[] stateArray = (Object[]) serializedView;
937
938 ObjectOutputStream out = new ObjectOutputStream(os);
939 out.writeObject(stateArray[0]);
940 out.writeObject(stateArray[1]);
941 out.close();
942 baos.close();
943
944 if (log.isLoggable(Level.FINEST))
945 {
946 log.finest("Exiting serializeView - serialized. Bytes : " + baos.size());
947 }
948 return baos.toByteArray();
949 }
950 catch (IOException e)
951 {
952 log.log(Level.SEVERE, "Exiting serializeView - Could not serialize state: " + e.getMessage(), e);
953 return null;
954 }
955 }
956
957
958 if (log.isLoggable(Level.FINEST))
959 {
960 log.finest("Exiting serializeView - do not serialize state in session.");
961 }
962
963 return serializedView;
964
965 }
966
967
968
969
970
971
972
973 protected boolean isSerializeStateInSession(FacesContext context)
974 {
975 String value = context.getExternalContext().getInitParameter(
976 SERIALIZE_STATE_IN_SESSION_PARAM);
977 boolean serialize = DEFAULT_SERIALIZE_STATE_IN_SESSION;
978 if (value != null)
979 {
980 serialize = Boolean.valueOf(value);
981 }
982 return serialize;
983 }
984
985
986
987
988
989
990
991 protected boolean isCompressStateInSession(FacesContext context)
992 {
993 String value = context.getExternalContext().getInitParameter(
994 COMPRESS_SERVER_STATE_PARAM);
995 boolean compress = DEFAULT_COMPRESS_SERVER_STATE_PARAM;
996 if (value != null)
997 {
998 compress = Boolean.valueOf(value);
999 }
1000 return compress;
1001 }
1002
1003 protected Object deserializeView(Object state)
1004 {
1005 if (log.isLoggable(Level.FINEST))
1006 {
1007 log.finest("Entering deserializeView");
1008 }
1009
1010 if(state instanceof byte[])
1011 {
1012 if (log.isLoggable(Level.FINEST))
1013 {
1014 log.finest("Processing deserializeView - deserializing serialized state. Bytes : "
1015 + ((byte[]) state).length);
1016 }
1017
1018 try
1019 {
1020 ByteArrayInputStream bais = new ByteArrayInputStream((byte[]) state);
1021 InputStream is = bais;
1022 if(is.read() == COMPRESSED_FLAG)
1023 {
1024 is = new GZIPInputStream(is);
1025 }
1026 ObjectInputStream ois = null;
1027 try
1028 {
1029 final ObjectInputStream in = new MyFacesObjectInputStream(is);
1030 ois = in;
1031 Object object = null;
1032 if (System.getSecurityManager() != null)
1033 {
1034 object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object []>()
1035 {
1036 public Object[] run() throws PrivilegedActionException, IOException, ClassNotFoundException
1037 {
1038 return new Object[] {in.readObject(), in.readObject()};
1039 }
1040 });
1041 }
1042 else
1043 {
1044 object = new Object[] {in.readObject(), in.readObject()};
1045 }
1046 return object;
1047 }
1048 finally
1049 {
1050 if (ois != null)
1051 {
1052 ois.close();
1053 ois = null;
1054 }
1055 }
1056 }
1057 catch (PrivilegedActionException e)
1058 {
1059 log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
1060 return null;
1061 }
1062 catch (IOException e)
1063 {
1064 log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
1065 return null;
1066 }
1067 catch (ClassNotFoundException e)
1068 {
1069 log.log(Level.SEVERE, "Exiting deserializeView - Could not deserialize state: " + e.getMessage(), e);
1070 return null;
1071 }
1072 }
1073 else if (state instanceof Object[])
1074 {
1075 if (log.isLoggable(Level.FINEST))
1076 {
1077 log.finest("Exiting deserializeView - state not serialized.");
1078 }
1079
1080 return state;
1081 }
1082 else if(state == null)
1083 {
1084 log.severe("Exiting deserializeView - this method should not be called with a null-state.");
1085 return null;
1086 }
1087 else
1088 {
1089 log.severe("Exiting deserializeView - this method should not be called with a state of type : "
1090 + state.getClass());
1091 return null;
1092 }
1093 }
1094
1095 private boolean isLegacyResponseStateManager(ResponseStateManager instance)
1096 {
1097
1098 Method[] methods = instance.getClass().getMethods();
1099 for (Method m : methods)
1100 {
1101 if (m.getName().equals("getState") &&
1102 Arrays.equals(m.getParameterTypes(),new Class[] {FacesContext.class, String.class}))
1103 {
1104 return false;
1105 }
1106 }
1107
1108 return true;
1109 }
1110
1111 protected static class SerializedViewCollection implements Serializable
1112 {
1113 private static final long serialVersionUID = -3734849062185115847L;
1114
1115 private final List<Object> _keys = new ArrayList<Object>(DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
1116 private final Map<Object, Object> _serializedViews = new HashMap<Object, Object>();
1117
1118
1119
1120 private transient Map<Object, Object> _oldSerializedViews = null;
1121
1122 public synchronized void add(FacesContext context, Object state)
1123 {
1124 Object key = new SerializedViewKey(context);
1125 _serializedViews.put(key, state);
1126
1127 while (_keys.remove(key))
1128 {
1129
1130 }
1131 _keys.add(key);
1132
1133 int views = getNumberOfViewsInSession(context);
1134 while (_keys.size() > views)
1135 {
1136 key = _keys.remove(0);
1137 Object oldView = _serializedViews.remove(key);
1138 if (oldView != null &&
1139 !CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF.equals(getCacheOldViewsInSessionMode(context)))
1140 {
1141 getOldSerializedViewsMap().put(key, oldView);
1142 }
1143 }
1144 }
1145
1146
1147
1148
1149
1150
1151
1152 protected int getNumberOfViewsInSession(FacesContext context)
1153 {
1154 String value = context.getExternalContext().getInitParameter(
1155 NUMBER_OF_VIEWS_IN_SESSION_PARAM);
1156 int views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
1157 if (value != null)
1158 {
1159 try
1160 {
1161 views = Integer.parseInt(value);
1162 if (views <= 0)
1163 {
1164 log.severe("Configured value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
1165 + " is not valid, must be an value > 0, using default value ("
1166 + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
1167 views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
1168 }
1169 }
1170 catch (Throwable e)
1171 {
1172 log.log(Level.SEVERE, "Error determining the value for " + NUMBER_OF_VIEWS_IN_SESSION_PARAM
1173 + ", expected an integer value > 0, using default value ("
1174 + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION + "): " + e.getMessage(), e);
1175 }
1176 }
1177 return views;
1178 }
1179
1180
1181
1182
1183 @SuppressWarnings("unchecked")
1184 protected Map<Object, Object> getOldSerializedViewsMap()
1185 {
1186 FacesContext context = FacesContext.getCurrentInstance();
1187 if (_oldSerializedViews == null && context != null)
1188 {
1189 String cacheMode = getCacheOldViewsInSessionMode(context);
1190 if (CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK.equals(cacheMode))
1191 {
1192 _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.WEAK, AbstractReferenceMap.WEAK, true);
1193 }
1194 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK.equals(cacheMode))
1195 {
1196 _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.WEAK, true);
1197 }
1198 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT.equals(cacheMode))
1199 {
1200 _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.SOFT, AbstractReferenceMap.SOFT, true);
1201 }
1202 else if (CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT.equals(cacheMode))
1203 {
1204 _oldSerializedViews = new ReferenceMap(AbstractReferenceMap.HARD, AbstractReferenceMap.SOFT);
1205 }
1206 }
1207
1208 return _oldSerializedViews;
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219 protected String getCacheOldViewsInSessionMode(FacesContext context)
1220 {
1221 String value = context.getExternalContext().getInitParameter(
1222 CACHE_OLD_VIEWS_IN_SESSION_MODE);
1223 if (value == null)
1224 {
1225 return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
1226 }
1227 else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT))
1228 {
1229 return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT;
1230 }
1231 else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK))
1232 {
1233 return CACHE_OLD_VIEWS_IN_SESSION_MODE_SOFT_WEAK;
1234 }
1235 else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK))
1236 {
1237 return CACHE_OLD_VIEWS_IN_SESSION_MODE_WEAK;
1238 }
1239 else if (value.equalsIgnoreCase(CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT))
1240 {
1241 return CACHE_OLD_VIEWS_IN_SESSION_MODE_HARD_SOFT;
1242 }
1243 else
1244 {
1245 return CACHE_OLD_VIEWS_IN_SESSION_MODE_OFF;
1246 }
1247 }
1248
1249 public Object get(Integer sequence, String viewId)
1250 {
1251 Object key = new SerializedViewKey(viewId, sequence);
1252 Object value = _serializedViews.get(key);
1253 if (value == null)
1254 {
1255 Map<Object,Object> oldSerializedViewMap = getOldSerializedViewsMap();
1256 if (oldSerializedViewMap != null)
1257 {
1258 value = oldSerializedViewMap.get(key);
1259 }
1260 }
1261 return value;
1262 }
1263 }
1264
1265 protected static class SerializedViewKey implements Serializable
1266 {
1267 private static final long serialVersionUID = -1170697124386063642L;
1268
1269 private final String _viewId;
1270 private final Integer _sequenceId;
1271
1272 public SerializedViewKey(String viewId, Integer sequence)
1273 {
1274 _sequenceId = sequence;
1275 _viewId = viewId;
1276 }
1277
1278 public SerializedViewKey(FacesContext context)
1279 {
1280 _sequenceId = RendererUtils.getViewSequence(context);
1281 _viewId = context.getViewRoot().getViewId();
1282 }
1283
1284 @Override
1285 public int hashCode()
1286 {
1287 final int prime = 31;
1288 int result = 1;
1289 result = prime * result + ((_sequenceId == null) ? 0 : _sequenceId.hashCode());
1290 result = prime * result + ((_viewId == null) ? 0 : _viewId.hashCode());
1291 return result;
1292 }
1293
1294 @Override
1295 public boolean equals(Object obj)
1296 {
1297 if (this == obj)
1298 {
1299 return true;
1300 }
1301 if (obj == null)
1302 {
1303 return false;
1304 }
1305 if (getClass() != obj.getClass())
1306 {
1307 return false;
1308 }
1309 final SerializedViewKey other = (SerializedViewKey) obj;
1310 if (_sequenceId == null)
1311 {
1312 if (other._sequenceId != null)
1313 {
1314 return false;
1315 }
1316 }
1317 else if (!_sequenceId.equals(other._sequenceId))
1318 {
1319 return false;
1320 }
1321 if (_viewId == null)
1322 {
1323 if (other._viewId != null)
1324 {
1325 return false;
1326 }
1327 }
1328 else if (!_viewId.equals(other._viewId))
1329 {
1330 return false;
1331 }
1332 return true;
1333 }
1334
1335 }
1336 }