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 2013/02/28 17:22:58 UTC

svn commit: r1451246 - in /myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces: bridge/ context/ util/map/

Author: mfreedman
Date: Thu Feb 28 16:22:58 2013
New Revision: 1451246

URL: http://svn.apache.org/r1451246
Log:
PORTLETBRIDGE-233: Add ability to create a dummy ExternalContext
PORTLETBRIDGE-232: Add ability for portlet to clear current request scope.
PORTLETBRIDGE-231: Request Threads can get stuck when Bridge removes a scope
PORTLETBRIDGE-221: Add explicit exclusions for trinidad in 329 branch

Modified:
    myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestMap.java
    myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java
    myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java

Modified: myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=1451246&r1=1451245&r2=1451246&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Thu Feb 28 16:22:58 2013
@@ -43,6 +43,8 @@ import java.util.Set;
 
 import java.util.Vector;
 
+import java.util.concurrent.ConcurrentLinkedQueue;
+
 import javax.el.ELContext;
 import javax.el.ELContextEvent;
 import javax.el.ELContextListener;
@@ -157,6 +159,10 @@ public class BridgeImpl
   private static final String NULL_VIEW_STATE_PARAM_VALUE = "org.apache.myfaces.portlet.faces.nullViewState";
   private static final String CACHED_VIEWROOT_LOCALE = "org.apache.myfaces.portlet.faces.cachedViewRootLocale";
   private static final String PROCESSED_PUBLIC_PARAMS ="org.apache.myfaces.portlet.faces.processedPublicParams";
+  private static final String REQUEST_SCOPE_REMOVAL_QUEUE = "org.apache.myfaces.portlet.faces.scopeRemovalQueue";
+  // Public to ADF bridge so they can clear the scope when the consumer's context has changed
+  public static final String CLEAR_REQUEST_SCOPE = "org.apache.myfaces.portlet.faces.clearRequestScope";
+  
   private static final int DEFAULT_MAX_MANAGED_REQUEST_SCOPES = 100;
 
   private Boolean mPreserveActionParams = Boolean.FALSE;
@@ -240,6 +246,13 @@ public class BridgeImpl
       if (lock == null)
       {
         portletContext.setAttribute(REQUEST_SCOPE_LOCK, new Object());
+        
+        // create the queue (for all instances) to push/hold removed
+        // request scopes through to avoid this running/blocking on the scope lock
+        ConcurrentLinkedQueue<Map<String, Object>> queue = (ConcurrentLinkedQueue<Map<String, Object>>) new ConcurrentLinkedQueue();
+        portletContext.setAttribute(REQUEST_SCOPE_REMOVAL_QUEUE, queue);
+        Thread predestroyThread = new PreDestroyNotifierThread(queue);
+        predestroyThread.start();
       }
     }
     
@@ -336,6 +349,7 @@ public class BridgeImpl
       context = getFacesContext(request, response, lifecycle, null);
    
       // in case a prior scope was managed temporarily on the session -- remove it
+      removeRequestScopes(getRequestScopeId(request));
       request.getPortletSession().removeAttribute(BRIDGE_PACKAGE_PREFIX + REQUEST_SCOPE_ID_RENDER_PARAM);
       
       // For actions we only execute the lifecycle phase
@@ -1319,6 +1333,7 @@ public class BridgeImpl
     // To make up for this we call its BridgePredestroy
     if (phase != null && phase != PortletPhase.RENDER_PHASE)
     {
+      // Call directly because outside of Scope lock
       notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
     }
   }
@@ -1335,6 +1350,7 @@ public class BridgeImpl
     // To make up for this we call its BridgePredestroy
     if (phase != null && phase != PortletPhase.RENDER_PHASE)
     {
+      // Call directly because outside of Scope lock
       notifyPreDestroy(srae.getValue()); // in outerclass (BridgeImpl)
     }
   }
@@ -1785,7 +1801,7 @@ public class BridgeImpl
       managedScopes = Integer.parseInt(managedScopesSetting);
     }
 
-    return new LRUMap(managedScopes);
+    return new LRUMap(managedScopes, (ConcurrentLinkedQueue<Map<String, Object>>) portletContext.getAttribute(REQUEST_SCOPE_REMOVAL_QUEUE));
   }
 
   @SuppressWarnings("unchecked")
@@ -1942,17 +1958,27 @@ public class BridgeImpl
       }
     }
     
-    // Only use this scope if it matches the current request mode
+
     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 )
+      // See if the Portlet has told us to clear this scope.
+      Boolean clearScope = (Boolean) request.getAttribute(CLEAR_REQUEST_SCOPE);
+      if (clearScope != null && clearScope.booleanValue())
+      {
+        clearBridgeRequestScopeData(scopeId);
+      }
+      else
+      // Only use this scope if it matches the current request mode
       {
-        // scope is for a different mode
-        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;
+        }
       }
     }
         
