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