Author: ate
Date: Thu Feb 22 17:28:50 2007
New Revision: 510753

URL: http://svn.apache.org/viewvc?view=rev&rev=510753
Log:
Fixing PB-38: Switching between View and Edit modes, portlet remembers only the 
last action (and not the last action in that mode) and goes to that regardless 
of the mode.
and    PB-49: Multiple instances of a struts portlet should be able to coexist 
on a single page

Added:
    
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
   (with props)
    
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
   (with props)
Modified:
    portals/bridges/trunk/struts/pom.xml
    portals/bridges/trunk/struts/project.xml
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServlet.java
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestDispatcher.java
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestWrapper.java
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortlet.java
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortletURL.java
    
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/config/RenderContextAttributes.java
    portals/bridges/trunk/struts/xdocs/features.xml

Added: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java?view=auto&rev=510753
==============================================================================
--- 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
 (added)
+++ 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
 Thu Feb 22 17:28:50 2007
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2004 The Apache Software Foundation.
+ * 
+ * Licensed 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.portals.bridges.util;
+
+import java.util.Enumeration;
+
+import javax.portlet.PortletSession;
+import javax.portlet.PortletSessionUtil;
+
+/**
+ * PortletWindowUtils
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ate Douma</a>
+ * @version $Id$
+ */
+public class PortletWindowUtils
+{
+    public static String PORTLET_WINDOW_ID = 
"org.apache.portals.bridges.util.portlet_window_id";
+    
+    /**
+     * Return the unique identification for the portlet window as assigned by 
the portal/portlet-container.
+     * <br/>
+     * This method makes use of the PortletSession to determine the window id 
as specified by the Portlet Specification 1.0, PLT.15.3,
+     * as well as stores the determined value under the [EMAIL PROTECTED] 
#PORTLET_WINDOW_ID} in the portlet scope session.
+     * 
+     * @param session the current PortletSession
+     * @return the unique identification of the portlet window
+     */
+    public static String getPortletWindowId(PortletSession session)
+    {
+        String portletWindowId = 
(String)session.getAttribute(PORTLET_WINDOW_ID);
+        if ( portletWindowId == null )
+        {
+            synchronized (session)
+            {
+                Double value = new Double(Math.random());
+                session.setAttribute(PORTLET_WINDOW_ID, value);
+                Enumeration names = 
session.getAttributeNames(PortletSession.APPLICATION_SCOPE);
+                while (names.hasMoreElements())
+                {
+                    String name = (String)names.nextElement();
+                    if 
(PortletSessionUtil.decodeAttributeName(name).equals(PORTLET_WINDOW_ID) && 
value.equals(session.getAttribute(name,PortletSession.APPLICATION_SCOPE)) )
+                    {
+                        portletWindowId = 
name.substring("javax.portlet.p.".length(),name.indexOf('?'));
+                        session.setAttribute(PORTLET_WINDOW_ID, 
portletWindowId);
+                        break;
+                    }                    
+                }
+            }
+        }
+        return portletWindowId;
+    }
+    
+    /**
+     * Returns the name an attribute is (or will be) encoded in the 
PortletSession APPLICATION_SCOPE.
+     * @param session PortletSession
+     * @param attributeName the attribute name to encode
+     */
+    public static String 
getApplicationScopeSessionAttributeName(PortletSession session, String 
attributeName)
+    {
+        return 
getApplicationScopeSessionAttributeName(getPortletWindowId(session),attributeName);
+    }
+
+    /**
+     * Returns the name an attribute is (or will be) encoded in the 
PortletSession APPLICATION_SCOPE.
+     * 
+     * @param portletWindowId the unique portlet window identification 
retrieved from [EMAIL PROTECTED] #getPortletWindowId(PortletSession)}.
+     * @param attributeName the attribute name to encode
+     */
+    public static String getApplicationScopeSessionAttributeName(String 
portletWindowId, String attributeName)
+    {
+        return "javax.portlet.p."+portletWindowId+"?"+attributeName;
+    }
+}

