You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by so...@apache.org on 2008/01/10 18:27:56 UTC

svn commit: r610847 - in /myfaces/portlet-bridge/trunk: api/src/main/java/javax/portlet/faces/ api/src/main/java/javax/portlet/faces/annotation/ api/src/main/java/javax/portlet/faces/component/ impl/src/main/java/org/apache/myfaces/portlet/faces/applic...

Author: sobryan
Date: Thu Jan 10 09:27:52 2008
New Revision: 610847

URL: http://svn.apache.org/viewvc?rev=610847&view=rev
Log:
PORTLETBRIDGE-22: Update PortletBridge to latest draft (revision 11)
PORTLETBRIDGE-21: Wrong leading slash in BRIDGE_SERVICE_CLASSPATH /GenericFacesPortlet

These issues have been fixes under a patch submitted to 
PORTLETBRIDGE-22 by Michael Freedman.  I had to remove the 
BridgeRenderFilter for reasons documented in the bug and have made an
inquiry to the EG on how this needs to be resolved from a spec 
standpoint.  Likely it'll be left up to an implementation detail for
the Apache community at which point I'll generate another bug.

Thanks Michael for all your work on this patch.

Added:
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgePreDestroy.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgeRequestScopeAttributeAdded.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/ExcludeFromManagedRequestScope.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/PortletNamingContainer.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/config/FacesConfigurationProcessor.java
Removed:
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainer.java
Modified:
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestHeaders.java
    myfaces/portlet-bridge/trunk/impl/src/main/resources/META-INF/faces-config.xml

Modified: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java (original)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java Thu Jan 10 09:27:52 2008
@@ -54,6 +54,8 @@
 
   public static final String MAX_MANAGED_REQUEST_SCOPES    = BRIDGE_PACKAGE_PREFIX
                                                              + "MAX_MANAGED_REQUEST_SCOPES";
+  public static final String RENDER_POLICY                 = BRIDGE_PACKAGE_PREFIX
+                                                              + "RENDER_POLICY";
 
   public static final String LIFECYCLE_ID                  = "javax.faces.LIFECYCLE_ID";
 
@@ -82,12 +84,9 @@
   // request scope and restore them as parameters in the subsequent renders
   public static final String PRESERVE_ACTION_PARAMS        = "preserveActionParams";
 
-  // allows a portlet to control render delgation. A value of "ALWAYS_DELEGATE" indicates
-  // the bridge doesn't render itself, it merely delegates. A value of "NEVER_DELEGATE"
-  // indicates the bridge never delegates, rather it always overrides and renders.
-  // A value of "DEFAULT" indicates the bridge will delegate first and only render
-  // if the delegatee throws an exception/throwable.
-  public static final String RENDER_POLICY                 = "renderPolicy";
+  // allows a portlet to which request attributes the bridge excludes from its
+  // managed request scope.
+  public static final String EXCLUDED_REQUEST_ATTRIBUTES    = "excludedRequestAttributes";
 
   // Parameter that can be added to an ActionURL to signify it is a direct link
   // and hence shouldn't be encoded by encodeActionURL as an actionURL
@@ -127,7 +126,7 @@
 
   public static enum PortletPhase
   {
-    ActionPhase, RenderPhase, ;
+    ACTION_PHASE, RENDER_PHASE, ;
   }
 
   public static enum BridgeRenderPolicy

Modified: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java (original)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java Thu Jan 10 09:27:52 2008
@@ -33,31 +33,10 @@
     }
   }
   
-  public static boolean isPortletActionRequest() 
+  public static Bridge.PortletPhase getPortletRequestPhase() 
   {
     Map<String, Object> m = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
-    Bridge.PortletPhase phase = (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
-    if (phase != null && phase == Bridge.PortletPhase.ActionPhase)
-    {
-      return true;
-    }
-    else 
-    {
-      return false;
-    }
+    return (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
   }
   
-  public static boolean isPortletRenderRequest() 
-  {
-    Map<String, Object> m = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
-    Bridge.PortletPhase phase = (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
-    if (phase != null && phase == Bridge.PortletPhase.RenderPhase)
-    {
-      return true;
-    }
-    else 
-    {
-      return false;
-    }
-  }
 }

Modified: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java (original)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java Thu Jan 10 09:27:52 2008
@@ -16,6 +16,9 @@
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.GenericPortlet;
@@ -60,7 +63,7 @@
 {
   public static final String BRIDGE_CLASS             = Bridge.BRIDGE_PACKAGE_PREFIX
                                                         + "BridgeImplClass";
-  public static final String BRIDGE_SERVICE_CLASSPATH = "/META-INF/services/javax.portlet.faces.Bridge";
+  public static final String BRIDGE_SERVICE_CLASSPATH = "META-INF/services/javax.portlet.faces.Bridge";
 
   private Class<? extends Bridge> mFacesBridgeClass   = null;
   private Bridge                  mFacesBridge        = null;
@@ -96,29 +99,22 @@
       throw new PortletException("Configuration Error: Initial Parameter '" + BRIDGE_CLASS
                                  + "' is not defined for portlet: " + getPortletName());
     }
-
-    // Context level attribute for whether to encode redirect URL
-    String renderPolicy = getPortletConfig().getInitParameter(
-                                                              Bridge.BRIDGE_PACKAGE_PREFIX
-                                                                  + Bridge.RENDER_POLICY);
-    if (renderPolicy != null)
-    {
-      getPortletContext().setAttribute(
-                                       Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "."
-                                           + Bridge.RENDER_POLICY,
-                                       Bridge.BridgeRenderPolicy.valueOf(renderPolicy));
-    }
-    String preserveActionParams = getPortletConfig()
-                                                    .getInitParameter(
-                                                                      Bridge.BRIDGE_PACKAGE_PREFIX
-                                                                          + Bridge.PRESERVE_ACTION_PARAMS);
-    if (preserveActionParams != null)
+    
+    // Get the other bridge configuration parameters and set as context attributes
+    List<String> excludedAttrs = getExcludedRequestAttributes();
+    if (excludedAttrs != null)
     {
       getPortletContext().setAttribute(
                                        Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "."
-                                           + Bridge.PRESERVE_ACTION_PARAMS,
-                                       Boolean.valueOf(preserveActionParams));
+                                           + Bridge.EXCLUDED_REQUEST_ATTRIBUTES,
+                                       excludedAttrs);
     }
+    
+    Boolean preserveActionParams = getPreserveActionParameters();
+    getPortletContext().setAttribute(
+                                      Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "."
+                                      + Bridge.PRESERVE_ACTION_PARAMS,
+                                      preserveActionParams);
 
     // Don't instanciate/initialize the bridge yet. Do it on first use
   }
