You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mf...@apache.org on 2011/03/07 23:04:54 UTC

svn commit: r1078973 - in /myfaces/portlet-bridge/core/trunk_3.0.x: ./ impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/ impl/src/main/java/org/apache/myfaces/portlet/faces/context/ impl/src/main/java/org/apache/myfaces/portlet/faces/util/

Author: mfreedman
Date: Mon Mar  7 22:04:54 2011
New Revision: 1078973

URL: http://svn.apache.org/viewvc?rev=1078973&view=rev
Log:
PORTLETBRIDGE-185: Bridge NPE in restore reosurce if scope not in Map
PORTLETBRIDGE-183: Potential NPE in FacesContext.release()
PORTLETBRIDGE-99: RequestScopeListener not serializable

Modified:
    myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextFactoryImpl.java
    myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java
    myfaces/portlet-bridge/core/trunk_3.0.x/pom.xml

Modified: myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=1078973&r1=1078972&r2=1078973&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Mon Mar  7 22:04:54 2011
@@ -111,9 +111,12 @@ import javax.servlet.ServletRequestAttri
 import javax.servlet.ServletRequestAttributeListener;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionActivationListener;
 import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionBindingListener;
 
+import javax.servlet.http.HttpSessionEvent;
+
 import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgePortletRequestWrapper;
 import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgeRenderRequestWrapper;
 import org.apache.myfaces.portlet.faces.context.PortletExceptionHanderFactoryImpl;
@@ -406,7 +409,7 @@ public class BridgeImpl
           // within the same request scope but Faces does (assumes this),
           // preserve the request scope data and the Faces view tree at
           // RequestScope.
-          saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
+          saveBridgeRequestScopeData(context, scopeId, preExistingAttributes, false);
         }
 
       }
@@ -607,18 +610,7 @@ public class BridgeImpl
     FacesContext context = null;
     Lifecycle lifecycle = null;
     String scopeId = getRequestScopeId(request);
-    if (scopeId != null)
-    {
-      // Its possible we didn't detect the mode change but its the wrong scope
-      // as the scope is encoded with the mode -- confirm its right
-      StringBuffer sb = new StringBuffer(10);
-      String modeCheck = sb.append(":").append(request.getPortletMode().toString()).append(":").toString();
-      if (scopeId.indexOf(modeCheck) < 0 )
-      {
-        // scope is for a different mode
-        scopeId = null;
-      }
-    }
+
     boolean restoredScope = false;
     boolean removeScope = false;
     
@@ -713,7 +705,7 @@ public class BridgeImpl
         // within the same request scope but Faces does (assumes this),
         // preserve the request scope data and the Faces view tree at
         // RequestScope.
-        saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
+        saveBridgeRequestScopeData(context, scopeId, preExistingAttributes, false);
       }
       else
       {
@@ -866,28 +858,30 @@ public class BridgeImpl
     }
     
     
-    // never restore a scope if relying on render redirect cache or its a renderURL
-    if (redirectParams == null && !clientDirectedView && request.getParameter(PortletExternalContextImpl.RENDERURL_NO_SCOPE) == null)
-    {
-      // If available -- restore the bridge request scope before getting the
-      // FacesContext in case anything in the context construction relies
-      // on these restored values.
-      // don't restore scope if mode changed
-      scopeId = getRequestScopeId(request);
-    }
+    // Get the scopeId -- will be null if first render
+    scopeId = getRequestScopeId(request);
     
-    if (scopeId != null)
-    { 
-      restoredScope = restoreBridgeRequestScopeData(request, scopeId);
-    }
-    else
+    // First render request or a clientDirectedView
+    if (scopeId == null)
     {
       // first request 
       // create a scope and store in the session until an action occurs
       // pass null as we aren't a StateAwareResponse
       scopeId = initBridgeRequestScope(request, null);
     }
