You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2008/10/03 12:19:35 UTC

svn commit: r701342 - in /myfaces/trinidad/branches/1.2.9.1-branch: trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/ trinidad-api/src/main/java/org/apache/myfaces/trinidad/co...

Author: matzew
Date: Fri Oct  3 03:19:33 2008
New Revision: 701342

URL: http://svn.apache.org/viewvc?rev=701342&view=rev
Log:
TRINIDAD-1245 - High Availability Testing Support

thanks to blake sullivan for his patch

Added:
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/CheckSerializationConfigurator.java
Modified:
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/PropertyKey.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/StateUtils.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyMenuModel.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyTreeModel.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/dispatch/DispatchResponseConfiguratorImpl.java
    myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.config.Configurator

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/PropertyKey.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/PropertyKey.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/PropertyKey.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/PropertyKey.java Fri Oct  3 03:19:33 2008
@@ -228,9 +228,9 @@
     
     // warn if we are state saving non-serializable values, as this will cause client
     // state saving and fail-over to fail.  See JIRA 1236
-    if (!(value instanceof Serializable) && _LOG.isWarning())
-      _LOG.warning("Unserializable value:" + value + " on property key:" + this);
-
+    if ((value != null) && !(value instanceof Serializable) && _LOG.isWarning())
+      _LOG.warning(_LOG.getMessage("UNSERIALIZABLE_PROPERTY_VALUE", new Object[]{value, this}));
+    
     return value;
   }
 
@@ -379,3 +379,4 @@
 }
 
 
+

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/StateUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/StateUtils.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/StateUtils.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/bean/util/StateUtils.java Fri Oct  3 03:19:33 2008
@@ -18,16 +18,23 @@
  */
 package org.apache.myfaces.trinidad.bean.util;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import java.util.concurrent.ConcurrentMap;
 
 import javax.faces.component.StateHolder;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 
 import org.apache.myfaces.trinidad.bean.FacesBean;
@@ -40,8 +47,158 @@
 /**
  * Utilities for handling state persistance.
  */
