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 2008/02/22 18:39:41 UTC

svn commit: r630260 - in /myfaces/portlet-bridge/core/trunk: api/src/main/java/javax/portlet/faces/ api/src/main/resources/META-INF/ impl/src/main/java/org/apache/myfaces/portlet/faces/application/ impl/src/main/java/org/apache/myfaces/portlet/faces/br...

Author: mfreedman
Date: Fri Feb 22 09:39:34 2008
New Revision: 630260

URL: http://svn.apache.org/viewvc?rev=630260&view=rev
Log:
PORTLETBRIDGE-23 - Brings implementation up to date with the current draft.  Changes include:
1) Supporting redirects during render
2) Call RestoreView phase listener when not using lifecyle to restore view in render.
3) defaultContentType/CharacterSetEncoding support.
4) removed adding APPLICATION_SCOPE map to session map.

Added:
    myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/BridgeUninitializedException.java
    myfaces/portlet-bridge/core/trunk/api/src/main/resources/META-INF/portlet1.0-bridge-faces1.2-faces-config-extensions.xsd
Modified:
    myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
    myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.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/bridge/wrapper/BridgeRenderRequestWrapper.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/context/PortletFacesContextImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletSessionMap.java

Modified: myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/Bridge.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/Bridge.java (original)
+++ myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/Bridge.java Fri Feb 22 09:39:34 2008
@@ -62,10 +62,6 @@
   // Attribute signifying whether this render is a postback or not.
   public static final String IS_POSTBACK_ATTRIBUTE         = BRIDGE_PACKAGE_PREFIX + "isPostback";
 
-  // Special session attribute name to hold the application_scope in the
-  // portlet_scope of the session so these are accessible as well.
-  public static final String APPLICATION_SCOPE_MAP         = "javax.portlet.faces.ApplicationScopeMap";
-  
   // Names for special QueryString parameters names the Bridge recognizes in
   // encodeActionURL as signifying to change the corresponding portlet values
   // in the resulting URL
@@ -91,7 +87,16 @@
   // 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
   public static final String DIRECT_LINK                   = BRIDGE_PACKAGE_PREFIX + "DirectLink";
-
+  
+  // Parameter that can be added to a ResourceURL or redirectURL to signify a back link to
+  // the current page should be added.
+  public static final String BACK_LINK                     = BRIDGE_PACKAGE_PREFIX + "BackLink";
+  
+  // Parameter that can be added to a ResourceURL to signify that this URL
+  // should be encoded as an action and not a regular resource.  This is used
+  // so h:outputLink can be used to represent a view navigation.
+  public static final String VIEW_LINK                     = BRIDGE_PACKAGE_PREFIX + "ViewLink";
+  
   // Session attribute pushed by bridge into session scope to give one access
   // to Application scope
   public static final String SESSION_APPLICATION_SCOPE_MAP = BRIDGE_PACKAGE_PREFIX
@@ -115,12 +120,12 @@
   // calling the Bridge to process a request
   public static final String DEFAULT_VIEWID                = BRIDGE_PACKAGE_PREFIX
                                                              + "defaultViewId";
-
+  
   // Following are the names of request attributes the Bridge must set before
   // acquiring its first FacesContext/FacesContextFactory in each request
   public static final String PORTLET_LIFECYCLE_PHASE       = BRIDGE_PACKAGE_PREFIX + "phase";
 
-  public static final String PORTLET_ISNAMESPACED_PROPERTY = "X-JAVAX-PORTLET-IS-NAMESPACED";
+  public static final String PORTLET_NAMESPACED_RESPONSE_PROPERTY = "X-JAVAX-PORTLET-NAMESPACED-RESPONSE";
 
   // The possible JSR168 portlet lifecycle phazses
 