-    
+    else if (clientDirectedView)
+    {
+      // Since the client has told us the specific view to use assume we shouldn't use existing scope
+      clearBridgeRequestScopeData(scopeId);
+    }
+    else
+    {
+      // If available -- restore the bridge request scope before getting the
+      // FacesContext in case anything in the context construction relies
+      // on these restored values.
+      // don't restore scope if mode changed
+      restoredScope = restoreBridgeRequestScopeData(request, scopeId);
+    } 
 
     FacesContext context = null;
     try
@@ -1001,8 +995,6 @@ public class BridgeImpl
       )
     throws BridgeException, BridgeUninitializedException, NullPointerException
   {
-    boolean redirectedDuringRender = false;
-
     // Note: if the scope wasn't restored then the Faces
     // FACES_VIEW_STATE
     // parameter will not have been carried into this render and hence
@@ -1050,11 +1042,10 @@ public class BridgeImpl
     else
     {
       redirectRender(context,
-        lifecycle, request, response,
+        lifecycle, request, response, scopeId,
         redirectParams, preExistingAttributes);
       
       context = FacesContext.getCurrentInstance();
-      redirectedDuringRender = true;
     }
 
 
@@ -1067,34 +1058,26 @@ public class BridgeImpl
     if ((redirectParams != null))
     {
       redirectRender(context,
-        lifecycle, request, response,
+        lifecycle, request, response, scopeId,
         redirectParams, preExistingAttributes);
       context = FacesContext.getCurrentInstance();
-      redirectedDuringRender = true;
     }
 
-    // At a minimum we need to update the VIEW_STATE_PARAM being maintained
-    // However, if this is a resource request then we also update the full scope
-
-    // Don't update if we have redirected during this render instead remove the scope
-    if (scopeId != null && !redirectedDuringRender)
-    {
-      context.getExternalContext().getRequestMap().put(SCOPE_VIEW_KEY, getScopeViewKey(context.getExternalContext()));
-      saveFacesMessageState(context);
-      saveBridgeRequestScopeData(context, scopeId, preExistingAttributes);
-      updateViewInfo(context, scopeId);
-    }
-    else
+    if (scopeId == null) 
     {
-      if (scopeId != null) removeRequestScopes(scopeId); 
-      // start a new/empty in session scope -- merely add the key used to discriminate whether 
-      // a follow-on resource request targets the same view as the render (PPR) or a different view (iFrame)
-      scopeId = initBridgeRequestScope(request, null);
-      HashMap<String, Object> m = (HashMap<String, Object>) new HashMap();
-      m.put(SCOPE_VIEW_KEY, getScopeViewKey(context.getExternalContext()));
-      putBridgeRequestScopeData(scopeId, m);
-      updateViewInfo(context, scopeId);
+      if (!mDebugLoggingEnabled.booleanValue())
+        context.getExternalContext().log("WARNING: Unexpected situation -- reached end of internal doFacesRender without a scopeId");
+      
+      // Don't expect to get here -- but just create a new scope
+      scopeId = createBridgeRequestScope(request);
     }
+    
+    // At a minimum we need to update the VIEW_STATE_PARAM being maintained
+    // However, if this is a resource request then we also update the full scope
+    context.getExternalContext().getRequestMap().put(SCOPE_VIEW_KEY, getScopeViewKey(context.getExternalContext()));
+    saveFacesMessageState(context);
+    saveBridgeRequestScopeData(context, scopeId, preExistingAttributes, BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE);
+    updateViewInfo(context, scopeId);
   }
 
   public void doFacesRequest(ResourceRequest request, ResourceResponse response)
@@ -1531,6 +1514,7 @@ public class BridgeImpl
                               Lifecycle lifecycle,
                               PortletRequest request,
                               MimeResponse response,