-public class StateUtils
+public final class StateUtils
 {
+  static
+  {
+    // initialize checks for serialization verification
+    boolean checkPropertyStateSerialization = false;
+    boolean checkComponentStateSerialization = false;
+    boolean checkComponentTreeStateSerialization = false;
+    boolean checkSessionSerialization = false;
+
+    String checkSerializationProperty;
+
+    // determine if we need to aggressively check the serialization of components
+    // we wrap the check in a try/catch in case of weird ecurity managers
+    try
+    {
+      checkSerializationProperty = 
+                       System.getProperty("org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION");
+    }
+    catch (Throwable t)
+    {
+      checkSerializationProperty = null;
+    }
+
+    if (checkSerializationProperty != null)
+    {
+      checkSerializationProperty = checkSerializationProperty.toUpperCase();
+      
+      String[] paramArray = checkSerializationProperty.split(",");
+      
+      Set<String> serializationFlags = new HashSet<String>(Arrays.asList(paramArray));
+      
+      if (!serializationFlags.contains("NONE"))
+      {
+        if (serializationFlags.contains("ALL"))
+        {
+          checkPropertyStateSerialization = true;
+          checkComponentStateSerialization = true;
+          checkComponentTreeStateSerialization = true;
+          checkSessionSerialization = true;
+        }
+        else
+        {
+          checkPropertyStateSerialization = serializationFlags.contains("PROPERTY");
+          checkComponentStateSerialization = serializationFlags.contains("COMPONENT");
+          checkComponentTreeStateSerialization = serializationFlags.contains("TREE");       
+          checkSessionSerialization = serializationFlags.contains("SESSION");
+        }
+      }
+    }
+
+    _CHECK_PROPERTY_STATE_SERIALIZATION = checkPropertyStateSerialization;
+    _CHECK_COMPONENT_STATE_SERIALIZATION = checkComponentStateSerialization;
+    _CHECK_COMPONENT_TREE_STATE_SERIALIZATION = checkComponentTreeStateSerialization;
+    _CHECK_SESSION_SERIALIZATION = checkSessionSerialization;
+  }
+
+  private static final boolean _CHECK_COMPONENT_TREE_STATE_SERIALIZATION;
+  private static final boolean _CHECK_COMPONENT_STATE_SERIALIZATION;
+  private static final boolean _CHECK_PROPERTY_STATE_SERIALIZATION;
+  private static final boolean _CHECK_SESSION_SERIALIZATION;
+
+  /**
+   * Returns <code>true</code> if properties should be checked for
+   * serializability when when generating the view's state object.
+   * <p>
+   * By default property state serialization checking is off.  It can be
+   * enabled by setting the system property
+   * <code>org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION</code>
+   * to <code>all</code> or, more rately, adding <code>property</code> to the
+   * comma-separated list of serialization checks to perform.
+   * <p>
+   * As property serialization checking is expensive, it is usually
+   * only enabled after component tree serialization checking has detected
+   * a problem
+   * @return
+   * @see #checkComponentStateSerialization
+   * @see #checkComponentTreeStateSerialization
+   */
+  private static boolean _checkPropertyStateSerialization()
+  {
+    return _CHECK_PROPERTY_STATE_SERIALIZATION;
+  }
+
+  /**
+   * Returns <code>true</code> if components should be checked for
+   * serializability when when generating the view's state object.
+   * <p>
+   * By default component state serialization checking is off.  It can be
+   * enabled by setting the system property
+   * <code>org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION</code>
+   * to <code>all</code> or, more rarely, adding <code>component</code> to the
+   * comma-separated list of serialization checks to perform.
+   * <p>
+   * As property serialization checking is expensive, it is usually
+   * only enabled after component tree serialization checking has detected
+   * a problem.  In addition, since component serialization checking only
+   * detects the problem component, it is usually combined with
+   * property state serialization checking either by specifying <code>all</code>.
+   * @return
+   * @see #checkComponentTreeStateSerialization
+   */
+  public static boolean checkComponentStateSerialization(FacesContext context)
+  {
+    return _CHECK_COMPONENT_STATE_SERIALIZATION;
+  }
+
+  /**
+   * Returns <code>true</code> if the component tree should be checked for
+   * serializability when when generating the view's state object.
+   * <p>
+   * By default component tree state serialization checking is off.  It can be
+   * enabled by setting the system property
+   * <code>org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION</code>
+   * to <code>all</code> or, more commonly, adding <code>tree</code> to the
+   * comma-separated list of serialization checks to perform.
+   * <p>
+   * Because unserializable objects defeat fail-over, it is important to
+   * check for serializability when testing applications.  While component
+   * tree state serializability checking isn't cheap, it is much faster to
+   * initially only enable checking of the component tree and then switch
+   * to <code>all</code> testing to determine the problem component and 
+   * property when the component tree testing determines a problem.
+   * @return
+   * @see #checkComponentStateSerialization
+   */
+  public static boolean checkComponentTreeStateSerialization(FacesContext context)
+  {
+    return _CHECK_COMPONENT_TREE_STATE_SERIALIZATION;
+  }
+
+  /**
+   * Returns <code>true</code> if Object written to the SessionMap should be checked for
+   * Serializability when <code>put</code> is called.
+   * <p>
+   * Configuring this property allows this aspect of high-availability to be tested without
+   * configuring the server to run in high-availability mode.
+   * <p>
+   * By default session serialization checking is off.  It can be
+   * enabled by setting the system property
+   * <code>org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION</code>
+   * to <code>all</code> or, more commonly, adding <code>session</code> to the
+   * comma-separated list of serialization checks to perform.
+   * @return
+   * @see #checkComponentStateSerialization
+   * @see #checkComponentTreeStateSerialization
+   */
+  public static boolean checkSessionSerialization(ExternalContext extContext)
+  {
+    return _CHECK_SESSION_SERIALIZATION;
+  }
+
   /**
    * Persists a property key.
    */
@@ -109,10 +266,30 @@
         _LOG.finest("SAVE {" + key + "=" + value + "}");
       }
 
+      Object saveValue;
+      
       if (useStateHolder)