@@ -191,6 +187,59 @@
                                                                            IOException
   {
     doBridgeDispatch(request, response, getDefaultViewId(request, request.getPortletMode()));
+  }
+
+  /**
+   * Returns the set of RequestAttribute names that the portlet wants the bridge to
+   * exclude from its managed request scope.  This default implementation picks up
+   * this list from the comma delimited init_param javax.portlet.faces.excludedRequestAttributes.
+   * 
+   * @return a List containing the names of the attributes to be excluded. null if it can't be
+   *         determined.
+   */
+  public List<String> getExcludedRequestAttributes()
+  {
+    String excludedAttrs = getPortletConfig()
+                              .getInitParameter(
+                                Bridge.BRIDGE_PACKAGE_PREFIX
+                                + Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
+    if (excludedAttrs == null)  
+    {
+      return null;
+    }
+    
+    String[] attrArray = excludedAttrs.split(",");
+    // process comma delimited String into a List
+    ArrayList<String> list = new ArrayList(attrArray.length);
+    for (int i = 0; i < attrArray.length; i++)
+    {
+      list.add(attrArray[i]);
+    }
+    return list;
+  }
+
+  /**
+   * Returns a boolean indicating whether or not the bridge should preserve all the
+   * action parameters in the subsequent renders that occur in the same scope.  This
+   * default implementation reads the values from the portlet init_param
+   * javax.portlet.faces.preserveActionParams.  If not present, false is returned.
+   * 
+   * @return a boolean indicating whether or not the bridge should preserve all the
+   * action parameters in the subsequent renders that occur in the same scope.
+   */
+  public Boolean getPreserveActionParameters()
+  {
+    String preserveActionParams = getPortletConfig()
+                                    .getInitParameter(
+                                      Bridge.BRIDGE_PACKAGE_PREFIX);
+    if (preserveActionParams == null)
+    {
+      return Boolean.FALSE;
+    }
+    else
+    {
+      return Boolean.valueOf(preserveActionParams);
+    }
   }
 
   /**

Added: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgePreDestroy.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgePreDestroy.java?rev=610847&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgePreDestroy.java (added)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgePreDestroy.java Thu Jan 10 09:27:52 2008
@@ -0,0 +1,11 @@
+package javax.portlet.faces.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface BridgePreDestroy {
+}

Added: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgeRequestScopeAttributeAdded.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgeRequestScopeAttributeAdded.java?rev=610847&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgeRequestScopeAttributeAdded.java (added)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/BridgeRequestScopeAttributeAdded.java Thu Jan 10 09:27:52 2008
@@ -0,0 +1,12 @@
+package javax.portlet.faces.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface BridgeRequestScopeAttributeAdded {
+}
+

Added: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/ExcludeFromManagedRequestScope.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/ExcludeFromManagedRequestScope.java?rev=610847&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/ExcludeFromManagedRequestScope.java (added)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/ExcludeFromManagedRequestScope.java Thu Jan 10 09:27:52 2008
@@ -0,0 +1,11 @@
+package javax.portlet.faces.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface ExcludeFromManagedRequestScope {
+}

Added: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/PortletNamingContainer.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/PortletNamingContainer.java?rev=610847&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/PortletNamingContainer.java (added)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/annotation/PortletNamingContainer.java Thu Jan 10 09:27:52 2008
@@ -0,0 +1,11 @@
+package javax.portlet.faces.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface PortletNamingContainer {
+}

Modified: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java (original)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java Thu Jan 10 09:27:52 2008
@@ -17,12 +17,14 @@
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 
+import javax.portlet.faces.annotation.PortletNamingContainer;
+
 /**
  * Bridge ViewRoot that implements NamingContainer which uses the ExternalContext.encodeNamespace to
  * introduce the consumer namespace into tree components.
  */
-public class PortletNamingContainerUIViewRoot extends UIViewRoot implements PortletNamingContainer,
-    Serializable
+@PortletNamingContainer
+public class PortletNamingContainerUIViewRoot extends UIViewRoot implements Serializable
 {
 
   //TODO: This should be regenerated each time this is modified.  Can this be added to maven?

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java Thu Jan 10 09:27:52 2008
@@ -36,11 +36,13 @@
 import javax.faces.context.ResponseWriter;
 import javax.faces.render.RenderKit;
 import javax.faces.render.RenderKitFactory;
+
+import javax.portlet.PortletContext;
 import javax.portlet.RenderResponse;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
+import javax.portlet.faces.annotation.PortletNamingContainer;
 import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
-import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
 
 /**
  * View handler implementation for JSF portlet bridge.
@@ -58,6 +60,7 @@
 
   // the ViewHandler to delegate to
   private ViewHandler mDelegate;
+  private Bridge.BridgeRenderPolicy mRenderPolicy = null;
 
   public PortletViewHandlerImpl(ViewHandler handler)
   {
@@ -81,7 +84,10 @@
 
     UIViewRoot viewRoot = super.createView(facesContext, viewId);
 
-    if (viewRoot.getClass() != UIViewRoot.class)
+    // Use the delegatees UIViewRoot if its not the native Faces one
+    // or it already implements the PortletNamingContainer behavior
+    if ((viewRoot.getClass() != UIViewRoot.class) || 
+        (viewRoot.getClass().getAnnotation(PortletNamingContainer.class) != null))
     {
       return viewRoot;
     }
@@ -105,24 +111,27 @@
       return;
     }
 
-    // Get the renderPolicy from the requestScope
-    Bridge.BridgeRenderPolicy renderPolicy = (Bridge.BridgeRenderPolicy) context
-                                                                                .getExternalContext()
-                                                                                .getRequestMap()
-                                                                                .get(
-                                                                                     PortletExternalContextImpl.RENDER_POLICY_ATTRIBUTE);
-
-    if (renderPolicy == null)
+    // If first time -- Get the renderPolicy from the context init parameter 
+    if (mRenderPolicy == null)
     {
-      renderPolicy = Bridge.BridgeRenderPolicy.valueOf("DEFAULT");
+      PortletContext pCtx = (PortletContext) context.getExternalContext().getContext();
+      String policy = pCtx.getInitParameter(Bridge.RENDER_POLICY);
+      if (policy != null)
+      {
+        mRenderPolicy = Bridge.BridgeRenderPolicy.valueOf(policy);
+      }
+      else
+      {
+        mRenderPolicy = Bridge.BridgeRenderPolicy.DEFAULT;
+      }
     }
 
-    if (renderPolicy == Bridge.BridgeRenderPolicy.ALWAYS_DELEGATE)
+    if (mRenderPolicy == Bridge.BridgeRenderPolicy.ALWAYS_DELEGATE)
     {
       super.renderView(context, viewToRender);
       return;
     }
-    else if (renderPolicy == Bridge.BridgeRenderPolicy.DEFAULT)
+    else if (mRenderPolicy == Bridge.BridgeRenderPolicy.DEFAULT)
     {
       try
       {
@@ -237,11 +246,11 @@
     {
       if (content instanceof char[])
       {
-        renderResponse.getWriter().write(new String((byte[]) content));
+        renderResponse.getWriter().write(new String((char[]) content));
       }
       else if (content instanceof byte[])
       {
-        renderResponse.getWriter().write(new String((char[]) content));
+        renderResponse.getWriter().write(new String((byte[]) content));
       }
       else
       {

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Thu Jan 10 09:27:52 2008
@@ -21,6 +21,11 @@
 
 import java.io.IOException;
 import java.io.Serializable;
+
+import java.lang.reflect.Method;
+
+import java.net.URL;
+
 import java.rmi.server.UID;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -29,6 +34,7 @@
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -65,9 +71,15 @@
 import javax.portlet.RenderResponse;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeException;
+import javax.portlet.faces.annotation.BridgePreDestroy;
+import javax.portlet.faces.annotation.BridgeRequestScopeAttributeAdded;
+import javax.portlet.faces.annotation.ExcludeFromManagedRequestScope;
+
 import javax.servlet.ServletConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSessionBindingEvent;
@@ -75,10 +87,11 @@
 
 import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgeRenderRequestWrapper;
 import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
+import org.apache.myfaces.portlet.faces.util.config.FacesConfigurationProcessor;
 import org.apache.myfaces.portlet.faces.util.config.WebConfigurationProcessor;
 
 public class BridgeImpl
-  implements Bridge, ELContextListener, PhaseListener
+  implements Bridge, ELContextListener, PhaseListener, ServletRequestAttributeListener
 {
 	private static final long	serialVersionUID	= 5807626987246270989L;
 
@@ -91,10 +104,12 @@
   private static final String FACES_VIEWROOT = "org.apache.myfaces.portlet.faces.facesViewRoot";
   private static final String FACES_MESSAGES = "org.apache.myfaces.portlet.faces.facesMessages";
   private static final String REQUEST_PARAMETERS = "org.apache.myfaces.portlet.faces.requestParameters";
+  private static final String PREEXISTING_ATTRIBUTE_NAMES = "org.apache.myfaces.portlet.faces.preExistingAttributeNames";
   private static final String REQUEST_SCOPE_ID_RENDER_PARAM = "_bridgeRequestScopeId";
   private static final int DEFAULT_MAX_MANAGED_REQUEST_SCOPES = 100;
 
-  private boolean mPreserveActionParams = false;
+  private Boolean mPreserveActionParams = false;
+  private List<String> mExcludedRequestAttributes = null;
 
   private PortletConfig mPortletConfig = null;
   private FacesContextFactory mFacesContextFactory = null;
@@ -115,17 +130,25 @@
     mPortletConfig = config;
     PortletContext portletContext = mPortletConfig.getPortletContext();
 
-    // get preserveActionParams here because we use later in this class.
-    // however don't process renderPolicy here because its used in
-    // ViewHandler (and needs to be at request scope) -- hence this
-    // is done in ExternalContext.
-    Boolean configParam = 
-      (Boolean) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
+    // get preserveActionParams and excludedAttributes configuration settings.
+    mPreserveActionParams = (Boolean) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
                                             "." + Bridge.PRESERVE_ACTION_PARAMS);
-    if (configParam != null)
+    
+    mExcludedRequestAttributes = (List <String>) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
+                                            "." + Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
+    if (mExcludedRequestAttributes != null)
     {
-      mPreserveActionParams = configParam.booleanValue();
+      // copy the list as we may be adding to it and don't want to worry that this might be immutable
+      mExcludedRequestAttributes = new ArrayList(mExcludedRequestAttributes);     
     }
+    else
+    {
+      // Otherwise create an empty list
+      mExcludedRequestAttributes = new ArrayList(5);
+    }
+   
+    // Read excludedAttributes that may be defined in any face-config.xml
+    readExcludedAttributesFromFacesConfig(portletContext, mExcludedRequestAttributes);
 
     // Set up the synchronziation object for the RequestScopeMap as we don't
     // want to sync on the PortletContext because its too broad. Note:
@@ -158,6 +181,10 @@
     // ExternalContext
     WebConfigurationProcessor webConfig = new WebConfigurationProcessor(portletContext);
     mFacesMappings = webConfig.getFacesMappings();
+    if (mFacesMappings == null || mFacesMappings.size() == 0)
+    {
+      throw new BridgeException("BridgeImpl.init(): unable to determine Faces servlet web.xml mapping.");
+    }
     for (int i = 0; i < mFacesMappings.size(); i++)
     {
       portletContext.log("Mapping: " + mFacesMappings.get(i));
@@ -171,7 +198,7 @@
     // available to Faces extensions -- allowing that code to NOT rely on
     // instanceof which can fail if a portlet container uses a single class
     // to implement both the action and render request/response objects
-    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.ActionPhase);
+    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.ACTION_PHASE);
 
     // Set the FacesServletMapping attribute so the ExternalContext can
     // pick it up and use it to reverse map viewIds to paths
@@ -186,9 +213,15 @@
     // acquiring the FacesContext because its possible (though unlikely)
     // the application has inserted itself in this process and sets up
     // needed request attributes.
-    List<String> excludedAttributes = getExcludedAttributes(request);
+    List<String> preExistingAttributes = getRequestAttributes(request);
+    // place on the request for use here and in the servletRequestAttributeListener
+    if (preExistingAttributes != null)
+    {
+      request.setAttribute(PREEXISTING_ATTRIBUTE_NAMES, preExistingAttributes);
+    }
 
     FacesContext context = null;
+    String scopeId = null;
     try
     {
       // Get the FacesContext instance for this request
@@ -198,7 +231,7 @@
       // Each action starts a new "action lifecycle"
       // The Bridge preserves request scoped data and if so configured
       // Action Parameters for the duration of an action lifecycle
-      String scopeId = initBridgeRequestScope(request, response);
+      scopeId = initBridgeRequestScope(request, response);
 
       // For actions we only execute the lifecycle phase
       getLifecycle().execute(context);
@@ -231,7 +264,7 @@
         // within the same request scope but Faces does (assumes this),
         // preserve the request scope data and the Faces view tree at
         // RequestScope.
-        saveBridgeRequestScopeData(context, scopeId, excludedAttributes);
+        saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
 
         // Finalize the action response -- key here is the reliance on
         // ExternalContext.encodeActionURL to migrate info encoded
@@ -259,12 +292,52 @@
     }
     finally
     {
+      dumpScopeId(scopeId, "ACTION_PHASE");
+      // our servletrequestattributelistener uses this as an indicator of whether 
+      // its actively working on a request -- remove it to indicate we are done
+      request.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
       if (context != null)
       {
         context.release();
       }
     }
   }
+  
+  private void dumpScopeId(String scopeId, String phase)
+  {
+    // Get the data from the scope
+    PortletContext ctx = mPortletConfig.getPortletContext();
+    ctx.log("dumpScopeId: " + phase);
+    synchronized (ctx.getAttribute(REQUEST_SCOPE_LOCK))
+    {
+      // get the managedScopeMap
+      LRUMap requestScopeMap = (LRUMap) ctx.getAttribute(REQUEST_SCOPE_MAP);
+      // No scope for all renders before first action to this portletApp
+      if (requestScopeMap == null)
+      {
+        ctx.log("There are No saved scoped.  Can't match: "+ scopeId);
+        return;
+      }
+
+      Map<String, Object> m = requestScopeMap.get(scopeId);
+      if (m == null)
+      {
+        ctx.log("Can't match scope: "+ scopeId);
+        return;
+      }
+      
+      Set<Map.Entry<String,Object>> set = m.entrySet();
+      Iterator<Map.Entry<String,Object>> i = set.iterator();
+      ctx.log("Elements in scope: " + scopeId);
+      while (i.hasNext())
+      {
+        Map.Entry<String,Object> entry = i.next();
+        ctx.log("     " + entry.getKey());
+      }
+      ctx.log("end dumpScopeId");
+    }
+       
+  }
 
   public void doFacesRequest(RenderRequest request, RenderResponse response)
     throws BridgeException
@@ -275,7 +348,7 @@
     // available to Faces extensions -- allowing that code to NOT rely on
     // instanceof which can fail if a portlet container uses a single class
     // to implement both the action and render request/response objects
-    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.RenderPhase);
+    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.RENDER_PHASE);
 
     // Set the FacesServletMapping attribute so the ExternalContext can
     // pick it up and use it to reverse map viewIds to paths
@@ -391,6 +464,10 @@
     }
     finally
     {
+      dumpScopeId(scopeId, "RENDER_PHASE");
+      // our servletrequestattributelistener uses this as an indicator of whether 
+      // its actively working on a request -- remove it to indicate we are done
+      request.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
       if (context != null)
       {
         context.release();
@@ -422,6 +499,82 @@
       elContext.putContext(PortletConfig.class, mPortletConfig);
     }
   }
+  
+  /*
+   * ServletRequestAttributeListener implementation
+   */
+  public void attributeAdded(ServletRequestAttributeEvent srae)
+  {
+    // use this phase attribute as an indicator of whether 
+    // we are actively working on a request
+    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+    
+    // do nothing if before/after bridge processing or in the render phase.
+    // Don't care about render phase because we don't update/change the managed
+    // scope based on changes during render.
+    // ALSO: do nothing if not in the Bridge's managed request scope
+    if (phase == null || phase == PortletPhase.RENDER_PHASE ||
+        isExcludedFromBridgeRequestScope(srae.getName(),
+                                               srae.getValue(),
+                                               (List<String>)
+                                                  srae.getServletRequest().getAttribute(PREEXISTING_ATTRIBUTE_NAMES)))
+    {
+      return;
+    }
+    
+    // Otherwise -- see if the added attribute implements the bridge's 
+    // BridgeRequestScopeAdded annotation -- call each method so annotated
+    Object o = srae.getValue();
+    Method[] methods = o.getClass().getMethods();
+    for (int i = 0; i < methods.length; i++)
+    {
+      if (methods[i].isAnnotationPresent(BridgeRequestScopeAttributeAdded.class))
+      {
+        try
+        {
+          methods[i].invoke(o, null);
+        }
+        catch (Exception e)
+        {
+            // TODO: log problem
+            // do nothing and forge ahead
+            ;
+        }
+      }
+    }
+  }
+  
+  public void attributeRemoved(ServletRequestAttributeEvent srae)
+  {
+    // use this phase attribute as an indicator of whether 
+    // we are actively working on a request
+    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+    
+    // If in an action this means the attribute has been removed before we have
+    // saved the action scope -- since the managed bean has been informed we are
+    // running in a portlet environment it should have ignored the PreDestroy.
+    // To make up for this we call its BridgePredestroy
+    if (phase != null && phase == PortletPhase.ACTION_PHASE)
+    {
+      notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
+    }
+  }
+  
+  public void attributeReplaced(ServletRequestAttributeEvent srae)
+  {
+    // use this phase attribute as an indicator of whether 
+    // we are actively working on a request
+    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+    
+    // If in an action this means the attribute has been replaced before we have
+    // saved the action scope -- since the managed bean has been informed we are
+    // running in a portlet environment it should have ignored the PreDestroy.
+    // To make up for this we call its BridgePredestroy
+    if (phase != null && phase == PortletPhase.ACTION_PHASE)
+    {
+      notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
+    }
+  }
 
   private FacesContextFactory getFacesContextFactory()
     throws BridgeException
@@ -503,7 +656,7 @@
     ExternalContext ec = context.getExternalContext();
     Map<String, Object> requestMap = ec.getRequestMap();
     Map<String, String[]> requestParameterMap = ec.getRequestParameterValuesMap();
-    if (!mPreserveActionParams)
+    if (mPreserveActionParams == Boolean.FALSE)
     {
       if (requestMap != null && requestParameterMap != null && 
           requestParameterMap.containsKey(ResponseStateManager.VIEW_STATE_PARAM))
@@ -545,8 +698,16 @@
 
       if (requestScopeMap == null)
       {
-        requestScopeMap = createRequestScopeMap(portletContext);
-        portletContext.setAttribute(REQUEST_SCOPE_MAP, requestScopeMap);
+        // Have only done renders to this point -- so no scope to update
+        return;
+      }
+      
+      // now see if this scope is in the Map
+      Map<String, Object> scopeMap = requestScopeMap.get(scopeId);
+      if (scopeMap == null)
+      {
+        // Scope has been previously removed -- so no scope to update
+        return;
       }
 
       // Prepare the value for storing as a preserved parameter
@@ -555,19 +716,6 @@
       String[] values = new String[1];
       values[0] = updatedViewStateParam;
 
-      // now see if this scope is in the Map
-      Map<String, Object> scopeMap = requestScopeMap.get(scopeId);
-      
-      Boolean isNew = false;
-
-      if (scopeMap == null) 
-      {
-        // allocate a Map  and put
-        scopeMap = new HashMap<String, Object>(1);
-        // delay adding to requestScopeMap until populated
-        isNew = true;
-      }
-      
       // Now get the RequestParameters from the scope
       @SuppressWarnings("unchecked")
       Map<String, String[]> requestParams = (Map<String, String[]>)scopeMap.get(REQUEST_PARAMETERS);
@@ -579,20 +727,10 @@
       }
       // finally update the value in the Map
       requestParams.put(ResponseStateManager.VIEW_STATE_PARAM, values);
-      
-      //TODO: We delay putting this on the map in case an exception occurs in the above
-      //      code.  The above code should never generate an exception, however, so this
-      //      could be simplified.
-      // if a newly allocated scope -- don't forget to add it in
-      if (isNew)
-      {
-        requestScopeMap.put(scopeId, scopeMap);
-      }
-      
     }
-
   }
   