Added: myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/BridgeUninitializedException.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/BridgeUninitializedException.java?rev=630260&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/BridgeUninitializedException.java (added)
+++ myfaces/portlet-bridge/core/trunk/api/src/main/java/javax/portlet/faces/BridgeUninitializedException.java Fri Feb 22 09:39:34 2008
@@ -0,0 +1,39 @@
+/*
+ * 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 javax.portlet.faces;
+
+import javax.faces.FacesException;
+
+public class BridgeUninitializedException extends BridgeException
+{
+  //TODO: Update to use static serialVersionUID ala other exceptions
+  //   when we figure out how to get maven to generate.
+
+  public BridgeUninitializedException()
+  {
+    super();
+  }
+
+  public BridgeUninitializedException(String message)
+  {
+    super(message);
+  }
+
+  public BridgeUninitializedException(String message, Throwable cause)
+  {
+    super(message, cause);
+  }
+
+  public BridgeUninitializedException(Throwable cause)
+  {
+    super(cause);
+  }
+}

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=630260&r1=630259&r2=630260&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 Fri Feb 22 09:39:34 2008
@@ -63,6 +63,11 @@
 {
   public static final String BRIDGE_CLASS             = Bridge.BRIDGE_PACKAGE_PREFIX
                                                         + "BridgeImplClass";
+  public static final String DEFAULT_CONTENT_TYPE            = Bridge.BRIDGE_PACKAGE_PREFIX
+                                                        + "defaultContentType";
+  public static final String DEFAULT_CHARACTERSET_ENCODING   = Bridge.BRIDGE_PACKAGE_PREFIX
+                                                        + "defaultCharacterSetEncoding";
+  
   public static final String BRIDGE_SERVICE_CLASSPATH = "META-INF/services/javax.portlet.faces.Bridge";
 
   private Class<? extends Bridge> mFacesBridgeClass   = null;
@@ -246,7 +251,7 @@
    * Returns the className of the bridge implementation this portlet uses. Subclasses override to
    * alter the default behavior. Default implementation first checks for a portlet context init
    * parameter: javax.portlet.faces.BridgeImplClass. If it doesn't exist then it looks for the
-   * resource file "/META-INF/services/javax.portlet.faces.Bridge" using the current threads
+   * resource file "META-INF/services/javax.portlet.faces.Bridge" using the current threads
    * classloader and extracts the classname from the first line in that file.
    * 
    * @return the class name of the Bridge class the GenericFacesPortlet uses. null if it can't be
@@ -263,6 +268,50 @@
     }
     return bridgeClassName;
   }
+  
+/**
+ * Returns the default content type for this portlet request. Subclasses override to
+ * alter the default behavior. Default implementation returns value of the portlet context init
+ * parameter: javax.portlet.faces.DefaultContentType. If it doesn't exist the portlet
+ * request's preferred response content type is returned.
+ * 
+ * Note:  This support is specific to the Portlet 1.0 Bridge.  Its value is
+ * likely to be ignored by the Portlet 2.0 Bridge or later.
+ * 
+ * @return the content type that should be used for this response.
+ */
+  public String getResponseContentType(PortletRequest request)
+  {
+    String contentType =
+      getPortletConfig().getPortletContext()
+        .getInitParameter(DEFAULT_CONTENT_TYPE);
+    
+    if (contentType == null)
+    {
+      contentType = request.getResponseContentType(); 
+    }
+    return contentType;
+  }
+
+  /**
+    * Returns the character set encoding used for this portlet response. Subclasses override to
+    * alter the default behavior. Default implementation returns value of the portlet context init
+    * parameter: javax.portlet.faces.DefaultCharacterSetEncoding. If it doesn't exist null
+    * is returned.
+    * 
+    * Note:  This support is specific to the Portlet 1.0 Bridge.  Its value is
+    * likely to be ignored by the Portlet 2.0 Bridge or later.
+    * 
+    * @return the content type that should be used for this response.
+    */
+  public String getResponseCharacterSetEncoding(PortletRequest request)
+  {
+    return
+      getPortletConfig().getPortletContext()
+        .getInitParameter(DEFAULT_CHARACTERSET_ENCODING);
+  }
+
+
 
   /**
    * Returns the defaultViewId to be used for this request. The defaultViewId is depends on the
@@ -306,6 +355,13 @@
     initBridge();
     // Push information for Bridge into request attributes
     setBridgeRequestContext(request, defaultViewId);
+    
+    // Set the response ContentType/CharacterSet
+    setResponseContentType(
+      response,
+      getResponseContentType(request),
+      getResponseCharacterSetEncoding(request));
+    
     try
     {
       mFacesBridge.doFacesRequest(request, response);
@@ -355,10 +411,36 @@
     }
   }
 
-  private void setBridgeRequestContext(PortletRequest request, String defaultViewId)
+  private void setBridgeRequestContext(
+    PortletRequest request,
+    String defaultViewId)
   {
     // Make the defaultViewId available to the Bridge
     request.setAttribute(Bridge.DEFAULT_VIEWID, defaultViewId);
+    
+  }
+  
+  private void setResponseContentType(
+    RenderResponse response,
+    String contentType,
+    String charSetEncoding)
+  {
+    if (contentType == null)
+    {
+      return;
+      
+    }
+    if (charSetEncoding != null)
+    {
+      StringBuffer buf = new StringBuffer(contentType);
+      buf.append(";");
+      buf.append(charSetEncoding);
+      response.setContentType(buf.toString());
+    }
+    else
+    {
+      response.setContentType(contentType);
+    }
   }
 
   private String getFromServicesPath(PortletContext context, String resourceName)

Added: myfaces/portlet-bridge/core/trunk/api/src/main/resources/META-INF/portlet1.0-bridge-faces1.2-faces-config-extensions.xsd
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/api/src/main/resources/META-INF/portlet1.0-bridge-faces1.2-faces-config-extensions.xsd?rev=630260&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk/api/src/main/resources/META-INF/portlet1.0-bridge-faces1.2-faces-config-extensions.xsd (added)
+++ myfaces/portlet-bridge/core/trunk/api/src/main/resources/META-INF/portlet1.0-bridge-faces1.2-faces-config-extensions.xsd Fri Feb 22 09:39:34 2008
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
+  targetNamespace="http://myfaces.apache.org/portletbridge" xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+  <xs:element name="excluded-attributes">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element minOccurs="0" maxOccurs="unbounded" name="excluded-attribute" type="xs:string" />
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+</xs:schema>
\ 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=630260&r1=630259&r2=630260&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 Fri Feb 22 09:39:34 2008
@@ -44,6 +44,9 @@
 import javax.portlet.faces.annotation.PortletNamingContainer;
 import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
 
+import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
+import org.apache.myfaces.portlet.faces.util.QueryString;
+
 /**
  * View handler implementation for JSF portlet bridge.
  * 
@@ -180,6 +183,16 @@
     catch (IOException e)
     {
       throw new FacesException(e);
+    }
+    
+    // If a redirect occurred -- merely return
+    // check here to see if a redirect occurred -- if so rerun doFacesRequest
+    // for this new view
+    QueryString redirectParams = (QueryString) context.getExternalContext()
+                      .getRequestMap().get(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS);
+    if ((redirectParams != null))
+    {
+      return;
     }
 
     // set up the ResponseWriter

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=630260&r1=630259&r2=630260&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 Fri Feb 22 09:39:34 2008
@@ -71,6 +71,7 @@
 import javax.portlet.RenderResponse;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeException;
+import javax.portlet.faces.BridgeUninitializedException;
 import javax.portlet.faces.annotation.BridgePreDestroy;
 import javax.portlet.faces.annotation.BridgeRequestScopeAttributeAdded;
 import javax.portlet.faces.annotation.ExcludeFromManagedRequestScope;
@@ -87,6 +88,7 @@
 
 import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgeRenderRequestWrapper;
 import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
+import org.apache.myfaces.portlet.faces.util.QueryString;
 import org.apache.myfaces.portlet.faces.util.config.FacesConfigurationProcessor;
 import org.apache.myfaces.portlet.faces.util.config.WebConfigurationProcessor;
 
@@ -97,6 +99,7 @@
 
 	// public so PortletStateManager can see/use
   public static final String UPDATED_VIEW_STATE_PARAM = "org.apache.myfaces.portlet.faces.updatedViewStateParam";
+  public static final String BRIDGE_REDIRECT_VIEWPARAMS = "org.apache.myfaces.portlet.faces.redirectViewParams";
 
   private static final String REQUEST_SCOPE_LOCK = "org.apache.myfaces.portlet.faces.requestScopeLock";
   private static final String REQUEST_SCOPE_MAP = "org.apache.myfaces.portlet.faces.requestScopeMap";
@@ -115,6 +118,7 @@
   private FacesContextFactory mFacesContextFactory = null;
   private Lifecycle mLifecycle = null;
   private List<String> mFacesMappings = null;
+  private boolean mInitialized = false;
 
 
   public BridgeImpl()
@@ -126,6 +130,8 @@
     throws BridgeException
   {
   	//TODO: Should we throw an exception if the bridge is already initialized?
+    if (mInitialized)
+      throw new BridgeException("Bridge already initialized.");
   	
     mPortletConfig = config;
     PortletContext portletContext = mPortletConfig.getPortletContext();
@@ -185,15 +191,20 @@
     {
       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));
-    }
+    
+    // remember that init() has been called so can test in other methods.
+    mInitialized = true;
+
   }
 
   public void doFacesRequest(ActionRequest request, ActionResponse response)
-    throws BridgeException
+    throws BridgeException, BridgeUninitializedException, NullPointerException
   {
+    if (!mInitialized) 
+      throw new BridgeUninitializedException();
+    else if (request == null || response == null)
+      throw new NullPointerException("request or response parameter is null");
+    
     // Set the Portlet lifecycle phase as a request attribute so its
     // available to Faces extensions -- allowing that code to NOT rely on
     // instanceof which can fail if a portlet container uses a single class
@@ -236,13 +247,14 @@
       // For actions we only execute the lifecycle phase
       getLifecycle().execute(context);
 
-      // Check responseComplete -- if responseComplete the
-      // lifecycle.execute
-      // resulted in a redirect navigation. To preserve Faces semantics
-      // the viewState isn't preserved nor is the data associated with the
-      // action lifecycle.
-
-      if (!context.getResponseComplete())
+      // Check if a redirect was called.  If so encode the redirect viewId
+      // as the action response without saving state.  Otherwise its not 
+      // a redirect so save the state for the subsequent render.
+      QueryString redirectParams = (QueryString) context.getExternalContext().getRequestMap().get(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS);
+
+      // Do nothing for redirect case because the ActionResponse is
+      // already encoded and no additional state needs to be saved.
+      if (redirectParams == null)
       {
         // navigation didn't redirect
 
@@ -265,7 +277,7 @@
         // preserve the request scope data and the Faces view tree at
         // RequestScope.
         saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
-
+        
         // Finalize the action response -- key here is the reliance on
         // ExternalContext.encodeActionURL to migrate info encoded
         // in the actionURL constructed from the target of this
@@ -274,8 +286,10 @@
         // asscoicated portlet render.
 
         finalizeActionResponse(context);
-
       }
+
+
+
     }
     catch (Exception e)
     {
@@ -340,10 +354,15 @@
   }
 
   public void doFacesRequest(RenderRequest request, RenderResponse response)
-    throws BridgeException
+    throws BridgeException, BridgeUninitializedException, NullPointerException
   {
-    String scopeId = null;
+    if (!mInitialized) 
+      throw new BridgeUninitializedException();
+    else if (request == null || response == null)
+      throw new NullPointerException("request or response parameter is null");
     
+    String scopeId = null;
+       
     // Set the Portlet lifecycle phase as a request attribute so its
     // available to Faces extensions -- allowing that code to NOT rely on
     // instanceof which can fail if a portlet container uses a single class
@@ -356,6 +375,10 @@
     {
       request.setAttribute(PortletExternalContextImpl.FACES_MAPPING_ATTRIBUTE, mFacesMappings);
     }
+    
+    // cache existing attributes in case a redirect occurs and
+    // we need to remove all but these preexisting ones.
+    List<String> preExistingAttributes = getRequestAttributes(request);
 
     FacesContext context = null;
     try
@@ -396,51 +419,8 @@
       {
         extCtx.getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE);
       }
-
-      // Note: if the scope wasn't restored then the Faces
-      // FACES_VIEW_STATE
-      // parameter will not have been carried into this render and hence
-      // default Faces impls will not see this render as occuring in a
-      // in a postback (isPostback() will return false. This means Faces
-      // will create a new Tree instead of restoring one -- the semantics
-      // one should get if the Bridge can't access its requestScope.
-
-      // if the requestScope restored the ViewRoot then this must be
-      // the first render after the action -- hence the tree isn't yet
-      // stored/managed by Faces -- we can merely render it
-      if (context.getViewRoot() == null)
-      {
-        // add self as PhaseListener to prevent action phases from
-        // executing
-        lifecycle.addPhaseListener(this);
-        try
-        {
-          lifecycle.execute(context);
-        }
-        catch (Exception e)
-        {
-          // When exception occurs remove stored scope so don't
-          // get stuck replaying the error when/if user refreshes
-          if (scopeId != null)
-          {
-            removeRequestScopes(scopeId);
-          }
-        }
-        finally
-        {
-          lifecycle.removePhaseListener(this);
-        }
-      }
-      getLifecycle().render(context);
       
-      // When we have navigated to this view between the action and render
-      // the initial VIEW_STATE_PARAM reflects the actions view -- update
-      // here to the one from this render so refresh will work.
-      if (scopeId != null)
-      {
-        updateViewStateParam(context, scopeId);
-      }
-
+      doFacesRender(request, response, context, lifecycle, scopeId, preExistingAttributes);
     }
     catch (Exception e)
     {
@@ -474,14 +454,119 @@
       }
     }
   }
+  
+  private void doFacesRender(
+      RenderRequest request,
+      RenderResponse response,
+      FacesContext context,
+      Lifecycle lifecycle,
+      String scopeId,
+      List <String> preExistingAttributes
+      )
+    throws BridgeException, BridgeUninitializedException, NullPointerException
+  {
+    boolean redirectedDuringRender = false;
+    
+    // Note: if the scope wasn't restored then the Faces
+    // FACES_VIEW_STATE
+    // parameter will not have been carried into this render and hence
+    // default Faces impls will not see this render as occuring in a
+    // in a postback (isPostback() will return false. This means Faces
+    // will create a new Tree instead of restoring one -- the semantics
+    // one should get if the Bridge can't access its requestScope.
+
+    // if the requestScope restored the ViewRoot then this must be
+    // the first render after the action -- hence the tree isn't yet
+    // stored/managed by Faces -- we can merely render it
+    if (context.getViewRoot() == null)
+    {
+      // add self as PhaseListener to prevent action phases from
+      // executing
+      lifecycle.addPhaseListener(this);
+      try
+      {
+        lifecycle.execute(context);
+      }
+      catch (Exception e)
+      {
+        // When exception occurs remove stored scope so don't
+        // get stuck replaying the error when/if user refreshes
+        if (scopeId != null)
+        {
+          removeRequestScopes(scopeId);
+        }
+      }
+      finally
+      {
+        lifecycle.removePhaseListener(this);
+      }
+    }
+    else
+    {
+      // using the cached view.  Still call the preRestoreView phase listeners
+      // as some extensions depend on this being called per request.
+      PhaseListener[] listeners = lifecycle.getPhaseListeners();
+      PhaseEvent event = new PhaseEvent(context, PhaseId.RESTORE_VIEW, lifecycle);
+      for (PhaseListener listener:listeners)
+      {
+        if (listener.getPhaseId() == PhaseId.ANY_PHASE || 
+            listener.getPhaseId() == PhaseId.RESTORE_VIEW)
+        {
+          listener.beforePhase(event);
+        }
+      }
+    }
+      
+    // check here to see if a redirect occurred -- if so rerun doFacesRequest
+    // for this new view
+    QueryString redirectParams = (QueryString) context.getExternalContext()
+                      .getRequestMap().get(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS);
+    if ((redirectParams == null))
+    {
+      getLifecycle().render(context);
+    }
+    else
+    {
+      redirectRender(context, lifecycle, request, response, redirectParams, preExistingAttributes);
+      context = FacesContext.getCurrentInstance();
+      redirectedDuringRender = true;
+    }
+   
+    
+    // check here to see if a redirect occurred -- if so rerun doFacesRequest
+    // for this new view
+    redirectParams = (QueryString) context.getExternalContext()
+                      .getRequestMap().get(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS);
+    if ((redirectParams != null))
+    {
+      redirectRender(context, lifecycle, request, response, redirectParams, preExistingAttributes);
+      context = FacesContext.getCurrentInstance();
+      redirectedDuringRender = true;
+    }
+     
+    // When we have navigated to this view between the action and render
+    // the initial VIEW_STATE_PARAM reflects the actions view -- update
+    // here to the one from this render so refresh will work.
+    if (scopeId != null)
+    {
+      updateViewInfo(context, scopeId, redirectedDuringRender);
+    }
+  }
+
 
   public void destroy()
   {
+    if (!mInitialized)
+      // do nothing if destroy an uninitialzed bridge
+      return;
+    
+    mInitialized = false;
+    
     // remove any scopes being managed for this portlet
     // Each scope has a per portlet prefix -- pass in the prefix
     // constructed by adding the prefix to an empty string.
     removeRequestScopes(qualifyScopeId(mPortletConfig.getPortletName(), null, null));
-
+    
     mPortletConfig = null;
   }
 
@@ -575,7 +660,74 @@
       notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
     }
   }
+  
+  private void redirectRender(FacesContext context,
+                              Lifecycle lifecycle,
+                              RenderRequest request,
+                              RenderResponse response,
+                              QueryString redirectParams,
+                              List<String> preExistingAttrs)
+  {
+  
+    // remove any bridge special marker params as these can't be set in a 
+    // render redirect
+    redirectParams.removeParameter(Bridge.DIRECT_LINK);
+    redirectParams.removeParameter(Bridge.PORTLET_MODE_PARAMETER);
+    redirectParams.removeParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
+    redirectParams.removeParameter(Bridge.PORTLET_SECURE_PARAMETER);
+    
+    // Now turn the QueryString into a parameter map
+    Map <String, String[]> paramMap = new LinkedHashMap(redirectParams.numParameters());
+    Enumeration<String> nameEnum = redirectParams.getParameterNames();
+    while (nameEnum != null && nameEnum.hasMoreElements()) 
+    {
+      String name = nameEnum.nextElement();
+      Enumeration<String> valuesEnum = redirectParams.getParameterValues(name);
+      ArrayList<String> values = new ArrayList();
+      while (valuesEnum != null && valuesEnum.hasMoreElements())
+      {
+        values.add(valuesEnum.nextElement());
+        
+      }
 
+      paramMap.put(name, values.toArray(new String[values.size()]));
+    }
+      
+    // reset request attributes to those that existed before we were called.
+    Map<String, Object> m = context.getExternalContext().getRequestMap();
+    Set<Map.Entry<String, Object>> entrySet = m.entrySet();
+    Iterator<Map.Entry<String, Object>> i = entrySet.iterator();
+    String[] names = new String[400];
+    int count = 0;
+    while (i.hasNext())
+    {
+      Map.Entry<String, Object> entry = i.next();
+      if (!preExistingAttrs.contains(entry.getKey()))
+      {
+        // i.remove();
+        names[count++] = entry.getKey();
+      }
+    }
+    
+    for (int j = 0; j < count; j++)
+    {
+      m.remove(names[j]);
+    }
+    
+    // now wrap the request object to expose only those params as are in QS
+    BridgeRenderRequestWrapper requestWrapper = new BridgeRenderRequestWrapper(request, paramMap, false);
+    // close the FacesContext
+    context.release();
+    // start a new FacesContext
+    context = 
+        getFacesContextFactory().getFacesContext(mPortletConfig, request, response, lifecycle);
+    // call ExternalContext.setRequest with wrapped request
+    context.getExternalContext().setRequest(requestWrapper);
+    // Run lifecycle.execute again ... then render
+    doFacesRender(request, response, context, lifecycle, null, preExistingAttrs);
+    return;  // to continue on
+  }
+  
   private FacesContextFactory getFacesContextFactory()
     throws BridgeException
   {
@@ -676,17 +828,11 @@
     }
   }
   
-  private void updateViewStateParam(FacesContext context, String scopeId)
+  private void updateViewInfo(
+    FacesContext context,
+    String scopeId,
+    boolean redirectedDuringRender)
   {
-    
-    // First make sure we have a value to update
-    String updatedViewStateParam = (String) context.getExternalContext()
-        .getRequestMap().get(UPDATED_VIEW_STATE_PARAM);
-    
-    if (updatedViewStateParam == null)
-        return;
-    
-    // Otherwise we need to update/store this value in the scope
     PortletContext portletContext = mPortletConfig.getPortletContext();
 
     // Get the request scope lock -- because its added during init it should
@@ -710,12 +856,6 @@
         return;
       }
 
-      // Prepare the value for storing as a preserved parameter
-      // Store as an array of Strings with just one entry as per
-      // portlet request
-      String[] values = new String[1];
-      values[0] = updatedViewStateParam;
-
       // Now get the RequestParameters from the scope
       @SuppressWarnings("unchecked")
       Map<String, String[]> requestParams = (Map<String, String[]>)scopeMap.get(REQUEST_PARAMETERS);
@@ -725,8 +865,36 @@
         requestParams = new HashMap<String, String[]>(1);
         scopeMap.put(REQUEST_PARAMETERS, requestParams);
       }
-      // finally update the value in the Map
-      requestParams.put(ResponseStateManager.VIEW_STATE_PARAM, values);
+    
+      // Prepare the value for storing as a preserved parameter
+      // Store as an array of Strings with just one entry as per
+      // portlet request
+      String[] values = new String[1];
+      // First make sure we have a value to update
+      String updatedViewStateParam = (String) context.getExternalContext()
+          .getRequestMap().get(UPDATED_VIEW_STATE_PARAM);
+      
+      if (updatedViewStateParam != null)
+      {
+        values[0] = updatedViewStateParam;
+
+        // finally update the value in the Map
+        requestParams.put(ResponseStateManager.VIEW_STATE_PARAM, values);
+      }
+      
+      if (redirectedDuringRender)
+      {
+        // Add the VIEW_ID
+        values = new String[1];
+        values[0] = context.getViewRoot().getViewId();
+        // finally update the value in the Map
+        requestParams.put(PortletExternalContextImpl.REDIRECT_ID_PARAMETER_NAME, values);
+      }
+      else
+      {
+        // remove it in case was there from a prior redirect
+        requestParams.remove(PortletExternalContextImpl.REDIRECT_ID_PARAMETER_NAME);
+      }
     }
   }
   
@@ -908,7 +1076,8 @@
       isInNamespace(s, "javax.faces.") ||
       isInNamespace(s, "javax.servlet.") ||
       isInNamespace(s, "javax.servlet.include.") ||
-      s.equals(PREEXISTING_ATTRIBUTE_NAMES);
+      isInNamespace(s, "org.apache.myfaces.portlet.faces") ||
+      isInNamespace(s, "org.apache.myfaces.portlet.faces.context");
     }
   
   private boolean isConfiguredExcludedAttribute(String s)
@@ -1086,17 +1255,13 @@
     // information
     // in the subsequent render request(s).
 
+    String viewId = context.getViewRoot().getViewId();
+
+    // don't care about the return as it means nothing
     ViewHandler viewHandler = context.getApplication().getViewHandler();
-    String actionURL = viewHandler.getActionURL(context, context.getViewRoot().getViewId());
-    String encodedActionURL = context.getExternalContext().encodeActionURL(actionURL);
+    String viewURL = viewHandler.getActionURL(context, viewId);
+    context.getExternalContext().encodeActionURL(viewURL);
 
-    // Strictly speaking this is a redundant call (noop) as
-    // ExternalContext.redirect() JSR 301 rules require redirects of
-    // URLs containing viewIds (aka actionURLs) to be handled as
-    // regular Faces navigation not full client redirects. Its
-    // included here primarily to ensure that redirect is implemented
-    // correctly.
-    context.getExternalContext().redirect(encodedActionURL);
   }
   
   // notify this scope's attributes that they are being removed
@@ -1134,6 +1299,9 @@
 
   private void removeRequestScopes(String scopePrefix)
   {
+    
+    if (scopePrefix == null)
+      return; // Nothing to do
 
     // Get the RequestScope Map and remove all entries/scopes with this prefix
     PortletContext portletContext = mPortletConfig.getPortletContext();

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/wrapper/BridgeRenderRequestWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/wrapper/BridgeRenderRequestWrapper.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/wrapper/BridgeRenderRequestWrapper.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/wrapper/BridgeRenderRequestWrapper.java Fri Feb 22 09:39:34 2008
@@ -30,14 +30,24 @@
 {
   private Map<String, String[]> mActionParams     = null;
   private Map<String, String[]> mCombinedParamMap = null;
+  private boolean mCombineParams = true;
 
   public BridgeRenderRequestWrapper(RenderRequest request, 
                                     Map<String, String[]> actionParams)
                                       throws IllegalArgumentException
   {
+    this(request, actionParams, true);
+  }
+  
+  public BridgeRenderRequestWrapper(RenderRequest request, 
+                                    Map<String, String[]> actionParams,
+                                    boolean combineParams)
+                                      throws IllegalArgumentException
+  {
     super(request);
 
     mActionParams = actionParams;
+    mCombineParams = combineParams;
   }
 
   /**
@@ -148,13 +158,21 @@
   @Override
   public Map<String, String[]> getParameterMap()
   {
-    if (mActionParams == null || mActionParams.isEmpty())
+    if (!mCombineParams)
     {
-      return null;
+      return mActionParams;
     }
-    
-    if (mCombinedParamMap == null)
+    else if (mActionParams == null || mActionParams.isEmpty())
     {
+      return getParent().getParameterMap();
+    }
+    else if (mCombinedParamMap != null)
+    {
+      return mCombinedParamMap;
+    }
+    else 
+    {
+      // Combine the two Maps
       mCombinedParamMap = new LinkedHashMap<String, String[]>(getParent().getParameterMap());
 
       // now walk through the actionParams adding those that aren't
@@ -170,8 +188,8 @@
       
       // now make this an immutable Map
       mCombinedParamMap = Collections.unmodifiableMap(mCombinedParamMap);
+      
+      return mCombinedParamMap;
     }
-    
-    return mCombinedParamMap;
   }
 }

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=630260&r1=630259&r2=630260&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 Fri Feb 22 09:39:34 2008
@@ -22,13 +22,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
+
 import java.net.MalformedURLException;
 import java.net.URL;
+
 import java.security.Principal;
+
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -37,6 +41,8 @@
 import javax.faces.FacesException;
 import javax.faces.application.ViewHandler;
 import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
 import javax.portlet.PortletConfig;
@@ -54,6 +60,7 @@
 import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
 import javax.portlet.faces.BridgeUtil;
 
+import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
 import org.apache.myfaces.portlet.faces.util.QueryString;
 import org.apache.myfaces.portlet.faces.util.URLUtils;
 import org.apache.myfaces.portlet.faces.util.map.EnumerationIterator;
@@ -66,72 +73,71 @@
 import org.apache.myfaces.portlet.faces.util.map.PortletRequestParameterMap;
 import org.apache.myfaces.portlet.faces.util.map.PortletRequestParameterValuesMap;
 import org.apache.myfaces.portlet.faces.util.map.PortletSessionMap;
+
 /**
  * This implementation of {@link ExternalContext} is specific to the portlet implementation.
  * 
  * Methods of interests are: - encodeActionURL - redirect
  */