-        values[i + 1] = saveStateHolder(context, value);
+        saveValue = saveStateHolder(context, value);
       else
-        values[i + 1] = key.saveValue(context, value);
+        saveValue = key.saveValue(context, value);
+
+      // aggressively check the serializability of the value
+      if (_checkPropertyStateSerialization())
+      {
+        try
+        {
+          new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(saveValue);
+        }
+        catch (IOException e)
+        {          
+          throw new RuntimeException(_LOG.getMessage("UNSERIALIZABLE_PROPERTY_VALUE",
+                                                     new Object[]{saveValue, key}),
+                                     e);
+        }
+      }
+      
+      values[i + 1] = saveValue;
+      
       i+=2;
     }
 
@@ -385,3 +562,4 @@
 
 }
 
+

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/component/UIXComponentBase.java Fri Oct  3 03:19:33 2008
@@ -18,8 +18,11 @@
  */
 package org.apache.myfaces.trinidad.component;
 
+import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.IOException;
+import java.io.ObjectOutputStream;
+
 import java.net.URL;
 import java.util.Iterator;
 import java.util.List;
@@ -47,6 +50,7 @@
 import org.apache.myfaces.trinidad.bean.FacesBean;
 import org.apache.myfaces.trinidad.bean.FacesBeanFactory;
 import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.bean.util.StateUtils;
 import org.apache.myfaces.trinidad.bean.util.ValueMap;
 import org.apache.myfaces.trinidad.change.AttributeComponentChange;
 import org.apache.myfaces.trinidad.context.RequestContext;
@@ -831,21 +835,56 @@
 
     if (_LOG.isFiner())
       _LOG.finer("processSaveState() on " + this);
-
-    if (((_children == null) || _children.isEmpty()) &&
-        ((_facets == null) || _facets.isEmpty()))
+    
+    Object state = null;
+    
+    try
     {
-      return saveState(context);
+      if (((_children == null) || _children.isEmpty()) &&
+          ((_facets == null) || _facets.isEmpty()))
+      {
+        state = saveState(context);
+      }
+      else
+      {
+        TreeState treeState = new TreeState();
+        treeState.saveState(context, this);
+        if (treeState.isEmpty())
+          state = null;
+  
+        state = treeState;
+      }
     }
-    else
+    catch (RuntimeException e)
     {
-      TreeState state = new TreeState();
-      state.saveState(context, this);
-      if (state.isEmpty())
-        return null;
-
-      return state;
+      _LOG.warning(_LOG.getMessage("COMPONENT_CHILDREN_SAVED_STATE_FAILED", this));
+      
+      System.out.println(_LOG.getMessage("COMPONENT_CHILDREN_SAVED_STATE_FAILED", this));
+      
+      throw e;
     }
