You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mf...@apache.org on 2009/04/29 23:48:20 UTC

svn commit: r769955 - in /myfaces/portlet-bridge/core/trunk: api/src/main/java/javax/portlet/faces/ api/src/main/java/javax/portlet/faces/component/ impl/src/main/java/org/apache/myfaces/portlet/faces/application/ impl/src/main/java/org/apache/myfaces/...

Author: mfreedman
Date: Wed Apr 29 21:48:20 2009
New Revision: 769955

URL: http://svn.apache.org/viewvc?rev=769955&view=rev
Log:
PORTLETBRIDGE-63: Create view/ui viewroot changes
PORTLETBRIDGE-64: Wrap exceptions correctly
PORTLETBRIDGE-65: Client directed views should invalidate redirect cache
PORTLETBRIDGE-66: Client direct view: don't restore scope
PORTLETBRIDGE-67: Recursive render redirects broken
PORTLETBRIDGE-68: Temp request params not flushed
PORTLETBRIDGE-69: Improve PortletNamingContainer impl
PORTLETBRIDGE-70: GenericFacesPortlet doesn't ensure valid ContentType setting.

Added:
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationFactoryImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationImpl.java
Modified:
    myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
    myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java

Modified: myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java (original)
+++ myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java Wed Apr 29 21:48:20 2009
@@ -328,12 +328,25 @@
     String contentType = 
       getPortletConfig().getPortletContext().getInitParameter(DEFAULT_CONTENT_TYPE);
 
-    if (contentType == null)
+    if (contentType == null || !isInRequestedContentTypes(request, contentType))
     {
       contentType = request.getResponseContentType();
     }
     return contentType;
   }