-public class PortletExternalContextImpl extends ExternalContext
+public class PortletExternalContextImpl
+  extends ExternalContext
 {
 
-  public static final String    FACES_MAPPING_ATTRIBUTE            = "org.apache.myfaces.portlet.faces.context.facesMapping";
-
-  public static final String    RENDER_POLICY_ATTRIBUTE            = Bridge.BRIDGE_PACKAGE_PREFIX
-                                                                     + "." + Bridge.RENDER_POLICY;
+  public static final String FACES_MAPPING_ATTRIBUTE = 
+    "org.apache.myfaces.portlet.faces.context.facesMapping";
+  private static final String ENCODED_ACTION_URL_ATTRIBUTE_PREFIX =
+    "org.apache.myfaces.portlet.faces.context.";
 
-  // Query parameter to store the original viewId in the query string
-  public static final String    VIEW_ID_QUERY_PARAMETER            = "_VIEW_ID";
+  public static final String RENDER_POLICY_ATTRIBUTE = 
+    Bridge.BRIDGE_PACKAGE_PREFIX + "." + Bridge.RENDER_POLICY;
 
   // Render parameter to store the viewId
-  public static final String    ACTION_ID_PARAMETER_NAME           = "_ACTION_ID";
+  public static final String ACTION_ID_PARAMETER_NAME = "_xACTION_ID";
+  public static final String REDIRECT_ID_PARAMETER_NAME = "org.apache.myfaces.portlet.faces.redirectViewParams";
+  
 
-  public static final String    RESOURCE_METHOD_QUERY_PARAMETER    = "_xResourceMethod";
-  public static final String    RESOURCE_URL_QUERY_PARAMETER       = "_xResourceUrl";
-  public static final String    FACES_RESOURCE_QUERY_PARAMETER     = "_xFacesResource";
-  public static final String    PROCESS_AS_RENDER_QUERY_PARAMETER  = "_xProcessAsRender";
-  public static final String    REQUIRES_REWRITE_PARAMETER         = "_xRequiresRewrite";
-
-  private PortletContext        mPortletContext;
-  private PortletConfig         mPortletConfig;
-  private PortletRequest        mPortletRequest;
-  private PortletResponse       mPortletResponse;
+  private PortletContext mPortletContext;
+  private PortletConfig mPortletConfig;
+  private PortletRequest mPortletRequest;
+  private PortletResponse mPortletResponse;
 
   // Needed for distpach() which requires the actual PortletRequest/Response
   // objects not wrapped one's (since wrapping isn't official in 168)
-  private PortletRequest        mOrigPortletRequest                = null;
-  private PortletResponse       mOrigPortletResponse               = null;
+  private PortletRequest mOrigPortletRequest = null;
+  private PortletResponse mOrigPortletResponse = null;
 
   // External context maps
-  private Map<String, Object>   mApplicationMap                    = null;
-  private Map<String, Object>   mSessionMap                        = null;
-  private Map<String, Object>   mRequestMap                        = null;
-  private Map<String, String>   mRequestParameterMap               = null;
-  private Map<String, String[]> mRequestParameterValuesMap         = null;
-  private Map<String, String>   mRequestHeaderMap                  = null;
-  private Map<String, String[]> mRequestHeaderValuesMap            = null;
-  private Map<String, String>   mInitParameterMap                  = null;
+  private Map<String, Object> mApplicationMap = null;
+  private Map<String, Object> mSessionMap = null;
+  private Map<String, Object> mRequestMap = null;
+  private Map<String, String> mRequestParameterMap = null;
+  private Map<String, String[]> mRequestParameterValuesMap = null;
+  private Map<String, String> mRequestHeaderMap = null;
+  private Map<String, String[]> mRequestHeaderValuesMap = null;
+  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> mInternalRequestParameterMap = Collections.emptyMap();
   private Map<String, String[]> mInternalRequestParameterValuesMap = Collections.emptyMap();
 
-  private PortletRequestHeaders mPortletRequestHeaders             = null;
+  private PortletRequestHeaders mPortletRequestHeaders = null;
 
   // Requested Faces view
-  private String                mViewId                            = null;
+  private String mViewId = null;
 
   // Reverse engineered serlvet paths from mappings
-  private List<String>          mFacesMappings                     = null;
-  private String                mServletPath                       = null;
-  private String                mPathInfo                          = null;
+  private List<String> mFacesMappings = null;
+  private String mServletPath = null;
+  private String mPathInfo = null;
 
   // Current Portlet phase
-  private Bridge.PortletPhase   mPhase                             = null;
+  private Bridge.PortletPhase mPhase = null;
 
   @SuppressWarnings("unchecked")
-  public PortletExternalContextImpl(PortletConfig portletConfig, PortletRequest portletRequest,
-                                    PortletResponse portletResponse) throws FacesException
+  public PortletExternalContextImpl(PortletConfig portletConfig, PortletRequest portletRequest, 
+                                    PortletResponse portletResponse)
+    throws FacesException
   {
     mPortletConfig = portletConfig;
     mPortletContext = mPortletConfig.getPortletContext();
@@ -140,20 +146,9 @@
 
     mPhase = (Bridge.PortletPhase) mPortletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
 
-
-    // viewId is the actual context relative path to the resource
-    mViewId = getViewId();
-    
-    // Now reverse engineer the servlet paths from the mappings 
-    // So Faces thinks was a client request
     mFacesMappings = (List<String>) mPortletRequest.getAttribute(FACES_MAPPING_ATTRIBUTE);
-    mapPathsFromViewId(mViewId, mFacesMappings);
-
-
-    // JSF RI relies on a request attribute setting to properly handle
-    // suffix mapping -- but because their suffix mapping code is servlet dependent
-    // we need to set it for them
-    setFacesMapping();
+    
+    determineView();
 
   }
 
@@ -229,8 +224,10 @@
     else
     {
       path = url;
+      // construct an empty queryString to hold the viewId
+      queryStr = new QueryString("UTF8");
     }
-
+    
     // Determine the viewId by inspecting the URL
     if (!isRelativePath(path))
     {
@@ -238,13 +235,16 @@
     }
     else
     {
-        viewId = getViewIdFromRelativePath(path);
+      viewId = getViewIdFromRelativePath(path);
     }
 
     if (viewId == null)
     {
       throw new FacesException("encodeActionURL:  unable to recognize viewId");
     }
+    
+    // put the viewId in the QueryStr.
+    queryStr.addParameter(ACTION_ID_PARAMETER_NAME, viewId);
 
     if (mPhase == Bridge.PortletPhase.RENDER_PHASE)
     { // render - write
@@ -254,142 +254,177 @@
       // state)
       RenderResponse renderResponse = (RenderResponse) getResponse();
       PortletURL actionURL = renderResponse.createActionURL();
-      actionURL.setParameter(ACTION_ID_PARAMETER_NAME, viewId);
-      
-      // Add extra parameters so they don't get lost
-      if (queryStr != null)
+
+      // Add parameters so they don't get lost
+      Enumeration<String> list = queryStr.getParameterNames();
+      while (list.hasMoreElements())
       {
-        Enumeration<String> list = queryStr.getParameterNames();
-        while (list.hasMoreElements())
+        String param = list.nextElement().toString();
+        if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
         {
-          String param = list.nextElement().toString();
-          if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
+          try
           {
-            try 
-            {
-              actionURL.setPortletMode(new PortletMode(queryStr.getParameter(param)));
-            }
-            catch (Exception e)
-            {
-              ; // do nothing -- just ignore
-            }
+            actionURL.setPortletMode(new PortletMode(queryStr.getParameter(param)));
           }
-          else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
+          catch (Exception e)
           {
-            try 
-            {
-              actionURL.setWindowState(new WindowState(queryStr.getParameter(param)));
-            }
-            catch (Exception e)
-            {
-              ; // do nothing -- just ignore
-            }
+            ; // do nothing -- just ignore
           }
-          else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
+        }
+        else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
+        {
+          try
+          {
+            actionURL.setWindowState(new WindowState(queryStr.getParameter(param)));
+          }
+          catch (Exception e)
+          {
+            ; // do nothing -- just ignore
+          }
+        }
+        else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
+        {
+          try
           {
-            try 
-            {
-              actionURL.setSecure(Boolean.getBoolean(queryStr.getParameter(param)));
-            }
-            catch (Exception e)
-            {
-              ; // do nothing -- just ignore
-            }
+            actionURL.setSecure(Boolean.getBoolean(queryStr.getParameter(param)));
           }
-          else
+          catch (Exception e)
           {
-            actionURL.setParameter(param, queryStr.getParameter(param));
+            ; // do nothing -- just ignore
           }
         }
+        else
+        {
+          actionURL.setParameter(param, queryStr.getParameter(param));
+        }
       }
 
       // TODO hack to workaround double encoding problem
-      String actionURLStr = actionURL.toString();
-      actionURLStr = actionURLStr.replaceAll("\\&amp\\;", "&");
-
-      return actionURLStr;
+      url = actionURL.toString();
+      url = url.replaceAll("\\&amp\\;", "&");
     }
     else
     { // action - write the viewId to navigational state
       ActionResponse actionResponse = (ActionResponse) getResponse();
 
-      actionResponse.setRenderParameter(ACTION_ID_PARAMETER_NAME, viewId);
-
-      // set other request params (if any) into navigational states
-      if (queryStr != null)
+      // set request params into navigational states
+      Enumeration<String> list = queryStr.getParameterNames();
+      while (list.hasMoreElements())
       {
-        Enumeration<String> list = queryStr.getParameterNames();
-        while (list.hasMoreElements())
+        String param = list.nextElement();
+        if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
         {
-          String param = list.nextElement();
-          if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
+          try
           {
-            try 
-            {
-              actionResponse.setPortletMode(new PortletMode(queryStr.getParameter(param)));
-            }
-            catch (Exception e)
-            {
-            	//TODO: Ignoring is probably dangerous here as it means that we are
-            	//      EITHER using exceptions for flow control (which is extreemly
-            	//      inefficient) or we should log a message saying what the issue
-            	//      is.  According to the Javadocs an exception is thrown here if the
-            	//      portlet mode is not allowed or if sendRedirect has already been
-            	//      called.  In either case we should log an information type message
-            	//      here.
-              ; // do nothing -- just ignore
-            }
+            actionResponse.setPortletMode(new PortletMode(queryStr.getParameter(param)));
           }
-          else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
+          catch (Exception e)
           {
-            try 
-            {
-              actionResponse.setWindowState(new WindowState(queryStr.getParameter(param)));
-            }
-            catch (Exception e)
-            {
-              ; // do nothing -- just ignore
-            }
+            //TODO: Ignoring is probably dangerous here as it means that we are
+            //      EITHER using exceptions for flow control (which is extreemly
+            //      inefficient) or we should log a message saying what the issue
+            //      is.  According to the Javadocs an exception is thrown here if the
+            //      portlet mode is not allowed or if sendRedirect has already been
+            //      called.  In either case we should log an information type message
+            //      here.
+            ; // do nothing -- just ignore
           }
-          else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
+        }
+        else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
+        {
+          try
           {
-            ; // ignore -- do nothing as can't encode into an actionResponse
+            actionResponse.setWindowState(new WindowState(queryStr.getParameter(param)));
           }
-          else
+          catch (Exception e)
           {
-            actionResponse.setRenderParameter(param, queryStr.getParameter(param));
+            ; // do nothing -- just ignore
           }
         }
+        else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
+        {
+          ; // ignore -- do nothing as can't encode into an actionResponse
+        }
+        else
+        {
+          actionResponse.setRenderParameter(param, queryStr.getParameter(param));
+        }
       }
-
-      return url;
     }
+    // Because we want to support translating a redirect that occurs
+    // during a render as an in place navigation AND we can't reverse
+    // engineer the URL from the actionURL, we stash the queryStr on
+    // a request attribute, keyed with the generated URL.  If this generated
+    // url is passed to redirect() we can get the queryStr back and 
+    // process based on it.  Do here rather then in the render if statement
+    // because redirect relies on this to handle non-encoded Faces URLs whether
+    // in an action or a render.
+    getRequestMap().put(ENCODED_ACTION_URL_ATTRIBUTE_PREFIX.concat(url), queryStr);
+    
+    return url;
   }
 
   @Override
