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

svn commit: r646598 - in /myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched: api/src/main/java/javax/portlet/faces/ impl/src/main/java/org/apache/myfaces/portlet/faces/application/ impl/src/main/java/org/apache/myfaces/portlet/faces/...

Author: sobryan
Date: Wed Apr  9 16:39:32 2008
New Revision: 646598

URL: http://svn.apache.org/viewvc?rev=646598&view=rev
Log:
Some initial changes to this branch

Modified:
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/Bridge.java
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java
    myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/Bridge.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/Bridge.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/Bridge.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/Bridge.java Wed Apr  9 16:39:32 2008
@@ -16,6 +16,8 @@
 import javax.portlet.PortletException;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
 import javax.portlet.UnavailableException;
 
 /**
@@ -117,6 +119,12 @@
 
   /**
    * Special token parameter in the url passed to the bridge's ExternalContext.encodeResourceURL()
+   * that it recognizes as an indication that this resource should be handled in protocol.
+   */
+  public static final String IN_PROTOCOL_RESOURCE_LINK                   = BRIDGE_PACKAGE_PREFIX + "InProtocolResourceLink";
+
+  /**
+   * Special token parameter in the url passed to the bridge's ExternalContext.encodeResourceURL()
    * that it recognizes as an indication that an URL refering back to the page which
    * contains this portlet should be encoded in the resource url. This reference is
    * encoded as the value of a query string parameter whose name is the value of this back
@@ -208,7 +216,7 @@
 
   public static enum PortletPhase
   {
-    ACTION_PHASE, RENDER_PHASE;
+    ACTION_PHASE, RENDER_PHASE, EVENT_PHASE, RESOURCE_PHASE;
   }
 
   /** Enumeration whose values describe the render policy used by the bridge
@@ -290,8 +298,9 @@
    *           all other internal exceptions are converted to a BridgeException.
    */
   public void doFacesRequest(ActionRequest request, ActionResponse response)
-                                                                            throws BridgeDefaultViewNotSpecifiedException,
-                                                                            BridgeException;
+       throws BridgeDefaultViewNotSpecifiedException,
+              BridgeUninitializedException,
+              BridgeException;
 
   /**
    * Called by the portlet when it wants the bridge to process a render request.
@@ -309,8 +318,25 @@
    *           all other internal exceptions are converted to a BridgeException.
    */
   public void doFacesRequest(RenderRequest request, RenderResponse response)
-                                                                            throws BridgeDefaultViewNotSpecifiedException,
-                                                                            BridgeException;
+       throws BridgeDefaultViewNotSpecifiedException,
+              BridgeUninitializedException,
+              BridgeException;
+  /**
+   * Called by the portlet when it wants the bridge to process an in-protocol
+   * resource request.
+   * 
+   * @param request
+   *          the request object.
+   * @param response
+   *          the response object.
+   * @throws BridgeUninitializedException
+   *           thrown if the bridge is not initialized.      
+   * @throws BridgeException
+   *           all other internal exceptions are converted to a BridgeException.
+   */
+  public void doFacesRequest(ResourceRequest request, ResourceResponse response)
+       throws BridgeUninitializedException,
+              BridgeException;
 
   /**
    * Called by the portlet to take the bridge out of service. Once out of service, the bridge must

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/api/src/main/java/javax/portlet/faces/GenericFacesPortlet.java Wed Apr  9 16:39:32 2008
@@ -29,6 +29,8 @@
 import javax.portlet.PortletRequest;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
 import javax.portlet.WindowState;
 
 /**
@@ -219,6 +221,7 @@
 
   }
 
+
   @Override
   public void processAction(ActionRequest request, ActionResponse response)
                                                                            throws PortletException,
@@ -226,6 +229,17 @@
   {
     doBridgeDispatch(request, response, getDefaultViewId(request, request.getPortletMode()));
   }
+  
+  /**
+   * Handles resource requests and dispatches to the Bridge
+   */
+  @Override
+  public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException,
+                                                                        IOException
+  {
+    doBridgeDispatch(request, response, getDefaultViewId(request, request.getPortletMode()));
+
+  }
 
   /**
    * Returns the set of RequestAttribute names that the portlet wants the bridge to
@@ -415,6 +429,28 @@
     initBridge();
     // Push information for Bridge into request attributes
     setBridgeRequestContext(request, defaultViewId);
+    try
+    {
+      mFacesBridge.doFacesRequest(request, response);
+    }
+    catch (BridgeException e)
+    {
+      throw new PortletException(
+                                 "doBridgeDispatch failed:  error from Bridge in executing the request",
+                                 e);
+    }
+
+  }
+  
+  private void doBridgeDispatch(ResourceRequest request, ResourceResponse response, String defaultViewId)
+                                                                                                     throws PortletException
+  {
+    // initial Bridge if not already active
+    initBridge();
+    // Push information for Bridge into request attributes
+    setBridgeRequestContext(request, defaultViewId);
+    
+   
     try
     {
       mFacesBridge.doFacesRequest(request, response);

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java Wed Apr  9 16:39:32 2008
@@ -20,11 +20,20 @@
 package org.apache.myfaces.portlet.faces.application;
 
 import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.CharArrayWriter;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
 import java.io.Writer;
+
+import java.nio.ByteBuffer;
+
 import java.util.Locale;
 import java.util.Map;
+import java.util.logging.Level;
+
 import javax.faces.FacesException;
 import javax.faces.FactoryFinder;
 import javax.faces.application.StateManager;
@@ -38,12 +47,15 @@
 import javax.faces.render.RenderKitFactory;
 
 import javax.portlet.PortletContext;
+import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
 import javax.portlet.faces.annotation.PortletNamingContainer;
 import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
 
+import javax.portlet.filter.PortletResponseWrapper;
+
 import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
 import org.apache.myfaces.portlet.faces.util.QueryString;
 
@@ -102,7 +114,193 @@
   }
 
 
+/*
+  @Override
+  public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
+                                                                       FacesException
+  {
+    // Do nothing when not running in portlet request
+    if (!BridgeUtil.isPortletRequest())
+    {
+      super.renderView(context, viewToRender);
+      return;
+    }
+
+    // If first time -- Get the renderPolicy from the context init parameter 
+    if (mRenderPolicy == null)
+    {
+      PortletContext pCtx = (PortletContext) context.getExternalContext().getContext();
+      String policy = pCtx.getInitParameter(Bridge.RENDER_POLICY);
+      if (policy != null)
+      {
+        mRenderPolicy = Bridge.BridgeRenderPolicy.valueOf(policy);
+      }
+      else
+      {
+        mRenderPolicy = Bridge.BridgeRenderPolicy.DEFAULT;
+      }
+    }
+
+    if (mRenderPolicy == Bridge.BridgeRenderPolicy.ALWAYS_DELEGATE)
+    {
+      super.renderView(context, viewToRender);
+      return;
+    }
+    else if (mRenderPolicy == Bridge.BridgeRenderPolicy.DEFAULT)
+    {
+      try
+      {
+        super.renderView(context, viewToRender);
+        return;
+      }
+      catch (Throwable t)
+      {
+        // catch all throws and swallow -- falling through to our own
+        // render
+      }
+    }
+
+    // suppress rendering if "rendered" property on the component is
+    // false
+    if (!viewToRender.isRendered())
+    {
+      return;
+    }
+
+    ExternalContext extContext = context.getExternalContext();
+    RenderResponse renderResponse = (RenderResponse) extContext.getResponse();
+
+    try
+    {
+      extContext.getRequestMap().remove("javax.servlet.include.servlet_path");
+      dispatchPageToBuildView(context, extContext, viewToRender);
+    }
+    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
+    RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder
+                                                                     .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
+    RenderKit renderKit = renderFactory.getRenderKit(context, viewToRender.getRenderKitId());
+
+    ResponseWriter oldWriter = context.getResponseWriter();
+    StringBuilderWriter strWriter = new StringBuilderWriter(context, 4096);
+    ResponseWriter newWriter;
+    if (null != oldWriter)
+    {
+      newWriter = oldWriter.cloneWithWriter(strWriter);
+    }
+    else
+    {
+      newWriter = renderKit.createResponseWriter(strWriter, null,
+                                                 renderResponse.getCharacterEncoding());
+    }
+    context.setResponseWriter(newWriter);
+
+    newWriter.startDocument();
+
+    doRenderView(context, viewToRender);
+
+    newWriter.endDocument();
+
+    // replace markers in the body content and write it to response.
+
+    ResponseWriter responseWriter;
+
+    // Dispatch may have output to an OutputStream instead of a Writer
+    Writer renderResponseWriter = null;
+    try {
+      renderResponseWriter = renderResponse.getWriter();
+    } 
+    catch (IllegalStateException ise) {     
+      // got this exception because we've called getOutputStream() previously
+      renderResponseWriter = new BufferedWriter(
+                             new OutputStreamWriter(
+                               renderResponse.getPortletOutputStream(),
+                               renderResponse.getCharacterEncoding()));
+    }
+    if (null != oldWriter)
+    {
+      responseWriter = oldWriter.cloneWithWriter(renderResponseWriter);
+    }
+    else
+    {
+      responseWriter = newWriter.cloneWithWriter(renderResponseWriter);
+    }
+    context.setResponseWriter(responseWriter);
+
+    strWriter.write(responseWriter);
+    renderResponseWriter.flush();
+
+    if (null != oldWriter)
+    {
+      context.setResponseWriter(oldWriter);
+    }
+
+    RenderResponse wrappedResponse = (RenderResponse) extContext.getRequestMap().get(Bridge.AFTER_VIEW_CONTENT);
+    if (wrappedResponse != null)
+    {
+      wrappedResponse.flushBuffer();
+    }
+  }
+  
+
+  private void dispatchPageToBuildView(FacesContext context,
+                                          ExternalContext extContext,
+                                          UIViewRoot viewToRender)
+      throws IOException
+  {
+      String viewURI = viewToRender.getViewId();
+      RenderRequest request = (RenderRequest) extContext.getRequest();
+
+      // update the JSTL locale attribute in request scope so that JSTL
+      // picks up the locale from viewRoot. This attribute must be updated
+      // before the JSTL setBundle tag is called because that is when the
+      // new LocalizationContext object is created based on the locale.
+      extContext.getRequestMap().put("javax.servlet.jsp.jstl.fmt.locale", context.getViewRoot().getLocale());
+
+      // save the original response
+      RenderResponse originalResponse = (RenderResponse) extContext.getResponse();
+
+      // replace the response with our wrapper
+      PortletViewHandlerResponseWrapper wrapped = new PortletViewHandlerResponseWrapper(originalResponse, context.getViewRoot().getLocale());
+      if (!(wrapped instanceof PortletResponseWrapper))
+        throw new IOException();
+      
+      extContext.setResponse(wrapped);
+      
+      // set request attribute indicating we can deal with content
+      // that is supposed to be delayed until after JSF tree is ouput.
+      extContext.getRequestMap().put(Bridge.RENDER_CONTENT_AFTER_VIEW, Boolean.TRUE);
+
 
+      // build the view by executing the page
+      extContext.dispatch(viewURI);
+
+      // replace the original response
+      extContext.setResponse(originalResponse);
+
+      // Put the AFTER_VIEW_CONTENT into request scope
+      // temporarily
+      extContext.getRequestMap().put(
+            Bridge.AFTER_VIEW_CONTENT,
+            wrapped);
+
+  }
+*/
+  
   @Override
   public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
                                                                        FacesException
