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 2007/11/16 21:48:15 UTC

svn commit: r595816 [1/3] - in /myfaces/portlet-bridge/trunk: 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/bridge/ impl/src/main/java/org/apa...

Author: sobryan
Date: Fri Nov 16 12:48:15 2007
New Revision: 595816

URL: http://svn.apache.org/viewvc?rev=595816&view=rev
Log:
PORTLETBRIDGE-12: PortletViewHandler - viewId handling

Patch submitted by Michael Freedman and tested by Bernhard Huemer.  
Thanks guys!

Added:
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java
Modified:
    myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java

Modified: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java?rev=595816&r1=595815&r2=595816&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java (original)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/Bridge.java Fri Nov 16 12:48:15 2007
@@ -1,220 +1,227 @@
-/*
- * 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.portlet.ActionRequest;
-import javax.portlet.ActionResponse;
-import javax.portlet.PortletConfig;
-import javax.portlet.PortletException;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
-import javax.portlet.UnavailableException;
-
-/**
- * The <CODE>Bridge</CODE> interface is used by a portlet to execute a JSF artifact. Its lifecycle
- * follows the pattern used by other web components such as portlets or servlets, namely:
- * <ul>
- * <li><code>init</code>: one time (per portlet) initialization. Usually invoked during portlet
- * <code>init</code> but may also occur lazily. Context is passed to the Bridge at initialization
- * via <code>PortletContext</code> attributes. See method description for details. </li>
- * <li><code>doFacesRequest</code>: called for each portlet request that is to be handled by
- * Faces. Must only be called after the bridge has been initialized. </li>
- * <li><code>destroy</code>: called to destroy this bridge instance. Usually invoked during
- * portlet <code>destroy</code> but may also occur earlier if the portlet decides to reclaim
- * resources. </li>
- * </ul>
- * <P>
- * Portlet developers are encouraged to allow deployers an ability to configure the particular
- * Bridge implementation it uses within a given deployment. This ensures a best fit solution for a
- * given application server, portlet container, and/or Faces environment. The specifics for this
- * configuation are undefined. Each portlet can define a preferred mechanism. Subclasses of
- * {@link GenericFacesPortlet} automatically inherit this behavior as it recognizes a defined
- * portlet initialization parameter.
- * <p>
- * Implementations of this <code>Bridge</code> interface are required to have a <code>code</code>
- * constructor.
- */
-
-public interface Bridge
-{
-
-  // Base Bridge attribute/context parameter prefix
-  public static final String BRIDGE_PACKAGE_PREFIX         = "javax.portlet.faces.";
-
-  // Following are the names of context init parameters that control
-  // Bridge behavior. These are specified in the web.xml
-
-  public static final String MAX_MANAGED_REQUEST_SCOPES    = BRIDGE_PACKAGE_PREFIX
-                                                             + "MAX_MANAGED_REQUEST_SCOPES";
-
-  public static final String LIFECYCLE_ID                  = "javax.faces.LIFECYCLE_ID";
-
-  // 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";
-
-  // Following are the names of context attributes that a portlet can set prior
-  // to calling the bridge's init() method to control Bridge behavior.
-
-  // These attributes are scoped to a specific portlet in the context
-  // hence to acquire one must include the portlet name within attribute name:
-  // BRIDGE_PACKAGE_PREFIX + context.getPortletName() + attributeName
-
-  // if "true" indicates the bridge will preserve all the action params in its
-  // request scope and restore them as parameters in the subsequent renders
-  public static final String PRESERVE_ACTION_PARAMS        = "preserveActionParams";
-
-  // allows a portlet to control render delgation. A value of "ALWAYS_DELEGATE" indicates
-  // the bridge doesn't render itself, it merely delegates. A value of "NEVER_DELEGATE"
-  // indicates the bridge never delegates, rather it always overrides and renders.
-  // A value of "DEFAULT" indicates the bridge will delegate first and only render
-  // if the delegatee throws an exception/throwable.
-  public static final String RENDER_POLICY                 = "renderPolicy";
-
-  // 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";
-
-  // 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
-                                                             + "ApplicationScopeMap";
-
-  // Request attribute pushed by bridge in renderView to indicate it can
-  // handle a filter putting the AFTER_VIEW_CONTENT in a buffer on the request.
-  // Allows rendering order to be preserved in jsps
-  public static final String RENDER_CONTENT_AFTER_VIEW     = BRIDGE_PACKAGE_PREFIX
-                                                             + "RenderContentAfterView";
-
-  // Request attribute set by servlet filter in request/responseWrapper to
-  // place the AFTER_VIEW_CONTENT in a buffer on the request.
-  // Allows filter to transfer such content back to the bridge/renderView so
-  // if can output in correct order. Should only be done if
-  // RENDER_CONTENT_AFTER_VIEW request attribute is true.
-  public static final String AFTER_VIEW_CONTENT            = BRIDGE_PACKAGE_PREFIX
-                                                             + "AfterViewContent";
-
-  // Following are names of request attributes a portlet must set before
-  // 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";
-
-  // The possible JSR168 portlet lifecycle phazses
-
-  public static enum PortletPhase
-  {
-    ActionPhase, RenderPhase, ;
-  }
-
-  public static enum BridgeRenderPolicy
-  {
-    DEFAULT, ALWAYS_DELEGATE, NEVER_DELEGATE, ;
-  }
-
-  /**
-   * Called by the portlet. It indicates that the bridge is being placed into service.
-   * <p>
-   * The portlet calls the <code>init</code> method exactly once before invoking other lifecycle
-   * methods. Usually, done immediately after instantiating the bridge. The <code>init</code>
-   * method must complete successfully before the bridge can receive any requests.
-   * <p>
-   * The portlet cannot place the bridge into service if the <code>init</code> method Throws a
-   * <code>BridgeException</code>.
-   * <p>
-   * Initialization context is passed to bridge via <code>PortletContext</code> attributes. The
-   * following attributes are defined:
-   * <ul>
-   * <li><code>javax.portlet.faces.encodeRedirectURL</code>: instructs the bridge to call
-   * <code>ExternalContext.encodeActionURL()</code> before processing the redirect request. This
-   * exists because some (newer) versions of JSF 1.2 call <code>encodeActionURL</code> before
-   * calling <code>redirect</code> while others do not. This flag adjusts the behavior of the
-   * bridge in accordance with the JSF 1.2 implementation it runs with.
-   * <li><code>javax.portlet.faces.numManagedActionScopes</code>: defines the maximum number of
-   * actionScopes this bridge preserves at any given time. Value is an integer. ActionScopes are
-   * managed on a per Bridge class portlet context wide basis. As a typical portlet application uses
-   * the same bridge implementation for all its Faces based portlets, this means that all
-   * actionScopes are managed in a single bucket.<br>
-   * For convenience this interface defines the <code>NUM_MANAGED_ACTIONSCOPES</code> constant.
-   * <li><code>javax.faces.lifecycleID</code>: defines the Faces <code>Lifecycle</code> id
-   * that bridge uses when acquiring the <code>Faces.Lifecycle</code> via which it executes the
-   * request. As a context wide attribute, all bridge instances in this portlet application will use
-   * this lifecyle.
-   * <li><code>javax.portlet.faces.[portlet name].preserveActionParams</code>: instructs the
-   * bridge to preserve action parameters in the action scope and represent them in subsequent
-   * renders. Should be used only when binding to a Faces implementation that relies on accessing
-   * such parameters during its render phase. As this is a portlet/bridge instance specific
-   * attribute, the <code>PortletContext</code>attribute name is qualified by the portlet
-   * instance name. This allows different portlets within the same portlet application to have
-   * different settings.<br>
-   * For convenience this interfaces defines a number of constants that simplifies constructing
-   * and/or recognizing this name.
-   * </ul>
-   * 
-   * @param config
-   *          a <code>PortletConfig</code> object containing the portlet's configuration and
-   *          initialization parameters
-   * @exception PortletException
-   *              if an exception has occurred that interferes with the portlet's normal operation.
-   * @exception UnavailableException
-   *              if the portlet cannot perform the initialization at this time.
-   */
-  public void init(PortletConfig config) throws BridgeException;
-
-  /**
-   * Called by the portlet when it wants the bridge to process an action request.
-   * 
-   * @param request
-   *          the request object.
-   * @param response
-   *          the response object.
-   * @throws BridgeDefaultViewNotSpecifiedException
-   *           thrown if the request indicates to the Bridge that is should use the default ViewId
-   *           and the portlet hasn't supplied one.
-   * @throws BridgeException
-   *           all other internal exceptions are converted to a BridgeException.
-   */
-  public void doFacesRequest(ActionRequest request, ActionResponse response)
-                                                                            throws BridgeDefaultViewNotSpecifiedException,
-                                                                            BridgeException;
-
-  /**
-   * Called by the portlet when it wants the bridge to process a render request.
-   * 
-   * @param request
-   *          the request object.
-   * @param response
-   *          the response object.
-   * @throws BridgeDefaultViewNotSpecifiedException
-   *           thrown if the request indicates to the Bridge that is should use the default ViewId
-   *           and the portlet hasn't supplied one.
-   * @throws BridgeException
-   *           all other internal exceptions are converted to a BridgeException.
-   */
-  public void doFacesRequest(RenderRequest request, RenderResponse response)
-                                                                            throws BridgeDefaultViewNotSpecifiedException,
-                                                                            BridgeException;
-
-  /**
-   * Called by the portlet to take the bridge out of service. Once out of service, the bridge must
-   * be reinitialized before processing any further requests.
-   */
-  public void destroy();
-
-}
+/*
+ * 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.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.PortletConfig;
+import javax.portlet.PortletException;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.UnavailableException;
+
+/**
+ * The <CODE>Bridge</CODE> interface is used by a portlet to execute a JSF artifact. Its lifecycle
+ * follows the pattern used by other web components such as portlets or servlets, namely:
+ * <ul>
+ * <li><code>init</code>: one time (per portlet) initialization. Usually invoked during portlet
+ * <code>init</code> but may also occur lazily. Context is passed to the Bridge at initialization
+ * via <code>PortletContext</code> attributes. See method description for details. </li>
+ * <li><code>doFacesRequest</code>: called for each portlet request that is to be handled by
+ * Faces. Must only be called after the bridge has been initialized. </li>
+ * <li><code>destroy</code>: called to destroy this bridge instance. Usually invoked during
+ * portlet <code>destroy</code> but may also occur earlier if the portlet decides to reclaim
+ * resources. </li>
+ * </ul>
+ * <P>
+ * Portlet developers are encouraged to allow deployers an ability to configure the particular
+ * Bridge implementation it uses within a given deployment. This ensures a best fit solution for a
+ * given application server, portlet container, and/or Faces environment. The specifics for this
+ * configuation are undefined. Each portlet can define a preferred mechanism. Subclasses of
+ * {@link GenericFacesPortlet} automatically inherit this behavior as it recognizes a defined
+ * portlet initialization parameter.
+ * <p>
+ * Implementations of this <code>Bridge</code> interface are required to have a <code>code</code>
+ * constructor.
+ */
+
+public interface Bridge
+{
+
+  // Base Bridge attribute/context parameter prefix
+  public static final String BRIDGE_PACKAGE_PREFIX         = "javax.portlet.faces.";
+
+  // Following are the names of context init parameters that control
+  // Bridge behavior. These are specified in the web.xml
+
+  public static final String MAX_MANAGED_REQUEST_SCOPES    = BRIDGE_PACKAGE_PREFIX
+                                                             + "MAX_MANAGED_REQUEST_SCOPES";
+
+  public static final String LIFECYCLE_ID                  = "javax.faces.LIFECYCLE_ID";
+
+  // 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
+  public static final String PORTLET_MODE_PARAMETER = BRIDGE_PACKAGE_PREFIX + "PortletMode";
+  public static final String PORTLET_WINDOWSTATE_PARAMETER = BRIDGE_PACKAGE_PREFIX + "WindowState";
+  public static final String PORTLET_SECURE_PARAMETER = BRIDGE_PACKAGE_PREFIX + "Secure";
+
+  // Following are the names of context attributes that a portlet can set prior
+  // to calling the bridge's init() method to control Bridge behavior.
+
+  // These attributes are scoped to a specific portlet in the context
+  // hence to acquire one must include the portlet name within attribute name:
+  // BRIDGE_PACKAGE_PREFIX + context.getPortletName() + attributeName
+
+  // if "true" indicates the bridge will preserve all the action params in its
+  // request scope and restore them as parameters in the subsequent renders
+  public static final String PRESERVE_ACTION_PARAMS        = "preserveActionParams";
+
+  // allows a portlet to control render delgation. A value of "ALWAYS_DELEGATE" indicates
+  // the bridge doesn't render itself, it merely delegates. A value of "NEVER_DELEGATE"
+  // indicates the bridge never delegates, rather it always overrides and renders.
+  // A value of "DEFAULT" indicates the bridge will delegate first and only render
+  // if the delegatee throws an exception/throwable.
+  public static final String RENDER_POLICY                 = "renderPolicy";
+
+  // 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";
+
+  // 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
+                                                             + "ApplicationScopeMap";
+
+  // Request attribute pushed by bridge in renderView to indicate it can
+  // handle a filter putting the AFTER_VIEW_CONTENT in a buffer on the request.
+  // Allows rendering order to be preserved in jsps
+  public static final String RENDER_CONTENT_AFTER_VIEW     = BRIDGE_PACKAGE_PREFIX
+                                                             + "RenderContentAfterView";
+
+  // Request attribute set by servlet filter in request/responseWrapper to
+  // place the AFTER_VIEW_CONTENT in a buffer on the request.
+  // Allows filter to transfer such content back to the bridge/renderView so
+  // if can output in correct order. Should only be done if
+  // RENDER_CONTENT_AFTER_VIEW request attribute is true.
+  public static final String AFTER_VIEW_CONTENT            = BRIDGE_PACKAGE_PREFIX
+                                                             + "AfterViewContent";
+
+  // Following are names of request attributes a portlet must set before
+  // 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";
+
+  // The possible JSR168 portlet lifecycle phazses
+
+  public static enum PortletPhase
+  {
+    ActionPhase, RenderPhase, ;
+  }
+
+  public static enum BridgeRenderPolicy
+  {
+    DEFAULT, ALWAYS_DELEGATE, NEVER_DELEGATE, ;
+  }
+
+  /**
+   * Called by the portlet. It indicates that the bridge is being placed into service.
+   * <p>
+   * The portlet calls the <code>init</code> method exactly once before invoking other lifecycle
+   * methods. Usually, done immediately after instantiating the bridge. The <code>init</code>
+   * method must complete successfully before the bridge can receive any requests.
+   * <p>
+   * The portlet cannot place the bridge into service if the <code>init</code> method Throws a
+   * <code>BridgeException</code>.
+   * <p>
+   * Initialization context is passed to bridge via <code>PortletContext</code> attributes. The
+   * following attributes are defined:
+   * <ul>
+   * <li><code>javax.portlet.faces.encodeRedirectURL</code>: instructs the bridge to call
+   * <code>ExternalContext.encodeActionURL()</code> before processing the redirect request. This
+   * exists because some (newer) versions of JSF 1.2 call <code>encodeActionURL</code> before
+   * calling <code>redirect</code> while others do not. This flag adjusts the behavior of the
+   * bridge in accordance with the JSF 1.2 implementation it runs with.
+   * <li><code>javax.portlet.faces.numManagedActionScopes</code>: defines the maximum number of
+   * actionScopes this bridge preserves at any given time. Value is an integer. ActionScopes are
+   * managed on a per Bridge class portlet context wide basis. As a typical portlet application uses
+   * the same bridge implementation for all its Faces based portlets, this means that all
+   * actionScopes are managed in a single bucket.<br>
+   * For convenience this interface defines the <code>NUM_MANAGED_ACTIONSCOPES</code> constant.
+   * <li><code>javax.faces.lifecycleID</code>: defines the Faces <code>Lifecycle</code> id
+   * that bridge uses when acquiring the <code>Faces.Lifecycle</code> via which it executes the
+   * request. As a context wide attribute, all bridge instances in this portlet application will use
+   * this lifecyle.
+   * <li><code>javax.portlet.faces.[portlet name].preserveActionParams</code>: instructs the
+   * bridge to preserve action parameters in the action scope and represent them in subsequent
+   * renders. Should be used only when binding to a Faces implementation that relies on accessing
+   * such parameters during its render phase. As this is a portlet/bridge instance specific
+   * attribute, the <code>PortletContext</code>attribute name is qualified by the portlet
+   * instance name. This allows different portlets within the same portlet application to have
+   * different settings.<br>
+   * For convenience this interfaces defines a number of constants that simplifies constructing
+   * and/or recognizing this name.
+   * </ul>
+   * 
+   * @param config
+   *          a <code>PortletConfig</code> object containing the portlet's configuration and
+   *          initialization parameters
+   * @exception PortletException
+   *              if an exception has occurred that interferes with the portlet's normal operation.
+   * @exception UnavailableException
+   *              if the portlet cannot perform the initialization at this time.
+   */
+  public void init(PortletConfig config) throws BridgeException;
+
+  /**
+   * Called by the portlet when it wants the bridge to process an action request.
+   * 
+   * @param request
+   *          the request object.
+   * @param response
+   *          the response object.
+   * @throws BridgeDefaultViewNotSpecifiedException
+   *           thrown if the request indicates to the Bridge that is should use the default ViewId
+   *           and the portlet hasn't supplied one.
+   * @throws BridgeException
+   *           all other internal exceptions are converted to a BridgeException.
+   */
+  public void doFacesRequest(ActionRequest request, ActionResponse response)
+                                                                            throws BridgeDefaultViewNotSpecifiedException,
+                                                                            BridgeException;
+
+  /**
+   * Called by the portlet when it wants the bridge to process a render request.
+   * 
+   * @param request
+   *          the request object.
+   * @param response
+   *          the response object.
+   * @throws BridgeDefaultViewNotSpecifiedException
+   *           thrown if the request indicates to the Bridge that is should use the default ViewId
+   *           and the portlet hasn't supplied one.
+   * @throws BridgeException
+   *           all other internal exceptions are converted to a BridgeException.
+   */
+  public void doFacesRequest(RenderRequest request, RenderResponse response)
+                                                                            throws BridgeDefaultViewNotSpecifiedException,
+                                                                            BridgeException;
+
+  /**
+   * Called by the portlet to take the bridge out of service. Once out of service, the bridge must
+   * be reinitialized before processing any further requests.
+   */
+  public void destroy();
+
+}