-  public void redirect(String url) throws IOException
+  public void redirect(String url)
+    throws IOException
   {
-    // Distinguish between redirects within this app and external links
-    // redirects within this app are dealt (elsewhere) as navigations
-    // so do nothing. External links are redirected
-
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE
-        && (url.startsWith("#") || isExternalURL(url) || isDirectLink(url)))
+    // Distinguish between redirects to other Faces views in this app
+    // and everything else.
+    // Redirects to a view are dealt (elsewhere) as navigations -- 
+    // encode this information for later use by the bridge controller.
+    // Other links are redirected.
+    
+    // First look to see if this is an already encoded 
+    QueryString params = (QueryString) getRequestMap().get(ENCODED_ACTION_URL_ATTRIBUTE_PREFIX.concat(url));
+    if (params != null)
+    {
+      // Because we want to support translating a redirect that occurs
+      // during a render as an in place navigation AND we can't reverse
+      // engineer the URL from the actionURL, we stash the original URL on
+      // a request attribute, keyed with the generated URL.  If this generated
+      // url is passed to redirect() we can get the original url back and 
+      // process based on it.
+      getRequestMap().put(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS, params);
+    }
+    else if ((url.startsWith("#") || isExternalURL(url) || isDirectLink(url)) ||
+         !isFacesURL(url))
     {
-      ((ActionResponse) getResponse()).sendRedirect(url);
+      if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
+      {
+        ((ActionResponse) getResponse()).sendRedirect(url);
+        FacesContext.getCurrentInstance().responseComplete();
+      }
+    } else
+    {
+      // is it an unencoded Faces URL -- process it.
+      // recurse on redirect after calling encodeActionURL which will 
+      // cause the attribute to be set.
+      redirect(encodeActionURL(url));
+      FacesContext.getCurrentInstance().responseComplete();
     }