@@ -273,6 +471,7 @@
     renderResponse.flushBuffer();
   }
 
+
   /**
    * <p>
    * This is a separate method to account for handling the content after the view tag.
@@ -311,8 +510,7 @@
   {
     viewToRender.encodeAll(context);
   }
-  
-
+    
   private static final class StringBuilderWriter extends Writer
   {
     private StringBuilder       mBuilder;

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Wed Apr  9 16:39:32 2008
@@ -27,6 +27,7 @@
 import java.net.URL;
 
 import java.rmi.server.UID;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -41,6 +42,7 @@
 import javax.el.ELContext;
 import javax.el.ELContextEvent;
 import javax.el.ELContextListener;
+
 import javax.faces.FacesException;
 import javax.faces.FactoryFinder;
 import javax.faces.application.Application;
@@ -58,18 +60,26 @@
 import javax.faces.lifecycle.LifecycleFactory;
 import javax.faces.render.ResponseStateManager;
 import javax.faces.webapp.FacesServlet;
+
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
+import javax.portlet.ClientDataRequest;
+import javax.portlet.MimeResponse;
 import javax.portlet.PortalContext;
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletContext;
 import javax.portlet.PortletPreferences;
 import javax.portlet.PortletRequest;
+import javax.portlet.PortletRequestDispatcher;
 import javax.portlet.PortletResponse;
 import javax.portlet.PortletSession;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+import javax.portlet.StateAwareResponse;
 import javax.portlet.faces.Bridge;
+import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
 import javax.portlet.faces.BridgeException;
 import javax.portlet.faces.BridgeUninitializedException;
 import javax.portlet.faces.annotation.BridgePreDestroy;
@@ -86,6 +96,7 @@
 import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionBindingListener;
 
+import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgePortletRequestWrapper;
 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;
@@ -95,19 +106,26 @@
 public class BridgeImpl
   implements Bridge, ELContextListener, PhaseListener, ServletRequestAttributeListener
 {
-	private static final long	serialVersionUID	= 5807626987246270989L;
+  private static final long serialVersionUID = 5807626987246270989L;
 
-	// 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";
-  private static final String REQUEST_SCOPE_LISTENER = "org.apache.myfaces.portlet.faces.requestScopeWatch";
+  // 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";
+  private static final String REQUEST_SCOPE_LISTENER = 
+    "org.apache.myfaces.portlet.faces.requestScopeWatch";
   private static final String FACES_VIEWROOT = "org.apache.myfaces.portlet.faces.facesViewRoot";
   private static final String FACES_MESSAGES = "org.apache.myfaces.portlet.faces.facesMessages";
-  private static final String REQUEST_PARAMETERS = "org.apache.myfaces.portlet.faces.requestParameters";
-  private static final String PREEXISTING_ATTRIBUTE_NAMES = "org.apache.myfaces.portlet.faces.preExistingAttributeNames";
+  private static final String REQUEST_PARAMETERS = 
+    "org.apache.myfaces.portlet.faces.requestParameters";
+  private static final String PREEXISTING_ATTRIBUTE_NAMES = 
+    "org.apache.myfaces.portlet.faces.preExistingAttributeNames";
   private static final String REQUEST_SCOPE_ID_RENDER_PARAM = "_bridgeRequestScopeId";
   private static final int DEFAULT_MAX_MANAGED_REQUEST_SCOPES = 100;
 
@@ -129,30 +147,33 @@
   public void init(PortletConfig config)
     throws BridgeException
   {
-  	//TODO: Should we throw an exception if the bridge is already initialized?
+    //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();
 
     // get preserveActionParams and excludedAttributes configuration settings.
-    mPreserveActionParams = (Boolean) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
-                                            "." + Bridge.PRESERVE_ACTION_PARAMS);
-    
-    mExcludedRequestAttributes = (List <String>) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
-                                            "." + Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
+    mPreserveActionParams = 
+        (Boolean) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + mPortletConfig.getPortletName() + 
+                                              "." + Bridge.PRESERVE_ACTION_PARAMS);
+
+    mExcludedRequestAttributes = 
+        (List<String>) portletContext.getAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + 
+                                                   mPortletConfig.getPortletName() + "." + 
+                                                   Bridge.EXCLUDED_REQUEST_ATTRIBUTES);
     if (mExcludedRequestAttributes != null)
     {
       // copy the list as we may be adding to it and don't want to worry that this might be immutable
-      mExcludedRequestAttributes = new ArrayList(mExcludedRequestAttributes);     
+      mExcludedRequestAttributes = new ArrayList(mExcludedRequestAttributes);
     }
     else
     {
       // Otherwise create an empty list
       mExcludedRequestAttributes = new ArrayList(5);
     }
-   
+
     // Read excludedAttributes that may be defined in any face-config.xml
     readExcludedAttributesFromFacesConfig(portletContext, mExcludedRequestAttributes);
 
@@ -164,7 +185,7 @@
     // putting it in the PortletContext. Hence the sync object allows us
     // to limit syncronizing the PortletContext to once per portlet (init
     // time);
-    
+
     // TODO: What about synching on a static object or using a class lock?
     //       Perhaps even the LRUMap itself if said map is a singleton?
     synchronized (portletContext)
@@ -191,20 +212,21 @@
     {
       throw new BridgeException("BridgeImpl.init(): unable to determine Faces servlet web.xml mapping.");
     }
-    
+
     // remember that init() has been called so can test in other methods.
     mInitialized = true;
 
   }
 
   public void doFacesRequest(ActionRequest request, ActionResponse response)
-    throws BridgeException, BridgeUninitializedException, NullPointerException
+    throws BridgeException, BridgeDefaultViewNotSpecifiedException, BridgeUninitializedException, 
+           NullPointerException
   {
-    if (!mInitialized) 
+    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
@@ -242,7 +264,14 @@
       // Each action starts a new "action lifecycle"
       // The Bridge preserves request scoped data and if so configured
       // Action Parameters for the duration of an action lifecycle
-      scopeId = initBridgeRequestScope(request, response);
+      scopeId = initBridgeRequestScope(request);
+      // set in response render parameter so will receive in future calls
+      // however don't store internally until there is specific state to
+      // manage
+      response.setRenderParameter(REQUEST_SCOPE_ID_RENDER_PARAM, scopeId);
+      
+      // in case a prior scope was managed temporarily on the session -- remove it
+      request.removeAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM);
 
       // For actions we only execute the lifecycle phase
       getLifecycle().execute(context);
@@ -250,7 +279,8 @@
       // 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);
+      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.
@@ -277,7 +307,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
@@ -289,7 +319,6 @@
       }
 
 
-
     }
     catch (Exception e)
     {
@@ -316,7 +345,7 @@
       }
     }
   }
-  
+
   private void dumpScopeId(String scopeId, String phase)
   {
     // Get the data from the scope
@@ -329,40 +358,41 @@
       // No scope for all renders before first action to this portletApp
       if (requestScopeMap == null)
       {
-        ctx.log("There are No saved scoped.  Can't match: "+ scopeId);
+        ctx.log("There are No saved scoped.  Can't match: " + scopeId);
         return;
       }
 
       Map<String, Object> m = requestScopeMap.get(scopeId);
       if (m == null)
       {
-        ctx.log("Can't match scope: "+ scopeId);
+        ctx.log("Can't match scope: " + scopeId);
         return;
       }
-      
-      Set<Map.Entry<String,Object>> set = m.entrySet();
-      Iterator<Map.Entry<String,Object>> i = set.iterator();
+
+      Set<Map.Entry<String, Object>> set = m.entrySet();
+      Iterator<Map.Entry<String, Object>> i = set.iterator();
       ctx.log("Elements in scope: " + scopeId);
       while (i.hasNext())
       {
-        Map.Entry<String,Object> entry = i.next();
+        Map.Entry<String, Object> entry = i.next();
         ctx.log("     " + entry.getKey());
       }
       ctx.log("end dumpScopeId");
     }
-       
+
   }
 
   public void doFacesRequest(RenderRequest request, RenderResponse response)
-    throws BridgeException, BridgeUninitializedException, NullPointerException
+    throws BridgeException, BridgeDefaultViewNotSpecifiedException, BridgeUninitializedException, 
+           NullPointerException
   {
-    if (!mInitialized) 
+    if (!mInitialized)
       throw new BridgeUninitializedException();
     else if (request == null || response == null)
       throw new NullPointerException("request or response parameter is null");
-    
-    String scopeId = null;
-       
+
+    String scopeId = getRequestScopeId(request);
+
     // 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
@@ -375,7 +405,7 @@
     {
       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);
@@ -393,9 +423,7 @@
       // extension
       RenderRequest extRequest = (RenderRequest) extCtx.getRequest();
 
-      scopeId = extRequest.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
-
-      if (restoreBridgeRequestScopeData(context, scopeId))
+      if (restoreBridgeRequestScopeData(request, scopeId))
       {
         // Because the Bridge is required to always save/restore the
         // VIEW_STATE
@@ -419,7 +447,7 @@
       {
         extCtx.getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE);
       }
-      
+
       doFacesRender(request, response, context, lifecycle, scopeId, preExistingAttributes);
     }
     catch (Exception e)
@@ -430,7 +458,7 @@
       {
         removeRequestScopes(scopeId);
       }
-      
+
       context.getExternalContext().log("Exception thrown in doFacesRequest:render", e);
       if (!(e instanceof BridgeException))
       {
@@ -454,19 +482,14 @@
       }
     }
   }
-  
-  private void doFacesRender(
-      RenderRequest request,
-      RenderResponse response,
-      FacesContext context,
-      Lifecycle lifecycle,
-      String scopeId,
-      List <String> preExistingAttributes
-      )
+
+  private void doFacesRender(PortletRequest request, MimeResponse 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
@@ -507,7 +530,7 @@
       // 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)
+      for (PhaseListener listener: listeners)
       {
         if (listener.getPhaseId() == PhaseId.ANY_PHASE || 
             listener.getPhaseId() == PhaseId.RESTORE_VIEW)
@@ -516,11 +539,11 @@
         }
       }
     }
-      
+
     // 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);
+    QueryString redirectParams = 
+      (QueryString) context.getExternalContext().getRequestMap().get(BridgeImpl.BRIDGE_REDIRECT_VIEWPARAMS);
     if ((redirectParams == null))
     {
       getLifecycle().render(context);
@@ -531,19 +554,19 @@
       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);
+    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.
@@ -553,20 +576,156 @@
     }
   }
 
+  public void doFacesRequest(ResourceRequest request, ResourceResponse response)
+    throws BridgeException, BridgeDefaultViewNotSpecifiedException, 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
+    // to implement both the action and render request/response objects
+    request.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, Bridge.PortletPhase.RESOURCE_PHASE);
+
+    // Determine whether this is a Faces resource or a regular one.
+    if (request.getParameter(PortletExternalContextImpl.RESOURCE_ACTION_ID_PARAMETER_NAME) == null)
+    {
+      try
+      {
+        String target = request.getResourceID();
+        PortletRequestDispatcher rd = 
+          mPortletConfig.getPortletContext().getRequestDispatcher(target);
+        rd.forward(request, response);
+        return;
+      }
+      catch (Exception e)
+      {
+        if (!(e instanceof BridgeException))
+        {
+          Throwable rootCause = e.getCause();
+          throw new BridgeException(e.getMessage(), rootCause);
+        }
+        else
+        {
+          throw (BridgeException) e;
+        }
+      }
+    }
+
+    // Otherwise this is a Faces resource
+
+    // Set the FacesServletMapping attribute so the ExternalContext can
+    // pick it up and use it to reverse map viewIds to paths
+    if (mFacesMappings != null)
+    {
+      request.setAttribute(PortletExternalContextImpl.FACES_MAPPING_ATTRIBUTE, mFacesMappings);
+    }
+
+    // cache names of existing request attributes so can exclude them
+    // from being saved in the bridge's request scope. Note: this is done
+    // before
+    // acquiring the FacesContext because its possible (though unlikely)
+    // the application has inserted itself in this process and sets up
+    // needed request attributes.
+    List<String> preExistingAttributes = getRequestAttributes(request);
+    // place on the request for use here and in the servletRequestAttributeListener
+    if (preExistingAttributes != null)
+    {
+      request.setAttribute(PREEXISTING_ATTRIBUTE_NAMES, preExistingAttributes);
+    }
+
+    String scopeId = getRequestScopeId(request);
+    if (scopeId == null)
+    {
+      // first request is a resource request
+      // create a scope and store in the session until an action occurs
+      scopeId = initBridgeRequestScope(request);
+
+      // store in session until next action
+      PortletSession session = request.getPortletSession(true);
+      session.setAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM, scopeId);
+    }
+
+    restoreBridgeRequestScopeData(request, scopeId);
+
+    FacesContext context = null;
+    try
+    {
+      // Get the FacesContext instance for this request
+      Lifecycle lifecycle = getLifecycle();
+      context = 
+          getFacesContextFactory().getFacesContext(mPortletConfig, request, response, lifecycle);
+      ExternalContext extCtx = context.getExternalContext();
+
+      // Use request from ExternalContext in case its been wrapped by an
+      // extension
+      RenderRequest extRequest = (RenderRequest) extCtx.getRequest();
+
+      // Ensure the ContentType is set before rendering
+      if (extCtx.getResponseContentType() == null)
+      {
+        response.setContentType(extRequest.getResponseContentType());
+      }
+
+      // ensure that isPostback attribute set if VIEW_STATE param exists
+      if (extCtx.getRequestParameterValuesMap().containsKey(ResponseStateManager.VIEW_STATE_PARAM))
+      {
+        extCtx.getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE);
+      }
+
+      doFacesRender(request, response, context, lifecycle, scopeId, preExistingAttributes);
+    }
+    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);
+      }
+
+      context.getExternalContext().log("Exception thrown in doFacesRequest:render", e);
+      if (!(e instanceof BridgeException))
+      {
+        Throwable rootCause = e.getCause();
+        throw new BridgeException(e.getMessage(), rootCause);
+      }
+      else
+      {
+        throw (BridgeException) e;
+      }
+    }
+    finally
+    {
+      dumpScopeId(scopeId, "RENDER_PHASE");
+      // our servletrequestattributelistener uses this as an indicator of whether 
+      // its actively working on a request -- remove it to indicate we are done
+      request.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+      if (context != null)
+      {
+        context.release();
+      }
+    }
+  }
+
 
   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;
   }
 
@@ -584,29 +743,29 @@
       elContext.putContext(PortletConfig.class, mPortletConfig);
     }
   }
-  
+
   /*
    * ServletRequestAttributeListener implementation
    */
