dev@javaserverfaces.java.net

[REVIEW] New StateManager implementation

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Thu, 18 May 2006 13:35:30 -0700

New StateManager implemenatation based off
jhooks directed array graph suggestion.
This alternate version is uses a lighter
weight structure for storing the tree.

I've attached the source of the new StateManagerImpl
as the diff is pretty much useless.


SECTION: Modified Files
----------------------------
M src/com/sun/faces/application/StateManagerImpl.java
 
M src/com/sun/faces/util/DebugUtil.java
 - commented out the methods that
   would print the tree based off a
   TreeStructure object - they weren't
   in use.

M test/com/sun/faces/lifecycle/TestSaveStateInPage.java
 - modified to relfect new changes

R src/com/sun/faces/util/TreeStructure.java
A test/com/sun/faces/util/TreeStructure.java
  - Moved TreeStructure to the util package
    under test as the DeprStateManagerImpl still
    uses it.


SECTION: Diffs
----------------------------
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.48
diff -u -r1.48 StateManagerImpl.java
--- src/com/sun/faces/application/StateManagerImpl.java 17 May 2006
19:00:44 -0000 1.48
+++ src/com/sun/faces/application/StateManagerImpl.java 18 May 2006
20:30:41 -0000
@@ -1,36 +1,31 @@
-/*
- * $Id: StateManagerImpl.java,v 1.48 2006/05/17 19:00:44 rlubke Exp $
- */
-
 /*
-* The contents of this file are subject to the terms
-* of the Common Development and Distribution License
-* (the License). You may not use this file except in
-* compliance with the License.
-*
-* You can obtain a copy of the License at
-* https://javaserverfaces.dev.java.net/CDDL.html or
-* legal/CDDLv1.0.txt.
-* See the License for the specific language governing
-* permission and limitations under the License.
-*
-* When distributing Covered Code, include this CDDL
-* Header Notice in each file and include the License file
-* at legal/CDDLv1.0.txt.
-* If applicable, add the following below the CDDL Header,
-* with the fields enclosed by brackets [] replaced by
-* your own identifying information:
-* "Portions Copyrighted [year] [name of copyright owner]"
-*
-* [Name of File] [ver.__] [Date]
-*
-* Copyright 2005 Sun Microsystems Inc. All Rights Reserved
-*/
-
-// StateManagerImpl.java
+ * The contents of this file are subject to the terms
+ * of the Common Development and Distribution License
+ * (the License). You may not use this file except in
+ * compliance with the License.
+ *
+ * You can obtain a copy of the License at
+ * https://javaserverfaces.dev.java.net/CDDL.html or
+ * legal/CDDLv1.0.txt.
+ * See the License for the specific language governing
+ * permission and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL
+ * Header Notice in each file and include the License file
+ * at legal/CDDLv1.0.txt.
+ * If applicable, add the following below the CDDL Header,
+ * with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * [Name of File] [ver.__] [Date]
+ *
+ * Copyright 2006 Sun Microsystems Inc. All Rights Reserved
+ */
 
 package com.sun.faces.application;
 
+import javax.faces.FacesException;
 import javax.faces.application.StateManager;
 import javax.faces.component.NamingContainer;
 import javax.faces.component.UIComponent;
@@ -39,12 +34,19 @@
 import javax.faces.context.FacesContext;
 import javax.faces.render.ResponseStateManager;
 
+import java.io.Externalizable;
 import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -54,192 +56,47 @@
 import com.sun.faces.renderkit.RenderKitUtils;
 import com.sun.faces.util.LRUMap;
 import com.sun.faces.util.MessageUtils;
-import com.sun.faces.util.TreeStructure;
 import com.sun.faces.util.Util;
 