+                              String scopeId,
                               QueryString redirectParams,
                               List<String> preExistingAttrs)
   {
@@ -1551,9 +1535,16 @@ public class BridgeImpl
     // into the new wrapped request so the redirect will use include
     Boolean hasRenderRedirectedAfterForward = (Boolean) request.getAttribute(HAS_RENDER_REDIRECTED_AFTER_FORWARD);
     
+    // Reset the scope
+    if (scopeId != null)
+    {
+      clearBridgeRequestScopeData(scopeId);
+    }
+    
     // close the FacesContext
     context.release();
     
+    
     // Now put the HAS_RENDER_REDIRECTED_AFTER_FORWARDflag back
     if (hasRenderRedirectedAfterForward != null)
     {
@@ -1573,7 +1564,7 @@ public class BridgeImpl
     context.getExternalContext().getSessionMap().remove(BridgeImpl.RENDER_REDIRECT_VIEWPARAMS);
     
     // Run lifecycle.execute again ... then render
-    doFacesRender(request, response, context, lifecycle, null, preExistingAttrs);
+    doFacesRender(request, response, context, lifecycle, scopeId, preExistingAttrs);
     
     // Reacquire the context as it may have changed if a recursive redirect render occurred
     context = FacesContext.getCurrentInstance();
@@ -1937,8 +1928,17 @@ public class BridgeImpl
       return initBridgeRequestScope(request, null);
     }
     
-    // Check to see if this resource request is targeting the same view or a different one
     Map<String, Object> m = getScopeMap(scopeId);
+    
+    // If the scope is actually empty then this is first request -- hence 
+    // the resource must be targeting the same view
+    if (m == null || m.equals(Collections.EMPTY_MAP))
+    {
+      putBridgeRequestScopeData(scopeId, Collections.EMPTY_MAP, false);
+      return scopeId;
+    }
+    
+    // Check to see if this resource request is targeting the same view or a different one
     Map<String, String> childResourceScopeMap = (Map<String, String>) m.get(CHILD_RESOURCE_REQUEST_SCOPE_MAP);
     String scopeIdKey = (String) m.get(SCOPE_VIEW_KEY);
     String childIdKey = getScopeViewKey(extCtx);
@@ -1961,6 +1961,8 @@ public class BridgeImpl
       if (childScopeId == null)
       {
         childScopeId = createBridgeRequestScope(request);
+        // place scope in the scopeMap
+        clearBridgeRequestScopeData(childScopeId);
         
         if (childResourceScopeMap == null)
         {
@@ -1991,7 +1993,6 @@ public class BridgeImpl
 
   private String getRequestScopeId(PortletRequest request)
   {
-    boolean fromSession = false;
     String scopeId = request.getParameter(REQUEST_SCOPE_ID_RENDER_PARAM);
 
     if (scopeId == null)
@@ -2000,7 +2001,6 @@ public class BridgeImpl
       if (session != null)
       {
         scopeId = (String) session.getAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM);
-        fromSession = true;
       }
     }
     
@@ -2036,10 +2036,14 @@ public class BridgeImpl
 
   private String initBridgeRequestScope(PortletRequest request, StateAwareResponse response)
   {
-
+    // This call just gets us a new scopeId
 
     String requestScopeId = createBridgeRequestScope(request);
+    
+    // This call ensures the new scopeId is in the ScopeMap 
+    clearBridgeRequestScopeData(requestScopeId);
 
+    // Now ensure the scopeId can be recovered in the next request
     if (response != null)
     {
       // set in response render parameter so will receive in future calls
@@ -2057,21 +2061,28 @@ public class BridgeImpl
 
     return requestScopeId;
   }
+  
+  private void clearBridgeRequestScopeData(String scopeId)
+  {
+    notifyPreDestroy(getScopeMap(scopeId));
+    putBridgeRequestScopeData(scopeId, Collections.EMPTY_MAP, false);
+  }
 
   private void saveBridgeRequestScopeData(FacesContext context, String scopeId, 
-                                          List<String> preExistingList)
+                                          List<String> preExistingList, boolean mergeExisting)
   {
     // Store the RequestMap @ the bridge's request scope
     putBridgeRequestScopeData(scopeId, 
-                              copyRequestMap(context.getExternalContext().getRequestMap(), preExistingList));
+                              copyRequestMap(context.getExternalContext().getRequestMap(), preExistingList), mergeExisting);
 
     // flag the data so can remove it if the session terminates
     // as its unlikely useful if the session disappears
     watchScope(context, scopeId);
   }
+  
 
   @SuppressWarnings("unchecked")
-  private void putBridgeRequestScopeData(String scopeId, Map<String, Object> o)
+  private void putBridgeRequestScopeData(String scopeId, Map<String, Object> o, boolean mergeExisting)
   {
     PortletContext portletContext = mPortletConfig.getPortletContext();
 
@@ -2087,8 +2098,8 @@ public class BridgeImpl
         requestScopeMap = createRequestScopeMap(portletContext);
         portletContext.setAttribute(REQUEST_SCOPE_MAP, requestScopeMap);
       }
-      
-      if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE)
+    
+      if (mergeExisting)
       {
         // Because we didn't restore them at the beginning of the request
         // Merge any existing scope attributes that weren't written during this request
@@ -2528,6 +2539,11 @@ public class BridgeImpl
   // notify this scope's attributes that they are being removed
   private void notifyPreDestroy(Map<String, Object> scope)
   {
+    if (scope == null || scope.equals(Collections.EMPTY_MAP))
+    {
+      return;
+    }
+    
     // Scopes can now contain a Map to child scopes -- first check to see if this scope 
     // contains such a Map -- if so them remove these scopes too.
     Map<String, String> childMap = (Map<String, String>) scope.get(CHILD_RESOURCE_REQUEST_SCOPE_MAP);
@@ -2573,6 +2589,45 @@ public class BridgeImpl
       }
     }
   }