Propchange: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/PortletWindowUtils.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java?view=auto&rev=510753
==============================================================================
--- 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
 (added)
+++ 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
 Thu Feb 22 17:28:50 2007
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-2004 The Apache Software Foundation.
+ *
+ * Licensed 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.portals.bridges.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Proxy for a Servlet HttpSession to wrap a PortletSession, providing only 
access to PORTLET_SCOPE session attributes
+ * and hiding the APPLICATION_SCOPE attributes from the Servlet.
+ * <br/>
+ * This Proxy can be used to isolate two instances of the same Portlet 
dispatching to Servlets so they don't overwrite or read
+ * each others session attributes.
+ * <br/>
+ * Caveat: APPLICATION_SCOPE sessions attributes cannot be used anymore 
(directly) for inter-portlet communication,
+ * or when using Servlets directly which also need to "attach" to the 
PORTLET_SCOPE session attributes.<br/>
+ * The  [EMAIL PROTECTED] PortletWindowUtils} class can help out with that 
though.
+
+ * @see PortletWindowUtils
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ate Douma</a>
+ * @version $Id$
+ * 
+ */
+public class ServletPortletSessionProxy implements InvocationHandler
+{
+    HttpSession servletSession;
+    PortletSession portletSession;
+
+    public static HttpSession createProxy(HttpServletRequest request)
+    {
+        HttpSession servletSession = request.getSession();
+        PortletRequest portletRequest = (PortletRequest) 
request.getAttribute("javax.portlet.request");
+        if (portletRequest != null)
+        {
+            PortletSession portletSession = portletRequest.getPortletSession();
+            servletSession = (HttpSession) 
Proxy.newProxyInstance(servletSession.getClass().getClassLoader(),
+                    servletSession.getClass().getInterfaces(), new 
ServletPortletSessionProxy(servletSession,
+                            portletSession));
+        }
+        return servletSession;
+    }
+
+    private ServletPortletSessionProxy(HttpSession servletSession, 
PortletSession portletSession)
+    {
+        this.servletSession = servletSession;
+        this.portletSession = portletSession;
+    }
+
+    /**
+     * (non-Javadoc)
+     * 
+     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
+     *      java.lang.reflect.Method, java.lang.Object[])
+     */
+    public Object invoke(Object proxy, Method m, Object[] args) throws 
Throwable
+    {
+        Object retval = null;
+        if (("getAttribute".equals(m.getName()) || 
"getValue".equals(m.getName())) && args.length == 1 && args[0] instanceof 
String)
+        {
+            retval = portletSession.getAttribute((String)args[0]);
+        }
+        else if (("setAttribute".equals(m.getName()) || 
"putValue".equals(m.getName())) && args.length == 2 && args[0] instanceof 
String)
+        {
+            portletSession.setAttribute((String)args[0], args[1]);
+        }
+        else if (("removeAttribute".equals(m.getName()) || 
"removeValue".equals(m.getName())) && args.length == 1 && args[0] instanceof 
String)
+        {
+            portletSession.removeAttribute((String)args[0]);
+        }
+        else if (("getAttributeNames".equals(m.getName()) || 
"getValueNames".equals(m.getName())) && args.length == 0)
+        {
+            
+            retval = portletSession.getAttributeNames();
+        }
+        else
+        {
+            retval = m.invoke(servletSession, args);
+        }
+        return retval;
+    }
+}

Propchange: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
portals/bridges/trunk/common/src/java/org/apache/portals/bridges/util/ServletPortletSessionProxy.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: portals/bridges/trunk/struts/pom.xml
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/pom.xml?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- portals/bridges/trunk/struts/pom.xml (original)
+++ portals/bridges/trunk/struts/pom.xml Thu Feb 22 17:28:50 2007
@@ -58,6 +58,10 @@
             <artifactId>commons-digester</artifactId>
         </dependency>                           
         <dependency>
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>                           
+        <dependency>
             <groupId>commons-logging</groupId>
             <artifactId>commons-logging</artifactId>
         </dependency>             

