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
+}