Added: myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java?rev=595816&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java (added)
+++ myfaces/portlet-bridge/trunk/api/src/main/java/javax/portlet/faces/BridgeUtil.java Fri Nov 16 12:48:15 2007
@@ -0,0 +1,63 @@
+/*
+ * 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 java.util.Map;
+
+import javax.faces.context.FacesContext;
+
+import javax.portlet.faces.Bridge;
+
+public class BridgeUtil
+{
+  public static boolean isPortletRequest() 
+  {
+    Map m = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
+    Bridge.PortletPhase phase = (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
+    if (phase != null)
+    {
+      return true;
+    }
+    else 
+    {
+      return false;
+    }
+  }
+  
+  public static boolean isPortletActionRequest() 
+  {
+    Map m = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
+    Bridge.PortletPhase phase = (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
+    if (phase != null && phase == Bridge.PortletPhase.ActionPhase)
+    {
+      return true;
+    }
+    else 
+    {
+      return false;
+    }
+  }
+  
+  public static boolean isPortletRenderRequest() 
+  {
+    Map m = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
+    Bridge.PortletPhase phase = (Bridge.PortletPhase) m.get(Bridge.PORTLET_LIFECYCLE_PHASE);
+    if (phase != null && phase == Bridge.PortletPhase.RenderPhase)
+    {
+      return true;
+    }
+    else 
+    {
+      return false;
+    }
+  }
+}

Added: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java?rev=595816&view=auto
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java (added)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java Fri Nov 16 12:48:15 2007
@@ -0,0 +1,137 @@
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.myfaces.portlet.faces.application;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+import java.util.Map;
+
+import javax.faces.application.StateManager;
+import javax.faces.application.StateManagerWrapper;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import javax.faces.render.ResponseStateManager;
+
+import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
+
+public class PortletStateManagerImpl
+  extends StateManagerWrapper
+{
+  private StateManager mDelegatee = null;
+  
+  public PortletStateManagerImpl(StateManager sm)
+  {
+    mDelegatee = sm;
+  }
+  
+  /*
+   * Override saveView so we can grab the returned state and place
+   * it in the request scope so the Bridge can find it and use for subsequent
+   * renders that occur in this managed bridge (action) request scope.
+   * 
+   * Basically what is going one here is that JSF either stores the entire state
+   * or at least enough info to get back to its entire state in a hidden field
+   * represented by the VIEW_STATE_PARAM.  In addition the existence of this
+   * parameter in any given request is used to determine if one is running in a
+   * postback or not.  
+   * Because in the portlet environment renders occur in a separate request from
+   * action we need to preserve this parameter in the first request after an 
+   * action so JSF will know its in a postback.  However after the first render
+   * following an action additional renders can occur (before the next action).
+   * These renders also need to signal they are running in a postback by exposing
+   * this parameter however the value should not be the one that was sent to the 
+   * original action but rather the one that resulted after the last render.
+   * 
+   * To do this the Bridge has to catch the value that is being written into
+   * the hidden field.  It does this by overriding writeState and replace the 
+   * value its maintaining for the VIEW_STATE_PARAM with this value written as
+   * a String.
+   */
+  public void writeState(FacesContext context, Object state)
+    throws IOException
+  {
+    // Replace current response writer so can grab what is written
+    ResponseWriter oldRW = context.getResponseWriter();
+    StringWriter stringWriter = new StringWriter(128);
+    ResponseWriter newRW = oldRW.cloneWithWriter(stringWriter);
+    context.setResponseWriter(newRW);
+    
+    mDelegatee.writeState(context, state);
+    
+    // Restore real responsewriter
+    context.setResponseWriter(oldRW);
+    
+    // Get written state
+    newRW.flush();
+    String stateValue = new String(stringWriter.getBuffer());
+    
+
+    // Write it to the old response writer
+    oldRW.write(stateValue);
+    
+    // Now extract the parameter value from the buffer:
+    stateValue = extractViewStateParamValue(stateValue);
+    
+    if (stateValue != null) 
+    {
+      Map m = context.getExternalContext().getRequestMap();
+      m.put(BridgeImpl.UPDATED_VIEW_STATE_PARAM, stateValue);
+    }
+    
+  }
+  
+  public StateManager getWrapped()
+  {
+    return mDelegatee;
+  }
+  
+  private String extractViewStateParamValue(String buf)
+  {
+    // Locate the VIEW_STATE_PARAM field
+    int i = buf.indexOf(ResponseStateManager.VIEW_STATE_PARAM);
+    if (i < 0) return null;
+    
+    // now locate the end of the element so don't read beyond it.
+    int end = buf.indexOf("/>", i);
+    if (end < 0) return null;
+    
+    // now locate the value attribute
+    int valStart = buf.indexOf("value", i);
+    if (valStart < 0 || valStart > end) 
+    {
+      // must be earlier in the element
+      buf = buf.substring(0, end);
+      end = buf.length() - 1;
+      i = buf.lastIndexOf("<");
+      if (i < 0) return null;
+      valStart = buf.indexOf("value", i);
+      if (valStart < 0) return null;
+    }
+    
+    // now extract the value between the quotes
+    valStart = buf.indexOf('"', valStart);
+    if (valStart < 0) return null;
+    int valEnd = buf.indexOf('"', valStart + 1);
+    if (valEnd < 0 || valEnd > end) return null;
+    return buf.substring(valStart + 1, valEnd);
+  }
+}