+    
+    // if component state serialization checking is on, attempt to Serialize the
+    // component state immediately in order to determine which component's state
+    // failed state saving.  Note that since our parent will attempt this same
+    // serialization, turning this on is expensive and should only be used once
+    // a serialization error has been detected and we want to know which
+    // component's state failed
+    if (StateUtils.checkComponentStateSerialization(context))
+    {
+      try
+      {
+        new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(state);  
+      }
+      catch (IOException e)
+      {
+        System.out.println(_LOG.getMessage("COMPONENT_SAVED_STATE_FAILED", this));
+        
+        throw new RuntimeException(_LOG.getMessage("COMPONENT_SAVED_STATE_FAILED", this), e);
+      }
+    }
+
+    return state;
   }
 
   // TODO  will have deep problems if UIComponent.saveState() ever

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyMenuModel.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyMenuModel.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyMenuModel.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyMenuModel.java Fri Oct  3 03:19:33 2008
@@ -26,6 +26,7 @@
 import javax.faces.model.DataModel;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.CollectionUtils;
 
 /**
  * Creates a MenuModel from a List of beans.
@@ -186,9 +187,10 @@
     List<Object> path = (List<Object>) childKey;
     if ((path == null) || (path.size() <= 1))
       return null;
-    // Make a copy of the sublist - subList does not return
-    // a serializable object
-    return new ArrayList<Object>(path.subList(0, path.size() - 1));
+    
+    // wrap sublist in a Serializable copy, since sublist usually returns non-Serializable
+    // instances
+    return CollectionUtils.getSerializableList(path.subList(0, path.size() - 1));
   }
 
   @Override
@@ -411,4 +413,4 @@
   private Object _focusRowKey;
   private static final TrinidadLogger _LOG =
     TrinidadLogger.createTrinidadLogger(ChildPropertyMenuModel.class);
-}
\ No newline at end of file
+}

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyTreeModel.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyTreeModel.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyTreeModel.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/model/ChildPropertyTreeModel.java Fri Oct  3 03:19:33 2008
@@ -26,6 +26,7 @@
 import javax.faces.model.DataModel;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+import org.apache.myfaces.trinidad.util.CollectionUtils;
 
 /**
  * Creates a TreeModel from a List of beans.
@@ -188,9 +189,10 @@
     List<Object> path = (List<Object>) childKey;
     if ((path == null) || (path.size() <= 1))
       return null;
-    // Make a copy of the sublist - subList does not return
-    // a serializable object
-    return new ArrayList<Object>(path.subList(0, path.size() - 1));
+
+    // wrap sublist in a Serializable copy, since sublist usually returns non-Serializable
+    // instances
+    return CollectionUtils.getSerializableList(path.subList(0, path.size() - 1));
   }
 
   @Override

Added: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java?rev=701342&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java (added)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/java/org/apache/myfaces/trinidad/util/CollectionUtils.java Fri Oct  3 03:19:33 2008
@@ -0,0 +1,285 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidad.util;
+
+import java.io.ObjectStreamException;
+import java.io.Serializable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.RandomAccess;
+
+/**
+ * This class contains Collection utilities.
+ */
+public final class CollectionUtils
+{
+  private CollectionUtils()
+  {
+    // no-op
+  }
+
+  /**
+   * Returns a Collection based on the passed in Collection <code>c</code>,
+   * guaranteed to be Serializable. If <code>c</code> is Serializable,
+   * <code>c</code> will be returned, otherwise, <code>c</code> will be
+   * wrapped in a Collection that implements Serializable and upon
+   * Serialization the contents of <code>c</code> will be copied into
+   * the result.
+   * <p>
+   * The results is very similar to creating a new ArrayList with the
+   * contents of <code>c</code>, but no wrapper is created unless necessary
+   * and the actual creation of the Serializable copy is deferred until
+   * Serialization occurs.
+   * @param c The Collection to get a Serializable version of
+   * @return A Serializable version of Collection <code>c</code>
+   * @see #getSerializableList
+   */
+  public static <T> Collection<T> getSerializableCollection(Collection<T> c)
+  {
+    if (c instanceof Serializable)
+      return c;
+    else
+      return new SerializableCollection<T>(c);
+  }
+
+  /**
+   * Returns a List based on the passed in List <code>l</code>,
+   * guaranteed to be Serializable. If <code>l</code> is Serializable,
+   * <code>l</code> will be returned, otherwise, <code>l</code> will be
+   * wrapped in a List that implements Serializable and upon
+   * Serialization the contents of <code>l</code> will be copied into
+   * the result.
+   * <p>
+   * If <code>l</code> implements RandomAccess, any returned List will also
+   * implement RandomAccess.
+   * <p>
+   * The results is very similar to creating a new ArrayList with the
+   * contents of <code>l</code>, but no wrapper is created unless necessary
+   * and the actual creation of the Serializable copy is deferred until
+   * Serialization occurs.
+   * @param l The List to get a Serializable version of
+   * @return A Serializable version of List <code>l</code>
+   * @see #getSerializableCollection
+   */
+  public static <T> List<T> getSerializableList(List<T> l)
+  {
+    if (l instanceof Serializable)
+      return l;
+    else
+    {
+      if (l instanceof RandomAccess)
+      {
+        return new SerializableRandomAccessList<T>(l);
+      }
+      else
+      {
+        return new SerializableList<T>(l);
+      }
+    }
+  }
+  
+  
+  private static class SerializableCollection<E> implements Collection<E>, Serializable
+  {
+    SerializableCollection(Collection<E> delegate)
+    {
+      if (delegate == null)
+        throw new NullPointerException();
+      
+      if (delegate instanceof Serializable)
+        throw new IllegalStateException();
+      
+      _delegate = delegate;
+    }
+        
+    public int size()
+    {
+      return _delegate.size();
+    }
+
+    public boolean isEmpty()
+    {
+      return _delegate.isEmpty();
+    }
+
+    public boolean contains(Object o)
+    {
+      return _delegate.contains(o);
+    }
+
+    public Iterator<E> iterator()
+    {
+      return _delegate.iterator();
+    }
+
+    public Object[] toArray()
+    {
+      return _delegate.toArray();
+    }
+
+    public <T> T[] toArray(T[] a)
+    {
+      return _delegate.toArray(a);
+    }
+
+    public boolean add(E e)
+    {
+      return _delegate.add(e);
+    }
+
+    public boolean remove(Object o)
+    {
+      return _delegate.remove(0);
+    }
+
+    public boolean containsAll(Collection<?> c)
+    {
+      return _delegate.containsAll(c);
+    }
+
+    public boolean addAll(Collection<? extends E> c)
+    {
+      return _delegate.addAll(c);
+    }
+
+    public boolean removeAll(Collection<?> c)
+    {
+      return _delegate.removeAll(c);
+    }
+
+    public boolean retainAll(Collection<?> c)
+    {
+      return _delegate.retainAll(c);
+    }
+
+    public void clear()
+    {
+      _delegate.clear();
+    }
+    
+    protected Object writeReplace() throws ObjectStreamException
+    {
+      // copy delegate into a Serializable ArrayList on Serialization
+      return new ArrayList(_delegate);
+    }
+
+    /**
+     * All Collections
+     * @param o
+     * @return
+     */
+    public boolean equals(Object o)
+    {
+      return (o == this) || _delegate.equals(o);
+    }
+
+    public int hashCode()
+    {
+      return _delegate.hashCode();
+    }
+
+    public String toString()
+    {
+      return _delegate.toString();
+    }
+
+    private static final long serialVersionUID = 0L;
+
+    private final transient Collection<E> _delegate;
+  }
+
+
+  private static class SerializableList<E> extends SerializableCollection<E> implements List<E>
+  {
+    SerializableList(List<E> delegate)
+    {
+      super(delegate);
+      _delegate = delegate;
+    }
+    
+    public void add(int index, E element)
+    {
+      _delegate.add(index, element);
+    }
+
+    public E remove(int index)
+    {
+      return _delegate.remove(index);
+    }
+
+    public boolean addAll(int index, Collection<? extends E> c)
+    {
+      return _delegate.addAll(index, c);
+    }
+
+    public E get(int index)
+    {
+      return _delegate.get(index);
+    }
+
+    public E set(int index, E element)
+    {
+      return _delegate.set(index, element);
+    }
+
+    public int indexOf(Object o)
+    {
+      return _delegate.indexOf(o);
+    }
+
+    public int lastIndexOf(Object o)
+    {
+      return _delegate.lastIndexOf(o);
+    }
+
+    public ListIterator<E> listIterator()
+    {
+      return _delegate.listIterator();
+    }
+
+    public ListIterator<E> listIterator(int index)
+    {
+      return _delegate.listIterator(index);
+    }
+
+    public List<E> subList(int fromIndex, int toIndex)
+    {
+      return CollectionUtils.getSerializableList(_delegate.subList(fromIndex, toIndex));
+    }
+ 
+    private static final long serialVersionUID = 0L;
+    
+    private final transient List<E> _delegate;
+  }
+
+  private static class SerializableRandomAccessList<E> extends SerializableList<E> implements RandomAccess
+  {
+    SerializableRandomAccessList(List<E> delegate)
+    {
+      super(delegate);
+    }
+
+    private static final long serialVersionUID = 0L;
+  }
+   
+}

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-api/src/main/xrts/org/apache/myfaces/trinidad/resource/LoggerBundle.xrts Fri Oct  3 03:19:33 2008
@@ -399,4 +399,16 @@
 <!-- DEPRECATED_RELATIVE_ID_SYNTAX -->
 <resource key="DEPRECATED_RELATIVE_ID_SYNTAX">Could not find the component with scopedId {0} from {1} with the supported syntax. The component was found with the deprecated syntax. Please use the supported syntax.</resource>
 