@@ -2003,6 +2029,7 @@ public class BridgeImpl
   
   private void clearBridgeRequestScopeData(String scopeId)
   {
+    // Call directly because outside of Scope lock
     notifyPreDestroy(getScopeMap(scopeId));
     putBridgeRequestScopeData(scopeId, Collections.EMPTY_MAP, false);
   }
@@ -2777,11 +2804,13 @@ public class BridgeImpl
      */
     private static final long serialVersionUID = 4372455368577337965L;
     private int mMaxCapacity;
+    private ConcurrentLinkedQueue<Map<String, Object>> mQueue;
 
-    public LRUMap(int maxCapacity)
+    public LRUMap(int maxCapacity, ConcurrentLinkedQueue<Map<String, Object>> notifyPreDestroyQueue)
     {
       super(maxCapacity, 1.0f, true);
       mMaxCapacity = maxCapacity;
+      mQueue = notifyPreDestroyQueue;
     }
 
     @Override
@@ -2802,9 +2831,15 @@ public class BridgeImpl
       dumpScopeId(key, "RemovePhase");
       Map<String, Object> o = super.remove(key);
       // notify attributes maintained in this object (map) they are going away
-      // Method in the outer BridgeImpl class
-      if (o != null)
-        notifyPreDestroy(o);
+      // Done by pushing the Map to a queue that another thread is pulling from
+      if (o != null) 
+      {
+        synchronized (mQueue)
+        {
+          mQueue.add(o);
+          mQueue.notifyAll();
+        }
+      }
       return o;
     }
 
@@ -2816,6 +2851,53 @@ public class BridgeImpl
     }
 
   }
+  
+  private final class PreDestroyNotifierThread extends Thread
+  {
+    ConcurrentLinkedQueue <Map<String, Object>> mQueue;
+    
+    public PreDestroyNotifierThread(ConcurrentLinkedQueue queue)
+    {
+      mQueue = queue;
+    }
+    
+    public void run()
+    {
+      ArrayList<Map<String, Object>> scopes = (ArrayList<Map<String, Object>>) new ArrayList(10);
+      while (true)
+      {
+        synchronized(mQueue)
+        {
+          while (mQueue.isEmpty())
+          {
+            try 
+            {
+              mQueue.wait();
+            }
+            catch (InterruptedException e)
+            {;}
+          }
+          
+          for (Iterator<Map<String, Object>> i = mQueue.iterator(); i.hasNext();)
+          {
+            Map m = i.next();
+            if (m != Collections.EMPTY_MAP)
+            {
+              scopes.add((Map<String, Object>)m);
+            }
+          }
+          mQueue.clear();
+        }
+        
+        for (Iterator<Map<String, Object>> i = scopes.iterator(); i.hasNext();)
+        {
+            Map<String, Object> m = i.next();
+            notifyPreDestroy(m);
+        }
+        scopes.clear();
+      }
+    }
+  }
 
   // TODO: Should we store these as attributes of the ViewTree??? It would
   // work as

Modified: myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=1451246&r1=1451245&r2=1451246&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Thu Feb 28 16:22:58 2013
@@ -279,7 +279,10 @@ public class PortletExternalContextImpl
     boolean isPortletURLSelfReference = false;
     boolean isStrictXhtmlEncoded = isStrictXhtmlEncoded(url);
     Bridge.PortletPhase urlType = Bridge.PortletPhase.ACTION_PHASE;
-
+    
+    // We support creating a dummy ExternalContext prior to activating Faces.  However this op doesn't make sense
+    assert FacesContext.getCurrentInstance() != null;
+    
     // First check to see if the special URI indicating we should encode
     // a Nonfaces target to just the current portlet (without an associated
     // path based resource).