+
   public void attributeAdded(ServletRequestAttributeEvent srae)
   {
     // use this phase attribute as an indicator of whether 
     // we are actively working on a request
-    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
-    
+    PortletPhase phase = 
+      (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+
     // do nothing if before/after bridge processing or in the render phase.
     // Don't care about render phase because we don't update/change the managed
     // scope based on changes during render.
     // ALSO: do nothing if not in the Bridge's managed request scope
-    if (phase == null || phase == PortletPhase.RENDER_PHASE ||
-        isExcludedFromBridgeRequestScope(srae.getName(),
-                                               srae.getValue(),
-                                               (List<String>)
-                                                  srae.getServletRequest().getAttribute(PREEXISTING_ATTRIBUTE_NAMES)))
+    if (phase == null || phase == PortletPhase.RENDER_PHASE || 
+        isExcludedFromBridgeRequestScope(srae.getName(), srae.getValue(), 
+                                         (List<String>) srae.getServletRequest().getAttribute(PREEXISTING_ATTRIBUTE_NAMES)))
     {
       return;
     }
-    
+
     // Otherwise -- see if the added attribute implements the bridge's 
     // BridgeRequestScopeAdded annotation -- call each method so annotated
     Object o = srae.getValue();
@@ -621,65 +780,64 @@
         }
         catch (Exception e)
         {
-            // TODO: log problem
-            // do nothing and forge ahead
-            ;
+          // TODO: log problem
+          // do nothing and forge ahead
+          ;
         }
       }
     }
   }