Modified: portals/bridges/trunk/struts/project.xml
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/project.xml?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- portals/bridges/trunk/struts/project.xml (original)
+++ portals/bridges/trunk/struts/project.xml Thu Feb 22 17:28:50 2007
@@ -49,9 +49,10 @@
       <id>commons-digester</id>
       <version>1.5</version>
       <url>http://jakarta.apache.org/commons/digester.html</url>
-      <properties>
-        <war.bundle>true</war.bundle>
-      </properties>
+    </dependency>
+    <dependency>
+      <id>commons-beanutils</id>
+      <version>1.7.0</version>
     </dependency>
     <dependency>
       <id>struts</id>

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServlet.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServlet.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServlet.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServlet.java
 Thu Feb 22 17:28:50 2007
@@ -128,21 +128,14 @@
         if (!request.getAttribute(StrutsPortlet.REQUEST_TYPE).equals(
                 StrutsPortlet.ACTION_REQUEST))
         {
-            StrutsPortletRenderContext context = null;
+            StrutsPortletRenderContext context = 
(StrutsPortletRenderContext)request.getAttribute(StrutsPortlet.RENDER_CONTEXT);
                
-            String portletName = (String) 
request.getAttribute(StrutsPortlet.PORTLET_NAME);
-               
-                       String contextKey = StrutsPortlet.RENDER_CONTEXT + "_" 
+ portletName;
-            context = (StrutsPortletRenderContext) request
-                    .getSession(true)
-                    .getAttribute(contextKey);
             if (context != null)
             {
                 if (log.isDebugEnabled())
                 {
                     log.debug("render context path: " + context.getPath());
                 }
-                request.getSession().removeAttribute(contextKey);
                 if (context.getActionForm() != null) {
                        String attribute = mapping.getAttribute();
                        if (attribute != null) {

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestDispatcher.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestDispatcher.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestDispatcher.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestDispatcher.java
 Thu Feb 22 17:28:50 2007
@@ -22,7 +22,6 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -101,20 +100,8 @@
                             originURL);
                 }
             }
-            String portletName = (String) 
req.getAttribute(StrutsPortlet.PORTLET_NAME);
-            try
-            {
-                req.getSession(true).setAttribute(StrutsPortlet.RENDER_CONTEXT 
+ "_" + portletName, context);
-            }
-            catch (IllegalStateException ise)
-            {
-                // catch Session already invalidated Exception
-                if (log.isDebugEnabled())
-                {
-                    log.debug("Session invalidated: redirecting to: "+path+" 
instead.");
-                }
-                ((HttpServletResponse)response).sendRedirect(path);
-            }
+            // save context in the request, StrutsPortlet will store it in the 
Portlet Session later on
+            req.setAttribute(StrutsPortlet.RENDER_CONTEXT, context);
         } 
         else
         {

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestWrapper.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestWrapper.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestWrapper.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/PortletServletRequestWrapper.java
 Thu Feb 22 17:28:50 2007
@@ -19,6 +19,7 @@
 import javax.servlet.ServletContext;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -33,10 +34,17 @@
 {
     private static final Log log = 
LogFactory.getLog(PortletServletRequestWrapper.class);
     private ServletContext context;
-    public PortletServletRequestWrapper(ServletContext context, 
HttpServletRequest request)
+    private HttpSession session;
+    
+    public PortletServletRequestWrapper(ServletContext context, 
HttpServletRequest request, HttpSession proxiedSession)
     {
         super(request);
         this.context = context;
+        session = proxiedSession;
+        if ( proxiedSession == null )
+        {
+            session = request.getSession();
+        }
     }
 
     public String getPathInfo()
@@ -95,5 +103,10 @@
             return new PortletServletRequestDispatcher(dispatcher, path, 
false);
         else
             return null;
+    }
+
+    public HttpSession getSession()
+    {
+        return session;
     }
 }

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortlet.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortlet.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortlet.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortlet.java
 Thu Feb 22 17:28:50 2007
@@ -25,6 +25,7 @@
 import javax.portlet.PortletException;
 import javax.portlet.PortletRequest;
 import javax.portlet.PortletResponse;
+import javax.portlet.PortletSession;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.servlet.RequestDispatcher;
@@ -39,6 +40,7 @@
 import org.apache.portals.bridges.common.ServletContextProvider;
 import org.apache.portals.bridges.struts.config.StrutsPortletConfig;
 import org.apache.portals.bridges.struts.util.EmptyHttpServletResponseWrapper;
+import org.apache.portals.bridges.util.ServletPortletSessionProxy;
 
 /**
  * StrutsPortlet
@@ -56,6 +58,8 @@
      * Name of portlet preference for Struts Portlet Config Location
      */
     public static final String STRUTS_PORTLET_CONFIG_LOCATION = 
"StrutsPortletConfigLocation";
+    
+    public static final String PORTLET_SCOPE_STRUTS_SESSION = 
"PortletScopeStrutsSession";
     /**
      * Name of portlet preference for Action page
      */
@@ -97,6 +101,7 @@
      */
     private String defaultViewPage = null;
     private ServletContextProvider servletContextProvider;
+    private boolean portletScopeStrutsSession = false;
     private static final Log log = LogFactory.getLog(StrutsPortlet.class);
     public static final String REQUEST_TYPE = 
"org.apache.portals.bridges.struts.request_type";
     public static final String PAGE_URL = 
"org.apache.portals.bridges.struts.page_url";
@@ -108,6 +113,8 @@
     public static final String PORTLET_NAME = 
"org.apache.portals.bridges.struts.portlet_name";
     public static final String STRUTS_PORTLET_CONFIG = 
"org.apache.portals.bridges.struts.portlet_config";
     public static final String DEFAULT_STRUTS_PORTLET_CONFIG_LOCATION = 
"WEB-INF/struts-portlet-config.xml";
+    public static final String SERVLET_PORTLET_SESSION_PROXY = 
"org.apache.portals.bridges.util.servlet_portlet_session_proxy";
+    public static final String SERVLET_PORTLET_APPLICATION_SESSION = 
"org.apache.portals.bridges.util.servlet_portlet_application_session";
     public static final String ACTION_REQUEST = "ACTION";
     public static final String VIEW_REQUEST = "VIEW";
     public static final String CUSTOM_REQUEST = "CUSTOM";
@@ -152,6 +159,7 @@
                     + " is incorrectly configured. Invalid init parameter "
                     + PARAM_SERVLET_CONTEXT_PROVIDER + " value "
                     + contextProviderClassName);