+  
+  private boolean isInRequestedContentTypes(PortletRequest request, String contentTypeToCheck)
+  {
+    Enumeration e = request.getResponseContentTypes();
+    while (e.hasMoreElements()) 
+    {
+      if (contentTypeToCheck.equalsIgnoreCase((String) e.nextElement()))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
 
   /**
    * Returns the character set encoding used for this portlet response. Subclasses override to

Modified: myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java (original)
+++ myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/component/PortletNamingContainerUIViewRoot.java Wed Apr 29 21:48:20 2009
@@ -10,30 +10,13 @@
  */
 package javax.portlet.faces.component;
 
-import java.io.IOException;
 import java.io.Serializable;
 
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.el.MethodExpression;
-import javax.el.ValueExpression;
-
-import javax.faces.FacesException;
-import javax.faces.component.ContextCallback;
 import javax.faces.context.FacesContext;
 import javax.faces.component.NamingContainer;
-import javax.faces.component.UIComponent;
 import javax.faces.component.UIViewRoot;
 import javax.faces.context.ExternalContext;
 
-import javax.faces.el.ValueBinding;
-import javax.faces.event.AbortProcessingException;
-import javax.faces.event.FacesEvent;
-import javax.faces.event.PhaseListener;
-
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
 import javax.portlet.faces.annotation.PortletNamingContainer;
@@ -51,59 +34,54 @@
 
   //TODO: This should be regenerated each time this is modified.  Can this be added to maven?
   private static final long   serialVersionUID = -4524288011655837711L;
-  private static final String PORTLET_NAMESPACE_ID = Bridge.BRIDGE_PACKAGE_PREFIX + "PortletNamespaceId";
+  private static final String PORTLET_ENCODED_NAMESPACE_ID = Bridge.BRIDGE_PACKAGE_PREFIX + "PortletEncodedNamespaceId";
   
-  private String mNamespace;
-
+  // Assumes that first use of the UIViewRoot always occurs in a render as portlet namespace
+  // is only available during a render.  If this isn't the case we disable use of the
+  // NamingContainer
   public PortletNamingContainerUIViewRoot()
   {
     super();
+    
+    getAttributes().put(PORTLET_ENCODED_NAMESPACE_ID, Boolean.FALSE);
   }
 
   /**
-   * Implements NamingContainer semantics.  Ensures that the returned identifier
-   * contains the consumer (portal) provided unique portlet id.  This ensures that
-   * those components in this NamingContainer generate ids which will not collide
-   * in the consumer page.  Implementation merely calls the static form of this
-   * method.
+   * NamingContainer semantics worked generically (serviced by subclasses) as long as the class
+   * is marked as implementing NamingContainer and we use the portletNamespace Id as
+   * (part of) the component's id.
    */
 
   @Override
   public String getContainerClientId(FacesContext context)
   {
-    // only add NamingContainer behavior when running in a portlet request
-    if (BridgeUtil.isPortletRequest())
+    if (BridgeUtil.isPortletRequest() && ((Boolean) this.getAttributes().get(PORTLET_ENCODED_NAMESPACE_ID)).equals(Boolean.TRUE))
     {
-
-    /* Note: In portlet 1.0 the namespace is guaranteed valid for the request it
-     * was passed -- so its possible that resusing the saved one will no longer
-     * be valid.  However this is less likely than JSF expecting to not use the
-     * clientId from here to refer to an element in the reconstructed tree -- 
-     * Note though this is also unlikely we know of portlet 1.0 extended impls
-     * that support ajax via an extended portlet 1.0 where they run the full 
-     * lifecycle during a render and hence need action semantics in the render
-     */
-      if (mNamespace != null || (mNamespace = (String) this.getAttributes().get(PORTLET_NAMESPACE_ID)) != null)
-      {
-        return mNamespace;
-      }
+      return super.getContainerClientId(context);
+    }
+    else
+    {
+      return null;
+    }
+  }
+  
+  @Override
+  public void setId(String id)
+  {
+    if (BridgeUtil.isPortletRequest()) 
+    {
+      Boolean encoded = Boolean.FALSE;
       /* Can only calculate the namespace during a render (in portlet 1.0) */
-      else if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)
+      if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)
       {
-        ExternalContext ec = context.getExternalContext();
-        mNamespace = ec.encodeNamespace("");
-        // also write it as a component so it is preserved across save/restore
-        // using the same value ensures consistentcy in portlet environments where
-        // such a namespace varies by request
-        this.getAttributes().put(PORTLET_NAMESPACE_ID, mNamespace);
-        return mNamespace;
+        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
+        id = ec.encodeNamespace("_" + id);
+        // now indicate that this id is encoded
+        encoded = Boolean.TRUE;
       }
-      else
-        throw new NullPointerException("getContainerClientId: null portlet namespace in non-render phase");
+      getAttributes().put(PORTLET_ENCODED_NAMESPACE_ID, encoded);
     }
-
-    return null;
-
+    super.setId(id);
   }
   
 }