-
-    // TODO: Should we recognize a redirect during a rendere to an internal
-    // link and treat as a navigation?
-
+    
+     // else nothing to do
+     // TODO:  is there an exception to throw here?
   }
+  
 
   @Override
   public String encodeResourceURL(String s)
   {
+    boolean containsBackLinkMarker = false, containsViewLinkMarker = false;
+    if (s.indexOf(Bridge.BACK_LINK) != -1)
+    {
+      containsBackLinkMarker = true;
+    }
 
     if (!isExternalURL(s))
     {
+      // Only non-external URLs can be viewLinks
+      if (s.indexOf(Bridge.VIEW_LINK) != -1)
+      {
+        containsViewLinkMarker = true;
+      }
+
       if (!s.startsWith("/"))
       {
         // must be a relative path -- convert it to contextPath relative
@@ -414,7 +449,7 @@
         path = path.substring(0, path.lastIndexOf("/"));
         s = URLUtils.convertFromRelative(path, s);
       }
-    
+
       // prepend the context path since portletResponse.encodeURL() requires a full path URI
       // Don't need to check return from getRequestContextPath because there must
       // always be a vlaue even if an empty string
@@ -425,16 +460,30 @@
       }
     }
 
-    String resourceURLStr = mPortletResponse.encodeURL(s);
+    // Check for backlink and viewlink markers -- if they exist replace
+    if (containsBackLinkMarker || containsViewLinkMarker)
+    {
+      s = replaceResourceQueryStringMarkers(s, containsBackLinkMarker, containsViewLinkMarker);
+    }
+
+    if (!containsViewLinkMarker)
+    {
+      s = mPortletResponse.encodeURL(s);
+    }
+    else
+    {
+      s = encodeActionURL(s);
+    }
 
     // Avoid double encoding