+        this.portletScopeStrutsSession = 
getPortletScopeStrutsSessionParameter(config).booleanValue();
         this.defaultActionPage = getActionPageParameter(config);
         this.defaultCustomPage = getCustomPageParameter(config);
         this.defaultEditPage = getEditPageParameter(config);
@@ -214,12 +222,25 @@
     
     protected String getStrutsPageURL(PortletRequest request)
     {
-        return request.getParameter(StrutsPortletURL.PAGE);
+        if ( ACTION_REQUEST.equals(request.getAttribute(REQUEST_TYPE)))
+        {
+            return request.getParameter(StrutsPortletURL.PAGE);
+        }
+        return 
request.getParameter(StrutsPortletURL.PAGE+request.getPortletMode().toString());
     }
     
     protected String getStrutsOriginURL(PortletRequest request)
     {
-        return request.getParameter(StrutsPortletURL.ORIGIN);
+        if ( ACTION_REQUEST.equals(request.getAttribute(REQUEST_TYPE)))
+        {
+            return request.getParameter(StrutsPortletURL.ORIGIN);
+        }
+        return 
request.getParameter(StrutsPortletURL.ORIGIN+request.getPortletMode().toString());
+    }
+    
+    protected String getKeepRenderAttributes(PortletRequest request)
+    {
+        return 
request.getParameter(StrutsPortletURL.KEEP_RENDER_ATTRIBUTES+request.getPortletMode().toString());
     }
     
     protected String getActionPageParameter(PortletConfig config)