Added: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationFactoryImpl.java?rev=769955&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationFactoryImpl.java (added)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationFactoryImpl.java Wed Apr 29 21:48:20 2009
@@ -0,0 +1,45 @@
+/* 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.application;
+
+import javax.faces.application.Application;
+import javax.faces.application.ApplicationFactory;
+
+
+public class PortletApplicationFactoryImpl extends ApplicationFactory
+{
+  private ApplicationFactory mHandler;
+  
+  public PortletApplicationFactoryImpl(ApplicationFactory handler)
+  {
+    mHandler = handler;
+  }
+  
+  public Application getApplication()
+  {
+    return new PortletApplicationImpl(mHandler.getApplication());
+  }
+  
+  public void setApplication(Application app)
+  {
+    mHandler.setApplication(app);
+  }
+   
+}
\ No newline at end of file

Added: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationImpl.java?rev=769955&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationImpl.java (added)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletApplicationImpl.java Wed Apr 29 21:48:20 2009
@@ -0,0 +1,376 @@
+/* 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.application;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+import javax.el.ELContextListener;
+import javax.el.ELException;
+import javax.el.ELResolver;
+import javax.el.ExpressionFactory;
+import javax.el.ValueExpression;
+
+import javax.faces.FacesException;
+import javax.faces.application.Application;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.el.ReferenceSyntaxException;
+
+import javax.portlet.faces.BridgeUtil;
+import javax.portlet.faces.annotation.ExcludeFromManagedRequestScope;
+import javax.portlet.faces.annotation.PortletNamingContainer;
+import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
+
+
+public class PortletApplicationImpl extends Application
+{
+  private Application mWrapped;
+  
+  public PortletApplicationImpl(Application app)
+  {
+    mWrapped = app;
+  }
+  
+  // The following concrete methods were added for JSF 1.2.  They supply default 
+  // implementations that throw UnsupportedOperationException.  
+  // This allows old Application implementations to still work.
+  public void addELResolver(ELResolver resolver) {
+      mWrapped.addELResolver(resolver);
+  }
+  
+  public ELResolver getELResolver() {
+      return mWrapped.getELResolver();
+  }
+  
+  public ResourceBundle getResourceBundle(FacesContext ctx, String name) 
+          throws FacesException, NullPointerException {
+      return mWrapped.getResourceBundle(ctx, name);
+  }
+  
+  public UIComponent createComponent(ValueExpression componentExpression,
+                                     FacesContext facesContext,
+                                     String componentType) 
+          throws FacesException, NullPointerException {
+      return mWrapped.createComponent(componentExpression, facesContext, componentType);
+  }
+
+  public ExpressionFactory getExpressionFactory() {
+      return mWrapped.getExpressionFactory();
+  }
+  
+  public void addELContextListener(ELContextListener listener) {
+      mWrapped.addELContextListener(listener);
+  }
+  
+  public void removeELContextListener(ELContextListener listener) {
+      mWrapped.removeELContextListener(listener);
+  }
+  
+  public ELContextListener[] getELContextListeners() {
+      return mWrapped.getELContextListeners();
+  }
+  
+  public Object evaluateExpressionGet(FacesContext context,
+                                      String expression,
+                                      Class expectedType)
+           throws ELException {
+      return mWrapped.evaluateExpressionGet(context, expression, expectedType);
+  }
+  
+  public javax.faces.event.ActionListener getActionListener()
+  {
+    return mWrapped.getActionListener();
+  }
+
+  public void setActionListener(javax.faces.event.ActionListener listener)
+  {
+    mWrapped.setActionListener(listener);
+  }
+
+  public Locale getDefaultLocale()
+  {
+    return mWrapped.getDefaultLocale();
+  }
+
+  public void setDefaultLocale(Locale locale)
+  {
+    mWrapped.setDefaultLocale(locale);
+  }
+
+  public String getDefaultRenderKitId()
+  {
+    return mWrapped.getDefaultRenderKitId();
+  }
+
+  public void setDefaultRenderKitId(String renderKitId)
+  {
+    mWrapped.setDefaultRenderKitId(renderKitId);
+  }
+
+  public String getMessageBundle()
+  {
+    return mWrapped.getMessageBundle();
+  }
+
+  public void setMessageBundle(String bundle)
+  {
+    mWrapped.setMessageBundle(bundle);
+  }
+
+  /**
+   * Return the NavigationHandler object which is responsible for mapping from
+   * a logical (viewid, fromAction, outcome) to the URL of a view to be rendered.
+   */
+  public javax.faces.application.NavigationHandler getNavigationHandler()
+  {
+    return mWrapped.getNavigationHandler();
+  }
+
+  public void setNavigationHandler(javax.faces.application.NavigationHandler handler)
+  {
+    mWrapped.setNavigationHandler(handler);
+  }
+
+  /**
+   * Get the object used by the VariableResolver to read and write named properties
+   * on java beans, Arrays, Lists and Maps. This object is used by the ValueBinding
+   * implementation, and during the process of configuring "managed bean" properties.
+   *
+   * @deprecated
+   */
+  public javax.faces.el.PropertyResolver getPropertyResolver()
+  {
+    return mWrapped.getPropertyResolver();
+  }
+
+  /**
+   * @deprecated
+   */
+  public void setPropertyResolver(javax.faces.el.PropertyResolver resolver)
+  {
+    mWrapped.setPropertyResolver(resolver);
+  }
+
+  /**
+   * Get the object used to resolve expressions of form "#{...}".
+   *
+   * @deprecated
+   */
+  public javax.faces.el.VariableResolver getVariableResolver()
+  {
+    return mWrapped.getVariableResolver();
+  }
+
+  /**
+   * @deprecated
+   */
+  public void setVariableResolver(javax.faces.el.VariableResolver resolver)
+  {
+    mWrapped.setVariableResolver(resolver);
+  }
+  
+  public javax.faces.application.ViewHandler getViewHandler()
+  {
+    return mWrapped.getViewHandler();
+  }
+
+  public void setViewHandler(javax.faces.application.ViewHandler handler)
+  {
+    mWrapped.setViewHandler(handler);
+  }
+
+  public javax.faces.application.StateManager getStateManager()
+  {
+    return mWrapped.getStateManager();
+  }
+
+  public void setStateManager(javax.faces.application.StateManager manager)
+  {
+    mWrapped.setStateManager(manager);
+  }
+
+  /**
+   * Define a new mapping from a logical "component type" to an actual java class name.
+   * This controls what type is created when method createComponent of this class is
+   * called.
+   * <p>
+   * Param componentClass must be the fully-qualified class name of some class
+   * extending the UIComponent class. The class must have a default constructor,
+   * as instances of it will be created using Class.newInstance.
+   * <p> 
+   * It is permitted to override a previously defined mapping, ie to call this
+   * method multiple times with the same componentType string. The createComponent
+   * method will simply use the last defined mapping.
+   */
+  public void addComponent(String componentType,
+                                    String componentClass)
+  {
+    mWrapped.addComponent(componentType, componentClass);
+  }
+
+  
+  /**
+   * Create a new UIComponent subclass, using the mappings defined by previous
+   * calls to the addComponent method of this class.
+   * <p>
+   * @throws FacesException if there is no mapping defined for the specified
+   * componentType, or if an instance of the specified type could not be
+   * created for any reason.
+   */
+  public javax.faces.component.UIComponent createComponent(String componentType)
+          throws FacesException
+  {
+    UIComponent component = mWrapped.createComponent(componentType);
+    if (BridgeUtil.isPortletRequest() &&
+        component.getClass() == UIViewRoot.class &&
+        UIViewRoot.class.getAnnotation(PortletNamingContainer.class) == null
+       )
+    {
+      // replace with our own UIViewRoot
+      component = new PortletNamingContainerUIViewRoot();
+    }
+    return component;
+  }
+
+  /**
+   * Create an object which has an associating "binding" expression tying the component
+   * to a user property.
+   * <p>
+   * First the specified value-binding is evaluated; if it returns a non-null value then
+   * the component "already exists" and so the resulting value is simply returned.
+   * <p>
+   * Otherwise a new UIComponent instance is created using the specified componentType,
+   * and the new object stored via the provided value-binding before being returned.
+   *
+   * @deprecated
+   */
+  public javax.faces.component.UIComponent createComponent(
+          javax.faces.el.ValueBinding componentBinding,
+          javax.faces.context.FacesContext context,
+          String componentType)
+          throws FacesException
+  {
+    return mWrapped.createComponent(componentBinding, context, componentType);
+  }
+  
+  public Iterator<String> getComponentTypes()
+  {
+    return mWrapped.getComponentTypes();
+  }
+
+  public void addConverter(String converterId,
+                                    String converterClass)
+  {
+    mWrapped.addConverter(converterId, converterClass);
+  }
+
+  public void addConverter(Class targetClass,
+                                    String converterClass)
+  {
+    mWrapped.addConverter(targetClass, converterClass);
+  }
+
+  public javax.faces.convert.Converter createConverter(String converterId)
+  {
+    return mWrapped.createConverter(converterId);
+  }
+
+  public javax.faces.convert.Converter createConverter(Class targetClass)
+  {
+    return mWrapped.createConverter(targetClass);
+  }
+
+  public Iterator<String> getConverterIds()
+  {
+    return mWrapped.getConverterIds();
+  }
+
+  public Iterator<Class> getConverterTypes()
+  {
+    return mWrapped.getConverterTypes();
+  }
+
+  /**
+   * Create an object which can be used to invoke an arbitrary method via an
+   * EL expression at a later time. This is similar to createValueBinding 
+   * except that it can invoke an arbitrary method (with parameters) rather
+   * than just get/set a javabean property.
+   * <p>
+   * This is used to invoke ActionListener method, and ValueChangeListener
+   * methods.
+   *
+   * @deprecated
+   */
+  public javax.faces.el.MethodBinding createMethodBinding(
+          String ref, Class[] params)
+          throws ReferenceSyntaxException
+  {
+    return mWrapped.createMethodBinding(ref, params);
+  }
+
+  public Iterator<Locale> getSupportedLocales()
+  {
+    return mWrapped.getSupportedLocales();
+  }
+
+  public void setSupportedLocales(Collection<Locale> locales)
+  {
+    mWrapped.setSupportedLocales(locales);
+  }
+
+  public void addValidator(String validatorId,
+                                    String validatorClass)
+  {
+    mWrapped.addValidator(validatorId, validatorClass);
+  }
+
+  public javax.faces.validator.Validator createValidator(String validatorId)
+          throws FacesException
+  {
+    return mWrapped.createValidator(validatorId);
+  }
+
+  public Iterator<String> getValidatorIds()
+  {
+    return mWrapped.getValidatorIds();
+  }
+
+  /**
+   * Create an object which can be used to invoke an arbitrary method via an
+   * EL expression at a later time. This is similar to createValueBinding 
+   * except that it can invoke an arbitrary method (with parameters) rather
+   * than just get/set a javabean property.
+   * <p>
+   * This is used to invoke ActionListener method, and ValueChangeListener
+   * methods.
+   *
+   * @deprecated
+   */
+  public javax.faces.el.ValueBinding createValueBinding(String ref)
+          throws ReferenceSyntaxException
+  {
+    return mWrapped.createValueBinding(ref);
+  }
+  
+}
\ No newline at end of file

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java Wed Apr 29 21:48:20 2009
@@ -151,6 +151,7 @@
       }
     }
     