+  
   private LRUMap createRequestScopeMap(PortletContext portletContext) 
   {
     // see if portlet has defined how many requestScopes to manage
@@ -692,12 +830,12 @@
   }
 
   private void saveBridgeRequestScopeData(FacesContext context, String scopeId, 
-                                          List<String> excludeList)
+                                          List<String> preExistingList)
   {
 
     // Store the RequestMap @ the bridge's request scope
     putBridgeRequestScopeData(scopeId, 
-                              copyRequestMap(context.getExternalContext().getRequestMap(), excludeList));
+                              copyRequestMap(context.getExternalContext().getRequestMap(), preExistingList));
 
     // flag the data so can remove it if the session terminates
     // as its unlikely useful if the session disappears
@@ -725,7 +863,7 @@
     }
   }
 
-  private Map<String, Object> copyRequestMap(Map<String, Object> m, List<String> excludeList)
+  private Map<String, Object> copyRequestMap(Map<String, Object> m, List<String> preExistingList)
   {
     Map<String, Object> copy = new HashMap<String, Object>(m.size());
      
@@ -736,8 +874,7 @@
       // Don't copy any of the portlet or Faces objects
   		String key = entry.getKey();
   		Object value = entry.getValue();
-  		if(!excludeList.contains(key) &&
-  			 !contextObject(key, value))
+  		if(!isExcludedFromBridgeRequestScope(key, value, preExistingList))
   		{
   			copy.put(key, value);
   		}
@@ -746,12 +883,20 @@
   }
   
   @SuppressWarnings("unchecked")