@@ -252,6 +273,11 @@
         return config.getInitParameter(STRUTS_PORTLET_CONFIG_LOCATION);
     }
     
+    protected Boolean getPortletScopeStrutsSessionParameter(PortletConfig 
config)
+    {
+        return 
Boolean.valueOf(config.getInitParameter(PORTLET_SCOPE_STRUTS_SESSION));
+    }
+    
     public void doEdit(RenderRequest request, RenderResponse response)
             throws PortletException, IOException
     {
@@ -286,21 +312,23 @@
         ServletContext servletContext = getServletContext(this, request, 
response);
         HttpServletRequest req = getHttpServletRequest(this, request, 
response);
         HttpServletResponse res = getHttpServletResponse(this, request, 
response);
-        HttpSession session = req.getSession();
         String portletName = this.getPortletConfig().getPortletName();
         req.setAttribute(PORTLET_NAME, portletName);
         boolean actionRequest = ACTION_REQUEST.equals(requestType);
         
+        // save requestType early so getStrutsPageURL and getStrutsOrigURL can 
determine the type
+        req.setAttribute(StrutsPortlet.REQUEST_TYPE, requestType);
+        
+        PortletSession portletSession = request.getPortletSession();
+        
         try
         {
-            StrutsPortletErrorContext errorContext = 
(StrutsPortletErrorContext) req
-                    .getSession().getAttribute(StrutsPortlet.ERROR_CONTEXT + 
"_" + portletName);
+            StrutsPortletErrorContext errorContext = 
(StrutsPortletErrorContext) 
portletSession.getAttribute(StrutsPortlet.ERROR_CONTEXT);
             if (errorContext != null)
             {
                 if (!actionRequest)
                 {
-                    req.getSession().removeAttribute(
-                            StrutsPortlet.ERROR_CONTEXT + "_" + portletName);
+                    
portletSession.removeAttribute(StrutsPortlet.ERROR_CONTEXT);
                     renderError(res, errorContext);
                 }
                 return;
@@ -310,24 +338,35 @@
             
             if ( !actionRequest )
             {
-                keepRenderAttributes = 
request.getParameter(StrutsPortletURL.KEEP_RENDER_ATTRIBUTES);
+                keepRenderAttributes = getKeepRenderAttributes(request);
             }
             if ( keepRenderAttributes == null )
             {
-                
strutsPortletConfig.getRenderContextAttributes().clearAttributes(session);
+                
strutsPortletConfig.getRenderContextAttributes().clearAttributes(portletSession);
             }
             else
             {
-                
strutsPortletConfig.getRenderContextAttributes().restoreAttributes(req);
+                
strutsPortletConfig.getRenderContextAttributes().restoreAttributes(request);
             }
                                 
             String path = null;
             String pageURL = getStrutsPageURL(request);
+            
             if (pageURL == null)
                 path = defaultPage;
             else
             {
                 path = pageURL;
+                if ( !actionRequest )
+                {
+                    // restore possible render context from the session and 
store it as request attribute for the StrutsServlet to be able to find it
+                    StrutsPortletRenderContext renderContext = 
(StrutsPortletRenderContext)portletSession.getAttribute(RENDER_CONTEXT);
+                    if ( renderContext != null )
+                    {                        
+                        portletSession.removeAttribute(RENDER_CONTEXT);
+                        req.setAttribute(RENDER_CONTEXT, renderContext);
+                    }
+                }
             }
 
             if (log.isDebugEnabled())
@@ -369,10 +408,20 @@
                     req.setAttribute(StrutsPortlet.PAGE_URL, path);
                 }
                 
-                req.setAttribute(StrutsPortlet.REQUEST_TYPE, requestType);
+                HttpSession proxiedSession = null;
+                if ( portletScopeStrutsSession )
+                {
+                    proxiedSession = 
(HttpSession)portletSession.getAttribute(SERVLET_PORTLET_SESSION_PROXY);
+                    if (proxiedSession == null)
+                    {
+                        proxiedSession = 
ServletPortletSessionProxy.createProxy(req);
+                        
portletSession.setAttribute(SERVLET_PORTLET_SESSION_PROXY, proxiedSession);
+                    }
+                }
+                req.setAttribute(SERVLET_PORTLET_APPLICATION_SESSION, 
req.getSession());
                 try
                 {
-                    rd.include(new 
PortletServletRequestWrapper(servletContext, req), res);
+                    rd.include(new 
PortletServletRequestWrapper(servletContext, req, proxiedSession), res);
                 } 
                 catch (ServletException e)
                 {
@@ -392,15 +441,13 @@
                         pageURL = StrutsPortletURL.getOriginURL(req);
                         if ( pageURL != null )
                         {    
-                          ((ActionResponse) 
response).setRenderParameter(StrutsPortletURL.PAGE, pageURL);
+                          ((ActionResponse) 
response).setRenderParameter(StrutsPortletURL.PAGE+request.getPortletMode().toString(),
 pageURL);
                         }
                         if (log.isDebugEnabled())
                             log.debug("action render error context");
                         try
                         {
-                            req.getSession(true).setAttribute(
-                                    StrutsPortlet.ERROR_CONTEXT + "_" + 
portletName,
-                                    
req.getAttribute(StrutsPortlet.ERROR_CONTEXT));
+                            
portletSession.setAttribute(StrutsPortlet.ERROR_CONTEXT,req.getAttribute(StrutsPortlet.ERROR_CONTEXT));
                         }
                         catch (IllegalStateException ise)
                         {
@@ -420,9 +467,24 @@
                         } 
                         else
                         {
-                            
strutsPortletConfig.getRenderContextAttributes().saveAttributes(req);
+                            try
+                            {
+                                
strutsPortletConfig.getRenderContextAttributes().saveAttributes(request);
+                            }
+                            catch (IllegalStateException ise)
+                            {
+                                // catch Session already invalidated exception
+                                // There isn't much we can do here other than
+                                // redirecting the user to the start page
+                                return;
+                            }
+                            StrutsPortletRenderContext renderContext = 
(StrutsPortletRenderContext)req.getAttribute(RENDER_CONTEXT);
+                            if ( renderContext != null )
+                            {
+                                portletSession.setAttribute(RENDER_CONTEXT, 
renderContext);
+                            }
                             ((ActionResponse) response).setRenderParameter(
-                                    StrutsPortletURL.KEEP_RENDER_ATTRIBUTES, 
"1");
+                                    
StrutsPortletURL.KEEP_RENDER_ATTRIBUTES+request.getPortletMode().toString(), 
"1");
 
                             if ((renderURL = (String) req
                                     
.getAttribute(StrutsPortlet.REDIRECT_PAGE_URL)) != null)
@@ -437,7 +499,7 @@
                                 if (renderURL == null && log.isWarnEnabled())
                                     log.warn("Warning: Using the original 
action URL for render URL: " +pageURL+".\nA redirect should have been issued.");
                                 ((ActionResponse) response).setRenderParameter(
-                                        StrutsPortletURL.PAGE, pageURL);
+                                        
StrutsPortletURL.PAGE+request.getPortletMode().toString(), pageURL);
                             }
                         }
                     }
