dev@javaserverfaces.java.net

Review: support fail over with server side state saving.

From: Jayashri Visvanathan <Jayashri.Visvanathan_at_Sun.COM>
Date: Thu, 05 Aug 2004 12:27:53 -0700

Fix the server side state saving to support failover. Since the
UIComponent instances are not serializable, instead of saving
the view in session, this change bundles saves the SerializedView (result of
calling getTreeStructureToSave() and getTreeStateToSave()) in session.
This can enabled using the ServletContextInitParameter
"com.sun.faces.enableHighAvailability"

M src/com/sun/faces/application/StateManagerImpl.java
  modify state saving in server mode logic in saveSerializedView() and
  restoreView() to support failover case.

M src/com/sun/faces/application/ViewHandlerImpl.java
  Move debug statements inside the "if" block so that they are output only
  for state saving in client case.

M src/com/sun/faces/taglib/jsf_core/ViewTag.java
  stateSaving in server mode if "HA" enabled returns SerializedView and not
  null. So check for that. Otherwise, client side state saving logic will
  be executed.


A test/com/sun/faces/application/TestHAStateManagerImpl.java
  unit test to verify failover state saving mode.


Index: src/com/sun/faces/application/StateManagerImpl.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/StateManagerImpl.java,v
retrieving revision 1.23
diff -u -r1.23 StateManagerImpl.java
--- src/com/sun/faces/application/StateManagerImpl.java 22 Jul 2004 17:40:44 -0000 1.23
+++ src/com/sun/faces/application/StateManagerImpl.java 5 Aug 2004 19:09:21 -0000
@@ -47,12 +47,27 @@
 
     private static final String FACES_VIEW_LIST =
         RIConstants.FACES_PREFIX + "VIEW_LIST";
+
+ private static final String ENABLE_HA_PARAM = "enableHighAvailability";
+
+ private static final String JSF_ENABLE_HA_PARAM =
+ RIConstants.FACES_PREFIX + ENABLE_HA_PARAM;
+
+ private static final String APPSERVER_ENABLE_HA_PARAM =
+ "com.sun.appserver." + ENABLE_HA_PARAM;
+
 
     /**
      * Number of views to be saved in session.
      */
     int noOfViews = 0;
-
+
+ /**
+ * value of <code>com.sun.faces.enableHighAvailability</code>
+ * <code>com.sun.appserver.enableHighAvailability</code>
+ * parameter
+ */
+ private Boolean haStateSavingSet = null;
 
     public SerializedView saveSerializedView(FacesContext context)
         throws IllegalStateException{
@@ -70,12 +85,13 @@
         removeTransientChildrenAndFacets(context, viewRoot, new HashSet());
 
         if (!isSavingStateInClient(context)) {
+ // save state in server
             if (log.isDebugEnabled()) {
- log.debug("Saving view in session for viewId " +
+ log.debug("Begin saving view in session for viewId " +
                           viewRoot.getViewId());
             }
+ Map sessionMap = Util.getSessionMap(context);
             synchronized (this) {
- Map sessionMap = Util.getSessionMap(context);
                 // viewList maintains a list of viewIds corresponding to
                 // all the views stored in session.
                 ArrayList viewList = (ArrayList) sessionMap.get(
@@ -99,10 +115,35 @@
                 if (!foundMatch) {
                     viewList.add(viewRoot.getViewId());
                 }
- sessionMap.put(viewRoot.getViewId(), viewRoot);
                 sessionMap.put(FACES_VIEW_LIST, viewList);
+
+ // if highly available state saving option is chosen, save
+ // the SerializedView in session instead of UIViewRoot since
+ // the UIComponent instances are not serializable.
+ if (isHAStateSavingSet(context)) {
+ if (log.isDebugEnabled()) {
+ log.debug("Highly Available state saving option enabled ");
+ log.debug("Begin creating serialized view for " +
+ viewRoot.getViewId());
+ }
+ result = new SerializedView(getTreeStructureToSave(context),
+ getComponentStateToSave(context));
+ if (log.isDebugEnabled()) {
+ log.debug("End creating serialized view " +
+ viewRoot.getViewId());
+ }
+ sessionMap.put(viewRoot.getViewId(), result);
+
+ } else {
+ sessionMap.put(viewRoot.getViewId(), viewRoot);
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("End saving view in session for viewId " +
+ viewRoot.getViewId());
             }
         } else {
+ // save state in client
             if (log.isDebugEnabled()) {
                 log.debug("Begin creating serialized view for " +
                           viewRoot.getViewId());
@@ -190,6 +231,7 @@
 
         UIViewRoot viewRoot = null;
         if (isSavingStateInClient(context)) {
+ // restore view from response.
             if (log.isDebugEnabled()) {
                 log.debug("Begin restoring view from response " + viewId);
             }
@@ -198,8 +240,8 @@
                 restoreComponentState(context, viewRoot, renderKitId);
             } else {
                 if (log.isDebugEnabled()) {
- log.debug("Possibly a new request. Tree structure could not be restored for "
- + viewId);
+ log.debug("Possibly a new request. Tree structure could not "
+ + " be restored for " + viewId);
                 }
             }
             if (log.isDebugEnabled()) {
@@ -207,15 +249,38 @@
             }
         } else {
             // restore tree from session.
+ // if high available state saving option is chosen, restore
+ // the SerializedView from session instead of UIViewRoot.
+ if (log.isDebugEnabled()) {
+ log.debug("Begin restoring view in session for viewId " + viewId);
+ }
             Map sessionMap = Util.getSessionMap(context);
             synchronized (this) {
- viewRoot = (UIViewRoot) sessionMap.get(viewId);
- if (log.isDebugEnabled()) {
- log.debug(
- "Restoring view from session for viewId " + viewId);
+ if (isHAStateSavingSet(context)) {
+ if (log.isDebugEnabled()) {
+ log.debug("High available state saving option enabled");
+ log.debug("Begin restoring serialized view for "+viewId);
+ }
+ SerializedView serializedView = (SerializedView)
+ sessionMap.get(viewId);
+ viewRoot = restoreSerializedView(context, serializedView,
+ viewId);
+ if (log.isDebugEnabled()) {
+ log.debug("End restoring serialized view " + viewId);
+ }
+
+ } else {
+ viewRoot = (UIViewRoot) sessionMap.get(viewId);
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "Restoring view from session for viewId " + viewId);
+ }
                 }
                 removeViewFromSession(context, viewRoot);
             }
+ if (log.isDebugEnabled()) {
+ log.debug("End restoring view in session for viewId " + viewId);
+ }
         }
         return viewRoot;
     }
@@ -420,5 +485,55 @@
             restoreComponentTreeStructure(facetTreeStructure, facetComponent);
         }
     }
-
+
+ /**
+ * Returns true one of <code>com.sun.faces.enableHighAvailability</code>
+ * or <code>com.sun.appserver.enableHighAvailability</code>
+ * servlet context parameter is set.
+ */
+ protected boolean isHAStateSavingSet(FacesContext context) {
+ if (null != haStateSavingSet) {
+ return haStateSavingSet.booleanValue();
+ }
+ haStateSavingSet = Boolean.FALSE;
+
+ String haStateSavingParam = context.getExternalContext().
+ getInitParameter(JSF_ENABLE_HA_PARAM);
+ if (haStateSavingParam != null){
+ haStateSavingSet = Boolean.valueOf(haStateSavingParam);
+ } else {
+ haStateSavingParam = context.getExternalContext().
+ getInitParameter(APPSERVER_ENABLE_HA_PARAM);
+ if (haStateSavingParam != null){
+ haStateSavingSet = Boolean.valueOf(haStateSavingParam);
+ }
+ }
+ return haStateSavingSet.booleanValue();
+ }
+
+ /**
+ * Returns the <code> UIViewRoot</code> corresponding the
+ * <code> viewId </code> by restoring the view structure and state.
+ */
+ protected UIViewRoot restoreSerializedView(FacesContext context,
+ SerializedView sv, String viewId) {
+ if ( sv == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Possibly a new request. Tree structure could not "
+ + " be restored for " + viewId);
+ }
+ return null;
+ }
+ TreeStructure structRoot = (TreeStructure) sv.getStructure();
+ if (structRoot == null) {
+ return null;
+ }
+ UIComponent viewRoot = structRoot.createComponent();
+ if (viewRoot != null) {
+ restoreComponentTreeStructure(structRoot, viewRoot);
+ Object state = sv.getState();
+ viewRoot.processRestoreState(context, state);
+ }
+ return ((UIViewRoot)viewRoot);
+ }
 }