-  
+
   public void attributeRemoved(ServletRequestAttributeEvent srae)
   {
     // use this phase attribute as an indicator of whether 
     // we are actively working on a request
-    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
-    
-    // If in an action this means the attribute has been removed before we have
-    // saved the action scope -- since the managed bean has been informed we are
+    PortletPhase phase = 
+      (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+
+    // If not in a render this means the attribute has been removed before we have
+    // saved the request scope -- since the managed bean has been informed we are
     // running in a portlet environment it should have ignored the PreDestroy.
     // To make up for this we call its BridgePredestroy
-    if (phase != null && phase == PortletPhase.ACTION_PHASE)
+    if (phase != null && phase != PortletPhase.RENDER_PHASE)
     {
       notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
     }
   }
-  
+
   public void attributeReplaced(ServletRequestAttributeEvent srae)
   {
     // use this phase attribute as an indicator of whether 
     // we are actively working on a request
-    PortletPhase phase = (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
-    
+    PortletPhase phase = 
+      (PortletPhase) srae.getServletRequest().getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
+
     // If in an action this means the attribute has been replaced before we have
     // saved the action scope -- since the managed bean has been informed we are
     // running in a portlet environment it should have ignored the PreDestroy.
     // To make up for this we call its BridgePredestroy
-    if (phase != null && phase == PortletPhase.ACTION_PHASE)
+    if (phase != null && phase != PortletPhase.RENDER_PHASE)
     {
       notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
     }
   }
-  
-  private void redirectRender(FacesContext context,
-                              Lifecycle lifecycle,
-                              RenderRequest request,
-                              RenderResponse response,
-                              QueryString redirectParams,
+
+  private void redirectRender(FacesContext context, Lifecycle lifecycle, PortletRequest request, 
+                              MimeResponse 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());
+    Map<String, String[]> paramMap = new LinkedHashMap(redirectParams.numParameters());
     Enumeration<String> nameEnum = redirectParams.getParameterNames();
-    while (nameEnum != null && nameEnum.hasMoreElements()) 
+    while (nameEnum != null && nameEnum.hasMoreElements())
     {
       String name = nameEnum.nextElement();
       Enumeration<String> valuesEnum = redirectParams.getParameterValues(name);
@@ -687,12 +845,12 @@
       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();
@@ -708,14 +866,15 @@
         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);
+    BridgePortletRequestWrapper requestWrapper = 
+      new BridgePortletRequestWrapper(request, paramMap, false);
     // close the FacesContext
     context.release();
     // start a new FacesContext
@@ -725,9 +884,9 @@
     context.getExternalContext().setRequest(requestWrapper);
     // Run lifecycle.execute again ... then render
     doFacesRender(request, response, context, lifecycle, null, preExistingAttrs);
-    return;  // to continue on
+    return; // to continue on
   }
-  
+
   private FacesContextFactory getFacesContextFactory()
     throws BridgeException
   {
@@ -827,11 +986,8 @@
       requestMap.put(REQUEST_PARAMETERS, requestParameterMap);
     }
   }
-  
-  private void updateViewInfo(
-    FacesContext context,
-    String scopeId,
-    boolean redirectedDuringRender)
+
+  private void updateViewInfo(FacesContext context, String scopeId, boolean redirectedDuringRender)
   {
     PortletContext portletContext = mPortletConfig.getPortletContext();
 
@@ -847,7 +1003,7 @@
         // Have only done renders to this point -- so no scope to update
         return;
       }
-      
+
       // now see if this scope is in the Map
       Map<String, Object> scopeMap = requestScopeMap.get(scopeId);
       if (scopeMap == null)
@@ -858,22 +1014,23 @@
 
       // Now get the RequestParameters from the scope
       @SuppressWarnings("unchecked")
-      Map<String, String[]> requestParams = (Map<String, String[]>)scopeMap.get(REQUEST_PARAMETERS);
-      
-      if (requestParams == null) 
+      Map<String, String[]> requestParams = 
+        (Map<String, String[]>) scopeMap.get(REQUEST_PARAMETERS);
+
+      if (requestParams == null)
       {
         requestParams = new HashMap<String, String[]>(1);
         scopeMap.put(REQUEST_PARAMETERS, requestParams);
       }
-    
+
       // 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);
-      
+      String updatedViewStateParam = 
+        (String) context.getExternalContext().getRequestMap().get(UPDATED_VIEW_STATE_PARAM);
+
       if (updatedViewStateParam != null)
       {
         values[0] = updatedViewStateParam;
@@ -881,7 +1038,7 @@
         // finally update the value in the Map
         requestParams.put(ResponseStateManager.VIEW_STATE_PARAM, values);
       }
-      
+
       if (redirectedDuringRender)
       {
         // Add the VIEW_ID
@@ -897,26 +1054,26 @@
       }
     }
   }