@@ -481,5 +543,15 @@
             writer.println("</td></tr>");
         }
         writer.println("</table>");
+    }
+    
+    public HttpSession getApplicationSession(HttpServletRequest request)
+    {
+        HttpSession appSession = 
(HttpSession)request.getAttribute(SERVLET_PORTLET_APPLICATION_SESSION);
+        if ( appSession == null )
+        {
+            appSession = request.getSession();
+        }
+        return appSession;
     }
 }

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortletURL.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortletURL.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortletURL.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/StrutsPortletURL.java
 Thu Feb 22 17:28:50 2007
@@ -16,6 +16,7 @@
 package org.apache.portals.bridges.struts;
 
 import javax.portlet.PortletURL;
+import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
@@ -34,7 +35,7 @@
     
     public static String getPageURL(ServletRequest request)
     {
-        return request.getParameter(PAGE);
+        return (String)request.getAttribute(StrutsPortlet.PAGE_URL);
     }
     public static String getOriginURL(ServletRequest request)
     {
@@ -57,12 +58,17 @@
             if (pageURL.startsWith(contextPath))
                 pageURL = pageURL.substring(contextPath.length());
         }
-        portletURL.setParameter(PAGE, pageURL.replaceAll("&amp;","&"));
         if (actionURL)
         {
+            portletURL.setParameter(PAGE, pageURL.replaceAll("&amp;","&"));
             String originURL = request.getParameter(PAGE);
             if (originURL != null)
                 portletURL.setParameter(ORIGIN, originURL);
+        }
+        else
+        {
+            RenderRequest renderRequest = 
(RenderRequest)request.getAttribute("javax.portlet.request");
+            
portletURL.setParameter(PAGE+renderRequest.getPortletMode().toString(), 
pageURL.replaceAll("&amp;","&"));
         }
         return portletURL;
     }