-  private List<String> getExcludedAttributes(PortletRequest request)
+  private List<String> getRequestAttributes(PortletRequest request)
   {
   	return Collections.list((Enumeration<String>)request.getAttributeNames());
   }
+  
+  private boolean isExcludedFromBridgeRequestScope(String key, Object value, List<String> preExistingList)
+  {
+    return ((value.getClass().getAnnotation(ExcludeFromManagedRequestScope.class) != null) ||
+         (preExistingList != null && preExistingList.contains(key)) ||
+         isPreDefinedExcludedObject(key, value) ||
+         isConfiguredExcludedAttribute(key));
+  }
 
-  private boolean contextObject(String s, Object o)
+  private boolean isPreDefinedExcludedObject(String s, Object o)
   {
     return o instanceof PortletConfig || o instanceof PortletContext || 
       o instanceof PortletRequest || o instanceof PortletResponse || o instanceof PortletSession || 
@@ -763,10 +908,36 @@
       isInNamespace(s, "javax.faces.") ||
       isInNamespace(s, "javax.servlet.") ||
       isInNamespace(s, "javax.servlet.include.") ||
-      // TODO: remove once support configuring these
-      s.startsWith("org.apache.myfaces.trinidad.") ||
-      s.startsWith("com.sun.faces.");
+      s.equals(PREEXISTING_ATTRIBUTE_NAMES);
     }