-/**
- * <B>StateManagerImpl</B> is the default implementation class for
- * StateManager.
- *
- * @version $Id: StateManagerImpl.java,v 1.48 2006/05/17 19:00:44
rlubke Exp $
- * @see javax.faces.application.ViewHandler
- */
 public class StateManagerImpl extends StateManager {
 
+ private static final Logger LOGGER =
+ Util.getLogger(Util.FACES_LOGGER + Util.APPLICATION_LOGGER);
 
- // Log instance for this class
- private static final Logger LOGGER =
- Util.getLogger(Util.FACES_LOGGER + Util.APPLICATION_LOGGER);
-
- /**
- * Keyed by renderKitId, this Map contains a boolean that
- * indicates if the ResponseStateManager for the renderKitId
- * has non-deprecated methods. True indicates the presence
- * of non-deprecated methods.
- */
     private HashMap<String, Boolean> responseStateManagerInfo = null;
-
+
     private char requestIdSerial = 0;
 
     /** Number of views in logical view to be saved in session. */
     private int noOfViews = 0;
     private int noOfViewsInLogicalView = 0;
+ private Map<String,Class<?>> classMap =
+ new ConcurrentHashMap<String,Class<?>>(32);
 
 
- // ----------------------------------------------------------
Public Methods
-
-
- /**
- * Builds a hierarchy of TreeStrucure objects simulating the component
- * tree hierarchy.
- */
- public void buildTreeStructureToSave(FacesContext context,
- UIComponent component,
- TreeStructure treeStructure,
- Set<String> componentIds) {
-
- // traverse the component hierarchy and save the tree structure
- // information for every component.
-
- // Set for catching duplicate IDs
- if (null == componentIds) {
- componentIds = new HashSet<String>();
- }
-
- // save the structure info of the children of the component
- // being processed.
- Iterator<UIComponent> kids = component.getChildren().iterator();
- String id;
- while (kids.hasNext()) {
- UIComponent kid = kids.next();
-
- // check for id uniqueness
- id = kid.getClientId(context);
- if (id != null && !componentIds.add(id)) {
- if (LOGGER.isLoggable(Level.SEVERE)) {
- LOGGER.log(Level.SEVERE,
- "jsf.duplicate_component_id_error",
- id);
- }
- throw new IllegalStateException(
- MessageUtils.getExceptionMessageString(
- MessageUtils.DUPLICATE_COMPONENT_ID_ERROR_ID, id));
- }
-
- // if a component is marked transient do not persist its
state as
- // well as its children.
- if (!kid.isTransient()) {
- TreeStructure treeStructureChild = new TreeStructure(kid);
- treeStructure.addChild(treeStructureChild);
- buildTreeStructureToSave(context, kid, treeStructureChild,
- componentIds);
- }
- }
-
- // save structure info of the facets of the component currenly
being
- // processed.
- for (String facetName : component.getFacets().keySet()) {
- UIComponent facetComponent = component.getFacets().
- get(facetName);
-
- // check for id uniqueness
- id = facetComponent.getClientId(context);
- if (id != null && !componentIds.add(id)) {
- if (LOGGER.isLoggable(Level.SEVERE)) {
- LOGGER.log(Level.SEVERE,
"jsf.duplicate_component_id_error",
- id);
- }
- throw new IllegalStateException(
- MessageUtils.getExceptionMessageString(
- MessageUtils.DUPLICATE_COMPONENT_ID_ERROR_ID, id));
- }
-
- // if a facet is marked transient do not persist its state
as well as
- // its children.
- if (!(facetComponent.isTransient())) {
- TreeStructure treeStructureFacet =
- new TreeStructure(facetComponent);
- treeStructure.addFacet(facetName, treeStructureFacet);
- // process children of facet.
- buildTreeStructureToSave(context,
- facetComponent,
treeStructureFacet,
- componentIds);
- }
- }
-
- }
-
-
- /** Reconstitutes the component tree from TreeStructure hierarchy */
- public void restoreComponentTreeStructure(TreeStructure treeStructure,
- UIComponent component) {
-
- // traverse the tree strucure hierarchy and restore component
- // structure.
-
- // restore the structure of the children of the component being
processed.
- Iterator kids = treeStructure.getChildren();
- while (kids.hasNext()) {
- TreeStructure kid = (TreeStructure) kids.next();
- UIComponent child = kid.createComponent();
- component.getChildren().add(child);
- restoreComponentTreeStructure(kid, child);
- }
-
- // process facets
- Iterator facets = treeStructure.getFacetNames();
- while (facets.hasNext()) {
- String facetName = (String) facets.next();
- TreeStructure facetTreeStructure =
- treeStructure.getTreeStructureForFacet(facetName);
- UIComponent facetComponent =
facetTreeStructure.createComponent();
- component.getFacets().put(facetName, facetComponent);
- restoreComponentTreeStructure(facetTreeStructure,
facetComponent);
- }
-
- }
 
+ // ----------------------------------------------------------
Public Methods
 
     @SuppressWarnings("Deprecation")
     public UIViewRoot restoreView(FacesContext context, String viewId,
                                   String renderKitId) {
 
- if (null == renderKitId) {
- String message = MessageUtils.getExceptionMessageString
- (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
"renderKitId");
- throw new IllegalArgumentException(message);
- }
-
         UIViewRoot viewRoot = null;
         if (isSavingStateInClient(context)) {
- // restore view from response.
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.log(Level.FINE, "Begin restoring view from
response "
- + viewId);
- }
- viewRoot = restoreTreeStructure(context, viewId, renderKitId);
+ viewRoot = restoreTree(context, viewId, renderKitId);
+
             if (viewRoot != null) {
- restoreComponentState(context, viewRoot, renderKitId);
- } else {
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.fine(
- "Possibly a new request. Tree structure could
not "
- + " be restored for " + viewId);
- }
- }
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.fine("End restoring view from response " + viewId);
+ restoreState(context, viewRoot, renderKitId);
             }
         } else {
             // restore tree from session.
             // The ResponseStateManager implementation may be using the
new
             // methods or deprecated methods. We need to know which one
             // to call.
- Object id = null;
+ Object id;
             ResponseStateManager rsm =
                   RenderKitUtils.getResponseStateManager(context,
renderKitId);
- if (hasDeclaredMethod(responseStateManagerInfo,
- renderKitId,
+ if (hasDeclaredMethod(renderKitId,
                                   rsm,
                                   "getState")) {
                 Object[] stateArray = (Object[]) rsm.getState(context,
viewId);
@@ -253,9 +110,9 @@
                     LOGGER.fine("Begin restoring view in session for
viewId "
                                 + viewId);
                 }
- String idString = (String) id,
- idInLogicalMap = null,
- idInActualMap = null;
+ String idString = (String) id;
+ String idInLogicalMap;
+ String idInActualMap;
 
                 int sep = idString.indexOf(NamingContainer.SEPARATOR_CHAR);
                 assert(-1 != sep);
@@ -277,8 +134,6 @@
                     return null;
                 }
 
-
- TreeStructure structRoot = null;
                 Object [] stateArray = null;
                 synchronized (sessionObj) {
                     Map logicalMap = (Map) externalCtx.getSessionMap()
@@ -286,11 +141,16 @@
                     if (logicalMap != null) {
                         Map actualMap = (Map)
logicalMap.get(idInLogicalMap);
                         if (actualMap != null) {
- context.getExternalContext().getRequestMap()
- .put(RIConstants.LOGICAL_VIEW_MAP,
- idInLogicalMap);
+ Map<String,Object> requestMap =
+
context.getExternalContext().getRequestMap();
+ requestMap.put(RIConstants.LOGICAL_VIEW_MAP,
+ idInLogicalMap);
+ if (rsm.isPostback(context)) {
+ requestMap.put(RIConstants.ACTUAL_VIEW_MAP,
+ idInActualMap);
+ }
                             stateArray =
- (Object []) actualMap.get(idInActualMap);
+ (Object[]) actualMap.get(idInActualMap);
                         }
                     }
                 }
@@ -302,10 +162,8 @@
                     }
                     return null;
                 }