Modified: 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/config/RenderContextAttributes.java
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/config/RenderContextAttributes.java?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/config/RenderContextAttributes.java
 (original)
+++ 
portals/bridges/trunk/struts/src/java/org/apache/portals/bridges/struts/config/RenderContextAttributes.java
 Thu Feb 22 17:28:50 2007
@@ -5,8 +5,8 @@
 import java.util.Enumeration;
 import java.util.List;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletSession;
 
 import org.apache.commons.digester.Digester;
 
@@ -90,6 +90,11 @@
         prefixAttributesList = new ArrayList();
     }
     
+    private static boolean isNotEmpty(String str)
+    {
+        return str != null && str.length() > 0;
+    }
+    
     private Attribute[] createArray(List attributes)
     {
         Attribute[] array = null;
@@ -146,7 +151,12 @@
         prefixAttributesList = null;
     }
     
-    public void saveAttributes(HttpServletRequest request)
+    /**
+     * Save attributes in the PortletSession. This will ensure
+     * that each portlet instance will have its own render attributes.
+     * @param request The PortletRequest
+     */
+    public void saveAttributes(PortletRequest request)
     {
         ArrayList keepAttributes = new ArrayList();
         ArrayList tempAttributes = new ArrayList();
@@ -202,23 +212,32 @@
                 keepAttributes.add(null); // indicating subsequent 
attributeValues are temporarily
                 keepAttributes.addAll(tempAttributes);
             }
-            request.getSession().setAttribute(name,keepAttributes);
+            request.getPortletSession().setAttribute(name,keepAttributes);
         }
         else if (tempAttributes.size() > 0)
         {
             tempAttributes.add(0,null); // indicating subsequent 
attributeValues are temporarily
-            request.getSession().setAttribute(name,tempAttributes);
+            request.getPortletSession().setAttribute(name,tempAttributes);
         }
     }
     
-    public void clearAttributes(HttpSession session)
+    /**
+     * Remove attributes from the PortletSession
+     * @param session The PortletSession
+     */
+    public void clearAttributes(PortletSession session)
     {
         session.removeAttribute(name);
     }
     