+<!-- UNSERIALIZABLE_PROPERTY_VALUE -->
+<resource key="UNSERIALIZABLE_PROPERTY_VALUE">Unserializable value:{0} on property key:{1}</resource>
+
+<!-- COMPONENT_SAVED_STATE_FAILED -->
+<resource key="COMPONENT_SAVED_STATE_FAILED">Failed to save state for component:{0}</resource>
+
+<!-- COMPONENT_CHILDREN_SAVED_STATE_FAILED -->
+<resource key="COMPONENT_CHILDREN_SAVED_STATE_FAILED">Failed to save state for children of component:{0}</resource>
+
+<!-- COMPONENT_TREE_SERIALIZATION_FAILED -->
+<resource key="COMPONENT_TREE_SERIALIZATION_FAILED">Failed to serialize component tree state</resource>
+
 </resources>

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/application/StateManagerImpl.java Fri Oct  3 03:19:33 2008
@@ -48,6 +48,11 @@
 
 import com.sun.facelets.FaceletViewHandler;
 
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.myfaces.trinidad.bean.util.StateUtils;
+
 /**
  * StateManager that handles a hybrid client/server strategy:  a
  * SerializedView is stored on the server, and only a small token
@@ -978,6 +983,22 @@
     {
       _structure = structure;
       _state = state;
+      
+      // if component tree serialization checking is on (in order to validate
+      // fail over support, attempt to Serialize all of the component state
+      //  immediately
+      if (StateUtils.checkComponentTreeStateSerialization(fc))
+      {
+        try
+        {
+          new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(state);
+        }
+        catch (IOException e)
+        {          
+          throw new RuntimeException(_LOG.getMessage("COMPONENT_TREE_SERIALIZATION_FAILED"), e);
+        }
+      }
+                  
       // we need this state, as we are going to recreate the UIViewRoot later. see
       // the popRoot() method:
       _cachedState = (root != null)
@@ -1066,53 +1087,6 @@
     }    
   }
 
-  /* =-=AEW A utility function to dump out all the state that's getting
-     sent over.  To compile, you need to make most of TreeState public */
-  /*
-  static private void _dumpState(Object state, int depth)
-  {
-    String out = _SPACES.substring(0, depth * 2);
-    Object objectState = state;
-
-    if (state instanceof org.apache.myfaces.trinidad.component.TreeState)
-      objectState = ((org.apache.myfaces.trinidad.component.TreeState) state)._state;
-
-    if (objectState == null)
-      out += "null";
-    else if (objectState instanceof Object[])
-      out += "array";
-    else
-      out += objectState.toString() + "(" + objectState.getClass() + ")";
-
-    if (objectState instanceof Object[])
-    {
-      Object[] array = (Object[]) objectState;
-      for (int i = 0; i < array.length; i++)
-        _dumpState(array[i], depth + 1);
-    }
-
-
-    if (state instanceof org.apache.myfaces.trinidad.component.TreeState)
-    {
-      Object[] array = ((org.apache.myfaces.trinidad.component.TreeState)state)._children;
-      if (array != null)
-      {
-        for (int i = 0; i < array.length; i++)
-          _dumpState(array[i], depth + 1);
-      }
-
-      array = ((org.apache.myfaces.trinidad.component.TreeState)state)._facets;
-      if (array != null)
-      {
-        for (int i = 0; i < array.length; i++)
-          _dumpState(array[i], depth + 1);
-      }
-    }
-  }
-
-  static private final String _SPACES = "                                                                            ";
-  */
-
   private final StateManager _delegate;
   private       Boolean      _useViewRootCache;
   private       Boolean      _useApplicationViewCache;