+
     UIViewRoot viewRoot = null;
     
     // The bridge allows viewIds to carry querystrings -- e.g. a qs that has the 
@@ -161,16 +162,28 @@
     int qsLoc = viewId.indexOf('?');
     if (qsLoc < 0)
       qsLoc = viewId.length();
-
-    String prior = setUIViewRootComponent(facesContext);
-    try 
-    {
-      viewRoot = super.createView(facesContext, viewId.substring(0, qsLoc));
-    }
-    finally
+    
+    viewRoot = super.createView(facesContext, viewId.substring(0, qsLoc));
+    
+    // As we have provided an ApplicationImpl to override createComponent
+    // to detect when to swap in our NamingContainer the returned viewRoot
+    // from above should already be the one we want.  Because its possible
+    // its still the native UIViewRoot -- i.e. createComponent wasn't called 
+    // the following code checks/and does the right thing to satisfy the spec.
+    
+    if (viewRoot.getClass() == UIViewRoot.class &&
+        UIViewRoot.class.getAnnotation(PortletNamingContainer.class) == null)
     {
-      if (prior != null)
-        resetUIViewRootComponent(facesContext, prior);
+      String prior = setUIViewRootComponent(facesContext);
+      try 
+      {
+        viewRoot = super.createView(facesContext, viewId.substring(0, qsLoc));
+      }
+      finally
+      {
+        if (prior != null)
+          resetUIViewRootComponent(facesContext, prior);
+      }
     }
     
     if (qsLoc < viewId.length())

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Wed Apr 29 21:48:20 2009
@@ -118,7 +118,7 @@
   private static final String REQUEST_SCOPE_ID_RENDER_PARAM = "__jpfbReqScopeId";
   private static final int DEFAULT_MAX_MANAGED_REQUEST_SCOPES = 100;
 