-  
-  
-  private LRUMap createRequestScopeMap(PortletContext portletContext) 
+
+
+  private LRUMap createRequestScopeMap(PortletContext portletContext)
   {
     // see if portlet has defined how many requestScopes to manage
     // for this portlet
     int managedScopes = DEFAULT_MAX_MANAGED_REQUEST_SCOPES;
-    
+
     String managedScopesSetting = 
-    	portletContext.getInitParameter(Bridge.MAX_MANAGED_REQUEST_SCOPES);
+      portletContext.getInitParameter(Bridge.MAX_MANAGED_REQUEST_SCOPES);
     if (managedScopesSetting != null)
     {
       managedScopes = Integer.parseInt(managedScopesSetting);
     }
-    
+
     return new LRUMap(managedScopes);
   }
 
   @SuppressWarnings("unchecked")
-	private RenderRequest restoreActionParams(FacesContext context)
+  private RenderRequest restoreActionParams(FacesContext context)
   {
     // this is a little trickier then saving because there is no
     // corresponding set. Instead we wrap the request object and set it
@@ -945,9 +1102,9 @@
       while (clientIds.hasNext())
       {
         String clientId = (String) clientIds.next();
-        for(Iterator<FacesMessage> messages = context.getMessages(clientId);messages.hasNext();)
+        for (Iterator<FacesMessage> messages = context.getMessages(clientId); messages.hasNext(); )
         {
-        	state.addMessage(clientId, messages.next());
+          state.addMessage(clientId, messages.next());
         }
       }
       // save state in ViewRoot attributes
@@ -968,31 +1125,41 @@
 
       if (state != null)
       {
-      	for(String clientId:state.getClientIds())
-      	{
-      		for(FacesMessage message:state.getMessages(clientId))
-      		{
-      			context.addMessage(clientId, message);
+        for (String clientId: state.getClientIds())
+        {
+          for (FacesMessage message: state.getMessages(clientId))
+          {
+            context.addMessage(clientId, message);
           }
         }
       }
     }
   }
 
-  private String initBridgeRequestScope(ActionRequest request, ActionResponse response)
+  private String getRequestScopeId(PortletRequest request)
+  {
+    String scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
+
+    if (scopeId == null)
+    {
+      PortletSession session = request.getPortletSession();
+      if (session != null)
+      {
+        scopeId = (String) session.getAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM);
+      }
+    }
+    return scopeId;
+  }
+
+  private String initBridgeRequestScope(ClientDataRequest request)
   {
 
     // Generate an RMI UID, which is a unique identifier WITHIN the local
     // host. This will be used as the new lifecyleID
     UID uid = new UID();
-    String requestScopeId = qualifyScopeId(mPortletConfig.getPortletName(),
-                                           request.getPortletSession(true).getId(),
-                                           uid.toString());
-
-    // set in response render parameter so will receive in future calls
-    // however don't store internally until there is specific state to
-    // manage
-    response.setRenderParameter(REQUEST_SCOPE_ID_RENDER_PARAM, requestScopeId);
+    String requestScopeId = 
+      qualifyScopeId(mPortletConfig.getPortletName(), request.getPortletSession(true).getId(), 
+                     uid.toString());
 
     return requestScopeId;
   }
@@ -1034,34 +1201,34 @@
   private Map<String, Object> copyRequestMap(Map<String, Object> m, List<String> preExistingList)
   {
     Map<String, Object> copy = new HashMap<String, Object>(m.size());
-     
-  	for(Map.Entry<String, Object> entry:m.entrySet())
-  	{
+
+    for (Map.Entry<String, Object> entry: m.entrySet())
+    {
       // TODO -- restore the ACTION PARAMS if there
 
       // Don't copy any of the portlet or Faces objects
-  		String key = entry.getKey();
-  		Object value = entry.getValue();
-  		if(!isExcludedFromBridgeRequestScope(key, value, preExistingList))
-  		{
-  			copy.put(key, value);
-  		}
-  	}
+      String key = entry.getKey();
+      Object value = entry.getValue();
+      if (!isExcludedFromBridgeRequestScope(key, value, preExistingList))
+      {
+        copy.put(key, value);
+      }
+    }
     return copy;
   }
-  
+
   @SuppressWarnings("unchecked")
   private List<String> getRequestAttributes(PortletRequest request)
   {
-  	return Collections.list((Enumeration<String>)request.getAttributeNames());
+    return Collections.list((Enumeration<String>) request.getAttributeNames());
   }
-  
-  private boolean isExcludedFromBridgeRequestScope(String key, Object value, List<String> preExistingList)
+
+  private boolean isExcludedFromBridgeRequestScope(String key, Object value, 
+                                                   List<String> preExistingList)
   {
-    return ((value.getClass().getAnnotation(ExcludeFromManagedRequestScope.class) != null) ||
-         (preExistingList != null && preExistingList.contains(key)) ||
-         isPreDefinedExcludedObject(key, value) ||
-         isConfiguredExcludedAttribute(key));
+    return ((value.getClass().getAnnotation(ExcludeFromManagedRequestScope.class) != null) || 
+            (preExistingList != null && preExistingList.contains(key)) || 
+            isPreDefinedExcludedObject(key, value) || isConfiguredExcludedAttribute(key));
   }
 
   private boolean isPreDefinedExcludedObject(String s, Object o)