- structRoot = (TreeStructure) stateArray[0];
- viewRoot = (UIViewRoot) structRoot.createComponent();
- restoreComponentTreeStructure(structRoot, viewRoot);
 
+ viewRoot = restoreTree(((Object[]) stateArray[0]));
                 viewRoot.processRestoreState(context, stateArray[1]);
 
                 if (LOGGER.isLoggable(Level.FINE)) {
@@ -314,18 +172,18 @@
                 }
             }
         }
- return viewRoot;
 
+ return viewRoot;
     }
 
 
     @SuppressWarnings("Deprecation")
- public SerializedView saveSerializedView(FacesContext context)
- throws IllegalStateException {
+ @Override
+ public SerializedView saveSerializedView(FacesContext context) {
+
 
         SerializedView result = null;
- Object treeStructure = null;
- Object componentState = null;
+
         // irrespective of method to save the tree, if the root is
transient
         // no state information needs to be persisted.
         UIViewRoot viewRoot = context.getViewRoot();
@@ -341,10 +199,11 @@
             LOGGER.fine("Begin creating serialized view for "
                         + viewRoot.getViewId());
         }
- result = new SerializedView(treeStructure =
- getTreeStructureToSave(context),
- componentState =
-
getComponentStateToSave(context));
+ List<TreeNode> treeList = new ArrayList<TreeNode>(32);
+ captureChild(treeList, 0, viewRoot);
+ Object state = viewRoot.processSaveState(context);
+ Object[] tree = treeList.toArray();
+
         if (LOGGER.isLoggable(Level.FINE)) {
             LOGGER.fine("End creating serialized view " +
viewRoot.getViewId());
         }
@@ -367,66 +226,75 @@
             // apps that need this multi-window
behavior.
             int logicalMapSize = getNumberOfViewsParameter(context);
             int actualMapSize =
getNumberOfViewsInLogicalViewParameter(context);
-
- Object stateArray[] = {treeStructure, componentState};
+
             ExternalContext externalContext = context.getExternalContext();
             Object sessionObj = externalContext.getSession(true);
             Map<String, Object> sessionMap = Util.getSessionMap(context);
 
 
             synchronized (sessionObj) {
- LRUMap<String, LRUMap<String, Object[]>> logicalMap;
- LRUMap<String, Object[]> actualMap;
- if (null == (logicalMap =
+ LRUMap<String, LRUMap<String, Object[]>> logicalMap =
                       (LRUMap<String, LRUMap<String, Object[]>>) sessionMap
- .get(RIConstants.LOGICAL_VIEW_MAP))) {
- logicalMap =
- new LRUMap<String, LRUMap<String, Object[]>>(
- logicalMapSize);
+ .get(RIConstants.LOGICAL_VIEW_MAP);
+ if (logicalMap == null) {
+ logicalMap = new LRUMap<String, LRUMap<String,
Object[]>>(
+ logicalMapSize);
                     sessionMap.put(RIConstants.LOGICAL_VIEW_MAP,
logicalMap);
                 }
 
+ Map<String, Object> requestMap =
+ externalContext.getRequestMap();
                 String idInLogicalMap = (String)
- externalContext.getRequestMap()
- .get(RIConstants.LOGICAL_VIEW_MAP);
- if (null == idInLogicalMap) {
+ requestMap.get(RIConstants.LOGICAL_VIEW_MAP);
+ if (idInLogicalMap == null) {
                     idInLogicalMap = createUniqueRequestId();
                 }
                 assert(null != idInLogicalMap);
 
- String idInActualMap = createUniqueRequestId();
- if (null == (actualMap = logicalMap.get(idInLogicalMap))) {
+ // this value will not be null if this is a post
+ // back
+ String idInActualMap = (String)
+ requestMap.get(RIConstants.ACTUAL_VIEW_MAP);
+ if (idInActualMap == null) {
+ idInActualMap = createUniqueRequestId();
+ }
+ LRUMap<String, Object[]> actualMap =
+ logicalMap.get(idInLogicalMap);
+ if (actualMap == null) {
                     actualMap = new LRUMap<String,
Object[]>(actualMapSize);
                     logicalMap.put(idInLogicalMap, actualMap);
                 }
+
                 String id = idInLogicalMap +
NamingContainer.SEPARATOR_CHAR +
                             idInActualMap;
- result = new SerializedView(id, null);
- actualMap.put(idInActualMap, stateArray);
+ result = new SerializedView(id, null);
+ Object[] stateArray = actualMap.get(idInActualMap);
+ // reuse the array if possible
+ if (stateArray != null) {
+ stateArray[0] = tree;
+ stateArray[1] = state;
+ } else {
+ actualMap.put(idInActualMap, new Object[] { tree,
state });
+ }
             }
+ } else {
+ result = new SerializedView(tree, state);
         }
 
- return result;
+ return result;
 
     }
-
-
- public Object saveView(FacesContext context) {
-
- return (super.saveView(context));
-
- }
-
+
 
     @SuppressWarnings("Deprecation")
+ @Override
     public void writeState(FacesContext context, SerializedView state)
           throws IOException {
 
         String renderKitId = context.getViewRoot().getRenderKitId();
         ResponseStateManager rsm =
               RenderKitUtils.getResponseStateManager(context, renderKitId);
- if (hasDeclaredMethod(responseStateManagerInfo,
- renderKitId,
+ if (hasDeclaredMethod(renderKitId,
                               rsm,
                               "getState")) {
             Object[] stateArray = new Object[2];
@@ -437,15 +305,7 @@
             rsm.writeState(context, state);
         }
 
- }
-
-
- public void writeState(FacesContext context, Object state)
- throws IOException {
-
- super.writeState(context, state);
-
- }
+ }
 
 
     // -------------------------------------------------------
Protected Methods
@@ -480,120 +340,206 @@
     }
 
 
- @SuppressWarnings("Deprecation")
- protected Object getComponentStateToSave(FacesContext context) {
-
- return context.getViewRoot().processSaveState(context);
-
- }
-
+ // ---------------------------------------------------------
Private Methods
 
     /**
- * Returns the value of ServletContextInitParameter that specifies the
- * maximum number of views to be saved in this logical view. If
none is specified
- * returns
<code>DEFAULT_NUMBER_OF_VIEWS_IN_LOGICAL_VIEW_IN_SESSION</code>.
- */
- protected int getNumberOfViewsInLogicalViewParameter(FacesContext
context) {
-
- if (noOfViewsInLogicalView != 0) {
+ * Returns the value of ServletContextInitParameter that
specifies the
+ * maximum number of views to be saved in this logical view. If
none is specified
+ * returns
<code>DEFAULT_NUMBER_OF_VIEWS_IN_LOGICAL_VIEW_IN_SESSION</code>.
+ * @param context the FacesContext
+ * @return number of logical views
+ */
+ protected int
getNumberOfViewsInLogicalViewParameter(FacesContext context) {
+
+ if (noOfViewsInLogicalView != 0) {
+ return noOfViewsInLogicalView;
+ }
+ WebConfiguration webConfig =
+
WebConfiguration.getInstance(context.getExternalContext());
+ String noOfViewsStr = webConfig
+
.getContextInitParameter(WebContextInitParameter.NumberOfLogicalViews);
+ String defaultValue =
+
WebContextInitParameter.NumberOfLogicalViews.getDefaultValue();
+ try {
+ noOfViewsInLogicalView = Integer.valueOf(noOfViewsStr);
+ } catch (NumberFormatException nfe) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.fine("Error parsing the
servetInitParameter "
+ +
+
WebContextInitParameter.NumberOfLogicalViews.getQualifiedName()
+ + ". Using default "
+ +
+ noOfViewsInLogicalView);
+ }
+ try {
+ noOfViewsInLogicalView = Integer.valueOf(defaultValue);
+ } catch (NumberFormatException ne) {
+ // won't occur
+ }
+ }
+
             return noOfViewsInLogicalView;
+
         }
- WebConfiguration webConfig =
- WebConfiguration.getInstance(context.getExternalContext());
- String noOfViewsStr = webConfig
-
.getContextInitParameter(WebContextInitParameter.NumberOfLogicalViews);
- String defaultValue =
-
WebContextInitParameter.NumberOfLogicalViews.getDefaultValue();
- try {
- noOfViewsInLogicalView = Integer.valueOf(noOfViewsStr);
- } catch (NumberFormatException nfe) {
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.fine("Error parsing the servetInitParameter "
- +
-
WebContextInitParameter.NumberOfLogicalViews.getQualifiedName()
- + ". Using default "
- +
- noOfViewsInLogicalView);
+
+
+ /**
+ * Returns the value of ServletContextInitParameter that
specifies the
+ * maximum number of logical views to be saved in session. If
none is specified
+ * returns <code>DEFAULT_NUMBER_OF_VIEWS_IN_SESSION</code>.
+ * @param context the FacesContext
+ * @return number of logical views
+ */
+ protected int getNumberOfViewsParameter(FacesContext context) {
+
+ if (noOfViews != 0) {
+ return noOfViews;
             }
+ WebConfiguration webConfig =
+
WebConfiguration.getInstance(context.getExternalContext());
+ String noOfViewsStr = webConfig
+
.getContextInitParameter(WebContextInitParameter.NumberOfViews);
+ String defaultValue =
+ WebContextInitParameter.NumberOfViews.getDefaultValue();
             try {
- noOfViewsInLogicalView = Integer.valueOf(defaultValue);
- } catch (NumberFormatException ne) {
- // won't occur
- }
- }
+ noOfViews = Integer.valueOf(noOfViewsStr);
+ } catch (NumberFormatException nfe) {
+ if (LOGGER.isLoggable(Level.FINE)) {
+ LOGGER.fine("Error parsing the
servetInitParameter "
+ +
+
WebContextInitParameter.NumberOfViews.getQualifiedName()
+ + ". Using default "
+ +
+ noOfViews);
+ }
+ try {
+ noOfViews = Integer.valueOf(defaultValue);
+ } catch (NumberFormatException ne) {
+ // won't occur
+ }
+ }
        
- return noOfViewsInLogicalView;
+ return noOfViews;
+
+ }
+
+
+
+ private static void captureChild(List<TreeNode> tree, int parent,
+ UIComponent c) {
+
+ if (!c.isTransient()) {
+ TreeNode n = new TreeNode(parent, c);
+ int pos = tree.size();
+ tree.add(n);
+ captureRest(tree, pos, c);
+ }
 
     }
 
 
- /**
- * Returns the value of ServletContextInitParameter that specifies the
- * maximum number of logical views to be saved in session. If none
is specified
- * returns <code>DEFAULT_NUMBER_OF_VIEWS_IN_SESSION</code>.
- */
- protected int getNumberOfViewsParameter(FacesContext context) {
-
- if (noOfViews != 0) {
- return noOfViews;
+ private static void captureFacet(List<TreeNode> tree, int parent,
String name,
+ UIComponent c) {
+
+ if (!c.isTransient()) {
+ FacetNode n = new FacetNode(parent, name, c);
+ int pos = tree.size();
+ tree.add(n);
+ captureRest(tree, pos, c);
         }
- WebConfiguration webConfig =
- WebConfiguration.getInstance(context.getExternalContext());
- String noOfViewsStr = webConfig
-
.getContextInitParameter(WebContextInitParameter.NumberOfViews);
- String defaultValue =
- WebContextInitParameter.NumberOfViews.getDefaultValue();
- try {
- noOfViews = Integer.valueOf(noOfViewsStr);
- } catch (NumberFormatException nfe) {
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.fine("Error parsing the servetInitParameter "
- +
-
WebContextInitParameter.NumberOfViews.getQualifiedName()
- + ". Using default "
- +
- noOfViews);
+
+ }
+
+
+ private static void captureRest(List<TreeNode> tree, int pos,
UIComponent c) {
+
+ // store children
+ int sz = c.getChildCount();
+ if (sz > 0) {
+ List<UIComponent> child = c.getChildren();
+ for (int i = 0; i < sz; i++) {
+ captureChild(tree, pos, child.get(i));
             }
- try {
- noOfViews = Integer.valueOf(defaultValue);
- } catch (NumberFormatException ne) {
- // won't occur
+ }
+
+ // store facets
+ sz = c.getFacetCount();
+ if (sz > 0) {
+ for (Entry<String, UIComponent> entry :
c.getFacets().entrySet()) {
+ captureFacet(tree,
+ pos,
+ entry.getKey(),
+ entry.getValue());
             }
- }
-
- return noOfViews;
+ }
 
     }
 
 
- @SuppressWarnings("Deprecation")
- protected Object getTreeStructureToSave(FacesContext context) {
+ /**
+ * Looks for the presence of a declared method (by name) in the
specified
+ * class and returns a <code>boolean</code> outcome (true, if the
method
+ * exists).
+ *
+ * @param renderKitId The object that will be used for the
lookup. This key
+ * will also be stored in the <code>Map</code> with a corresponding
+ * <code>Boolean</code> value indicating the result of the search.
+ * @param instance The instance of the class that will be used as
+ * the search domain.
+ * @param methodName The name of the method we are looking for.
+ *
+ * @return <code>true</code> if the method exists, otherwise
+ * <code>false</code>
+ */
+ private boolean hasDeclaredMethod(String renderKitId,
+ ResponseStateManager instance,
+ String methodName) {
 
- TreeStructure structRoot = null;
- UIComponent viewRoot = context.getViewRoot();
- if (!(viewRoot.isTransient())) {
- structRoot = new TreeStructure(viewRoot);
- buildTreeStructureToSave(context, viewRoot, structRoot, null);
+ boolean result;
+ if (responseStateManagerInfo == null) {
+ responseStateManagerInfo = new HashMap<String, Boolean>();
+ }
+ Boolean value = responseStateManagerInfo.get(renderKitId);
+ if (value != null) {
+ return value;
         }
- return structRoot;
+ result = Util.hasDeclaredMethod(instance, methodName);
+ responseStateManagerInfo.put(renderKitId, result);
+ return result;
 
     }
 
 
- @SuppressWarnings("Deprecation")
- protected void restoreComponentState(FacesContext context,
- UIViewRoot root, String
renderKitId) {
+ private UIComponent newInstance(TreeNode n) throws FacesException {
 
- if (null == renderKitId) {
- String message = MessageUtils.getExceptionMessageString
- (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
"renderKitId");
- throw new IllegalArgumentException(message);
+ try {
+ Class<?> t = classMap.get(n.componentType);
+ if (t == null) {
+ t = Util.loadClass(n.componentType, n);
+ if (t != null) {
+ classMap.put(n.componentType, t);
+ } else {
+ throw new NullPointerException();
+ }
+ }
+
+ UIComponent c = (UIComponent) t.newInstance();
+ c.setId(n.id);
+ return c;
+ } catch (Exception e) {
+ throw new FacesException(e);
         }
- Object state = null;
+
+ }
+
+ @SuppressWarnings("Deprecation")
+ private void restoreState(FacesContext context,
+ UIViewRoot root,
+ String renderKitId) {
         ResponseStateManager rsm =
               RenderKitUtils.getResponseStateManager(context, renderKitId);
- if (hasDeclaredMethod(responseStateManagerInfo,
- renderKitId,
+ Object state;
+ if (hasDeclaredMethod(renderKitId,
                               rsm,
                               "getState")) {
             Object[] stateArray =
@@ -603,119 +549,165 @@
             state = rsm.getComponentStateToRestore(context);
         }
         root.processRestoreState(context, state);
-
     }
 
 
- /**
- * Returns the <code> UIViewRoot</code> corresponding the
- * <code> viewId </code> by restoring the view structure and state.
- */
     @SuppressWarnings("Deprecation")
- protected UIViewRoot restoreSerializedView(FacesContext context,
- SerializedView sv,
- String viewId) {
-
- if (sv == null) {
- if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.fine("Possibly a new request. Tree structure
could not "
- + " be restored for " + viewId);
- }
- return null;
+ private UIViewRoot restoreTree(FacesContext context,
+ String viewId,
+ String renderKitId) {
+
+ ResponseStateManager rsm =
+ RenderKitUtils.getResponseStateManager(context, renderKitId);
+ Object[] treeStructure;
+ if (hasDeclaredMethod(renderKitId,
+ rsm,
+ "getState")) {
+
+ Object[] stateArray = (Object[]) rsm.getState(context, viewId);
+ treeStructure = (Object[]) stateArray[0];
+ } else {
+ treeStructure = (Object[]) rsm
+ .getTreeStructureToRestore(context, viewId);
         }
- TreeStructure structRoot = (TreeStructure) sv.getStructure();
- if (structRoot == null) {
+
+ if (treeStructure == null) {
             return null;
         }
- UIComponent viewRoot = structRoot.createComponent();
- if (viewRoot != null) {
- restoreComponentTreeStructure(structRoot, viewRoot);
- Object state = sv.getState();
- viewRoot.processRestoreState(context, state);
+
+ return restoreTree(treeStructure);
+ }
+
+ private String createUniqueRequestId() {
+
+ if (requestIdSerial++ == Character.MAX_VALUE) {
+ requestIdSerial = 0;
         }
- return ((UIViewRoot) viewRoot);
+ return UIViewRoot.UNIQUE_ID_PREFIX + ((int) requestIdSerial);
 
     }
 
 
- @SuppressWarnings("Deprecation")
- protected UIViewRoot restoreTreeStructure(FacesContext context,
- String viewId,
- String renderKitId) {
-
- if (null == renderKitId) {
- String message = MessageUtils.getExceptionMessageString
- (MessageUtils.NULL_PARAMETERS_ERROR_MESSAGE_ID,
"renderKitId");
- throw new IllegalArgumentException(message);
+ private UIViewRoot restoreTree(Object[] tree) throws FacesException {
+
+ UIComponent c;
+ FacetNode fn;
+ TreeNode tn;
+ for (int i = 0; i < tree.length; i++) {
+ if (tree[i]instanceof FacetNode) {
+ fn = (FacetNode) tree[i];
+ c = newInstance(fn);
+ tree[i] = c;
+ if (i != fn.parent) {
+ ((UIComponent) tree[fn.parent]).getFacets()
+ .put(fn.facetName, c);
+ }
+
+ } else {
+ tn = (TreeNode) tree[i];
+ c = newInstance(tn);
+ tree[i] = c;
+ if (i != tn.parent) {
+ ((UIComponent) tree[tn.parent]).getChildren().add(c);
+ }
+ }
         }
- UIComponent viewRoot = null;
- TreeStructure structRoot = null;
- ResponseStateManager rsm =
- RenderKitUtils.getResponseStateManager(context, renderKitId);
- if (hasDeclaredMethod(responseStateManagerInfo,
- renderKitId,
- rsm,
- "getState")) {
- Object[] stateArray = (Object[]) rsm.getState(context, viewId);
- structRoot = (TreeStructure) stateArray[0];
- } else {
- structRoot = (TreeStructure) rsm
- .getTreeStructureToRestore(context, viewId);
+ return (UIViewRoot) tree[0];
+
+ }
+
+
+ private static class TreeNode implements Externalizable {
+
+
+ public String componentType;
+ public String id;
+
+ public int parent;
+
+ private static final long serialVersionUID = -835775352718473281L;
+
+
+ // ------------------------------------------------------------
Constructors
+
+
+ public TreeNode() { }
+
+
+ public TreeNode(int parent, UIComponent c) {
+
+ this.parent = parent;
+ this.id = c.getId();
+ this.componentType = c.getClass().getName();
+
         }
- if (structRoot == null) {
- return null;
+
+
+ // --------------------------------------------- Methods From
Externalizable
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+
+ out.writeInt(this.parent);
+ out.writeUTF(this.componentType);
+ if (this.id != null) {
+ out.writeUTF(this.id);
+ }
+
+ }
+
+
+ public void readExternal(ObjectInput in)
+ throws IOException, ClassNotFoundException {
+
+ this.parent = in.readInt();
+ this.componentType = in.readUTF();
+ if (in.available() > 0) {
+ this.id = in.readUTF();
+ }
+
         }
- viewRoot = structRoot.createComponent();
- restoreComponentTreeStructure(structRoot, viewRoot);
- return ((UIViewRoot) viewRoot);
 
     }
 
+ private static final class FacetNode extends TreeNode {
 
- // ---------------------------------------------------------
Private Methods
 
+ public String facetName;
 
- private String createUniqueRequestId() {
+ private static final long serialVersionUID = -3777170310958005106L;
+
+
+ // ------------------------------------------------------------
Constructors
+
+ public FacetNode() { }
+
+ public FacetNode(int parent, String name, UIComponent c) {
+
+ super(parent, c);
+ this.facetName = name;
 
- if (requestIdSerial++ == Character.MAX_VALUE) {
- requestIdSerial = 0;
         }
- return UIViewRoot.UNIQUE_ID_PREFIX + ((int) requestIdSerial);
 
- }
 
+ // ----------------------------------------------------------
Public Methods
 
- /**
- * Looks for the presence of a declared method (by name) in the
specified
- * class and returns a <code>boolean</code> outcome (true, if the
method
- * exists).
- *
- * @param resultMap A <code>Map</code> possibly containing the
specified
- * "key" argument, and the corresponding <code>boolean</code> value
- * indicating the outcome of the search.
- * @param key The object that will be used for the lookup. This key
- * will also be stored in the <code>Map</code> with a corresponding
- * <code>Boolean</code> value indicating the result of the search.
- * @param instance The instance of the class that will be used as
- * the search domain.
- * @param methodName The name of the method we are looking for.
- */
- private boolean hasDeclaredMethod(Map<String, Boolean> resultMap,
- String key, ResponseStateManager
instance,
- String methodName) {
+ @Override
+ public void readExternal(ObjectInput in)
+ throws IOException, ClassNotFoundException {
+
+ super.readExternal(in);
+ this.facetName = in.readUTF();
 
- boolean result = false;
- if (resultMap == null) {
- resultMap = new HashMap<String, Boolean>();
         }
- Boolean value = resultMap.get(key);
- if (value != null) {
- return value;
+
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {
+
+ super.writeExternal(out);
+ out.writeUTF(this.facetName);
+
         }
- result = Util.hasDeclaredMethod(instance, methodName);
- resultMap.put(key, result);
- return result;
 
     }
 
-}
+} // END StateManagerImpl
\ No newline at end of file
Index: src/com/sun/faces/util/DebugUtil.java
===================================================================
RCS file:
/cvs/javaserverfaces-sources/jsf-ri/src/com/sun/faces/util/DebugUtil.java,v
retrieving revision 1.36
diff -u -r1.36 DebugUtil.java
--- src/com/sun/faces/util/DebugUtil.java 29 Mar 2006 23:03:53
-0000 1.36
+++ src/com/sun/faces/util/DebugUtil.java 18 May 2006 20:30:41 -0000
@@ -31,22 +31,22 @@
 
 // DebugUtil.java
 
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.io.Writer;
-import java.util.Iterator;
-
 import javax.faces.component.UIComponent;
 import javax.faces.component.ValueHolder;
+import javax.faces.context.FacesContext;
 import javax.faces.model.SelectItem;
 
-import com.sun.faces.renderkit.RenderKitUtils;
-import com.sun.faces.io.FastStringWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Iterator;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.faces.context.FacesContext;
+
+import com.sun.faces.io.FastStringWriter;
+import com.sun.faces.renderkit.RenderKitUtils;
 
 /**
  * <B>DebugUtil</B> is a class ...
@@ -246,54 +246,54 @@
     }
 
 
- /**
- * Output of printTree() as a String.
- * Useful when used with a Logger. For example:
- * logger.log(DebugUtil.printTree(root));
- */
- public static String printTree(TreeStructure root) {
- Writer writer = new FastStringWriter(1024);
- printTree(root, writer);
- return writer.toString();
- }
-
- /**
- * Output of printTree() to a PrintStream.
- * Usage:
- * DebugUtil.printTree(root, System.out);
- */
- public static void printTree(TreeStructure root, PrintStream out) {
- PrintWriter writer = new PrintWriter(out);
- printTree(root, writer);
- writer.flush();
- }
-
- public static void printTree(TreeStructure root, Writer out) {
- if (null == root) {
- return;
- }
- int i = 0;
- Object value = null;
-
-/* PENDING
- indentPrintln(out, "===>Type:" + root.getComponentType());
-*/
- indentPrintln(out, "id:" + root.id);
- indentPrintln(out, "type:" + root.className);
-
- Iterator items = null;
- SelectItem curItem = null;
- int j = 0;
-
- curDepth++;
- if (null != root.children) {
- Iterator<TreeStructure> it = root.children.iterator();
- while (it.hasNext()) {
- printTree(it.next(), out);
- }
- }
- curDepth--;
- }
+// /**
+// * Output of printTree() as a String.
+// * Useful when used with a Logger. For example:
+// * logger.log(DebugUtil.printTree(root));
+// */
+// public static String printTree(TreeStructure root) {
+// Writer writer = new FastStringWriter(1024);
+// printTree(root, writer);
+// return writer.toString();
+// }
+//
+// /**
+// * Output of printTree() to a PrintStream.
+// * Usage:
+// * DebugUtil.printTree(root, System.out);
+// */
+// public static void printTree(TreeStructure root, PrintStream out) {
+// PrintWriter writer = new PrintWriter(out);
+// printTree(root, writer);
+// writer.flush();
+// }
+//
+// public static void printTree(TreeStructure root, Writer out) {
+// if (null == root) {
+// return;
+// }
+// int i = 0;
+// Object value = null;
+//
+///* PENDING
+// indentPrintln(out, "===>Type:" + root.getComponentType());
+//*/
+// indentPrintln(out, "id:" + root.id);
+// indentPrintln(out, "type:" + root.className);
+//
+// Iterator items = null;
+// SelectItem curItem = null;
+// int j = 0;
+//
+// curDepth++;
+// if (null != root.children) {
+// Iterator<TreeStructure> it = root.children.iterator();
+// while (it.hasNext()) {
+// printTree(it.next(), out);
+// }
+// }
+// curDepth--;
+// }
 
     public static void printTree(Object [] root, Writer out) {
         if (null == root) {
Index: test/com/sun/faces/lifecycle/TestSaveStateInPage.java
===================================================================
RCS file:
/cvs/javaserverfaces-sources/jsf-ri/test/com/sun/faces/lifecycle/TestSaveStateInPage.java,v
retrieving revision 1.33
diff -u -r1.33 TestSaveStateInPage.java
--- test/com/sun/faces/lifecycle/TestSaveStateInPage.java 29 Mar 2006
23:04:56 -0000 1.33
+++ test/com/sun/faces/lifecycle/TestSaveStateInPage.java 18 May 2006
20:30:42 -0000
@@ -31,13 +31,6 @@
 
 package com.sun.faces.lifecycle;
 
-import com.sun.faces.cactus.JspFacesTestCase;
-import com.sun.faces.application.StateManagerImpl;
-import com.sun.faces.application.ViewHandlerImpl;
-import com.sun.faces.util.TreeStructure;
-import com.sun.faces.util.Util;
-import org.apache.cactus.WebRequest;
-
 import javax.faces.component.UIComponent;
 import javax.faces.component.UIComponentBase;
 import javax.faces.component.UIForm;
@@ -45,8 +38,18 @@
 import javax.faces.component.UIPanel;
 import javax.faces.component.UIViewRoot;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.cactus.WebRequest;
+
+import com.sun.faces.application.StateManagerImpl;
+import com.sun.faces.application.ViewHandlerImpl;
+import com.sun.faces.cactus.JspFacesTestCase;
+import com.sun.faces.cactus.TestingUtil;
+import com.sun.faces.util.Util;
+
 
 /**
  * <B>TestSaveStateInPage</B> is a class ...
@@ -185,17 +188,30 @@
         ViewHandlerImpl viewHandler = new ViewHandlerImpl();
         StateManagerImpl stateManager = new StateManagerImpl();
 
- TreeStructure structRoot =
- new TreeStructure(((UIComponent)
getFacesContext().getViewRoot()));
- stateManager.buildTreeStructureToSave(getFacesContext(),
- ((UIComponent) root),
- structRoot, null);
-
- // make sure restored tree structure is correct
- UIViewRoot viewRoot = (UIViewRoot) structRoot.createComponent();
- assertTrue(null != viewRoot);
- stateManager.restoreComponentTreeStructure(structRoot,
- ((UIComponent)
viewRoot));
+// TreeStructure structRoot =
+// new TreeStructure(((UIComponent)
getFacesContext().getViewRoot()));
+// stateManager.buildTreeStructureToSave(getFacesContext(),
+// ((UIComponent) root),
+// structRoot, null);
+//
+// // make sure restored tree structure is correct
+// UIViewRoot viewRoot = (UIViewRoot) structRoot.createComponent();
+// assertTrue(null != viewRoot);
+// stateManager.restoreComponentTreeStructure(structRoot,
+// ((UIComponent)
viewRoot));
+
+ List structureList = new ArrayList();
+ TestingUtil.invokePrivateMethod("captureChild",
+ new Class[] {List.class,
Integer.TYPE, UIComponent.class},
+ new Object[] { structureList,
0, root },
+ StateManagerImpl.class,
+ stateManager);
+ Object[] structArray = structureList.toArray();
+ UIViewRoot viewRoot = (UIViewRoot)
TestingUtil.invokePrivateMethod("restoreTree",
+
new Class[] { Object[].class },
+
new Object[] { structArray },
+
StateManagerImpl.class,
+
stateManager);
 
         UIComponent component = (UIComponent)
viewRoot.getChildren().get(0);
         assertTrue(component instanceof UIForm);


SECTION: New Files
----------------------------
SEE ATTACHMENTS