-  private Boolean mPreserveActionParams = false;
+  private Boolean mPreserveActionParams = Boolean.FALSE;
   private List<String> mExcludedRequestAttributes = null;
 
   private PortletConfig mPortletConfig = null;
@@ -189,7 +189,12 @@
     // portletConfig to any newly created contexts.
     ApplicationFactory appFactory = 
       (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
+    
+    // Wrapped desired Application with our own to override createComponent and
+    // insert our NamingContainerUIViewRoot component.  This was done through
+    // configuration via the META-INF/service/javax.faces.application.ApplicationFactory
     Application app = appFactory.getApplication();
+
     app.addELContextListener(this);
 
     // Process and cache the FacesServlet mappings for use by
@@ -335,13 +340,9 @@
       mPortletConfig.getPortletContext().log("Exception thrown in doFacesRequest:action", e);
       if (!(e instanceof BridgeException))
       {
-        Throwable rootCause = e.getCause();
-        throw new BridgeException(e.getMessage(), rootCause);
-      }
-      else
-      {
-        throw (BridgeException) e;
+        e = new BridgeException(e);
       }
+      throw (BridgeException) e;
     }
     finally
     {
@@ -453,18 +454,26 @@
     // we need to remove all but these preexisting ones.
     List<String> preExistingAttributes = getRequestAttributes(request);
     
+    // Now we need to determine if view we are going to render is the one
+    // encoded in the request (parameters) or specifically supplied
+    // either by the portlet itself or by a prior render redirect.
+    boolean clientDirectedView = ((request.getAttribute(Bridge.VIEW_ID) != null) ||
+        (request.getAttribute(Bridge.VIEW_PATH) != null));
+    
     // Now check to see if this is a Refresh (render) that follows a redirect
     // If it is use the redirect information cached in the session as the basis
     // for the request.
     QueryString redirectParams = (QueryString)
               request.getPortletSession(true).getAttribute(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS);
+    
+    boolean modeChanged = hasModeChanged(request, redirectParams);
 
-    if (redirectParams != null && hasModeChanged(request, redirectParams))  
+    if (redirectParams != null && (clientDirectedView || modeChanged))  
     {
       // if we are too rely on the render redirect cache we must still
-      // be in the same mode
+      // be in the same mode and/or the portlet can't have set an explicit view to use
       
-      // mode change while in redirectDuringRender state
+      // mode change/direct view set while in redirectDuringRender state
       // clear this state (as we are no longer in it)
       // and don't use the data
       redirectParams = null;
@@ -473,14 +482,14 @@
     }
     
     
-    // never restore a scope if relying on render redirect cache
-    if (redirectParams == null)
+    // never restore a scope if relying on render redirect cache/client directed view/mode change
+    if (redirectParams == null && !clientDirectedView)
     {
       // If available -- restore the bridge request scope before getting the
       // FacesContext in case anything in the context construction relies
       // on these restored values.
       // don't restore scope if mode changed
-      scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);;
+      scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
       if (scopeId != null)
       {
         // Its possible we didn't detect the mode change but its the wrong scope
@@ -553,13 +562,9 @@
       mPortletConfig.getPortletContext().log("Exception thrown in doFacesRequest:render: " + e.getMessage() + " : " + e.toString());
       if (!(e instanceof BridgeException))
       {
-        Throwable rootCause = e.getCause();
-        throw new BridgeException(e.getMessage(), rootCause);
-      }
-      else
-      {
-        throw (BridgeException) e;
+        e = new BridgeException(e);
       }
+      throw (BridgeException) e;
     }
     finally
     {
@@ -916,12 +921,24 @@
     // start a new FacesContext
     context = getFacesContext(request, response, lifecycle, redirectParams);
     
+    // Deal with possible recursion by clearing the cache, then calling doFacesRender
+    // to render the redirect, and then finally setting the cache, if its hasn't
+    // already been set.  In the (recursive) multi-render redirect case, the 
+    // last redirect will be the only one that sets the cache.
+    context.getExternalContext().getSessionMap().remove(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS);
+    
     // Run lifecycle.execute again ... then render
     doFacesRender(request, response, context, lifecycle, null, preExistingAttrs);
     
+    // Reacquire the context as it may have changed if a recursive redirect render occurred
+    context = FacesContext.getCurrentInstance();
+    
     // now cache the (last) redirect params on session for resuse in subsequent renders
     // that occur before an action
-    context.getExternalContext().getSessionMap().put(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS, redirectParams);
+    if (context.getExternalContext().getSessionMap().get(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS) == null)
+    {
+      context.getExternalContext().getSessionMap().put(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS, redirectParams);
+    }
 
   }
 
@@ -939,8 +956,7 @@
     }
     catch (FacesException e)
     {
-      Throwable rootCause = e.getCause();
-      throw new BridgeException(e.getMessage(), rootCause);
+      throw new BridgeException(e);
     }
   }
   