+  
+  private boolean isConfiguredExcludedAttribute(String s)
+  {
+    if (mExcludedRequestAttributes == null)
+    {
+      return false;
+    }
+    
+    if (mExcludedRequestAttributes.contains(s))
+    {
+      return true;
+    }
+    
+    // No direct match -- walk through this list and process namespace checks
+    Iterator<String> i = mExcludedRequestAttributes.iterator();
+    while (i.hasNext())
+    {
+      String exclude = i.next();
+      if (exclude.endsWith("*"))
+      {
+        if (isInNamespace(s, exclude.substring(0, exclude.length() - 1)))
+        {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
       
   private boolean isInNamespace(String s, String namespace)
   {
@@ -927,6 +1098,39 @@
     // correctly.
     context.getExternalContext().redirect(encodedActionURL);
   }
+  
+  // notify this scope's attributes that they are being removed
+  private void notifyPreDestroy(Map<String,Object> scope)
+  {
+    Set<Map.Entry<String,Object>>  s = scope.entrySet();
+    Iterator<Map.Entry<String,Object>> i = s.iterator();
+    while (i.hasNext())
+    {
+      notifyPreDestroy(i.next().getValue());
+    }
+  }
+  
+  // notify this scope's attributes that they are being removed
+  private void notifyPreDestroy(Object o)
+  {
+    Method[] methods = o.getClass().getMethods();
+    for (int m = 0; m < methods.length; m++)
+    {
+      if (methods[m].isAnnotationPresent(BridgePreDestroy.class))
+      {
+        try
+        {
+          methods[m].invoke(o, null);
+        }
+        catch (Exception e)
+        {
+            // TODO: log problem
+            // do nothing and forge ahead
+            ;
+        }
+      }
+    }
+  }
 
   private void removeRequestScopes(String scopePrefix)
   {
@@ -959,6 +1163,28 @@
       }
     }
   }
+  
+  private void readExcludedAttributesFromFacesConfig(PortletContext context,
+                                                     List<String> excludedAttributes)
+  {
+    FacesConfigurationProcessor processor = new FacesConfigurationProcessor(context);
+    List<String> list = processor.getExcludedAttributes();
+    
+    if (list == null)
+    {
+      return;
+    }
+    
+    ListIterator<String> i = (ListIterator<String>) list.listIterator();
+    while (i.hasNext())
+    {
+      String attr = i.next();
+      if (!excludedAttributes.contains(attr))
+      {
+        excludedAttributes.add(attr);
+      }
+    }
+  }
 
   /* Implement the PhaseListener methods */
 
@@ -1001,7 +1227,33 @@
     @Override
     protected boolean removeEldestEntry(Map.Entry<String, Map<String,Object>> eldest)
     {
-      return size() > mMaxCapacity;
+      // manually remove the entry so we can ensure notifyPreDestroy is only
+      // called once
+      if (size() > mMaxCapacity)
+      {
+        // side effect of this call is to notify PreDestroy
+        remove(eldest.getKey());
+      }
+      return false;
+    }
+    
+    public Map<String,Object> remove(String key) 
+    {
+      dumpScopeId(key, "RemovePhase");
+      Map<String,Object> o = super.remove(key);
+      // notify attributes maintained in this object (map) they are going away
+      // Method in the outer BridgeImpl class
+      if (o != null) notifyPreDestroy(o);
+      return o;
+    }
+    
+    public Map<String,Object> put(String key, Map<String,Object> value)
+    {
+      Map<String,Object> o = super.put(key, value);
+      // notify attributes maintained in this object (map) they are going away
+      // Method in the outer BridgeImpl class
+      if (o != null) notifyPreDestroy(o);
+      return o;      
     }
 
   }

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Thu Jan 10 09:27:52 2008
@@ -155,23 +155,6 @@
     // we need to set it for them
     setFacesMapping();
 
-    // Get the DelegateRender context parameter here and set as a request
-    // attribute
-    // so Bridge's ViewHandler has access to it. ViewHandler can't get from
-    // context
-    // itself because its a per portlet setting but without the config
-    // object
-    // the ViewHandler has no way to get the portlet's name.
-    Bridge.BridgeRenderPolicy renderPolicy = 
-      (Bridge.BridgeRenderPolicy) mPortletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX
-                                                               + mPortletConfig.getPortletName()
-                                                               + "."
-                                                               + Bridge.RENDER_POLICY);
-    if (renderPolicy != null)
-    {
-      mPortletRequest.setAttribute(RENDER_POLICY_ATTRIBUTE, renderPolicy);
-    }
-
   }
 
   public void release()