+  
+  // tests to see if any scopes exist that start with the given prefix
+  // used during session reactivation to test/remove session attr (listener) that is no longer needed
+  private boolean hasRequestScopes(String scopePrefix)
+  {
+
+    if (scopePrefix == null || mPortletConfig == null)
+      return false; // Nothing to do -- later case is the session is destroyed after the context
+
+    // Get the RequestScope Map and remove all entries/scopes with this prefix
+    PortletContext portletContext = mPortletConfig.getPortletContext();
+
+    // Get the request scope lock -- because its added during init it should
+    // always be there.
+    Object lock = portletContext.getAttribute(REQUEST_SCOPE_LOCK);
+    if (lock == null)
+      return false;
+
+    synchronized (lock)
+    {
+      // get the managedScopeMap
+      LRUMap requestScopeMap = (LRUMap) portletContext.getAttribute(REQUEST_SCOPE_MAP);
+
+      if (requestScopeMap != null)
+      {
+        Iterator<String> iterator = requestScopeMap.keySet().iterator();
+        while (iterator.hasNext())
+        {
+          String scopeId = iterator.next();
+          if (scopeId != null && scopeId.startsWith(scopePrefix))
+          {
+            // found one
+            return true;
+          }
+        }
+      }
+    }
+    return false;
+  }
 
   private void removeRequestScopes(String scopePrefix)
   {
@@ -2872,10 +2927,10 @@ public class BridgeImpl
     }
   }
 