@@ -984,8 +1000,7 @@
     }
     catch (FacesException e)
     {
-      Throwable rootCause = e.getCause();
-      throw new BridgeException(e.getMessage(), rootCause);
+      throw new BridgeException(e);
     }
   }
 

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java Wed Apr 29 21:48:20 2009
@@ -19,12 +19,7 @@
 
 package org.apache.myfaces.portlet.faces.context;
 
-import java.util.Iterator;
-
 import javax.faces.FacesException;
-import javax.faces.application.Application;
-import javax.faces.component.UIComponent;
-import javax.faces.component.UIViewRoot;
 import javax.faces.context.FacesContext;
 import javax.faces.context.FacesContextFactory;
 import javax.faces.lifecycle.Lifecycle;
@@ -32,9 +27,6 @@
 import javax.portlet.PortletRequest;
 import javax.portlet.PortletResponse;
 import javax.portlet.faces.Bridge;
-import javax.portlet.faces.annotation.PortletNamingContainer;
-
-import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
 
 import javax.servlet.ServletRequest;
 
@@ -67,7 +59,7 @@
       if (context instanceof PortletContext && request instanceof PortletRequest
         && response instanceof PortletResponse)
       {
-        return  new PortletFacesContextImpl(
+        return new PortletFacesContextImpl(
                                          new PortletExternalContextImpl((PortletContext) context,
                                                                         (PortletRequest) request,
                                                                         (PortletResponse) response),

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Wed Apr 29 21:48:20 2009
@@ -28,6 +28,7 @@
 
 import java.security.Principal;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -120,9 +121,9 @@
   private Map<String, String> mInitParameterMap = null;
 
   // maps for internal parameters (eg, those specified in query string of
-  // any defaultViewId)
-  private Map<String, String> mInternalRequestParameterMap = Collections.emptyMap();
-  private Map<String, String[]> mInternalRequestParameterValuesMap = Collections.emptyMap();
+  // any defaultViewId) -- 
+  private Map<String, String> mTempExtraRequestParameterMap = Collections.emptyMap();
+  private Map<String, String[]> mTempExtraRequestParameterValuesMap = Collections.emptyMap();
 
   private PortletRequestHeaders mPortletRequestHeaders = null;
 
@@ -652,9 +653,15 @@
   {
     if (mRequestParameterMap == null)
     {
+      // In cases where the viewId is derived from either an attribute set by the portlet 
+      // or from the defaultView Map, the viewId can contain additional querystring parameters.
+      // These are held by the ExternalContext in an internal temp Map until this method
+      // is called.
       mRequestParameterMap = 
           Collections.unmodifiableMap(new PortletRequestParameterMap(mPortletRequest, 
-                                                                     mInternalRequestParameterMap));
+                                                                     mTempExtraRequestParameterMap));
+      // Now that it has been used/added -- clear the temp holder as its no longer needed
+      mTempExtraRequestParameterMap = null;
     }
     return mRequestParameterMap;
   }
@@ -663,9 +670,15 @@
   {
     if (mRequestParameterValuesMap == null)
     {
+      // In cases where the viewId is derived from either an attribute set by the portlet 
+      // or from the defaultView Map, the viewId can contain additional querystring parameters.
+      // These are held by the ExternalContext in an internal temp Map until this method
+      // is called.
       mRequestParameterValuesMap = 
           Collections.unmodifiableMap(new PortletRequestParameterValuesMap(mPortletRequest, 
-                                                                           mInternalRequestParameterValuesMap));
+                                                                           mTempExtraRequestParameterValuesMap));
+      // Now that it has been used/added -- clear the temp holder as its no longer needed
+      mTempExtraRequestParameterValuesMap = null;
     }
     return mRequestParameterValuesMap;
   }