-    resourceURLStr = resourceURLStr.replaceAll("\\&amp\\;", "&");
+    s = s.replaceAll("\\&amp\\;", "&");
 
-    return resourceURLStr;
+    return s;
   }
 
   @Override
-  public void dispatch(String requestURI) throws IOException, FacesException
+  public void dispatch(String requestURI)
+    throws IOException, FacesException
   {
     if (requestURI == null)
     {
@@ -450,9 +499,8 @@
 
     if (prd == null)
     {
-      throw new IllegalArgumentException(
-                                         "No request dispatcher can be created for the specified path: "
-                                             + requestURI);
+      throw new IllegalArgumentException("No request dispatcher can be created for the specified path: " + 
+                                         requestURI);
     }
 
     try
@@ -531,8 +579,9 @@
   {
     if (mRequestParameterMap == null)
     {
-      mRequestParameterMap = Collections.unmodifiableMap(new PortletRequestParameterMap(                                                                                        mPortletRequest,
-                                                                                       mInternalRequestParameterMap));
+      mRequestParameterMap = 
+          Collections.unmodifiableMap(new PortletRequestParameterMap(mPortletRequest, 
+                                                                     mInternalRequestParameterMap));
     }
     return mRequestParameterMap;
   }
@@ -541,18 +590,17 @@
   {
     if (mRequestParameterValuesMap == null)
     {
-      mRequestParameterValuesMap = Collections
-                                              .unmodifiableMap(new PortletRequestParameterValuesMap(
-                                                                                                    mPortletRequest,
-                                                                                                    mInternalRequestParameterValuesMap));
+      mRequestParameterValuesMap = 
+          Collections.unmodifiableMap(new PortletRequestParameterValuesMap(mPortletRequest, 
+                                                                           mInternalRequestParameterValuesMap));
     }
     return mRequestParameterValuesMap;
   }
 
   public Iterator<String> getRequestParameterNames()
   {
-  	//Map is unmodifiable, so the iterator will be as well
-  	return getRequestParameterMap().keySet().iterator();
+    //Map is unmodifiable, so the iterator will be as well
+    return getRequestParameterMap().keySet().iterator();
   }
 
   public Map<String, String> getRequestHeaderMap()
@@ -626,7 +674,7 @@
   }
 
   @SuppressWarnings("unchecked")
-	public Set<String> getResourcePaths(String s)
+  public Set<String> getResourcePaths(String s)
   {
     return mPortletContext.getResourcePaths(s);
   }
@@ -694,12 +742,13 @@
   @Override
   public Iterator<Locale> getRequestLocales()
   {
-  	//TODO: Cache this value...
+    //TODO: Cache this value...
     return new EnumerationIterator<Locale>(mPortletRequest.getLocales());
   }
 
   @Override
-  public URL getResource(String s) throws MalformedURLException
+  public URL getResource(String s)
+    throws MalformedURLException
   {
     return mPortletContext.getResource(s);
   }
@@ -731,6 +780,11 @@
     mRequestParameterValuesMap = null;
     mRequestHeaderMap = null;
     mRequestHeaderValuesMap = null;
+    
+    // recalculate the view in case it has changed
+    // One case where it changes is when a redirect occurs
+    // during a render and we impl as a direct navigation
+    determineView();
   }
 
   /**
@@ -767,22 +821,22 @@
    * 
    */
   @Override