-  private final class RequestScopeListener
-    implements HttpSessionBindingListener
+  private final class RequestScopeListener 
+    implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable
   {
-    String mScopePrefix = null;
+    String mScopePrefix = null; 
 
     public RequestScopeListener(String scopePrefix)
     {
@@ -2889,8 +2944,46 @@ public class BridgeImpl
 
     public void valueUnbound(HttpSessionBindingEvent event)
     {
-      // Call is in the BridgeImpl class
+      // Call is in the BridgeImpl class -- note check for null 
+      // If we have passivated/reactivated
+      if (mScopePrefix != null)
+      {
+        removeRequestScopes(mScopePrefix);
+      }
+    }
+    
+    public void sessionWillPassivate(HttpSessionEvent se)
+    {  
+      // TODO: is passivate only called when the session is migrated or just saved?
+      //     -- i.e. is this a safe time to remove the scopes from the AppContext in the "old" context?
+      //     Until we get confirmation that it is -- do not remove
+      /*
       removeRequestScopes(mScopePrefix);
+      
+      RequestScopeListener rl = (RequestScopeListener) se.getSession().getAttribute(REQUEST_SCOPE_LISTENER);
+      if (rl != null && rl.equals(this))
+      {
+        se.getSession().removeAttribute(REQUEST_SCOPE_LISTENER);
+      }
+      
+      mScopePrefix = null;
+      */
+
+    }
+
+    public void sessionDidActivate(HttpSessionEvent se)
+    {
+      // If we migrsated to a new Context or otherwise can't reach these scopes anymore then 
+      // drop the listener.
+      if (!hasRequestScopes(mScopePrefix))
+      {
+        RequestScopeListener rl = (RequestScopeListener) se.getSession().getAttribute(REQUEST_SCOPE_LISTENER);
+        if (rl != null && rl.equals(this))
+        {
+          se.getSession().removeAttribute(REQUEST_SCOPE_LISTENER);
+        }
+        mScopePrefix = null;
+      }
     }
   }
 }

Modified: myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=1078973&r1=1078972&r2=1078973&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Mon Mar  7 22:04:54 2011
@@ -105,6 +105,8 @@ public class PortletExternalContextImpl
   // you try and add an attribute you don't want exlcuded within this package.
   private static final String ENCODED_ACTION_URL_ATTRIBUTE_PREFIX =
     "org.apache.myfaces.portlet.faces.context.";
+  
+  public static final String BOOKMARKABLE_URL = "_jsfBridgeBookmarkableUrl";  
 
   public static final String RENDER_POLICY_ATTRIBUTE = 
     Bridge.BRIDGE_PACKAGE_PREFIX + "." + Bridge.RENDER_POLICY;
@@ -491,7 +493,7 @@ public class PortletExternalContextImpl
       BaseURL baseURL = null;
       
       // first test if the url has been explicitly marked as bookmarkable
-      String bookmarkableURL = queryStr.getParameter(Bridge.BOOKMARKABLE_URL);
+      String bookmarkableURL = queryStr.getParameter(BOOKMARKABLE_URL);
       if (bookmarkableURL != null)
       {
         urlType = Bridge.PortletPhase.RENDER_PHASE;
@@ -503,7 +505,7 @@ public class PortletExternalContextImpl
         }
       }
       // Always remove - even if not there/not true
-      queryStr.removeParameter(Bridge.BOOKMARKABLE_URL);
+      queryStr.removeParameter(BOOKMARKABLE_URL);
       
       // Non-JSF actions are renderURLs as we merely dispatch to them
       if (urlType == Bridge.PortletPhase.ACTION_PHASE)
@@ -675,14 +677,14 @@ public class PortletExternalContextImpl
     // the special QS parameter as this QS param with a value of false means 
     // the scope should be added -- as one sees the default is a renderUrl without
     // scope -- so if its already exists in the QS its likely a redisplay url
-    if (!baseUrl.contains(Bridge.BOOKMARKABLE_URL))
+    if (!baseUrl.contains(BOOKMARKABLE_URL))
     {
       HashMap<String,List<String>> params = new HashMap<String,List<String>>(parameters);
       
       // add a new parameter that signifies its a render/bookmarkable  url
       ArrayList<String> val = new ArrayList(1);
       val.add(0, "true");
-      params.put(Bridge.BOOKMARKABLE_URL, val);
+      params.put(BOOKMARKABLE_URL, val);
       return URLUtils.appendURLArguments(baseUrl, params);
     }
     else