-    public void restoreAttributes(HttpServletRequest request)
+    /**
+     * Restore attributes from the PortletSession.
+     * @param request The portletRequest
+     */
+    public void restoreAttributes(PortletRequest request)
     {
-        ArrayList attributes = 
(ArrayList)request.getSession().getAttribute(name);
+        PortletSession portletSession = request.getPortletSession();
+        ArrayList attributes = (ArrayList)portletSession.getAttribute(name);
         if ( attributes != null )
         {
             for ( int size = attributes.size(), i = size - 1 ; i > -1; i-- )
@@ -228,7 +247,7 @@
                 {
                     if ( i == 0 )
                     {
-                        request.getSession().removeAttribute(name);
+                        portletSession.removeAttribute(name);
                     }
                     else
                     {

Modified: portals/bridges/trunk/struts/xdocs/features.xml
URL: 
http://svn.apache.org/viewvc/portals/bridges/trunk/struts/xdocs/features.xml?view=diff&rev=510753&r1=510752&r2=510753
==============================================================================
--- portals/bridges/trunk/struts/xdocs/features.xml (original)
+++ portals/bridges/trunk/struts/xdocs/features.xml Thu Feb 22 17:28:50 2007
@@ -68,6 +68,13 @@
             </a>
           </li>
           <li>
+            <a href="#1.0.1: Multiple StrutsPortlet instances PORTLET_SCOPE 
isolated StrutsServlet sessions">
+              1.0.1: Multiple StrutsPortlet instances with the StrutsServlet 
session isolated to PORTLET_SCOPE
+            </a>
+          </li>
+          
+                    
+          <li>
             Supports Struts releases 1.2.4 and 1.2.7
           </li>
         </ul>
@@ -431,6 +438,28 @@
         <p>
           Another benefit of such a "dual" mode Struts Application is that it 
can be tested as Web Application 
           which <em>is</em> somewhat easier than testing it as a Portlet.
+        </p>
+      </subsection>      
+      <subsection name="1.0.1: Multiple StrutsPortlet instances PORTLET_SCOPE 
isolated StrutsServlet sessions">
+        <p>
+          The Struts framework itself, as well as many Struts applications 
make have use of the (Servlet) Session for storing user state.
+          When you want to use multiple StrutsPortlets from the same web 
application this can cause conflicts and session state corruption.
+          With Struts Bridge release 1.0.1, this now has been solved by 
(optionally, and not by default) isolating the Session scope
+          seen by the StrutsServlet to PortletSession.PORTLET_SCOPE. 
+        </p>
+        <p>
+          If the optional StrutsPortlet init parameter 
<code>PortletScopeStrutsSession</code> is set to true, the Session object 
provided to the
+          StrutsServlet will be a Proxy for the PortletSession and will 
provide only access to the PortletSession.PORTLET_SCOPE attributes.
+        </p>
+        <p>
+          One caveat though: If you also need to use direct Servlet access to 
the Struts application (meaning: the browser is invoking the
+          Servlet directly, not through the Portlet), this Servlet won't "see" 
the previously APPLICATION_SCOPE Session attributes anymore.<br/>
+          This can be an issue for features like binary file (pdf) rendering 
through a servlet which needs to use the Session to access its data.
+          To solve this, the utility 
+          <a 
href="../portals-bridges-common/apidocs/org/apache/portals/bridges/util/PortletWindowUtils.html">PortletWindowUtils</a>
 class can
+          be used which provides methods to access a specific Portlet instance 
its PORTLET_SCOPE session attributes based on its PortletWindowId.<br/>
+          That PortletWindowId (which a Portlet can retrieve itself using the 
PortletWindowUtils) needs to be passed on to the Servlet first
+          (for example as query-string parameter on a link send to the 
browser) for it to be able to make use of it.
         </p>
       </subsection>      
     </section>



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to