@@ -1071,27 +1238,25 @@
       o instanceof PortletPreferences || o instanceof PortalContext || o instanceof FacesContext || 
       o instanceof ExternalContext || o instanceof ServletConfig || o instanceof ServletContext || 
       o instanceof ServletRequest || o instanceof ServletResponse || o instanceof HttpSession || 
-      isInNamespace(s, "javax.portlet.") ||
-      isInNamespace(s, "javax.portlet.faces.") ||
-      isInNamespace(s, "javax.faces.") ||
-      isInNamespace(s, "javax.servlet.") ||
-      isInNamespace(s, "javax.servlet.include.") ||
-      isInNamespace(s, "org.apache.myfaces.portlet.faces") ||
+      isInNamespace(s, "javax.portlet.") || isInNamespace(s, "javax.portlet.faces.") || 
+      isInNamespace(s, "javax.faces.") || isInNamespace(s, "javax.servlet.") || 
+      isInNamespace(s, "javax.servlet.include.") || 
+      isInNamespace(s, "org.apache.myfaces.portlet.faces") || 
       isInNamespace(s, "org.apache.myfaces.portlet.faces.context");
-    }
-  
+  }
+
   private boolean isConfiguredExcludedAttribute(String s)
   {
     if (mExcludedRequestAttributes == null)
     {
       return false;
     }
-    
+
     if (mExcludedRequestAttributes.contains(s))
     {
       return true;
     }
-    
+
     // No direct match -- walk through this list and process namespace checks
     Iterator<String> i = mExcludedRequestAttributes.iterator();
     while (i.hasNext())
@@ -1107,28 +1272,27 @@
     }
     return false;
   }
-      
+
   private boolean isInNamespace(String s, String namespace)
   {
     // This is a non-recursive check so s must be the result of removing the namespace.
     if (s.startsWith(namespace))
     {
-    // extract entire namespace and compare
-    s = s.substring(0, s.lastIndexOf('.') + 1);
-    return s.equals(namespace);
+      // extract entire namespace and compare
+      s = s.substring(0, s.lastIndexOf('.') + 1);
+      return s.equals(namespace);
     }
     return false;
   }
 
   @SuppressWarnings("unchecked")
-  private boolean restoreBridgeRequestScopeData(FacesContext context, String scopeId)
+  private boolean restoreBridgeRequestScopeData(PortletRequest request, String scopeId)
     throws BridgeException
   {
 
     PortletContext portletContext = mPortletConfig.getPortletContext();
     Map<String, Object> m;
-    Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
-    
+
     //TODO: Since this is a private method, is it easier to ensure scope id is not null here thus replacing this with
     //an assert
     if (scopeId == null)
@@ -1153,8 +1317,15 @@
         return false;
       }
     }
-    
-    requestMap.putAll(m);
+
+    Set<Map.Entry<String, Object>> s = m.entrySet();
+    Iterator<Map.Entry<String, Object>> i = s.iterator();
+    while (i.hasNext())
+    {
+      Map.Entry<String, Object> e = i.next();
+      request.setAttribute(e.getKey(), e.getValue());
+    }
+
     return true;
   }
 
@@ -1194,9 +1365,9 @@
   }
 
   /*
-   * A scope is qualified first by the portlet this scope has been created for 
+   * A scope is qualified first by the portlet this scope has been created for
    * and then second by the specific session this scope is used in.  By doing
-   * this we are able to remove this specific scope, all the scopes associated 
+   * this we are able to remove this specific scope, all the scopes associated
    * with a particular session, or all the scopes associated with a particular
    * portlet regardless of sessions.
    */
@@ -1204,11 +1375,12 @@
   private String qualifyScopeId(String portletId, String sessionId, String scopeId)
   {
     // a qualified scope Id must at a minimum be qualified by a portletId
-    if (portletId == null) portletId = mPortletConfig.getPortletName();
-    
+    if (portletId == null)
+      portletId = mPortletConfig.getPortletName();
+
     StringBuffer sb = new StringBuffer(portletId);
     sb.append(':');
-    if (sessionId != null) 
+    if (sessionId != null)
     {
       sb.append(sessionId);
       sb.append(':');
@@ -1234,10 +1406,9 @@
         // if invalidated we walk the entire REQUEST_SCOPE Map and
         // remove
         // every scope that starts with this prefix.
-        session.setAttribute(REQUEST_SCOPE_LISTENER, new RequestScopeListener(
-                                                       qualifyScopeId(mPortletConfig.getPortletName(),
-                                                                      session.getId(),
-                                                                      null)));
+        session.setAttribute(REQUEST_SCOPE_LISTENER, 
+                             new RequestScopeListener(qualifyScopeId(mPortletConfig.getPortletName(), 
+                                                                     session.getId(), null)));
       }
     }
   }
@@ -1263,19 +1434,21 @@
     context.getExternalContext().encodeActionURL(viewURL);
 
   }
-  
+
   // notify this scope's attributes that they are being removed
-  private void notifyPreDestroy(Map<String,Object> scope)
+
+  private void notifyPreDestroy(Map<String, Object> scope)
   {
-    Set<Map.Entry<String,Object>>  s = scope.entrySet();
-    Iterator<Map.Entry<String,Object>> i = s.iterator();
+    Set<Map.Entry<String, Object>> s = scope.entrySet();
+    Iterator<Map.Entry<String, Object>> i = s.iterator();
     while (i.hasNext())
     {
       notifyPreDestroy(i.next().getValue());
     }
   }
-  
+
   // notify this scope's attributes that they are being removed
+
   private void notifyPreDestroy(Object o)
   {
     Method[] methods = o.getClass().getMethods();
@@ -1289,9 +1462,9 @@
         }
         catch (Exception e)
         {
-            // TODO: log problem
-            // do nothing and forge ahead
-            ;
+          // TODO: log problem
+          // do nothing and forge ahead
+          ;
         }
       }
     }
@@ -1299,7 +1472,7 @@
 
   private void removeRequestScopes(String scopePrefix)
   {
-    
+
     if (scopePrefix == null || mPortletConfig == null)
       return; // Nothing to do -- later case is the session is destroyed after the context
 
@@ -1319,30 +1492,30 @@
 
       if (requestScopeMap != null)
       {
-      	Iterator<String> iterator = requestScopeMap.keySet().iterator();
-      	while(iterator.hasNext())
-      	{
-      		String scopeId = iterator.next();
+        Iterator<String> iterator = requestScopeMap.keySet().iterator();
+        while (iterator.hasNext())
+        {
+          String scopeId = iterator.next();
           if (scopeId != null && scopeId.startsWith(scopePrefix))
           {
-          	iterator.remove();
+            iterator.remove();
           }
-      	}
+        }
       }
     }
   }