@@ -1219,16 +1232,33 @@
       queryStr = new QueryString(viewId.substring(queryStart + 1), "UTF8");
 
       // TODO: Constants
-      mInternalRequestParameterMap = new HashMap<String, String>(5);
-      mInternalRequestParameterValuesMap = new HashMap<String, String[]>(5);
+      // We store these into a temporary Map until a client calls the corresponding
+      // ExternalContext public api to get the request parameter map(s).  In those
+      // methods we use these temp maps to build the overall Map that is returned.
+      // This roundabout technique is used to delay accessing request parameters until the 
+      // client first requests them.
+      mTempExtraRequestParameterMap = new HashMap<String, String>(5);
+      mTempExtraRequestParameterValuesMap = new HashMap<String, String[]>(5);
+      // Clear any existing Request ParameterMap to ensure reconstruction
+      // with these new extra entries.
+      mRequestParameterMap = null;
+      mRequestParameterValuesMap = null;
 
       Enumeration<String> list = queryStr.getParameterNames();
       while (list.hasMoreElements())
       {
         String param = list.nextElement();
-        mInternalRequestParameterMap.put(param, queryStr.getParameter(param));
-        mInternalRequestParameterValuesMap.put(param, new String[]
-            { queryStr.getParameter(param) });
+        mTempExtraRequestParameterMap.put(param, queryStr.getParameter(param));
+        
+        // Now deal with the multiValue case
+        Enumeration<String> e = queryStr.getParameterValues(param);
+        ArrayList<String> l = new ArrayList(5);
+        while (e.hasMoreElements())
+        {
+          l.add(e.nextElement());         
+        }
+        String[] values = new String[l.size()];
+        mTempExtraRequestParameterValuesMap.put(param, l.toArray(values));
       }
 
       viewId = viewId.substring(0, queryStart);

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java Wed Apr 29 21:48:20 2009
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -45,7 +46,7 @@
       }
       else
       {
-        mInternalAttributes = internal;
+        mInternalAttributes = new HashMap(internal);
       }
     }
     else
@@ -59,13 +60,15 @@
   {
     if (mPortletRequest != null)
     {
-      String value = mInternalAttributes.get(key);
+      // Read from the request before the internal ones ass these are the one's
+      // specifically sent by the client.
+      String value = mPortletRequest.getParameter(key);
       if (value != null)
       {
         return value;
       }
 
-      return mPortletRequest.getParameter(key);
+      return mInternalAttributes.get(key);
     }
     else
     {

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java?rev=769955&r1=769954&r2=769955&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java Wed Apr 29 21:48:20 2009
@@ -21,6 +21,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -45,7 +46,7 @@
       }
       else
       {
-        mInternalAttributes = internal;
+        mInternalAttributes = new HashMap(internal);
       }
     }
     else
@@ -59,13 +60,13 @@
   {
     if (mPortletRequest != null)
     {
-      String[] value = mInternalAttributes.get(key);
+      String[] value = mPortletRequest.getParameterValues(key);
       if (value != null)
       {
         return value;
       }
 
-      return mPortletRequest.getParameterValues(key);
+      return mInternalAttributes.get(key);
     }
     else
     {