-  public void setRequestCharacterEncoding(String encoding) throws UnsupportedEncodingException,
-                                                          IllegalStateException
+  public void setRequestCharacterEncoding(String encoding)
+    throws UnsupportedEncodingException, IllegalStateException
   {
     /* TODO: Temporary workaround for JIRA PORTLETBRIDGE-14 until EG
      * decides on best course of action.
-     * 
+     *
    if (mPhase != Bridge.PortletPhase.ACTION_PHASE)
     {
-          
+
         throw new IllegalStateException(
                                         "PortletExternalContextImpl.setRequestCharacterEncoding(): Request must be an ActionRequest");
     }
     */
-    
-  	//Part of temp workaround.  Do a noop if we are not in action phase
-    if(mPhase == Bridge.PortletPhase.ACTION_PHASE)
+
+    //Part of temp workaround.  Do a noop if we are not in action phase
+    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
       ((ActionRequest) mPortletRequest).setCharacterEncoding(encoding);
     }
@@ -894,8 +948,7 @@
   {
     if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
-      throw new IllegalStateException(
-                                      "PortletExternalContextImpl.getResponseCharacterEncoding(): Response must be a RenderRequest");
+      throw new IllegalStateException("PortletExternalContextImpl.getResponseCharacterEncoding(): Response must be a RenderRequest");
     }
 
     return ((RenderResponse) mPortletResponse).getCharacterEncoding();
@@ -930,8 +983,7 @@
   {
     if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
     {
-      throw new IllegalStateException(
-                                      "PortletExternalContextImpl.getResponseContentType(): Response must be a RenderRequest");
+      throw new IllegalStateException("PortletExternalContextImpl.getResponseContentType(): Response must be a RenderRequest");
     }
 
     return ((RenderResponse) mPortletResponse).getContentType();
@@ -993,9 +1045,18 @@
   /**
    * Gets the view identifier we should use for this request.
    */
-  private String getViewId() throws BridgeDefaultViewNotSpecifiedException
+  private String getViewId()
+    throws BridgeDefaultViewNotSpecifiedException
   {
-    String viewId = mPortletRequest.getParameter(ACTION_ID_PARAMETER_NAME);
+    // Use the REDIRECT_ID if it exists as this indicates a render redirect
+    // where we couldn't update the ACTION_ID
+    String viewId = mPortletRequest.getParameter(REDIRECT_ID_PARAMETER_NAME);
+    
+    // Normal case is its returned in the render parameter
+    if (viewId == null)
+    {
+      viewId = mPortletRequest.getParameter(ACTION_ID_PARAMETER_NAME);
+    }
 
     log("PortletExternalContextImpl.getViewId: found action_id = " + viewId);
 
@@ -1007,7 +1068,7 @@
       {
         throw new BridgeDefaultViewNotSpecifiedException();
       }
-      
+
       log("PortletExternalContextImpl.getViewId: action_id not found, defaulting to: " + viewId);
     }
 
@@ -1034,7 +1095,8 @@
       {
         String param = list.nextElement();
         mInternalRequestParameterMap.put(param, queryStr.getParameter(param));
-        mInternalRequestParameterValuesMap.put(param, new String[]{queryStr.getParameter(param)});
+        mInternalRequestParameterValuesMap.put(param, new String[]
+            { queryStr.getParameter(param) });
       }
 
       viewId = viewId.substring(0, queryStart);
@@ -1043,7 +1105,82 @@
 
     return viewId;
   }
-  
+
+  private String replaceResourceQueryStringMarkers(String s, boolean hasBackLink, 
+                                                   boolean hasViewLink)
+  {
+    String path = null;
+    QueryString queryStr = null;
+    int queryStart = -1;
+
+    // First: split URL into path and query string
+    // Hold onto QueryString for later processing
+    queryStart = s.indexOf('?');
+
+    // references aren't in the querystring so nothing to do
+    if (queryStart == -1)
+      return s;
+
+    FacesContext context = FacesContext.getCurrentInstance();
+
+    queryStr = new QueryString(s.substring(queryStart + 1), "UTF8");
+    path = s.substring(0, queryStart);
+
+    Enumeration<String> list = queryStr.getParameterNames();
+    while (list.hasMoreElements())
+    {
+      String param = list.nextElement().toString();
+      if (hasBackLink && param.equals(Bridge.BACK_LINK))
+      {
+        try
+        {
+          // Set backlink as parameter using value as param name
+          queryStr.setParameter(queryStr.getParameter(param), 
+                                encodeActionURL(context.getApplication().getViewHandler().getActionURL(context, 
+                                                                                                       context.getViewRoot().getViewId())));
+          ;
+        }
+        catch (Exception e)
+        {
+          ; // do nothing -- just ignore
+        }
+        // remove the backLink param.
+        queryStr.removeParameter(Bridge.BACK_LINK);
+      }
+      else if (hasViewLink && param.equals(Bridge.VIEW_LINK))
+      {
+        try
+        {
+          queryStr.removeParameter(Bridge.VIEW_LINK);
+        }
+        catch (Exception e)
+        {
+          ; // do nothing -- just ignore
+        }
+      }
+    }
+
+    // Now put the string back together
+    String qs = queryStr.toString();
+    if (qs.length() > 0)
+    {
+      s = path + "?" + qs;
+    }
+    else
+    {
+      s = path;
+    }
+    
+    // Now transform the URL into an actionURL if this is a ViewLink
+    if (hasViewLink)
+    {
+      return encodeActionURL(s);
+    } else
+    {
+      return s;
+    }
+  }
+
   private void mapPathsFromViewId(String viewId, List<String> mappings)
   {
     if (viewId == null || mappings == null)
@@ -1054,20 +1191,20 @@
       mPathInfo = viewId;
       return;
     }
-    
+
     // The only thing that matters is we use a configured mapping
     // So just use the first one
     String mapping = mappings.get(0);
     if (mapping.startsWith("*"))
     {
       // we are using suffix mapping
-      viewId = viewId.substring(0, viewId.lastIndexOf('.'))
-               + mapping.substring(mapping.indexOf('.'));
-      
+      viewId = 
+          viewId.substring(0, viewId.lastIndexOf('.')) + mapping.substring(mapping.indexOf('.'));
+
       // we are extension mapped
       mServletPath = viewId;
       mPathInfo = null;
-      
+
       // Workaround Faces RI that has Servlet dependencies if this isn't set
       mPortletRequest.setAttribute("javax.servlet.include.servlet_path", mServletPath);
     }
@@ -1100,7 +1237,7 @@
     {
       viewId = viewId.substring(0, i);
     }
-     
+
     int extLoc = viewId.lastIndexOf('.');
 
     if (extLoc != -1 && extLoc > viewId.lastIndexOf('/'))