Index: src/com/sun/faces/application/ViewHandlerImpl.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/application/ViewHandlerImpl.java,v
retrieving revision 1.44
diff -u -r1.44 ViewHandlerImpl.java
--- src/com/sun/faces/application/ViewHandlerImpl.java 20 Jul 2004 21:54:48 -0000 1.44
+++ src/com/sun/faces/application/ViewHandlerImpl.java 5 Aug 2004 19:09:21 -0000
@@ -408,18 +408,20 @@
             message = message +"context " + context;
             throw new NullPointerException(message);
         }
- if (log.isTraceEnabled()) {
- log.trace("Begin writing state to response for viewId" +
- context.getViewRoot().getViewId());
- }
+
         if (Util.getStateManager(context).isSavingStateInClient(context)) {
+ if (log.isTraceEnabled()) {
+ log.trace("Begin writing state to response for viewId" +
+ context.getViewRoot().getViewId());
+ }
             context.getResponseWriter().writeText(
                 RIConstants.SAVESTATE_FIELD_MARKER, null);
- }
- if (log.isTraceEnabled()) {
- log.trace("End writing state to response for viewId" +
+ if (log.isTraceEnabled()) {
+ log.trace("End writing state to response for viewId" +
                       context.getViewRoot().getViewId());
+ }
         }
+
     }
 
 
Index: src/com/sun/faces/taglib/jsf_core/ViewTag.java
===================================================================
RCS file: /cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/taglib/jsf_core/ViewTag.java,v
retrieving revision 1.25
diff -u -r1.25 ViewTag.java
--- src/com/sun/faces/taglib/jsf_core/ViewTag.java 10 May 2004 19:56:08 -0000 1.25
+++ src/com/sun/faces/taglib/jsf_core/ViewTag.java 5 Aug 2004 19:09:22 -0000
@@ -176,7 +176,11 @@
                 Util.SAVING_STATE_ERROR_MESSAGE_ID, params), ie);
         }
         try {
- if (view == null) {
+ // if high availability is enabled, view will not null even in the
+ // state saving in server mode. Thats why it is required to check
+ // state saving method here.
+ if (view == null ||
+ (!(stateManager.isSavingStateInClient(context)))) {
                 getPreviousOut().write(content);
             } else {
                 contentLen = content.length();



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe_at_javaserverfaces.dev.java.net
For additional commands, e-mail: dev-help_at_javaserverfaces.dev.java.net