Modified: myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java?rev=595816&r1=595815&r2=595816&view=diff
==============================================================================
--- myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java (original)
+++ myfaces/portlet-bridge/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletViewHandlerImpl.java Fri Nov 16 12:48:15 2007
@@ -1,436 +1,369 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.myfaces.portlet.faces.application;
-
-import java.io.IOException;
-import java.io.Writer;
-
-import java.util.Locale;
-
-import javax.faces.FacesException;
-import javax.faces.FactoryFinder;
-import javax.faces.application.StateManager;
-import javax.faces.application.ViewHandler;
-import javax.faces.component.UIViewRoot;
-import javax.faces.context.ExternalContext;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-import javax.faces.render.RenderKit;
-import javax.faces.render.RenderKitFactory;
-
-import javax.portlet.RenderResponse;
-
-import javax.portlet.faces.Bridge;
-import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
-
-import javax.servlet.ServletContext;
-
-import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
-import org.apache.myfaces.portlet.faces.util.URLUtils;
-
-/**
- * View handler implementation for JSF portlet bridge.
- * 
- * The only method we override here is getActionURL().
- * 
- * TODO JSF 1.2 note: JSF 1.2 RI implements ViewHandler.renderView() differently in order to handle
- * emitting non-JSF markup that follows the JSF tags after the JSF renders correctly. Unfortunately,
- * the RI handles this by introducing several servlet dependencies. Currently, the bridge handles
- * this by overriding the renderView() and ignoring (not interleafing) the non-JSF markup - see HACK
- * below
- */
-public class PortletViewHandlerImpl extends ViewHandler
-{
-
-  // the ViewHandler to delegate to
-  private ViewHandler mDelegate;
-
-  public PortletViewHandlerImpl(ViewHandler handler)
-  {
-    mDelegate = handler;
-  }
-
-  @Override
-  public Locale calculateLocale(FacesContext facesContext)
-  {
-    return mDelegate.calculateLocale(facesContext);
-  }
-
-  @Override
-  public String calculateRenderKitId(FacesContext facesContext)
-  {
-    return mDelegate.calculateRenderKitId(facesContext);
-  }
-
-  @Override
-  public UIViewRoot createView(FacesContext facesContext, String viewId)
-  {
-    // TODO HACK Bug 5961033
-    // In jsf-1.2_03-b09-FCS ViewHandlerImpl's createView() and
-    // restoreView() added codes that check if it's servlet (prefix) or
-    // extension (suffix) mapped. Until RI fixes that:
-    // https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=546
-    // we'll hack it by setting the following request attr prior to
-    // delegating
-    // to RI's createView()
-    // Note: This is a private constant defined in com.sun.faces.util.Util
-    // as:
-    // private static final String INVOCATION_PATH =
-    // RIConstants.FACES_PREFIX + "INVOCATION_PATH";
-    if (!(facesContext.getExternalContext().getContext() instanceof ServletContext))
-    {
-      facesContext.getExternalContext().getRequestMap().put("com.sun.faces.INVOCATION_PATH",
-                                                            "/faces");
-    }
-    UIViewRoot viewRoot = mDelegate.createView(facesContext, viewId);
-    if (viewRoot.getClass() != UIViewRoot.class)
-    {
-      return viewRoot;
-    }
-    else
-    {
-      return new PortletNamingContainerUIViewRoot(viewRoot);
-    }
-  }
-
-  /**
-   * The only thing we do here is stuff the original viewId in the query string so we can retrieve
-   * it later in PortletExternalContextImpl.encodeActionURL()
-   */
-  @Override
-  public String getActionURL(FacesContext facesContext, String viewId)
-  {
-    String actionURL = mDelegate.getActionURL(facesContext, viewId);
-
-    if (!(facesContext.getExternalContext().getContext() instanceof ServletContext)) // TODO
-    // -
-    // get
-    // from
-    // request
-    // attribute
-    {
-      actionURL = URLUtils.appendURLArguments(actionURL, new String[] {
-          PortletExternalContextImpl.VIEW_ID_QUERY_PARAMETER, viewId });
-    }
-
-    return actionURL;
-  }
-
-  @Override
-  public String getResourceURL(FacesContext facesContext, String path)
-  {
-    return mDelegate.getResourceURL(facesContext, path);
-  }
-
-  @Override
-  public UIViewRoot restoreView(FacesContext facesContext, String viewId)
-  {
-    // TODO HACK Bug 5961033
-    // In jsf-1.2_03-b09-FCS ViewHandlerImpl's createView() and
-    // restoreView() added codes that check if it's servlet (prefix) or
-    // extension (suffix) mapped. Until RI fixes that:
-    // https://javaserverfaces.dev.java.net/issues/show_bug.cgi?id=546
-    // we'll hack it by setting the following request attr prior to
-    // delegating
-    // to RI's restoreView()
-    // Note: This is a private constant defined in com.sun.faces.util.Util
-    // as:
-    // private static final String INVOCATION_PATH =
-    // RIConstants.FACES_PREFIX + "INVOCATION_PATH";
-    if (!(facesContext.getExternalContext().getContext() instanceof ServletContext))
-    {
-      facesContext.getExternalContext().getRequestMap().put("com.sun.faces.INVOCATION_PATH",
-                                                            "/faces");
-    }
-
-    return mDelegate.restoreView(facesContext, viewId);
-  }
-
-  @Override
-  public void writeState(FacesContext facesContext) throws IOException
-  {
-    mDelegate.writeState(facesContext);
-  }
-
-  @Override
-  public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
-                                                                       FacesException
-  {
-    // Get the renderPolicy from the requestScope
-    Bridge.BridgeRenderPolicy renderPolicy = (Bridge.BridgeRenderPolicy) context
-                                                                                .getExternalContext()
-                                                                                .getRequestMap()
-                                                                                .get(
-                                                                                     PortletExternalContextImpl.RENDER_POLICY_ATTRIBUTE);
-
-    if (renderPolicy == null)
-    {
-      renderPolicy = Bridge.BridgeRenderPolicy.valueOf("DEFAULT");
-    }
-
-    if (context.getExternalContext().getContext() instanceof ServletContext
-        || renderPolicy == Bridge.BridgeRenderPolicy.ALWAYS_DELEGATE)
-    {
-      mDelegate.renderView(context, viewToRender);
-      return;
-    }
-    else if (renderPolicy == Bridge.BridgeRenderPolicy.DEFAULT)
-    {
-      try
-      {
-        mDelegate.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
-    {
-
-      // 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);
-      // TODO JSF 1.2 - executePageToBuildView() creates
-      // ViewHandlerResponseWrapper
-      // to handle error page and text that exists after the <f:view> tag
-      // among other things which have lots of servlet dependencies -
-      // we're skipping this for now for portlet
-      extContext.dispatch(viewToRender.getViewId());
-      /*
-       * if (executePageToBuildView(context, viewToRender)) { response.flushBuffer(); return; }
-       */
-    }
-    catch (IOException e)
-    {
-      throw new FacesException(e);
-    }
-
-    // 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;
-    if (null != oldWriter)
-    {
-      responseWriter = oldWriter.cloneWithWriter(renderResponse.getWriter());
-    }
-    else
-    {
-      responseWriter = newWriter.cloneWithWriter(renderResponse.getWriter());
-    }
-    context.setResponseWriter(responseWriter);
-
-    strWriter.write(responseWriter);
-
-    if (null != oldWriter)
-    {
-      context.setResponseWriter(oldWriter);
-    }
-
-    Object content = extContext.getRequestMap().get(Bridge.AFTER_VIEW_CONTENT);
-    if (content != null)
-    {
-      if (content instanceof char[])
-      {
-        renderResponse.getWriter().write(new String((byte[]) content));
-      }
-      else if (content instanceof byte[])
-      {
-        renderResponse.getWriter().write(new String((char[]) content));
-      }
-      else
-      {
-        throw new IOException("PortletViewHandlerImpl: invalid" + "AFTER_VIEW_CONTENT buffer type");
-      }
-    }
-    renderResponse.flushBuffer();
-  }
-
-  /**
-   * <p>
-   * This is a separate method to account for handling the content after the view tag.
-   * </p>
-   * 
-   * <p>
-   * Create a new ResponseWriter around this response's Writer. Set it into the FacesContext, saving
-   * the old one aside.
-   * </p>
-   * 
-   * <p>
-   * call encodeBegin(), encodeChildren(), encodeEnd() on the argument <code>UIViewRoot</code>.
-   * </p>
-   * 
-   * <p>
-   * Restore the old ResponseWriter into the FacesContext.
-   * </p>
-   * 
-   * <p>
-   * Write out the after view content to the response's writer.
-   * </p>
-   * 
-   * <p>
-   * Flush the response buffer, and remove the after view content from the request scope.
-   * </p>
-   * 
-   * @param context
-   *          the <code>FacesContext</code> for the current request
-   * @param viewToRender
-   *          the view to render
-   * @throws IOException
-   *           if an error occurs rendering the view to the client
-   */
-  private void doRenderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
-                                                                          FacesException
-  {
-    ExternalContext extContext = context.getExternalContext();
-    viewToRender.encodeAll(context);
-  }
-
-  private static final class StringBuilderWriter extends Writer
-  {
-    private StringBuilder       mBuilder;
-    private FacesContext        mContext;
-
-    // TODO: These bridge needs to use it's own constants here. This will
-    // confine
-    // us to only work with the R.I.
-    private static final String SAVESTATE_FIELD_MARKER = "~com.sun.faces.saveStateFieldMarker~";
-
-    public StringBuilderWriter(FacesContext context, int initialCapacity)
-    {
-      if (initialCapacity < 0)
-      {
-        throw new IllegalArgumentException();
-      }
-      mBuilder = new StringBuilder(initialCapacity);
-      mContext = context;
-    }
-
-    @Override
-    public void write(char[] cbuf, int off, int len) throws IOException
-    {
-      if (off < 0 || off > cbuf.length || len < 0 || off + len > cbuf.length || off + len < 0)
-      {
-        throw new IndexOutOfBoundsException();
-      }
-      else if (len == 0)
-      {
-        return;
-      }
-      mBuilder.append(cbuf, off, len);
-    }
-
-    @Override
-    public void flush() throws IOException
-    {
-    }
-
-    @Override
-    public void close() throws IOException
-    {
-    }
-
-    /**
-     * Write a string.
-     * 
-     * @param str
-     *          String to be written
-     */
-    @Override
-    public void write(String str)
-    {
-      mBuilder.append(str);
-    }
-
-    @Override
-    public void write(String str, int off, int len)
-    {
-      write(str.substring(off, off + len));
-    }
-
-    public StringBuilder getBuffer()
-    {
-      return mBuilder;
-    }
-
-    @Override
-    public String toString()
-    {
-      return mBuilder.toString();
-    }
-
-    public void write(Writer writer) throws IOException
-    {
-      // TODO: Buffer?
-      StateManager stateManager = mContext.getApplication().getStateManager();
-      Object stateToWrite = stateManager.saveView(mContext);
-      int markLen = SAVESTATE_FIELD_MARKER.length();
-      int pos = 0;
-      int tildeIdx = mBuilder.indexOf(SAVESTATE_FIELD_MARKER);
-      while (tildeIdx > 0)
-      {
-        writer.write(mBuilder.substring(pos, (tildeIdx - pos)));
-        stateManager.writeState(mContext, stateToWrite);
-        pos += tildeIdx + markLen;
-        tildeIdx = mBuilder.indexOf(SAVESTATE_FIELD_MARKER, pos);
-      }
-      writer.write(mBuilder.substring(pos));
-    }
-  }
-
-  // END TODO HACK JSF 1.2
-}
+/* Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.myfaces.portlet.faces.application;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import java.util.Locale;
+
+import java.util.Map;
+
+import javax.faces.FacesException;
+import javax.faces.FactoryFinder;
+import javax.faces.application.StateManager;
+import javax.faces.application.ViewHandler;
+import javax.faces.application.ViewHandlerWrapper;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.RenderKit;
+import javax.faces.render.RenderKitFactory;
+
+import javax.portlet.RenderResponse;
+
+import javax.portlet.faces.Bridge;
+import javax.portlet.faces.BridgeUtil;
+import javax.portlet.faces.component.PortletNamingContainerUIViewRoot;
+
+import javax.servlet.ServletContext;
+
+import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
+import org.apache.myfaces.portlet.faces.util.URLUtils;
+
+/**
+ * View handler implementation for JSF portlet bridge.
+ * 
+ * The only method we override here is getActionURL().
+ * 
+ * TODO JSF 1.2 note: JSF 1.2 RI implements ViewHandler.renderView() differently in order to handle
+ * emitting non-JSF markup that follows the JSF tags after the JSF renders correctly. Unfortunately,
+ * the RI handles this by introducing several servlet dependencies. Currently, the bridge handles
+ * this by overriding the renderView() and ignoring (not interleafing) the non-JSF markup - see HACK
+ * below
+ */
+public class PortletViewHandlerImpl extends ViewHandlerWrapper
+{
+
+  // the ViewHandler to delegate to
+  private ViewHandler mDelegate;
+
+  public PortletViewHandlerImpl(ViewHandler handler)
+  {
+    mDelegate = handler;
+  }
+  
+  protected ViewHandler getWrapped()
+  {
+    return mDelegate;
+  }
+
+
+  @Override
+  public UIViewRoot createView(FacesContext facesContext, String viewId)
+  {
+
+    UIViewRoot viewRoot = mDelegate.createView(facesContext, viewId);
+ 
+    if (viewRoot.getClass() != UIViewRoot.class)
+    {
+      return viewRoot;
+    }
+    else
+    {
+      return new PortletNamingContainerUIViewRoot(viewRoot);
+    }
+
+  }
+
+
+
+  @Override
+  public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
+                                                                       FacesException
+  {
+    // Get the renderPolicy from the requestScope
+    Bridge.BridgeRenderPolicy renderPolicy = (Bridge.BridgeRenderPolicy) context
+                                                                                .getExternalContext()
+                                                                                .getRequestMap()
+                                                                                .get(
+                                                                                     PortletExternalContextImpl.RENDER_POLICY_ATTRIBUTE);
+
+    if (renderPolicy == null)
+    {
+      renderPolicy = Bridge.BridgeRenderPolicy.valueOf("DEFAULT");
+    }
+
+    if (!BridgeUtil.isPortletRequest()
+        || renderPolicy == Bridge.BridgeRenderPolicy.ALWAYS_DELEGATE)
+    {
+      mDelegate.renderView(context, viewToRender);
+      return;
+    }
+    else if (renderPolicy == Bridge.BridgeRenderPolicy.DEFAULT)
+    {
+      try
+      {
+        mDelegate.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
+    {
+
+      // 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);
+      // TODO JSF 1.2 - executePageToBuildView() creates
+      // ViewHandlerResponseWrapper
+      // to handle error page and text that exists after the <f:view> tag
+      // among other things which have lots of servlet dependencies -
+      // we're skipping this for now for portlet
+      
+      
+      // Bridge has had to set this attribute so  Faces RI will skip servlet dependent
+      // code when mapping from request paths to viewIds -- however we need to remove it
+      // as it screws up the dispatch
+      extContext.getRequestMap().remove("javax.servlet.include.servlet_path");
+      extContext.dispatch(viewToRender.getViewId());
+      /*
+       * if (executePageToBuildView(context, viewToRender)) { response.flushBuffer(); return; }
+       */
+    }
+    catch (IOException e)
+    {
+      throw new FacesException(e);
+    }
+
+    // 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;
+    if (null != oldWriter)
+    {
+      responseWriter = oldWriter.cloneWithWriter(renderResponse.getWriter());
+    }
+    else
+    {
+      responseWriter = newWriter.cloneWithWriter(renderResponse.getWriter());
+    }
+    context.setResponseWriter(responseWriter);
+
+    strWriter.write(responseWriter);
+
+    if (null != oldWriter)
+    {
+      context.setResponseWriter(oldWriter);
+    }
+
+    Object content = extContext.getRequestMap().get(Bridge.AFTER_VIEW_CONTENT);
+    if (content != null)
+    {
+      if (content instanceof char[])
+      {
+        renderResponse.getWriter().write(new String((byte[]) content));
+      }
+      else if (content instanceof byte[])
+      {
+        renderResponse.getWriter().write(new String((char[]) content));
+      }
+      else
+      {
+        throw new IOException("PortletViewHandlerImpl: invalid" + "AFTER_VIEW_CONTENT buffer type");
+      }
+    }
+    renderResponse.flushBuffer();
+  }
+
+  /**
+   * <p>
+   * This is a separate method to account for handling the content after the view tag.
+   * </p>
+   * 
+   * <p>
+   * Create a new ResponseWriter around this response's Writer. Set it into the FacesContext, saving
+   * the old one aside.
+   * </p>
+   * 
+   * <p>
+   * call encodeBegin(), encodeChildren(), encodeEnd() on the argument <code>UIViewRoot</code>.
+   * </p>
+   * 
+   * <p>
+   * Restore the old ResponseWriter into the FacesContext.
+   * </p>
+   * 
+   * <p>
+   * Write out the after view content to the response's writer.
+   * </p>
+   * 
+   * <p>
+   * Flush the response buffer, and remove the after view content from the request scope.
+   * </p>
+   * 
+   * @param context
+   *          the <code>FacesContext</code> for the current request
+   * @param viewToRender
+   *          the view to render
+   * @throws IOException
+   *           if an error occurs rendering the view to the client
+   */
+  private void doRenderView(FacesContext context, UIViewRoot viewToRender) throws IOException,
+                                                                          FacesException
+  {
+    viewToRender.encodeAll(context);
+  }
+  
+
+  private static final class StringBuilderWriter extends Writer
+  {
+    private StringBuilder       mBuilder;
+    private FacesContext        mContext;
+
+    // TODO: These bridge needs to use it's own constants here. This will
+    // confine
+    // us to only work with the R.I.
+    private static final String SAVESTATE_FIELD_MARKER = "~com.sun.faces.saveStateFieldMarker~";
+
+    public StringBuilderWriter(FacesContext context, int initialCapacity)
+    {
+      if (initialCapacity < 0)
+      {
+        throw new IllegalArgumentException();
+      }
+      mBuilder = new StringBuilder(initialCapacity);
+      mContext = context;
+    }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException
+    {
+      if (off < 0 || off > cbuf.length || len < 0 || off + len > cbuf.length || off + len < 0)
+      {
+        throw new IndexOutOfBoundsException();
+      }
+      else if (len == 0)
+      {
+        return;
+      }
+      mBuilder.append(cbuf, off, len);
+    }
+
+    @Override
+    public void flush() throws IOException
+    {
+    }
+
+    @Override
+    public void close() throws IOException
+    {
+    }
+
+    /**
+     * Write a string.
+     * 
+     * @param str
+     *          String to be written
+     */
+    @Override
+    public void write(String str)
+    {
+      mBuilder.append(str);
+    }
+
+    @Override
+    public void write(String str, int off, int len)
+    {
+      write(str.substring(off, off + len));
+    }
+
+    public StringBuilder getBuffer()
+    {
+      return mBuilder;
+    }
+
+    @Override
+    public String toString()
+    {
+      return mBuilder.toString();
+    }
+
+    public void write(Writer writer) throws IOException
+    {
+      // TODO: Buffer?
+      StateManager stateManager = mContext.getApplication().getStateManager();
+      Object stateToWrite = stateManager.saveView(mContext);
+      int markLen = SAVESTATE_FIELD_MARKER.length();
+      int pos = 0;
+      int tildeIdx = mBuilder.indexOf(SAVESTATE_FIELD_MARKER);
+      while (tildeIdx > 0)
+      {
+        writer.write(mBuilder.substring(pos, (tildeIdx - pos)));
+        stateManager.writeState(mContext, stateToWrite);
+        pos += tildeIdx + markLen;
+        tildeIdx = mBuilder.indexOf(SAVESTATE_FIELD_MARKER, pos);
+      }
+      writer.write(mBuilder.substring(pos));
+    }
+  }
+
+  // END TODO HACK JSF 1.2
+}