@@ -1136,11 +1273,8 @@
     // Okay now figure out whether this is prefix or suffixed mapped
     if (isSuffixedMapped(url, mFacesMappings))
     {
-      viewId = viewIdFromSuffixMapping(
-                                       url,
-                                       mFacesMappings,
-                                       mPortletContext
-                                                      .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
+      viewId = 
+          viewIdFromSuffixMapping(url, mFacesMappings, mPortletContext.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
     }
     else if (isPrefixedMapped(url, mFacesMappings))
     {
@@ -1207,6 +1341,28 @@
     }
     return false;
   }
+  
+  private void determineView()
+  {
+    // viewId is the actual context relative path to the resource
+    String viewId = getViewId();
+    
+    if (mViewId != null && viewId.equals((mViewId)))
+    {
+      return;  // No change
+    }
+    
+    mViewId = viewId;
+
+    // Now reverse engineer the servlet paths from the mappings 
+    // So Faces thinks was a client request
+    mapPathsFromViewId(mViewId, mFacesMappings);
+
+    // JSF RI relies on a request attribute setting to properly handle
+    // suffix mapping -- but because their suffix mapping code is servlet dependent
+    // we need to set it for them
+    setFacesMapping();
+  }
 
   private String viewIdFromPrefixMapping(String url, List<String> mappings)
   {
@@ -1234,22 +1390,22 @@
   {
     String mapping = null;
     String servletPath = this.getRequestServletPath();
-    
+
     // if PathInfo == null we are suffixed mapped
     if (this.getRequestPathInfo() == null)
     {
       mapping = servletPath.substring(servletPath.lastIndexOf('.'));
-      
+
     }
-    else 
+    else
     {
       mapping = servletPath;
     }
-    
+
     this.getRequestMap().put("com.sun.faces.INVOCATION_PATH", mapping);
   }
-  
-  
+
+
   private boolean isAbsoluteURL(String url)
   {
     // Quick check for most common case
@@ -1269,12 +1425,18 @@
     // i.e. contains no URI reserved characters
     String scheme = url.substring(0, i);
 
-    if (scheme.indexOf(";") != -1) return false;
-    else if (scheme.indexOf("/") != -1) return false;
-    else if (scheme.indexOf("#") != -1) return false;
-    else if (scheme.indexOf("?") != -1) return false;
-    else if (scheme.indexOf(" ") != -1) return false;
-    else return true; 
+    if (scheme.indexOf(";") != -1)
+      return false;
+    else if (scheme.indexOf("/") != -1)
+      return false;
+    else if (scheme.indexOf("#") != -1)
+      return false;
+    else if (scheme.indexOf("?") != -1)
+      return false;
+    else if (scheme.indexOf(" ") != -1)
+      return false;
+    else
+      return true;
   }
 
   private boolean isExternalURL(String url)
@@ -1299,6 +1461,23 @@
     }
     return true;
   }
+  
+  private boolean isFacesURL(String url)
+  {
+    String viewId = null;
+    
+    // Determine the viewId by inspecting the URL
+    if (!isRelativePath(url))
+    {
+      viewId = getViewIdFromPath(url);
+    }
+    else
+    {
+      viewId = getViewIdFromRelativePath(url);
+    }
+
+    return viewId != null;
+  }
 
   private boolean isDirectLink(String url)
   {
@@ -1334,6 +1513,10 @@
         {
           url = url.substring(0, queryStart + 1) + query;
         }
+        else
+        {
+          url = url.substring(0, queryStart);
+        }
       }
     }
 
@@ -1371,11 +1554,8 @@
     // mapping
     if (isSuffixedMapped(url, mFacesMappings))
     {
-      url = viewIdFromSuffixMapping(
-                                    url,
-                                    mFacesMappings,
-                                    mPortletContext
-                                                   .getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
+      url = 
+          viewIdFromSuffixMapping(url, mFacesMappings, mPortletContext.getInitParameter(ViewHandler.DEFAULT_SUFFIX_PARAM_NAME));
     }
 
     return url;

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextImpl.java Fri Feb 22 09:39:34 2008
@@ -281,7 +281,7 @@
       try
       {
         PortletResponse pr = (PortletResponse) mExternalContext.getResponse();
-        pr.addProperty(Bridge.PORTLET_ISNAMESPACED_PROPERTY, "true");
+        pr.addProperty(Bridge.PORTLET_NAMESPACED_RESPONSE_PROPERTY, "true");
       }
       catch (Exception e)
       {

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java Fri Feb 22 09:39:34 2008
@@ -36,9 +36,12 @@
 import javax.faces.context.FacesContext;
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
 
+import org.apache.myfaces.portlet.faces.util.map.PortletSessionMap;
+
 public class PortletELResolver extends ELResolver
 {
 
@@ -52,6 +55,8 @@
   public static final int      SESSION_PORTLET_SCOPE     = 2;
   public static final int      PORTLET_PREFERENCE_VALUE  = 3;
   public static final int      PORTLET_PREFERENCE_VALUES = 4;
+  
+  private Map<String,Object> mAppScopeSessionMap = null;
 
   public PortletELResolver()
   {
@@ -94,7 +99,11 @@
           return context.getContext(PortletConfig.class);
         case SESSION_APPLICATION_SCOPE:
           context.setPropertyResolved(true);
-          return extCtx.getSessionMap().get(Bridge.APPLICATION_SCOPE_MAP);
+          if (mAppScopeSessionMap == null)
+          {
+            mAppScopeSessionMap = new PortletSessionMap(extCtx.getRequest(), PortletSession.APPLICATION_SCOPE);
+          }
+          return mAppScopeSessionMap;
         case SESSION_PORTLET_SCOPE:
           context.setPropertyResolved(true);
           return extCtx.getSessionMap();

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java Fri Feb 22 09:39:34 2008
@@ -158,6 +158,17 @@
     initParameterMap();
     return Collections.enumeration(mParameterNames);
   }
+  
+  public Map getParameterMap()
+  {
+    initParameterMap();
+    return mParameterMap;
+  }
+  
+  public int numParameters()
+  {
+    return mParameterMap.size();
+  }
 
   public String getParameter(String name)
   {
@@ -166,17 +177,17 @@
     return values == null ? null : values.get(0).getValue();
   }
 
-  public Enumeration<Object> getParameterValues(String name)
+  public Enumeration<String> getParameterValues(String name)
   {
     initParameterMap();
     List<Parameter> params = mParameterMap.get(name);
     if (params == null || params.isEmpty())
     {
-      List<Object> temp = Collections.emptyList();
+      List<String> temp = Collections.emptyList();
       return Collections.enumeration(temp);
     }
     
-    List<Object> values = new ArrayList<Object>(params.size());
+    List<String> values = new ArrayList<String>(params.size());
     for (Parameter param : params)
     {
       values.add(param.getValue());

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletSessionMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletSessionMap.java?rev=630260&r1=630259&r2=630260&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletSessionMap.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletSessionMap.java Fri Feb 22 09:39:34 2008
@@ -65,15 +65,15 @@
   @Override
   protected Object getAttribute(String key)
   {
-    PortletSession portletSession = mPortletRequest.getPortletSession(true);
-
-    if (key.equals(Bridge.APPLICATION_SCOPE_MAP))
+    if (mPortletRequest != null)
     {
-      return getAppScopeMap(portletSession);
+      PortletSession portletSession = mPortletRequest.getPortletSession(true);
+
+      return portletSession.getAttribute(key, mScope);
     }
     else
     {
-      return portletSession.getAttribute(key, mScope);
+      throw new IllegalArgumentException(ILLEGAL_ARGUMENT);
     }
   }
 
@@ -123,25 +123,4 @@
       throw new IllegalArgumentException(ILLEGAL_ARGUMENT);
     }
   }
-
-  @SuppressWarnings("unchecked")
-  private Map<String, Object> getAppScopeMap(PortletSession portletSession)
-  {
-    if (mScope != PortletSession.PORTLET_SCOPE)
-    {
-      return null;
-    }
-
-    Map<String, Object> m = 
-      (Map<String, Object>)portletSession.getAttribute(Bridge.APPLICATION_SCOPE_MAP);
-
-    if (m == null)
-    {
-      m = new PortletSessionMap(mPortletRequest, PortletSession.APPLICATION_SCOPE);
-      portletSession.setAttribute(Bridge.APPLICATION_SCOPE_MAP, m);
-    }
-    
-    return m;
-  }
-
 }