@@ -263,7 +246,7 @@
       throw new FacesException("encodeActionURL:  unable to recognize viewId");
     }
 
-    if (mPhase == Bridge.PortletPhase.RenderPhase)
+    if (mPhase == Bridge.PortletPhase.RENDER_PHASE)
     { // render - write
       // the viewId into
       // the response
@@ -390,7 +373,7 @@
     // redirects within this app are dealt (elsewhere) as navigations
     // so do nothing. External links are redirected
 
-    if (mPhase == Bridge.PortletPhase.ActionPhase
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE
         && (url.startsWith("#") || isExternalURL(url) || isDirectLink(url)))
     {
       ((ActionResponse) getResponse()).sendRedirect(url);
@@ -455,7 +438,7 @@
       throw new java.lang.NullPointerException();
     }
 
-    if (mPhase == Bridge.PortletPhase.ActionPhase)
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
       throw new IllegalStateException("Request cannot be an ActionRequest");
     }
@@ -652,7 +635,7 @@
 
   public String encodeNamespace(String s)
   {
-    if (!BridgeUtil.isPortletRenderRequest())
+    if (BridgeUtil.getPortletRequestPhase() != Bridge.PortletPhase.RENDER_PHASE)
     {
       throw new IllegalStateException("Only RenderResponse can be used to encode a namespace");
     }
@@ -787,7 +770,7 @@
     /* TODO: Temporary workaround for JIRA PORTLETBRIDGE-14 until EG
      * decides on best course of action.
      * 
-   if (mPhase != Bridge.PortletPhase.ActionPhase)
+   if (mPhase != Bridge.PortletPhase.ACTION_PHASE)
     {
           
         throw new IllegalStateException(
@@ -796,7 +779,7 @@
     */
     
   	//Part of temp workaround.  Do a noop if we are not in action phase
-    if(mPhase == Bridge.PortletPhase.ActionPhase)
+    if(mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
       ((ActionRequest) mPortletRequest).setCharacterEncoding(encoding);
     }
@@ -829,13 +812,15 @@
   @Override
   public String getRequestCharacterEncoding()
   {
-    if (mPhase == Bridge.PortletPhase.RenderPhase)
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
-      throw new IllegalStateException(
-                                      "PortletExternalContextImpl.getRequestCharacterEncoding(): Request must be an ActionRequest");
+      return ((ActionRequest) mPortletRequest).getCharacterEncoding();
+    }
+    else
+    {
+      // RENDER_PHASE -- return null as per spec
+      return null;
     }
-
-    return ((ActionRequest) mPortletRequest).getCharacterEncoding();
   }
 
   /**
@@ -865,13 +850,15 @@
   @Override
   public String getRequestContentType()
   {
-    if (mPhase == Bridge.PortletPhase.RenderPhase)
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
-      throw new IllegalStateException(
-                                      "PortletExternalContextImpl.getRequestContentType(): Request must be an ActionRequest");
+      return ((ActionRequest) mPortletRequest).getContentType();
+    }
+    else
+    {
+      // RENDER_PHASE: return null as per spec
+      return null;
     }
-
-    return ((ActionRequest) mPortletRequest).getContentType();
   }
 
   /**
@@ -902,7 +889,7 @@
   @Override
   public String getResponseCharacterEncoding()
   {
-    if (mPhase == Bridge.PortletPhase.ActionPhase)
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
       throw new IllegalStateException(
                                       "PortletExternalContextImpl.getResponseCharacterEncoding(): Response must be a RenderRequest");
@@ -938,7 +925,7 @@
   @Override
   public String getResponseContentType()
   {
-    if (mPhase == Bridge.PortletPhase.ActionPhase)
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
       throw new IllegalStateException(
                                       "PortletExternalContextImpl.getResponseContentType(): Response must be a RenderRequest");

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java Thu Jan 10 09:27:52 2008
@@ -45,7 +45,7 @@
 import javax.faces.render.RenderKitFactory;
 import javax.portlet.PortletResponse;
 import javax.portlet.faces.Bridge;
-import javax.portlet.faces.component.PortletNamingContainer;
+import javax.portlet.faces.annotation.PortletNamingContainer;
 
 import org.apache.myfaces.portlet.faces.el.PortletELContextImpl;
 
@@ -273,7 +273,10 @@
 
     mViewRoot = viewRoot;
 
-    if (mViewRoot instanceof PortletNamingContainer)
+    // if ViewRoot annotated with PortletNamingContainer
+    // it supports portlet namespacing content -- mark
+    // response so consumers can detect
+    if (mViewRoot.getClass().getAnnotation(PortletNamingContainer.class) != null)
     {
       try
       {

Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/config/FacesConfigurationProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/config/FacesConfigurationProcessor.java?rev=610847&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/config/FacesConfigurationProcessor.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/config/FacesConfigurationProcessor.java Thu Jan 10 09:27:52 2008
@@ -0,0 +1,265 @@
+/* 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.portlet.faces.util.config;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import java.net.URL;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.portlet.PortletContext;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+//TODO: This is probably better under the Bridge package as a package private utility
+//TODO: This is probably better as a static utility class since it's never kept around.
+public class FacesConfigurationProcessor
+{
+
+  private static final String FACES_CONFIG_METAINF_PATH = "META-INF/faces-config.xml";
+  private static final String FACES_CONFIG_WEBINF_PATH = "/WEB-INF/faces-config.xml";
+  private List<String> mExcludedAttributes = null;
+
+  /**
+   * <p>
+   * When instantiated, the web.xml of the current application will be scanned looking for a
+   * references to the <code>FacesServlet</code>. <code>isFacesServletPresent()</code> will
+   * return the appropriate value based on the scan.
+   * </p>
+   * 
+   * @param context
+   *          the <code>ServletContext</code> for the application of interest
+   */
+  public FacesConfigurationProcessor(PortletContext context)
+  {
+    if (context != null)
+    {
+      scanForFacesMappings(context);
+    }
+  } // END WebXmlProcessor
+
+  public List<String> getExcludedAttributes()
+  {
+    return mExcludedAttributes;
+  } // END getFacesMappings
+
+  /**
+   * <p>
+   * Parse the web.xml for the current application and scan for a FacesServlet entry, if found, set
+   * the <code>facesServletPresent</code> property to true.
+   * 
+   * @param context
+   *          the ServletContext instance for this application
+   */
+  private void scanForFacesMappings(PortletContext context)
+  {
+
+    SAXParserFactory factory = getSAXFactory();
+    try
+    {
+      SAXParser parser = factory.newSAXParser();
+      FacesConfigXmlHandler handler = null;
+      
+      // read each faces-config.xml and see if any contain the bridge extension
+      // that defines some excluded attributes
+      ClassLoader cl = getCurrentClassLoader(context);
+      
+      for (Enumeration<URL> items = cl.getResources(FACES_CONFIG_METAINF_PATH);
+               items.hasMoreElements();) {
+         
+        URL nextElement = items.nextElement();
+        
+        if (handler == null) 
+        {
+          handler = new FacesConfigXmlHandler();
+        }
+        else
+        {
+          handler.reset();
+        }
+        parser.parse(nextElement.openStream(), handler);
+      }
+      
+      // Now see if the web app has one in its WEB-INF
+      InputStream configStream = context.getResourceAsStream(FACES_CONFIG_WEBINF_PATH);
+      if (configStream != null)
+      {
+        parser.parse(configStream, handler);
+      }
+    }
+    catch (Exception e)
+    {
+      // TODO add logging
+      // Do nothing
+      ;
+    }
+
+  } // END scanForFacesMappings
+  
+  private ClassLoader getCurrentClassLoader(Object fallbackClass) {
+      ClassLoader loader =
+          Thread.currentThread().getContextClassLoader();
+      if (loader == null) {
+          loader = fallbackClass.getClass().getClassLoader();
+      }
+      return loader;
+  }
+
+  /**
+   * <p>
+   * Return a <code>SAXParserFactory</code> instance that is non-validating and is namespace
+   * aware.
+   * </p>
+   * 
+   * @return configured <code>SAXParserFactory</code>
+   */
+  private SAXParserFactory getSAXFactory()
+  {
+
+    SAXParserFactory factory = SAXParserFactory.newInstance();
+    factory.setValidating(false);
+    factory.setNamespaceAware(true);
+    return factory;
+
+  } // END getConfiguredFactory
+
+  /**
+   * <p>
+   * A simple SAX handler to process the elements of interested within a web application's
+   * deployment descriptor.
+   * </p>
+   */
+  private class FacesConfigXmlHandler extends DefaultHandler
+  {
+
+    private static final String APPLICATION_ELEMENT          = "application";
+    private static final String APP_EXTENSION_ELEMENT     = "application-extension";
+    private static final String EXCLUDED_ATTRIBUTES_ELEMENT    = "excluded-attributes";
+    private static final String EXCLUDED_ATTRIBUTE_ELEMENT  = "excluded-attribute";
+
+    private boolean             mInApplicationElement        = false;
+    private boolean             mInApplicationExtensionElement    = false;
+    private boolean             mInExcludedAttributesElement   = false;
+   
+    private StringBuilder       mContent;
+
+
+    public void reset()
+    {
+      mInApplicationElement = mInApplicationExtensionElement =
+        mInExcludedAttributesElement = false;
+    }
+
+    @Override
+    public InputSource resolveEntity(String publicId, String systemId) throws SAXException
+    {
+
+      return new InputSource(new StringReader(""));
+
+    } // END resolveEntity
+
+    @Override
+    public void startElement(String uri, String localName, String qName, Attributes attributes)
+                                                                                               throws SAXException
+    {
+
+      if (APPLICATION_ELEMENT.equals(localName))
+      {
+        mInApplicationElement = true;
+      }
+      else if (APP_EXTENSION_ELEMENT.equals(localName))
+      {
+        mInApplicationExtensionElement = true;
+      }
+      else if (EXCLUDED_ATTRIBUTES_ELEMENT.equals(localName))
+      {
+          mInExcludedAttributesElement = true;
+      }
+      else if (EXCLUDED_ATTRIBUTE_ELEMENT.equals(localName))
+      {
+        if (mInApplicationElement && mInApplicationExtensionElement &&
+          mInExcludedAttributesElement)
+        {
+          mContent = new StringBuilder();
+        }
+      }
+    } // END startElement
+
+    @Override
+    public void characters(char[] ch, int start, int length) throws SAXException
+    {
+
+      if (mContent != null)
+      {
+        mContent.append(ch, start, length);
+      }
+
+    } // END characters
+
+    @Override
+    public void endElement(String uri, String localName, String qName) throws SAXException
+    {
+
+      if (APPLICATION_ELEMENT.equals(localName))
+      {
+        mInApplicationElement = false;
+      }
+      else if (APP_EXTENSION_ELEMENT.equals(localName))
+      {
+        mInApplicationExtensionElement = false;
+      }
+      else if (EXCLUDED_ATTRIBUTES_ELEMENT.equals(localName))
+      {
+          mInExcludedAttributesElement = false;
+      }
+      else if (EXCLUDED_ATTRIBUTE_ELEMENT.equals(localName) && mContent != null
+        && mContent.length() > 0)
+      {
+        // add mContent to the attrs list
+        String excludedAttribute = mContent.toString().trim();
+        
+        if (mExcludedAttributes == null)
+        {
+          mExcludedAttributes = (List<String> )new ArrayList(5);
+        }
+        
+        if (!mExcludedAttributes.contains(excludedAttribute))
+        {
+          mExcludedAttributes.add(excludedAttribute);
+        }
+      }
+
+      mContent = null;
+
+    } // END endElement
+
+  } // END FacesConfigXmlHandler
+
+}

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestHeaders.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestHeaders.java?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestHeaders.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestHeaders.java Thu Jan 10 09:27:52 2008
@@ -181,7 +181,7 @@
       }
     }
 