@@ -566,6 +569,10 @@ public class PortletExternalContextImpl
   public void redirect(String url)
     throws IOException
   {
+
+    // We support creating a dummy ExternalContext (before FacesContext established) but some ops aren't available
+    assert FacesContext.getCurrentInstance() != null;
+    
     Bridge.PortletPhase phase = getPortletPhase();
     
     switch (phase)
@@ -725,6 +732,7 @@ public class PortletExternalContextImpl
   {
     if (isPortletURL(s))
     {
+      // Fails assert in dummy externalContext situation
       return urlEncode(encodeResourceAsViewNavigationURL(s));
     }
     else if (isOpaqueURL(s))
@@ -738,6 +746,7 @@ public class PortletExternalContextImpl
     }
     else if (isViewLink(s))
     {
+      // Fails assert in dummy externalContext situation
       return urlEncode(encodeResourceAsViewNavigationURL(s));
     }
     else if (!isInProtocolResourceLink(s))
@@ -947,6 +956,9 @@ public class PortletExternalContextImpl
   public void dispatch(String requestURI)
     throws IOException, FacesException
   {
+    // We support creating a dummy ExternalContext (before FacesContext established) but some ops aren't available
+    assert FacesContext.getCurrentInstance() != null;
+    
     if (requestURI == null)
     {
       throw new java.lang.NullPointerException();
@@ -1187,6 +1199,9 @@ public class PortletExternalContextImpl
 
   public String encodeNamespace(String s)
   {
+    // We support creating a dummy ExternalContext (before FacesContext established) but some ops aren't available
+    assert FacesContext.getCurrentInstance() != null;
+    
     // Supposedly if this attribute is present we are running in Liferay
     if (getRequestMap().get("THEME_DISPLAY") == null)
     {
@@ -1823,6 +1838,8 @@ public class PortletExternalContextImpl
       String backLinkValue = queryStr.removeParameter(Bridge.BACK_LINK);
       if (backLinkValue!= null)
       {
+        // We support creating a dummy ExternalContext (before FacesContext established) but some ops aren't available
+        assert context != null;
         queryStr.setParameter(backLinkValue, encodeActionURL(context.getApplication().getViewHandler().getActionURL(context, 
                                 context.getViewRoot().getViewId())), false);
       }
@@ -2225,7 +2242,7 @@ public class PortletExternalContextImpl
     int i = url.indexOf(ctxPath);
     int q = url.indexOf('?');
 
-    if (i != -1 && i < q)
+    if (i != -1 && (q == -1 || i < q))
     {
       // make sure its actually the ContextPath and not the beginning of the target.
       // I.e. avoid thinking /simple.jspx contains the context path when the CP is

Modified: myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestMap.java?rev=1451246&r1=1451245&r2=1451246&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestMap.java (original)
+++ myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestMap.java Thu Feb 28 16:22:58 2013
@@ -48,6 +48,8 @@ public class PortletRequestMap extends P
   {
     if (mPortletRequest != null)
     {
+      Object attr = mPortletRequest.getAttribute(key);
+
       // Total Hack -- The bridge has to delay computing the viewId (and 
       // hence the paths until the paths are asked for so as not to prematurely
       // read the request parameters thus avoiding exceptions from
@@ -56,8 +58,10 @@ public class PortletRequestMap extends P
       // because it doesn't read the paths from the EC -- setting the paths
       // has the side effect of setting the RI request attribute (another hack)
       // which the RI uses instead of calculating.  
-      Object attr = mPortletRequest.getAttribute(key);
-      if (attr == null && key.equals("com.sun.faces.INVOCATION_PATH"))
+      // Note: skip if using a dummy ExternalContext (one that is created
+      // before the FacesContext.
+      if (attr == null && key.equals("com.sun.faces.INVOCATION_PATH") &&
+          FacesContext.getCurrentInstance() != null)
       {
         // side effect of this will cause the viewid to be computed
         // and this attribute to be set

Modified: myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java?rev=1451246&r1=1451245&r2=1451246&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java (original)
+++ myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterMap.java Thu Feb 28 16:22:58 2013
@@ -25,7 +25,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.portlet.ActionRequest;
 import javax.portlet.PortletRequest;
+import javax.portlet.ResourceRequest;
 
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
@@ -129,8 +131,8 @@ public class PortletRequestParameterMap 
     // this indicate that during an action/resource all non-public params are private params
     
     Map <String, String[]> privateParams = mPortletRequest.getPrivateParameterMap();;
-    if ((BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.ACTION_PHASE || 
-         BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE))
+    if (mPortletRequest instanceof ActionRequest || 
+         mPortletRequest instanceof ResourceRequest)
     {
       Map<String, String[]> allParams = mPortletRequest.getParameterMap();
       Map<String, String[]> publicParams = mPortletRequest.getPublicParameterMap();

Modified: myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java?rev=1451246&r1=1451245&r2=1451246&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java (original)
+++ myfaces/portlet-bridge/core/branches/trunk_2.0.x/impl/src/main/java/org/apache/myfaces/portlet/faces/util/map/PortletRequestParameterValuesMap.java Thu Feb 28 16:22:58 2013
@@ -27,7 +27,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.portlet.ActionRequest;
 import javax.portlet.PortletRequest;
+import javax.portlet.ResourceRequest;
 
 import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
@@ -164,8 +166,8 @@ public class PortletRequestParameterValu
     // this indicate that during an action/resource all non-public params are private params
     
     Map <String, String[]> privateParams = mPortletRequest.getPrivateParameterMap();
-    if ((BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.ACTION_PHASE || 
-         BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RESOURCE_PHASE))
+    if (mPortletRequest instanceof ActionRequest || 
+        mPortletRequest instanceof ResourceRequest)
     {
       Map<String, String[]> allParams = mPortletRequest.getParameterMap();
       Map<String, String[]> publicParams = mPortletRequest.getPublicParameterMap();