-  
-  private void readExcludedAttributesFromFacesConfig(PortletContext context,
+
+  private void readExcludedAttributesFromFacesConfig(PortletContext context, 
                                                      List<String> excludedAttributes)
   {
     FacesConfigurationProcessor processor = new FacesConfigurationProcessor(context);
     List<String> list = processor.getExcludedAttributes();
-    
+
     if (list == null)
     {
       return;
     }
-    
+
     ListIterator<String> i = (ListIterator<String>) list.listIterator();
     while (i.hasNext())
     {
@@ -1393,7 +1566,7 @@
     }
 
     @Override
-    protected boolean removeEldestEntry(Map.Entry<String, Map<String,Object>> eldest)
+    protected boolean removeEldestEntry(Map.Entry<String, Map<String, Object>> eldest)
     {
       // manually remove the entry so we can ensure notifyPreDestroy is only
       // called once
@@ -1404,24 +1577,26 @@
       }
       return false;
     }
-    
-    public Map<String,Object> remove(String key) 
+
+    public Map<String, Object> remove(String key)
     {
       dumpScopeId(key, "RemovePhase");
-      Map<String,Object> o = super.remove(key);
+      Map<String, Object> o = super.remove(key);
       // notify attributes maintained in this object (map) they are going away
       // Method in the outer BridgeImpl class
-      if (o != null) notifyPreDestroy(o);
+      if (o != null)
+        notifyPreDestroy(o);
       return o;
     }
-    
-    public Map<String,Object> put(String key, Map<String,Object> value)
+
+    public Map<String, Object> put(String key, Map<String, Object> value)
     {
-      Map<String,Object> o = super.put(key, value);
+      Map<String, Object> o = super.put(key, value);
       // notify attributes maintained in this object (map) they are going away
       // Method in the outer BridgeImpl class
-      if (o != null) notifyPreDestroy(o);
-      return o;      
+      if (o != null)
+        notifyPreDestroy(o);
+      return o;
     }
 
   }
@@ -1442,7 +1617,8 @@
      */
     private static final long serialVersionUID = 8438070672451887050L;
     // For saving and restoring FacesMessages
-    private Map<String, List<FacesMessage>> mMessages = new HashMap<String, List<FacesMessage>>(); // key=clientId;
+    private Map<String, List<FacesMessage>> mMessages = 
+      new HashMap<String, List<FacesMessage>>(); // key=clientId;
 
     // value=FacesMessages
 
@@ -1496,6 +1672,5 @@
       // Call is in the BridgeImpl class
       removeRequestScopes(mScopePrefix);
     }