-    if ((Bridge.PortletPhase) mPortletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE) == Bridge.PortletPhase.ActionPhase)
+    if ((Bridge.PortletPhase) mPortletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE) == Bridge.PortletPhase.ACTION_PHASE)
     {
 
       if (!containsHeader(mHeaderNames, "CONTENT-TYPE"))
@@ -220,6 +220,16 @@
         }
       }
 
+    }
+    // Technically don't need this test here but I will forget to change this code when
+    // JSR 286 is supported and there are more phases.
+    else if ((Bridge.PortletPhase) mPortletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE) == Bridge.PortletPhase.RENDER_PHASE)
+    {
+      // its the RENDER_PHASE -- spec says we must remove the CONTENT_TYPE if 
+      // came in the request -- so it matches null return from
+      // EC.getRequestContentType/CharacterSetEncoding
+      mHeaders.remove("CONTENT-TYPE");
+      mHeaderNames.remove("CONTENT-TYPE");
     }
 
     return true;

Modified: myfaces/portlet-bridge/trunk/impl/src/main/resources/META-INF/faces-config.xml
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/resources/META-INF/faces-config.xml?rev=610847&r1=610846&r2=610847&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/resources/META-INF/faces-config.xml (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/resources/META-INF/faces-config.xml Thu Jan 10 09:27:52 2008
@@ -17,7 +17,8 @@
     specific language governing permissions and limitations
     under the License.	   
 -->
-<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee">
+<faces-config version="1.2" xmlns="http://java.sun.com/xml/ns/javaee"
+    xmlns:bridge="http://www.apache.org/myfaces/xml/ns/bridge/bridge-extension">
     <application>
         <view-handler>org.apache.myfaces.portlet.faces.application.PortletViewHandlerImpl</view-handler>
         <state-manager>org.apache.myfaces.portlet.faces.application.PortletStateManagerImpl</state-manager>