Added: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/CheckSerializationConfigurator.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/CheckSerializationConfigurator.java?rev=701342&view=auto
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/CheckSerializationConfigurator.java (added)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/CheckSerializationConfigurator.java Fri Oct  3 03:19:33 2008
@@ -0,0 +1,88 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.myfaces.trinidadinternal.config;
+
+import java.io.Serializable;
+
+import java.util.Collections;
+import java.util.Map;
+
+import javax.faces.context.ExternalContext;
+
+import org.apache.myfaces.trinidad.bean.util.StateUtils;
+import org.apache.myfaces.trinidad.config.Configurator;
+import org.apache.myfaces.trinidad.context.ExternalContextDecorator;
+
+/**
+ * Configurator that uses a wrapped ExternalContext to return a Session Map that validates that
+ * only Serializable Objects are placed in the Map.
+ * @version $Revision$ $Date$
+ */
+public final class CheckSerializationConfigurator extends Configurator
+{
+
+  /**
+   * Override to return our ExternalContext wrapped if session serialization checking is enabled
+   * @param externalContext
+   * @return
+   */
+  @Override
+  public ExternalContext getExternalContext(ExternalContext externalContext)
+  {
+    if (StateUtils.checkSessionSerialization(externalContext))
+    {
+      return new SessionSerializationChecker(externalContext);
+    }
+    else
+    {
+      return externalContext;
+    }
+  }
+  
+  /**
+   * ExternalContextDecorator returning our wrapped SessionMap
+   */
+  private static class SessionSerializationChecker extends ExternalContextDecorator
+  {
+    public SessionSerializationChecker(ExternalContext extContext)
+    {
+      _extContext = extContext;
+      
+      // skank using type erasure to finess the fact that Collections.checkedMap() expects and
+      // will return a Map<String, Serializable> when in fact, we should be returning a
+      // Map<String, Onject>.  Using checkedMap also has the disadvantage that a ClassCastException
+      // is thrown when we would really prefer to throw a more-explanatory message
+      Map erasedMap = extContext.getSessionMap();
+      _sessionMap = (Map)Collections.checkedMap(erasedMap, String.class, Serializable.class);
+    }
+
+    protected ExternalContext getExternalContext()
+    {
+      return _extContext;
+    }
+
+    public Map getSessionMap()
+    {
+      return _sessionMap;
+    }
+    
+    private final ExternalContext _extContext;
+    private final Map _sessionMap;
+  }
+}

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/dispatch/DispatchResponseConfiguratorImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/dispatch/DispatchResponseConfiguratorImpl.java?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/dispatch/DispatchResponseConfiguratorImpl.java (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/config/dispatch/DispatchResponseConfiguratorImpl.java Fri Oct  3 03:19:33 2008
@@ -18,22 +18,13 @@
  */
 package org.apache.myfaces.trinidadinternal.config.dispatch;
 
-import java.io.IOException;
 import java.util.Map;
 
-import javax.faces.FacesException;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
-import javax.portlet.PortletContext;
-import javax.portlet.PortletException;
-import javax.portlet.PortletRequestDispatcher;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
 
 import org.apache.myfaces.trinidad.config.Configurator;
-import org.apache.myfaces.trinidad.context.ExternalContextDecorator;
 import org.apache.myfaces.trinidad.util.ExternalContextUtils;
-import org.apache.myfaces.trinidadinternal.webapp.wrappers.PortletContextWrapper;
 
 /**
  * TODO: Document this

Modified: myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.config.Configurator
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.config.Configurator?rev=701342&r1=701341&r2=701342&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.config.Configurator (original)
+++ myfaces/trinidad/branches/1.2.9.1-branch/trinidad-impl/src/main/resources/META-INF/services/org.apache.myfaces.trinidad.config.Configurator Fri Oct  3 03:19:33 2008
@@ -1,2 +1,3 @@
 org.apache.myfaces.trinidadinternal.config.upload.FileUploadConfiguratorImpl
 org.apache.myfaces.trinidadinternal.config.dispatch.DispatchResponseConfiguratorImpl
+org.apache.myfaces.trinidadinternal.config.CheckSerializationConfigurator