-
   }
 }

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/FacesContextFactoryImpl.java Wed Apr  9 16:39:32 2008
@@ -55,6 +55,54 @@
     // method as that call requires the facesContext to exist.
     if (isPortletRequest(request))
     {
+      // As its possible an in-protocol resource needs to access the FacesContext
+      // hence we could be passed the servlet objects in a portlet request
+      // try converting back to the portlet objects
+      Object pTemp = null;
+      PortletRequest pRequest = null;
+      ServletRequest sRequest = null;
+      
+      if (request instanceof PortletRequest)
+        pRequest = (PortletRequest) request;
+      else if (request instanceof ServletRequest)
+        sRequest = (ServletRequest) request;
+      
+      if (!(config instanceof PortletConfig))
+      {
+        if (pRequest != null)
+        {
+          pTemp = pRequest.getAttribute("javax.portlet.config");
+        } 
+        else if (sRequest != null)
+        {
+          pTemp = sRequest.getAttribute("javax.portlet.config");
+        }
+        
+        if (pTemp != null) config = pTemp;
+      }
+      if (!(response instanceof PortletResponse))
+      {
+        if (pRequest != null)
+        {
+          pTemp = pRequest.getAttribute("javax.portlet.response");
+        } 
+        else if (sRequest != null)
+        {
+          pTemp = sRequest.getAttribute("javax.portlet.response");
+        }
+        
+        if (pTemp != null) response = pTemp;
+      }      
+      if (!(request instanceof PortletRequest))
+      {
+        if (sRequest != null)
+        {
+          pTemp = sRequest.getAttribute("javax.portlet.request");
+        }
+        
+        if (pTemp != null) request = pTemp;
+      }
+      
       // make sure they passed the right objects
       if (config instanceof PortletConfig && request instanceof PortletRequest
         && response instanceof PortletResponse)

Modified: myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=646598&r1=646597&r2=646598&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/sobryan-PortletBridge20-patched/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Wed Apr  9 16:39:32 2008
@@ -32,7 +32,6 @@
 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;
@@ -45,6 +44,8 @@
 
 import javax.portlet.ActionRequest;
 import javax.portlet.ActionResponse;
+import javax.portlet.ClientDataRequest;
+import javax.portlet.MimeResponse;
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletContext;
 import javax.portlet.PortletException;
@@ -55,6 +56,7 @@
 import javax.portlet.PortletURL;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.ResourceURL;
 import javax.portlet.WindowState;
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeDefaultViewNotSpecifiedException;
@@ -92,7 +94,8 @@
     Bridge.BRIDGE_PACKAGE_PREFIX + "." + Bridge.RENDER_POLICY;
 
   // Render parameter to store the viewId
-  public static final String ACTION_ID_PARAMETER_NAME = "_xACTION_ID";
+  public static final String ACTION_ID_PARAMETER_NAME = "_xBridgeActionID";
+  public static final String RESOURCE_ACTION_ID_PARAMETER_NAME = "_xBridgeResourceActionID";
   public static final String REDIRECT_ID_PARAMETER_NAME = "org.apache.myfaces.portlet.faces.redirectViewParams";
   
 
@@ -412,6 +415,8 @@
   public String encodeResourceURL(String s)
   {
     boolean containsBackLinkMarker = false, isViewLink = false;
+    boolean isOutOfProtocolResource = false;
+    
     if (s.indexOf(Bridge.BACK_LINK) != -1)
     {
       containsBackLinkMarker = true;
@@ -421,6 +426,13 @@
     {
       // Only non-external URLs can be viewLinks
       isViewLink = isViewLink(s);
+      
+      // Non-Faces links are out of protocol by default
+      if (!isFacesURL(s))
+      {
+        isOutOfProtocolResource = !isInProtocolResourceLink(s);
+        s = removeInProtocolResourceLink(s);
+      }
 
       if (!s.startsWith("/"))
       {
@@ -446,15 +458,10 @@
         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
-      String ctxPath = getRequestContextPath();
-      if (ctxPath.length() > 0 && !s.startsWith(ctxPath))
-      {
-        s = ctxPath + s;
-      }
+    }
+    else
+    {
+      isOutOfProtocolResource = true;
     }
 
     // Check for backlink and viewlink markers -- if they exist replace
@@ -463,9 +470,12 @@
       s = replaceResourceQueryStringMarkers(s, containsBackLinkMarker, isViewLink);
     }
 
-    if (!isViewLink)
+    if (isOutOfProtocolResource)
     {
       s = mPortletResponse.encodeURL(s);
+    } else if (!isViewLink)
+    {
+      s = encodePortletResourceURL(s);
     }
     else
     {
@@ -477,6 +487,104 @@
 
     return s;
   }
+  
+  private String encodePortletResourceURL(String url)
+  {
+    // If a Faces resource, we assume that clients have called
+    // ViewHandler.getActionURL() before calling encodeResourceURL when
+    // doing a partial page URL.  Hence all other framework queryString
+    // params should already be encoded.
+    
+    // Though might prefer to defer this analysis until the request is
+    // submitted this info is available within ExternalContext but not the
+    // bridge code -- so we would have to reestablish the faces context to
+    // do it then even if we subsequently don't need it because its not a
+    // Faces resource.
+    
+    // Determine if there is a target viewId
+    String viewId = null, path = null;
+    QueryString queryStr = null;
+    int queryStart = -1;
+
+    // First: split URL into path and query string
+    // Hold onto QueryString for later processing
+    queryStart = url.indexOf('?');
+
+    if (queryStart != -1)
+    {
+      // Get the query string
+      queryStr = new QueryString(url.substring(queryStart + 1), "UTF8");
+      path = url.substring(0, queryStart);
+    }
+    else
+    {
+      path = url;
+      // construct an empty queryString to hold the viewId
+      queryStr = new QueryString("UTF8");
+    }
+    
+    // Now remove up through the ContextPath as we don't want it
+    String ctxPath = getRequestContextPath();
+    int i = path.indexOf(ctxPath);
+    if (i != -1)
+    {
+      path = path.substring(i + ctxPath.length());
+    }
+    
+    // Determine the viewId by inspecting the URL
+    // Can't be relative by the time we get here so don't check
+    viewId = getViewIdFromPath(path);
+
+    if (viewId != null)
+    {
+      // This is a Faces resource
+      // put the viewId in the QueryStr.
+      queryStr.addParameter(RESOURCE_ACTION_ID_PARAMETER_NAME, viewId);
+      queryStr.removeParameter(Bridge.PORTLET_MODE_PARAMETER);
+      queryStr.removeParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
+    }
+    
+
+    // Encode the URL
+    
+    ResourceURL resource = ((MimeResponse) mPortletResponse).createResourceURL();
+    resource.setResourceID(path);
+    
+    // Walk through the queryStr Params and add as resourceParams
+    // remove any attempt to set Mode/WindowState/etc. as 
+    // not feasible here
+    // Add parameters so they don't get lost
+    Enumeration<String> list = queryStr.getParameterNames();
+    while (list.hasMoreElements())
+    {
+      String param = list.nextElement().toString();
+      if (param.equals(Bridge.PORTLET_MODE_PARAMETER))
+      {
+        // do nothing -- just ignore -- can't encode in a resourceURL
+      }
+      else if (param.equals(Bridge.PORTLET_WINDOWSTATE_PARAMETER))
+      {
+        // do nothing -- just ignore -- can't encode in a resourceURL
+      }
+      else if (param.equals(Bridge.PORTLET_SECURE_PARAMETER))
+      {
+        try
+        {
+          resource.setSecure(Boolean.getBoolean(queryStr.getParameter(param)));
+        }
+        catch (Exception e)
+        {
+          ; // do nothing -- just ignore
+        }
+      }
+      else
+      {
+        resource.setParameter(param, queryStr.getParameter(param));
+      }
+    }
+
+    return resource.toString();
+  }
 
   @Override
   public void dispatch(String requestURI)
@@ -487,11 +595,6 @@
       throw new java.lang.NullPointerException();
     }
 
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
-    {
-      throw new IllegalStateException("Request cannot be an ActionRequest");
-    }
-
     PortletRequestDispatcher prd = mPortletContext.getRequestDispatcher(requestURI);
 
     if (prd == null)
@@ -502,7 +605,7 @@
 
     try
     {
-      prd.include((RenderRequest) mOrigPortletRequest, (RenderResponse) mOrigPortletResponse);
+      prd.include((PortletRequest) getRequest(), (PortletResponse) getResponse());
     }
     catch (PortletException e)
     {
@@ -683,14 +786,7 @@
 
   public String encodeNamespace(String s)
   {
-    if (BridgeUtil.getPortletRequestPhase() != Bridge.PortletPhase.RENDER_PHASE)
-    {
-      throw new IllegalStateException("Only RenderResponse can be used to encode a namespace");
-    }
-    else
-    {
-      return ((RenderResponse) mPortletResponse).getNamespace() + s;
-    }
+    return ((PortletResponse) mPortletResponse).getNamespace() + s;
   }
 
   @Override
@@ -821,21 +917,9 @@
   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)
+    if (mPhase != null && mPortletRequest instanceof ClientDataRequest)
     {
-      ((ActionRequest) mPortletRequest).setCharacterEncoding(encoding);
+      ((ClientDataRequest) mPortletRequest).setCharacterEncoding(encoding);
     }
   }
 
@@ -866,13 +950,13 @@
   @Override
   public String getRequestCharacterEncoding()
   {
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
+    if (mPhase != null && mPortletRequest instanceof ClientDataRequest)
     {
-      return ((ActionRequest) mPortletRequest).getCharacterEncoding();
+      return ((ClientDataRequest) mPortletRequest).getCharacterEncoding();
     }
     else
     {
-      // RENDER_PHASE -- return null as per spec
+      // other phases -- return null as per spec
       return null;
     }
   }
@@ -904,13 +988,13 @@
   @Override
   public String getRequestContentType()
   {
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
+    if (mPhase != null && mPortletRequest instanceof ClientDataRequest)
     {
-      return ((ActionRequest) mPortletRequest).getContentType();
+      return ((ClientDataRequest) mPortletRequest).getContentType();
     }
     else
     {
-      // RENDER_PHASE: return null as per spec
+      // Other PHASEs: return null as per spec
       return null;
     }
   }
@@ -943,12 +1027,12 @@
   @Override
   public String getResponseCharacterEncoding()
   {
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
+    if (mPhase != null && mPortletRequest instanceof MimeResponse)
     {
       throw new IllegalStateException("PortletExternalContextImpl.getResponseCharacterEncoding(): Response must be a RenderRequest");
     }
 
-    return ((RenderResponse) mPortletResponse).getCharacterEncoding();
+    return ((MimeResponse) mPortletResponse).getCharacterEncoding();
   }
 
   /**
@@ -978,12 +1062,12 @@
   @Override
   public String getResponseContentType()
   {
-    if (mPhase == Bridge.PortletPhase.ACTION_PHASE)
+    if (mPhase != null && mPortletRequest instanceof MimeResponse)
     {
       throw new IllegalStateException("PortletExternalContextImpl.getResponseContentType(): Response must be a RenderRequest");
     }
 
-    return ((RenderResponse) mPortletResponse).getContentType();
+    return ((MimeResponse) mPortletResponse).getContentType();
   }
 
   /**
@@ -1049,6 +1133,12 @@
     // where we couldn't update the ACTION_ID
     String viewId = mPortletRequest.getParameter(REDIRECT_ID_PARAMETER_NAME);
     
+    // Next Possibility is its a Resource Request
+    if (viewId == null)
+    {
+      viewId = mPortletRequest.getParameter(RESOURCE_ACTION_ID_PARAMETER_NAME);
+    }
+    
     // Normal case is its returned in the render parameter
     if (viewId == null)
     {
@@ -1273,8 +1363,8 @@
     }
     else
     {
-      // Set to what follows the URL
-      viewId = url;
+      // Not a Faces URL
+      viewId = null;
     }
     return viewId;
   }
@@ -1475,6 +1565,12 @@
     return isTokenLink(Bridge.DIRECT_LINK, url);
   }
   
+  private boolean isInProtocolResourceLink(String url)
+  {
+    return isTokenLink(Bridge.IN_PROTOCOL_RESOURCE_LINK, url);
+  }
+  
+  
   private boolean isViewLink(String url)
   {
     return isTokenLink(Bridge.VIEW_LINK, url);
@@ -1499,6 +1595,11 @@
   private String removeDirectLink(String url)
   {
     return removeTokenLink(Bridge.DIRECT_LINK, url);
+  }
+  
+  private String removeInProtocolResourceLink(String url)
+  {
+    return removeTokenLink(Bridge.IN_PROTOCOL_RESOURCE_LINK, url);
   }
   
   private String removeTokenLink(String token, String url)