001: /*
002: * Copyright 2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.myfaces.application.jsp;
017:
018: import org.apache.commons.collections.map.AbstractReferenceMap;
019: import org.apache.commons.collections.map.ReferenceMap;
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022: import org.apache.myfaces.application.MyfacesStateManager;
023: import org.apache.myfaces.application.TreeStructureManager;
024: import org.apache.myfaces.renderkit.MyfacesResponseStateManager;
025: import org.apache.myfaces.shared_impl.renderkit.RendererUtils;
026: import org.apache.myfaces.shared_impl.util.MyFacesObjectInputStream;
027:
028: import javax.faces.FactoryFinder;
029: import javax.faces.component.NamingContainer;
030: import javax.faces.component.UIComponent;
031: import javax.faces.component.UIViewRoot;
032: import javax.faces.context.ExternalContext;
033: import javax.faces.context.FacesContext;
034: import javax.faces.render.RenderKit;
035: import javax.faces.render.RenderKitFactory;
036: import javax.faces.render.ResponseStateManager;
037: import java.io.*;
038: import java.lang.reflect.Method;
039: import java.util.*;
040: import java.util.zip.GZIPInputStream;
041: import java.util.zip.GZIPOutputStream;
042:
043: /**
044: * Default StateManager implementation for use when views are defined
045: * via tags in JSP pages.
046: *
047: * @author Thomas Spiegl (latest modification by $Author: baranda $)
048: * @author Manfred Geiler
049: * @version $Revision: 545266 $ $Date: 2007-06-07 20:48:06 +0200 (Do, 07 Jun 2007) $
050: */
051: public class JspStateManagerImpl extends MyfacesStateManager {
052: private static final Log log = LogFactory
053: .getLog(JspStateManagerImpl.class);
054: private static final String SERIALIZED_VIEW_SESSION_ATTR = JspStateManagerImpl.class
055: .getName()
056: + ".SERIALIZED_VIEW";
057: private static final String SERIALIZED_VIEW_REQUEST_ATTR = JspStateManagerImpl.class
058: .getName()
059: + ".SERIALIZED_VIEW";
060: private static final String RESTORED_SERIALIZED_VIEW_REQUEST_ATTR = JspStateManagerImpl.class
061: .getName()
062: + ".RESTORED_SERIALIZED_VIEW";
063:
064: /**
065: * Only applicable if state saving method is "server" (= default).
066: * Defines the amount (default = 20) of the latest views are stored in session.
067: */
068: /**
069: * Only applicable if state saving method is "server" (= default).
070: * Defines the amount (default = 20) of the latest views are stored in session.
071: */
072: private static final String NUMBER_OF_VIEWS_IN_SESSION_PARAM = "org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION";
073:
074: /**
075: * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
076: */
077: /**
078: * Default value for <code>org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION</code> context parameter.
079: */
080: private static final int DEFAULT_NUMBER_OF_VIEWS_IN_SESSION = 20;
081:
082: /**
083: * Only applicable if state saving method is "server" (= default).
084: * If <code>true</code> (default) the state will be serialized to a byte stream before it is written to the session.
085: * If <code>false</code> the state will not be serialized to a byte stream.
086: */
087: private static final String SERIALIZE_STATE_IN_SESSION_PARAM = "org.apache.myfaces.SERIALIZE_STATE_IN_SESSION";
088:
089: /**
090: * Only applicable if state saving method is "server" (= default) and if <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> is <code>true</code> (= default).
091: * If <code>true</code> (default) the serialized state will be compressed before it is written to the session.
092: * If <code>false</code> the state will not be compressed.
093: */
094: private static final String COMPRESS_SERVER_STATE_PARAM = "org.apache.myfaces.COMPRESS_STATE_IN_SESSION";
095:
096: /**
097: * Default value for <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
098: */
099: private static final boolean DEFAULT_COMPRESS_SERVER_STATE_PARAM = true;
100:
101: /**
102: * Default value for <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
103: */
104: private static final boolean DEFAULT_SERIALIZE_STATE_IN_SESSION = true;
105:
106: private static final int UNCOMPRESSED_FLAG = 0;
107: private static final int COMPRESSED_FLAG = 1;
108:
109: private RenderKitFactory _renderKitFactory = null;
110:
111: public JspStateManagerImpl() {
112: if (log.isTraceEnabled())
113: log.trace("New JspStateManagerImpl instance created");
114: }
115:
116: protected Object getComponentStateToSave(FacesContext facesContext) {
117: if (log.isTraceEnabled())
118: log.trace("Entering getComponentStateToSave");
119:
120: UIViewRoot viewRoot = facesContext.getViewRoot();
121: if (viewRoot.isTransient()) {
122: return null;
123: }
124:
125: Object serializedComponentStates = viewRoot
126: .processSaveState(facesContext);
127: //Locale is a state attribute of UIViewRoot and need not be saved explicitly
128: if (log.isTraceEnabled())
129: log.trace("Exiting getComponentStateToSave");
130: return serializedComponentStates;
131: }
132:
133: /**
134: * Return an object which contains info about the UIComponent type
135: * of each node in the view tree. This allows an identical UIComponent
136: * tree to be recreated later, though all the components will have
137: * just default values for their members.
138: */
139: protected Object getTreeStructureToSave(FacesContext facesContext) {
140: if (log.isTraceEnabled())
141: log.trace("Entering getTreeStructureToSave");
142: UIViewRoot viewRoot = facesContext.getViewRoot();
143: if (viewRoot.isTransient()) {
144: return null;
145: }
146: TreeStructureManager tsm = new TreeStructureManager();
147: Object retVal = tsm.buildTreeStructureToSave(viewRoot);
148: if (log.isTraceEnabled())
149: log.trace("Exiting getTreeStructureToSave");
150: return retVal;
151: }
152:
153: /**
154: * Given a tree of UIComponent objects created the default constructor
155: * for each node, retrieve saved state info (from either the client or
156: * the server) and walk the tree restoring the members of each node
157: * from the saved state information.
158: */
159: protected void restoreComponentState(FacesContext facesContext,
160: UIViewRoot uiViewRoot, String renderKitId) {
161: if (log.isTraceEnabled())
162: log.trace("Entering restoreComponentState");
163:
164: //===========================================
165: // first, locate the saved state information
166: //===========================================
167:
168: Object serializedComponentStates;
169: if (isSavingStateInClient(facesContext)) {
170: RenderKit renderKit = getRenderKitFactory().getRenderKit(
171: facesContext, renderKitId);
172: ResponseStateManager responseStateManager = renderKit
173: .getResponseStateManager();
174:
175: if (isLegacyResponseStateManager(responseStateManager)) {
176: serializedComponentStates = responseStateManager
177: .getComponentStateToRestore(facesContext);
178: } else {
179: serializedComponentStates = responseStateManager
180: .getState(facesContext, uiViewRoot.getViewId());
181: }
182: if (serializedComponentStates == null) {
183: log
184: .error("No serialized component state found in client request!");
185: // mark UIViewRoot invalid by resetting view id
186: uiViewRoot.setViewId(null);
187: return;
188: }
189: } else {
190: Object[] stateObj = (Object[]) getSerializedViewFromServletSession(
191: facesContext, uiViewRoot.getViewId());
192: if (stateObj == null) {
193: log
194: .error("No serialized view found in server session!");
195: // mark UIViewRoot invalid by resetting view id
196: uiViewRoot.setViewId(null);
197: return;
198: }
199: SerializedView serializedView = new SerializedView(
200: stateObj[0], stateObj[1]);
201: serializedComponentStates = serializedView.getState();
202: if (serializedComponentStates == null) {
203: log
204: .error("No serialized component state found in server session!");
205: return;
206: }
207: }
208:
209: if (uiViewRoot.getRenderKitId() == null) {
210: //Just to be sure...
211: uiViewRoot.setRenderKitId(renderKitId);
212: }
213:
214: // now ask the view root component to restore its state
215: uiViewRoot.processRestoreState(facesContext,
216: serializedComponentStates);
217:
218: if (log.isTraceEnabled())
219: log.trace("Exiting restoreComponentState");
220: }
221:
222: /**
223: * See getTreeStructureToSave.
224: */
225: protected UIViewRoot restoreTreeStructure(
226: FacesContext facesContext, String viewId, String renderKitId) {
227: if (log.isTraceEnabled())
228: log.trace("Entering restoreTreeStructure");
229:
230: UIViewRoot uiViewRoot;
231: if (isSavingStateInClient(facesContext)) {
232: //reconstruct tree structure from request
233: RenderKit rk = getRenderKitFactory().getRenderKit(
234: facesContext, renderKitId);
235: ResponseStateManager responseStateManager = rk
236: .getResponseStateManager();
237: Object treeStructure = responseStateManager
238: .getTreeStructureToRestore(facesContext, viewId);
239: if (treeStructure == null) {
240: if (log.isDebugEnabled())
241: log
242: .debug("Exiting restoreTreeStructure - No tree structure state found in client request");
243: return null;
244: }
245:
246: TreeStructureManager tsm = new TreeStructureManager();
247: uiViewRoot = tsm.restoreTreeStructure(treeStructure);
248: if (log.isTraceEnabled())
249: log
250: .trace("Tree structure restored from client request");
251: } else {
252: //reconstruct tree structure from ServletSession
253: Object[] stateObj = (Object[]) getSerializedViewFromServletSession(
254: facesContext, viewId);
255: if (stateObj == null) {
256: if (log.isDebugEnabled())
257: log
258: .debug("Exiting restoreTreeStructure - No serialized view found in server session!");
259: return null;
260: }
261:
262: SerializedView serializedView = new SerializedView(
263: stateObj[0], stateObj[1]);
264: Object treeStructure = serializedView.getStructure();
265: if (treeStructure == null) {
266: if (log.isDebugEnabled())
267: log
268: .debug("Exiting restoreTreeStructure - No tree structure state found in server session, former UIViewRoot must have been transient");
269: return null;
270: }
271:
272: TreeStructureManager tsm = new TreeStructureManager();
273: uiViewRoot = tsm.restoreTreeStructure(serializedView
274: .getStructure());
275: if (log.isTraceEnabled())
276: log
277: .trace("Tree structure restored from server session");
278: }
279:
280: if (log.isTraceEnabled())
281: log.trace("Exiting restoreTreeStructure");
282: return uiViewRoot;
283: }
284:
285: public UIViewRoot restoreView(FacesContext facesContext,
286: String viewId, String renderKitId) {
287: if (log.isTraceEnabled())
288: log.trace("Entering restoreView - viewId: " + viewId
289: + " ; renderKitId: " + renderKitId);
290:
291: Object state;
292: if (isSavingStateInClient(facesContext)) {
293: if (log.isTraceEnabled())
294: log.trace("Restoring view from client");
295:
296: RenderKit renderKit = getRenderKitFactory().getRenderKit(
297: facesContext, renderKitId);
298: ResponseStateManager responseStateManager = renderKit
299: .getResponseStateManager();
300: state = responseStateManager.getState(facesContext, viewId);
301: } else {
302: if (log.isTraceEnabled())
303: log.trace("Restoring view from session");
304:
305: state = getSerializedViewFromServletSession(facesContext,
306: viewId);
307: }
308:
309: UIViewRoot uiViewRoot = null;
310:
311: if (state != null) {
312: Object[] stateArray = (Object[]) state;
313: TreeStructureManager tsm = new TreeStructureManager();
314: uiViewRoot = tsm.restoreTreeStructure(stateArray[0]);
315:
316: if (uiViewRoot != null) {
317: uiViewRoot.processRestoreState(facesContext,
318: stateArray[1]);
319: }
320: }
321:
322: /*
323: UIViewRoot uiViewRoot = restoreTreeStructure(facesContext, viewId, renderKitId);
324: if (uiViewRoot != null)
325: {
326: uiViewRoot.setViewId(viewId);
327:
328: restoreComponentState(facesContext, uiViewRoot, renderKitId);
329:
330: String restoredViewId = uiViewRoot.getViewId();
331: if (restoredViewId == null || !(restoredViewId.equals(viewId)))
332: {
333: if (log.isTraceEnabled()) log.trace("Exiting restoreView - restored view is null.");
334: return null;
335: }
336: }
337: */
338: if (log.isTraceEnabled())
339: log.trace("Exiting restoreView - " + viewId);
340:
341: return uiViewRoot;
342: }
343:
344: public SerializedView saveSerializedView(FacesContext facesContext)
345: throws IllegalStateException {
346: if (log.isTraceEnabled())
347: log.trace("Entering saveSerializedView");
348:
349: checkForDuplicateIds(facesContext, facesContext.getViewRoot(),
350: new HashSet<String>());
351:
352: if (log.isTraceEnabled())
353: log
354: .trace("Processing saveSerializedView - Checked for duplicate Ids");
355:
356: ExternalContext externalContext = facesContext
357: .getExternalContext();
358:
359: // SerializedView already created before within this request?
360: Object serializedView = externalContext.getRequestMap().get(
361: SERIALIZED_VIEW_REQUEST_ATTR);
362: if (serializedView == null) {
363: if (log.isTraceEnabled())
364: log
365: .trace("Processing saveSerializedView - create new serialized view");
366:
367: // first call to saveSerializedView --> create SerializedView
368: Object treeStruct = getTreeStructureToSave(facesContext);
369: Object compStates = getComponentStateToSave(facesContext);
370: serializedView = new Object[] { treeStruct, compStates };
371: externalContext.getRequestMap().put(
372: SERIALIZED_VIEW_REQUEST_ATTR, serializedView);
373:
374: if (log.isTraceEnabled())
375: log
376: .trace("Processing saveSerializedView - new serialized view created");
377: }
378:
379: Object[] serializedViewArray = (Object[]) serializedView;
380:
381: if (!isSavingStateInClient(facesContext)) {
382: if (log.isTraceEnabled())
383: log
384: .trace("Processing saveSerializedView - server-side state saving - save state");
385: //save state in server session
386: saveSerializedViewInServletSession(facesContext,
387: serializedView);
388:
389: if (log.isTraceEnabled())
390: log
391: .trace("Exiting saveSerializedView - server-side state saving - saved state");
392: return new SerializedView(serializedViewArray[0],
393: new Object[0]);
394: }
395:
396: if (log.isTraceEnabled())
397: log
398: .trace("Exiting saveSerializedView - client-side state saving");
399:
400: return new SerializedView(serializedViewArray[0],
401: serializedViewArray[1]);
402: }
403:
404: private static void checkForDuplicateIds(FacesContext context,
405: UIComponent component, Set<String> ids) {
406: String id = component.getId();
407: if (id != null && !ids.add(id)) {
408: throw new IllegalStateException("Client-id : " + id
409: + " is duplicated in the faces tree. Component : "
410: + component.getClientId(context) + ", path: "
411: + getPathToComponent(component));
412: }
413: Iterator it = component.getFacetsAndChildren();
414: boolean namingContainer = component instanceof NamingContainer;
415: while (it.hasNext()) {
416: UIComponent kid = (UIComponent) it.next();
417: if (namingContainer) {
418: checkForDuplicateIds(context, kid,
419: new HashSet<String>());
420: } else {
421: checkForDuplicateIds(context, kid, ids);
422: }
423: }
424: }
425:
426: private static String getPathToComponent(UIComponent component) {
427: StringBuffer buf = new StringBuffer();
428:
429: if (component == null) {
430: buf.append("{Component-Path : ");
431: buf.append("[null]}");
432: return buf.toString();
433: }
434:
435: getPathToComponent(component, buf);
436:
437: buf.insert(0, "{Component-Path : ");
438: buf.append("}");
439:
440: return buf.toString();
441: }
442:
443: private static void getPathToComponent(UIComponent component,
444: StringBuffer buf) {
445: if (component == null)
446: return;
447:
448: StringBuffer intBuf = new StringBuffer();
449:
450: intBuf.append("[Class: ");
451: intBuf.append(component.getClass().getName());
452: if (component instanceof UIViewRoot) {
453: intBuf.append(",ViewId: ");
454: intBuf.append(((UIViewRoot) component).getViewId());
455: } else {
456: intBuf.append(",Id: ");
457: intBuf.append(component.getId());
458: }
459: intBuf.append("]");
460:
461: buf.insert(0, intBuf.toString());
462:
463: if (component != null) {
464: getPathToComponent(component.getParent(), buf);
465: }
466: }
467:
468: public void writeState(FacesContext facesContext,
469: SerializedView serializedView) throws IOException {
470: if (log.isTraceEnabled())
471: log.trace("Entering writeState");
472:
473: UIViewRoot uiViewRoot = facesContext.getViewRoot();
474: //save state in response (client)
475: RenderKit renderKit = getRenderKitFactory().getRenderKit(
476: facesContext, uiViewRoot.getRenderKitId());
477: ResponseStateManager responseStateManager = renderKit
478: .getResponseStateManager();
479:
480: if (isLegacyResponseStateManager(responseStateManager)) {
481: responseStateManager.writeState(facesContext,
482: serializedView);
483: } else {
484: Object[] state = new Object[2];
485: state[0] = serializedView.getStructure();
486: state[1] = serializedView.getState();
487: responseStateManager.writeState(facesContext, state);
488: }
489:
490: if (log.isTraceEnabled())
491: log.trace("Exiting writeState");
492:
493: }
494:
495: /**
496: * MyFaces extension
497: * @param facesContext
498: * @param serializedView
499: * @throws IOException
500: */
501: public void writeStateAsUrlParams(FacesContext facesContext,
502: SerializedView serializedView) throws IOException {
503: if (log.isTraceEnabled())
504: log.trace("Entering writeStateAsUrlParams");
505:
506: if (isSavingStateInClient(facesContext)) {
507: if (log.isTraceEnabled())
508: log
509: .trace("Processing writeStateAsUrlParams - client-side state saving writing state");
510:
511: UIViewRoot uiViewRoot = facesContext.getViewRoot();
512: //save state in response (client)
513: RenderKit renderKit = getRenderKitFactory().getRenderKit(
514: facesContext, uiViewRoot.getRenderKitId());
515: ResponseStateManager responseStateManager = renderKit
516: .getResponseStateManager();
517: if (responseStateManager instanceof MyfacesResponseStateManager) {
518: ((MyfacesResponseStateManager) responseStateManager)
519: .writeStateAsUrlParams(facesContext,
520: serializedView);
521: } else {
522: log
523: .error("ResponseStateManager of render kit "
524: + uiViewRoot.getRenderKitId()
525: + " is no MyfacesResponseStateManager and does not support saving state in url parameters.");
526: }
527: }
528:
529: if (log.isTraceEnabled())
530: log.trace("Exiting writeStateAsUrlParams");
531: }
532:
533: //helpers
534:
535: protected RenderKitFactory getRenderKitFactory() {
536: if (_renderKitFactory == null) {
537: _renderKitFactory = (RenderKitFactory) FactoryFinder
538: .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
539: }
540: return _renderKitFactory;
541: }
542:
543: protected void saveSerializedViewInServletSession(
544: FacesContext context, Object serializedView) {
545: Map<String, Object> sessionMap = context.getExternalContext()
546: .getSessionMap();
547: SerializedViewCollection viewCollection = (SerializedViewCollection) sessionMap
548: .get(SERIALIZED_VIEW_SESSION_ATTR);
549: if (viewCollection == null) {
550: viewCollection = new SerializedViewCollection();
551: sessionMap
552: .put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
553: }
554: viewCollection.add(context, serializeView(context,
555: serializedView));
556: // replace the value to notify the container about the change
557: sessionMap.put(SERIALIZED_VIEW_SESSION_ATTR, viewCollection);
558: }
559:
560: protected Object getSerializedViewFromServletSession(
561: FacesContext context, String viewId) {
562: ExternalContext externalContext = context.getExternalContext();
563: Map<String, Object> requestMap = externalContext
564: .getRequestMap();
565: Object serializedView = null;
566: if (requestMap
567: .containsKey(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR)) {
568: serializedView = requestMap
569: .get(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR);
570: } else {
571: SerializedViewCollection viewCollection = (SerializedViewCollection) externalContext
572: .getSessionMap().get(SERIALIZED_VIEW_SESSION_ATTR);
573: if (viewCollection != null) {
574: String sequenceStr = externalContext
575: .getRequestParameterMap().get(
576: RendererUtils.SEQUENCE_PARAM);
577: Integer sequence = null;
578: if (sequenceStr == null) {
579: // use latest sequence
580: Map map = externalContext.getSessionMap();
581: sequence = (Integer) map
582: .get(RendererUtils.SEQUENCE_PARAM);
583: } else {
584: sequence = new Integer(sequenceStr);
585: }
586: if (sequence != null) {
587: Object state = viewCollection.get(sequence, viewId);
588: if (state != null) {
589: serializedView = deserializeView(state);
590: }
591: }
592: }
593: requestMap.put(RESTORED_SERIALIZED_VIEW_REQUEST_ATTR,
594: serializedView);
595: nextViewSequence(context);
596: }
597: return serializedView;
598: }
599:
600: protected void nextViewSequence(FacesContext facescontext) {
601: ExternalContext externalContext = facescontext
602: .getExternalContext();
603: Object sessionObj = externalContext.getSession(true);
604: synchronized (sessionObj) // synchronized to increase sequence if multiple requests
605: // are handled at the same time for the session
606: {
607: Map<String, Object> map = externalContext.getSessionMap();
608: Integer sequence = (Integer) map
609: .get(RendererUtils.SEQUENCE_PARAM);
610: if (sequence == null
611: || sequence.intValue() == Integer.MAX_VALUE) {
612: sequence = new Integer(1);
613: } else {
614: sequence = new Integer(sequence.intValue() + 1);
615: }
616: map.put(RendererUtils.SEQUENCE_PARAM, sequence);
617: externalContext.getRequestMap().put(
618: RendererUtils.SEQUENCE_PARAM, sequence);
619: }
620: }
621:
622: protected Object serializeView(FacesContext context,
623: Object serializedView) {
624: if (log.isTraceEnabled())
625: log.trace("Entering serializeView");
626:
627: if (isSerializeStateInSession(context)) {
628: if (log.isTraceEnabled())
629: log
630: .trace("Processing serializeView - serialize state in session");
631:
632: ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
633: try {
634: OutputStream os = baos;
635: if (isCompressStateInSession(context)) {
636: if (log.isTraceEnabled())
637: log
638: .trace("Processing serializeView - serialize compressed");
639:
640: os.write(COMPRESSED_FLAG);
641: os = new GZIPOutputStream(os, 1024);
642: } else {
643: if (log.isTraceEnabled())
644: log
645: .trace("Processing serializeView - serialize uncompressed");
646:
647: os.write(UNCOMPRESSED_FLAG);
648: }
649:
650: Object[] stateArray = (Object[]) serializedView;
651:
652: ObjectOutputStream out = new ObjectOutputStream(os);
653: out.writeObject(stateArray[0]);
654: out.writeObject(stateArray[1]);
655: out.close();
656: baos.close();
657:
658: if (log.isTraceEnabled())
659: log
660: .trace("Exiting serializeView - serialized. Bytes : "
661: + baos.size());
662: return baos.toByteArray();
663: } catch (IOException e) {
664: log.error(
665: "Exiting serializeView - Could not serialize state: "
666: + e.getMessage(), e);
667: return null;
668: }
669: }
670:
671: if (log.isTraceEnabled())
672: log
673: .trace("Exiting serializeView - do not serialize state in session.");
674:
675: return serializedView;
676:
677: }
678:
679: /**
680: * Reads the value of the <code>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</code> context parameter.
681: * @see SERIALIZE_STATE_IN_SESSION_PARAM
682: * @param context <code>FacesContext</code> for the request we are processing.
683: * @return boolean true, if the server state should be serialized in the session
684: */
685: protected boolean isSerializeStateInSession(FacesContext context) {
686: String value = context.getExternalContext().getInitParameter(
687: SERIALIZE_STATE_IN_SESSION_PARAM);
688: boolean serialize = DEFAULT_SERIALIZE_STATE_IN_SESSION;
689: if (value != null) {
690: serialize = Boolean.valueOf(value);
691: }
692: return serialize;
693: }
694:
695: /**
696: * Reads the value of the <code>org.apache.myfaces.COMPRESS_STATE_IN_SESSION</code> context parameter.
697: * @see COMPRESS_SERVER_STATE_PARAM
698: * @param context <code>FacesContext</code> for the request we are processing.
699: * @return boolean true, if the server state steam should be compressed
700: */
701: protected boolean isCompressStateInSession(FacesContext context) {
702: String value = context.getExternalContext().getInitParameter(
703: COMPRESS_SERVER_STATE_PARAM);
704: boolean compress = DEFAULT_COMPRESS_SERVER_STATE_PARAM;
705: if (value != null) {
706: compress = Boolean.valueOf(value);
707: }
708: return compress;
709: }
710:
711: protected Object deserializeView(Object state) {
712: if (log.isTraceEnabled())
713: log.trace("Entering deserializeView");
714:
715: if (state instanceof byte[]) {
716: if (log.isTraceEnabled())
717: log
718: .trace("Processing deserializeView - deserializing serialized state. Bytes : "
719: + ((byte[]) state).length);
720:
721: try {
722: ByteArrayInputStream bais = new ByteArrayInputStream(
723: (byte[]) state);
724: InputStream is = bais;
725: if (is.read() == COMPRESSED_FLAG) {
726: is = new GZIPInputStream(is);
727: }
728: ObjectInputStream in = new MyFacesObjectInputStream(is);
729: return new Object[] { in.readObject(), in.readObject() };
730: } catch (IOException e) {
731: log.error(
732: "Exiting deserializeView - Could not deserialize state: "
733: + e.getMessage(), e);
734: return null;
735: } catch (ClassNotFoundException e) {
736: log.error(
737: "Exiting deserializeView - Could not deserialize state: "
738: + e.getMessage(), e);
739: return null;
740: }
741: } else if (state instanceof Object[]) {
742: if (log.isTraceEnabled())
743: log
744: .trace("Exiting deserializeView - state not serialized.");
745:
746: return state;
747: } else if (state == null) {
748: log
749: .error("Exiting deserializeView - this method should not be called with a null-state.");
750: return null;
751: } else {
752: log
753: .error("Exiting deserializeView - this method should not be called with a state of type : "
754: + state.getClass());
755: return null;
756: }
757: }
758:
759: private boolean isLegacyResponseStateManager(
760: ResponseStateManager instance) {
761:
762: Method[] methods = instance.getClass().getMethods();
763: for (Method m : methods) {
764: if (m.getName().equals("getState")
765: && Arrays.equals(m.getParameterTypes(),
766: new Class[] { FacesContext.class,
767: String.class })) {
768: return false;
769: }
770: }
771:
772: return true;
773: }
774:
775: protected static class SerializedViewCollection implements
776: Serializable {
777: private static final long serialVersionUID = -3734849062185115847L;
778:
779: private final List<Object> _keys = new ArrayList<Object>(
780: DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
781: private final Map<Object, Object> _serializedViews = new HashMap<Object, Object>();
782:
783: // old views will be hold as soft references which will be removed by
784: // the garbage collector if free memory is low
785: private transient Map<Object, Object> _oldSerializedViews = null;
786:
787: public synchronized void add(FacesContext context, Object state) {
788: Object key = new SerializedViewKey(context);
789: _serializedViews.put(key, state);
790:
791: while (_keys.remove(key))
792: ;
793: _keys.add(key);
794:
795: int views = getNumberOfViewsInSession(context);
796: while (_keys.size() > views) {
797: key = _keys.remove(0);
798: Object oldView = _serializedViews.remove(key);
799: if (oldView != null) {
800: getOldSerializedViewsMap().put(key, oldView);
801: }
802: }
803: }
804:
805: /**
806: * Reads the amount (default = 20) of views to be stored in session.
807: * @see NUMBER_OF_VIEWS_IN_SESSION_PARAM
808: * @param context FacesContext for the current request, we are processing
809: * @return Number vf views stored in the session
810: */
811: protected int getNumberOfViewsInSession(FacesContext context) {
812: String value = context.getExternalContext()
813: .getInitParameter(NUMBER_OF_VIEWS_IN_SESSION_PARAM);
814: int views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
815: if (value != null) {
816: try {
817: views = Integer.parseInt(value);
818: if (views <= 0) {
819: log
820: .error("Configured value for "
821: + NUMBER_OF_VIEWS_IN_SESSION_PARAM
822: + " is not valid, must be an value > 0, using default value ("
823: + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION);
824: views = DEFAULT_NUMBER_OF_VIEWS_IN_SESSION;
825: }
826: } catch (Throwable e) {
827: log
828: .error(
829: "Error determining the value for "
830: + NUMBER_OF_VIEWS_IN_SESSION_PARAM
831: + ", expected an integer value > 0, using default value ("
832: + DEFAULT_NUMBER_OF_VIEWS_IN_SESSION
833: + "): " + e.getMessage(), e);
834: }
835: }
836: return views;
837: }
838:
839: /**
840: * @return old serialized views map
841: */
842: protected Map<Object, Object> getOldSerializedViewsMap() {
843: if (_oldSerializedViews == null) {
844: _oldSerializedViews = new ReferenceMap(
845: AbstractReferenceMap.WEAK,
846: AbstractReferenceMap.WEAK, true);
847: }
848: return _oldSerializedViews;
849: }
850:
851: public Object get(Integer sequence, String viewId) {
852: Object key = new SerializedViewKey(viewId, sequence);
853: Object value = _serializedViews.get(key);
854: if (value == null) {
855: value = getOldSerializedViewsMap().get(key);
856: }
857: return value;
858: }
859: }
860:
861: protected static class SerializedViewKey implements Serializable {
862: private static final long serialVersionUID = -1170697124386063642L;
863:
864: private final String _viewId;
865: private final Integer _sequenceId;
866:
867: public SerializedViewKey(String viewId, Integer sequence) {
868: _sequenceId = sequence;
869: _viewId = viewId;
870: }
871:
872: public SerializedViewKey(FacesContext context) {
873: _sequenceId = RendererUtils.getViewSequence(context);
874: _viewId = context.getViewRoot().getViewId();
875: }
876:
877: @Override
878: public int hashCode() {
879: final int PRIME = 31;
880: int result = 1;
881: result = PRIME
882: * result
883: + ((_sequenceId == null) ? 0 : _sequenceId
884: .hashCode());
885: result = PRIME * result
886: + ((_viewId == null) ? 0 : _viewId.hashCode());
887: return result;
888: }
889:
890: @Override
891: public boolean equals(Object obj) {
892: if (this == obj)
893: return true;
894: if (obj == null)
895: return false;
896: if (getClass() != obj.getClass())
897: return false;
898: final SerializedViewKey other = (SerializedViewKey) obj;
899: if (_sequenceId == null) {
900: if (other._sequenceId != null)
901: return false;
902: } else if (!_sequenceId.equals(other._sequenceId))
903: return false;
904: if (_viewId == null) {
905: if (other._viewId != null)
906: return false;
907: } else if (!_viewId.equals(other._viewId))
908: return false;
909: return true;
910: }
911:
912: }
913: }
|