Modified: myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextFactoryImpl.java?rev=1078973&r1=1078972&r2=1078973&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextFactoryImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletFacesContextFactoryImpl.java Mon Mar  7 22:04:54 2011
@@ -182,24 +182,27 @@ public class PortletFacesContextFactoryI
       
       @SuppressWarnings("unchecked")
       List<String> preExistingAttrs = (List<String>)reqAttrs.get(BridgeImpl.PREEXISTING_ATTRIBUTE_NAMES);
-      ArrayList<String> removeList = (ArrayList<String>) new ArrayList(preExistingAttrs.size());
-
-
-      Set<String> keys= reqAttrs.keySet();
-      
-      for(String key:keys)
+      if (preExistingAttrs != null)
       {
-        if (!preExistingAttrs.contains(key))
+        ArrayList<String> removeList = (ArrayList<String>) new ArrayList(preExistingAttrs.size());
+  
+  
+        Set<String> keys= reqAttrs.keySet();
+        
+        for(String key:keys)
         {
-          // Postpone the remove until after the iteration as it causes a ConcurrentModificationException on some appServers (WebSphere)
-          removeList.add(key);
+          if (!preExistingAttrs.contains(key))
+          {
+            // Postpone the remove until after the iteration as it causes a ConcurrentModificationException on some appServers (WebSphere)
+            removeList.add(key);
+          }
+        }
+        
+        // Postpone the remove until after the iteration as it causes a ConcurrentModificationException on some appServers (WebSphere)
+        for(Iterator<String> iter = removeList.iterator(); iter.hasNext();)
+        {
+          reqAttrs.remove(iter.next());
         }
-      }
-      
-      // Postpone the remove until after the iteration as it causes a ConcurrentModificationException on some appServers (WebSphere)
-      for(Iterator<String> iter = removeList.iterator(); iter.hasNext();)
-      {
-        reqAttrs.remove(iter.next());
       }
       
       if(ec instanceof PortletExternalContextImpl)

Modified: myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java?rev=1078973&r1=1078972&r2=1078973&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java (original)
+++ myfaces/portlet-bridge/core/trunk_3.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/QueryString.java Mon Mar  7 22:04:54 2011
@@ -19,6 +19,7 @@
 
 package org.apache.myfaces.portlet.faces.util;
 
+import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -31,7 +32,7 @@ import java.util.Map;
 /**
  * A class encapsulating an HTTP query string.
  */
-public final class QueryString
+public final class QueryString implements Serializable
 {
   private String mQueryString;
   private String mCharacterEncoding;
@@ -440,7 +441,7 @@ public final class QueryString
     }
   }
 
-  private class Parameter
+  private class Parameter implements Serializable
   {
     private String mName;
     private String mEncodedName;

Modified: myfaces/portlet-bridge/core/trunk_3.0.x/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk_3.0.x/pom.xml?rev=1078973&r1=1078972&r2=1078973&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk_3.0.x/pom.xml (original)
+++ myfaces/portlet-bridge/core/trunk_3.0.x/pom.xml Mon Mar  7 22:04:54 2011
@@ -46,8 +46,8 @@
     <portletSpecVersion>2.0</portletSpecVersion>
     <jsfSpecVersion>2.0</jsfSpecVersion>
     <specVersion>1.0</specVersion>
-    <jsrNumber>329</jsrNumber>
-    <specLink>http://www.jcp.org/en/jsr/detail?id=${jsrNumber}</specLink>
+    <jsrNumber>xxx</jsrNumber>
+    <!-- <specLink>http://www.jcp.org/en/jsr/detail?id=${jsrNumber}</specLink> -->
     <specName>Portlet ${portletSpecVersion} Bridge for JavaServer Faces ${jsfSpecVersion}</specName>
     <projectSeries>3.x</projectSeries>
     <mojarra.version>2.0.1</mojarra.version>