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 2009/06/10 22:11:32 UTC

svn commit: r783484 - in /myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces: bridge/ context/ el/ util/

Author: mfreedman
Date: Wed Jun 10 20:11:32 2009
New Revision: 783484

URL: http://svn.apache.org/viewvc?rev=783484&view=rev
Log:
PORTLETBRIDGE-80: Update EL variable names for portlet 2.0 
PORTLETBRIDGE-79: Process JSP EL differently than JSF_IMPL_TITLE
PORTLETBRIDGE-78: ELResolver returns wrong PortletConfig
PORTLETBRIDGE-77: detect versions for version dependent workarounds.

Added:
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/FacesVersionUtil.java
Modified:
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java?rev=783484&r1=783483&r2=783484&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/bridge/BridgeImpl.java Wed Jun 10 20:11:32 2009
@@ -91,6 +91,7 @@
 
 import org.apache.myfaces.portlet.faces.bridge.wrapper.BridgeRenderRequestWrapper;
 import org.apache.myfaces.portlet.faces.context.PortletExternalContextImpl;
+import org.apache.myfaces.portlet.faces.el.PortletELContextImpl;
 import org.apache.myfaces.portlet.faces.util.QueryString;
 import org.apache.myfaces.portlet.faces.util.config.FacesConfigurationProcessor;
 import org.apache.myfaces.portlet.faces.util.config.WebConfigurationProcessor;
@@ -185,17 +186,14 @@
       }
     }
 
-    // Add self as ELContextListener to the Faces App so we can add the
-    // portletConfig to any newly created contexts.
-    ApplicationFactory appFactory = 
-      (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);
-    
     // Wrapped desired Application with our own to override createComponent and
     // insert our NamingContainerUIViewRoot component.  This was done through
     // configuration via the META-INF/service/javax.faces.application.ApplicationFactory
-    Application app = appFactory.getApplication();
-
-    app.addELContextListener(this);
+    
+    // Add self as ELContextListener to the Faces App so we can add the
+    // portletConfig to any newly created contexts.    
+    ((ApplicationFactory)FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY))
+        .getApplication().addELContextListener(this);
 
     // Process and cache the FacesServlet mappings for use by
     // ExternalContext
@@ -740,10 +738,38 @@
     // Add the portletConfig to the ELContext so it is evaluated
     ELContext elContext = ece.getELContext();
 
-    // Only add if not already there
-    if (elContext.getContext(PortletConfig.class) == null)
-    {
-      elContext.putContext(PortletConfig.class, mPortletConfig);
+    // FacesContext (where the Faces/Bridge ELContext is created doesn't have
+    // access to the PortletConfig which the Bridge ELResolver needs.
+    // The config object is added as an attribute here in the ContextListener.
+    // However only add to a EL context created within Faces as the JSP
+    // ELContext/Resolver will naturally resolve the config (as long as the
+    // page devleper has used the <portlet:defineObjects> tag.
+    // Because listeners are called at app scope we must ensure that only
+    // the active portlet's config is added to the ELContext.  To do this, check
+    // the portletName previously stored as a request attribute against the config.
+    
+    // Make sure our bridge instance is handling this context
+    String portletName = (String) ((FacesContext) elContext.getContext(FacesContext.class)).getExternalContext().getRequestMap().get(PORTLET_NAME_ATTRIBUTE);
+    if (portletName != null && portletName.equals(mPortletConfig.getPortletName()))
+    {
+      PortletELContextImpl portletELContext;
+      if (elContext instanceof PortletELContextImpl)
+      {
+        // Grr -- turns out that by the time my resolver is called the ELContext may
+        // have been wrapped -- so mark here as a FacesResolver and then do a put context
+        portletELContext = (PortletELContextImpl) elContext;
+        portletELContext.setFacesResolved(true);
+        // Put the portletConfig object into this Map
+        portletELContext.setPortletConfig(mPortletConfig);
+
+      }
+      else
+      {
+        // create a PortletELContext to hold future resolver state and place on this context
+        portletELContext = new PortletELContextImpl(elContext.getELResolver());
+        portletELContext.setFacesResolved(false);
+      }
+      elContext.putContext(PortletELContextImpl.class, portletELContext);
     }
   }
 

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=783484&r1=783483&r2=783484&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Wed Jun 10 20:11:32 2009
@@ -64,6 +64,7 @@
 import javax.portlet.faces.BridgeUtil;
 
 import org.apache.myfaces.portlet.faces.bridge.BridgeImpl;
+import org.apache.myfaces.portlet.faces.util.FacesVersionUtil;
 import org.apache.myfaces.portlet.faces.util.QueryString;
 import org.apache.myfaces.portlet.faces.util.URLUtils;
 import org.apache.myfaces.portlet.faces.util.map.EnumerationIterator;
@@ -88,6 +89,12 @@
 
   public static final String FACES_MAPPING_ATTRIBUTE = 
     "org.apache.myfaces.portlet.faces.context.facesMapping";
+  
+  // Note: be careful -- as this attribute is prefixed to a value containg '.' it
+  // wouldn't be exlcuded using normal logic -- so instead BridgeImpl specially
+  // exlcudes/treats this package. -- i.e. all attrbiutes beginning with 
+  // "org.apache.myfaces.portlet.faces.context." are excluded -- so beware if
+  // 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.";
 
@@ -97,6 +104,9 @@
   // Render parameter to store the viewId
   public static final String JSF_TARGET_VIEWID_RENDER_PARAMETER = "__jpfbJSFTARGET";
   public static final String NO_SCOPE = "org.apache.myfaces.portlet.faces.noScope";
+  
+  public static final String SERVLET_INCLUDED_PATHINFO_ATTRIBUTE = "javax.servlet.include.path_info";
+  public static final String SERVLET_INCLUDED_SERVLETPATH_ATTRIBUTE = "javax.servlet.include.servlet_path";
 
 
   private PortletContext mPortletContext;
@@ -134,6 +144,10 @@
   private List<String> mFacesMappings = null;
   private String mServletPath = null;
   private String mPathInfo = null;
+  private String mIncludedServletPath = null;
+  private String mIncludedPathInfo = null;
+  
+  private boolean mUseIncludeAttributeServletDependencyWorkaround;
 
 
   @SuppressWarnings("unchecked")
@@ -149,12 +163,72 @@
 
     mFacesMappings = (List<String>) mPortletRequest.getAttribute(FACES_MAPPING_ATTRIBUTE);
     
+    setFacesVersionDependencyFlags();
+    
+    // Local portals commonly use the servlet dispatcher to execute the portlet container
+    // A side effect of this is the javax.servlet.include path attributes are set
+    // Unfortunately, Faces resolves viewId targets by first looking at these attributes 
+    // prior to consulting the externalContext (request info).  To avoid Faces
+    // from using these bad values -- clear them by caching them (we restore on release)
+    mIncludedPathInfo = (String) mPortletRequest.getAttribute(SERVLET_INCLUDED_PATHINFO_ATTRIBUTE);
+    mIncludedServletPath = (String) mPortletRequest.getAttribute(SERVLET_INCLUDED_SERVLETPATH_ATTRIBUTE);
+    mPortletRequest.removeAttribute(SERVLET_INCLUDED_PATHINFO_ATTRIBUTE);
+    mPortletRequest.removeAttribute(SERVLET_INCLUDED_SERVLETPATH_ATTRIBUTE);
+    
     // Because determining the view accesses request parameters -- delay until its demanded
     // so clients can still set request character encoding.
   }
+  
+  /**
+   * Sometimes the bridge has to workaround issues related to specific versions of a Faces
+   * implementation that can't be done in a generic/unobtrusive way.  Here we try to determine
+   * which workarounds should be enabled.  Currently there is onyl one: Faces RI (Mojarra) versions
+   * before 1.2_13 contained some servlet dependent code that gets hit during view resolution unless
+   * the bridge has set the ServletPath include attribute.  Unfortunately, Liferay (5.2) portlet container
+   * also writes/uses this attribute.  
+   */
+  private void setFacesVersionDependencyFlags()
+  {
+    mUseIncludeAttributeServletDependencyWorkaround = true;
+    // First check to see if there is a web.xml init parameter setting 
+    String disable = mPortletContext.getInitParameter("org.apache.myfaces.portlet.bridge.disableMojarraViewResolutionWorkaround");
+    if (disable != null)
+    {
+      mUseIncludeAttributeServletDependencyWorkaround = !Boolean.valueOf(disable).booleanValue();
+    }
+    else
+    {
+    switch (FacesVersionUtil.getFacesType())
+      {
+        case MOJARRA:
+          if (FacesVersionUtil.getFacesImplPatchVersion() >= 13)
+          {
+            mUseIncludeAttributeServletDependencyWorkaround = false;
+          }
+          break;
+        case MYFACES:
+          mUseIncludeAttributeServletDependencyWorkaround = false;
+          break;
+        default:
+          mUseIncludeAttributeServletDependencyWorkaround = true;
+          break;
+      }
+    }
+  }
+  
 
   public void release()
   {
+    
+    // Restore the included path attributes if we unset them
+    if (mIncludedPathInfo != null)
+    {
+      mPortletRequest.setAttribute(SERVLET_INCLUDED_PATHINFO_ATTRIBUTE, mIncludedPathInfo);
+    }
+    if (mIncludedServletPath != null)
+    {
+      mPortletRequest.setAttribute(SERVLET_INCLUDED_SERVLETPATH_ATTRIBUTE, mIncludedServletPath);
+    }
 
     mPortletContext = null;
     mPortletRequest = null;
@@ -1425,7 +1499,9 @@
       mPathInfo = null;
 
       // Workaround Faces RI that has Servlet dependencies if this isn't set
-      mPortletRequest.setAttribute("javax.servlet.include.servlet_path", mServletPath);
+      // Workaround Faces RI that has Servlet dependencies if this isn't set
+      if (mUseIncludeAttributeServletDependencyWorkaround)
+        mPortletRequest.setAttribute(SERVLET_INCLUDED_SERVLETPATH_ATTRIBUTE, mServletPath);
     }
     else
     {

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java?rev=783484&r1=783483&r2=783484&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELContextImpl.java Wed Jun 10 20:11:32 2009
@@ -19,11 +19,16 @@
 
 package org.apache.myfaces.portlet.faces.el;
 
+import java.util.Map;
+
 import javax.el.ELContext;
 import javax.el.ELResolver;
 import javax.el.FunctionMapper;
 import javax.el.VariableMapper;
 
+import javax.portlet.PortletConfig;
+import javax.portlet.faces.preference.Preference;
+
 /**
  * Concrete implementation of {@link javax.el.ELContext}. ELContext's constructor is protected to
  * control creation of ELContext objects through their appropriate factory methods. This version of
@@ -32,10 +37,15 @@
  */
 public class PortletELContextImpl extends ELContext
 {
-
+  
   private FunctionMapper mFunctionMapper;
   private VariableMapper mVariableMapper;
   private ELResolver     mResolver;
+  private PortletConfig  mPortletConfig;
+  private Map<String, Object> mHttpSessionMap;
+  private Map<String, Preference> mMutablePortletPreferencesMap;
+  private boolean mIsFacesResolved = false;
+  
 
   /**
    * Constructs a new ELContext associated with the given ELResolver.
@@ -72,5 +82,45 @@
   {
     return mResolver;
   }
+  
+  public PortletConfig getPortletConfig()
+  {
+    return mPortletConfig;
+  }
+  
+  public void setPortletConfig(PortletConfig config)
+  {
+    mPortletConfig = config;
+  }
+  
+  public Map<String, Object> getHttpSessionMap()
+  {
+    return mHttpSessionMap;
+  }
+  
+  public void setHttpSessionMap(Map<String, Object> m)
+  {
+    mHttpSessionMap = m;
+  }
+  
+  public Map<String, Preference> getMutablePortletPreferencesMap()
+  {
+    return mMutablePortletPreferencesMap;
+  }
+  
+  public void setMutablePortletPreferencesMap(Map<String, Preference> m)
+  {
+    mMutablePortletPreferencesMap = m;
+  }
+  
+  public boolean isFacesResolved()
+  {
+    return mIsFacesResolved;
+  }
+  
+  public void setFacesResolved(boolean facesResolved)
+  {
+    mIsFacesResolved = facesResolved;
+  }
 
 }

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java?rev=783484&r1=783483&r2=783484&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/el/PortletELResolver.java Wed Jun 10 20:11:32 2009
@@ -34,12 +34,14 @@
 import javax.el.PropertyNotWritableException;
 import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
+
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletPreferences;
 import javax.portlet.PortletRequest;
 import javax.portlet.PortletSession;
 import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
+import javax.portlet.faces.Bridge;
 import javax.portlet.faces.BridgeUtil;
 import javax.portlet.faces.preference.Preference;
 
@@ -47,286 +49,410 @@
 import org.apache.myfaces.portlet.faces.preference.PreferenceImpl;
 
 public class PortletELResolver extends ELResolver
-{
-
-  // Important preserve index (order) between array and constants
-  // Just as important -- we binary search this array
-  // So it must be in alphabetic order
-  public static final String[] IMPLICIT_OBJECTS = new String[] {"portletConfig",
-      "portletPreferences",
-      "renderRequest", "renderResponse", 
-      "sessionApplicationScope", "sessionPortletScope"};
-
-  public static final int      PORTLET_CONFIG            = 0;
-  public static final int      PORTLET_PREFERENCES       = 1;
-  public static final int      RENDER_REQUEST            = 2;
-  public static final int      RENDER_RESPONSE           = 3;
-  public static final int      SESSION_APPLICATION_SCOPE = 4;
-  public static final int      SESSION_PORTLET_SCOPE     = 5;
-
-  public PortletELResolver()
   {
-  }
 
-  @Override
-  public Object getValue(ELContext context, Object base, Object property) throws ELException
-  {
-    // variable resolution is a special case of property resolution
-    // where the base is null.
-    if (property == null)
-    {
-      throw new PropertyNotFoundException("Null property");
+    // All are recognized/processed when its a Faces EL resolve
+    // While only those that are marked are recognized/processed when its a JSP EL resolve
+    public static enum BRIDGE_IMPLICT_OBJECTS_ENUM 
+    {
+      portletConfig,
+      
+      // request releated
+      renderRequest,
+      renderResponse,
+      
+      // session related
+      httpSessionScope, // also supported in a JSP EL resolve
+      portletSession, // also supported in a JSF EL resolve
+      portletSessionScope, // also supported in a JSF EL resolve
+      
+      // preference related
+      mutablePortletPreferencesValues,  // also supported in a JSP EL resolve
+      portletPreferences, // also supported in a JSF EL resolve
+      portletPreferencesValues // also supported in a JSF EL resolve
     }
+    
 
-    FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
-    ExternalContext extCtx = facesContext.getExternalContext();
-
-    // only process if running in a portlet request
-    if (!BridgeUtil.isPortletRequest() || base != null)
+    public PortletELResolver()
     {
-      return null;
     }
 
-    int index = -1;
-    if (property instanceof String)
-    {
-      index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
+    @Override
+    public Object getValue(ELContext context, Object base, Object property) throws ELException
+    {
+      // variable resolution is a special case of property resolution
+      // where the base is null.
+      if (property == null)
+      {
+        throw new PropertyNotFoundException("Null property");
+      }
+      
+      // only process if running in a portlet request
+      if (!BridgeUtil.isPortletRequest() || base != null)
+      {
+        return null;
+      }
+      
+      // Recognize whether we are resolving in a Faces context or JSP context 
+      // as the resolution differs.  I.e. in the JSP context we defer to
+      // its implicit object resolver to resolve the <portlet:defineObjects> objects.
+      PortletELContextImpl portletELContext = (PortletELContextImpl) context.getContext(PortletELContextImpl.class);
+      
+      if (portletELContext == null)
+      {
+        return null;
+      }
+      
+      return getResolvedValue(context, portletELContext, base, property, portletELContext.isFacesResolved());
     }
-    switch (index)
-    {
-      case RENDER_REQUEST:
-        context.setPropertyResolved(true);
-        return extCtx.getRequest();
-      case RENDER_RESPONSE:
-        context.setPropertyResolved(true);
-        return extCtx.getResponse();
-      case PORTLET_CONFIG:
-         context.setPropertyResolved(true);
-        return context.getContext(PortletConfig.class);
-      case SESSION_APPLICATION_SCOPE:
-        context.setPropertyResolved(true);
-        Map m = (Map) extCtx.getRequestMap().get("javax.portlet.faces.SessionApplicationScopeMap");
-        if (m == null)
+    
+    private Object getResolvedValue(ELContext context,
+                                         PortletELContextImpl bridgeContext,
+                                         Object base,
+                                         Object property,
+                                         boolean isFacesResolved)
+    throws ELException
+    {
+    
+      FacesContext facesContext = (FacesContext) context.getContext(FacesContext.class);
+      ExternalContext extCtx = facesContext.getExternalContext();
+      
+      if (property instanceof String)
+      {
+        try
         {
-          m = new PortletSessionMap(extCtx.getRequest(), PortletSession.APPLICATION_SCOPE);
-          extCtx.getRequestMap().put("javax.portlet.faces.SessionApplicationScopeMap", m);
-        }
-        return m;
-      case SESSION_PORTLET_SCOPE:
-        context.setPropertyResolved(true);
-        return extCtx.getSessionMap();
-      case PORTLET_PREFERENCES:
-        context.setPropertyResolved(true);
-        m = (Map) extCtx.getRequestMap().get("javax.portlet.faces.PreferenceMap");
-        if (m == null)
+          switch (Enum.valueOf(BRIDGE_IMPLICT_OBJECTS_ENUM.class, (String) property))
+          {
+            case portletConfig:
+              // only resolved in a Faces expression
+              if (isFacesResolved)
+              {
+                PortletConfig config = bridgeContext.getPortletConfig();
+                if (config != null)
+                {
+                  context.setPropertyResolved(true);
+                  return config;
+                } else
+                {
+                  throw new ELException("EL Resolve failed: can't resolve portletConfig because its not set on this Faces EL Resolver.");
+                }
+              }
+              else
+              {
+                return null;
+              }
+            case renderRequest:
+              // only resolved in a Faces expression
+              if (isFacesResolved)
+              {
+                if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)
+                {
+                  context.setPropertyResolved(true);
+                  return extCtx.getRequest();
+                } else
+                {
+                  throw new ELException("EL Resolve failed: can't resolve renderRequest in a non-render request");
+                }
+              }
+              else
+              {
+                return null;
+              }
+            case renderResponse:
+              // only resolved in a Faces expression
+              if (isFacesResolved)
+              {
+                if (BridgeUtil.getPortletRequestPhase() == Bridge.PortletPhase.RENDER_PHASE)
+                {
+                  context.setPropertyResolved(true);
+                  return extCtx.getResponse();
+                } else
+                {
+                  throw new ELException("EL Resolve failed: can't resolve renderResponse in a non-render request");
+                }
+              }
+              else
+              {
+                return null;
+              }
+            case httpSessionScope:
+              context.setPropertyResolved(true);
+              return getHttpSessionMap(extCtx, bridgeContext);
+            case portletSession:
+              context.setPropertyResolved(true);
+              return extCtx.getSession(false);
+            case portletSessionScope:
+              context.setPropertyResolved(true);
+              return extCtx.getSessionMap();
+            case mutablePortletPreferencesValues:
+              context.setPropertyResolved(true);
+              return getMutablePortletPreferencesValues(extCtx, bridgeContext);
+
+            case portletPreferences:
+              context.setPropertyResolved(true);
+              return ((PortletRequest) extCtx.getRequest()).getPreferences();
+            case portletPreferencesValues:
+              context.setPropertyResolved(true);
+              return ((PortletRequest) extCtx.getRequest()).getPreferences().getMap();
+            default:
+              return null;
+          }
+        } catch (IllegalArgumentException e)
         {
-          m = getPreferenceMap(((PortletRequest) extCtx.getRequest()).getPreferences());
-          extCtx.getRequestMap().put("javax.portlet.faces.SessionApplicationScopeMap", m);
-        }
-        return m;
-        default:
           return null;
-    }
-  }
+        }
+      }
+      else
+      {
+        return null;
+      }
+   }
 
-  @Override
-  public void setValue(ELContext context, Object base, Object property, Object val)
-                                                                                   throws ELException
-  {
     
-    // only process if running in a portlet request
-    if (!BridgeUtil.isPortletRequest() || base != null)
+
+    @Override
+    public void setValue(ELContext context, Object base, Object property, Object val)
+                                                                                     throws ELException
     {
-      return;
-    }
+      
+      // only process if running in a portlet request
+      if (!BridgeUtil.isPortletRequest() || base != null)
+      {
+        return;
+      }
 
 
-    if (property == null)
-    {
-      throw new PropertyNotFoundException("Null property");
-    }
-    
-    int index = -1;
-    if (property instanceof String)
-    {
-      index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
-    }
-    
-    if (index >= 0)
-    {
-      throw new PropertyNotWritableException((String) property);
+      if (property == null)
+      {
+        throw new PropertyNotFoundException("Null property");
+      }
+         
+      // As these properties aren't writable in either the Faces or JSP resolver
+      // don't distinguish in what context we are running.
+      if (property instanceof String)
+      {
+        try
+        {
+          // If exception not thrown then we had a hit
+          Enum.valueOf(BRIDGE_IMPLICT_OBJECTS_ENUM.class, (String) property);
+          throw new PropertyNotWritableException((String) property);
+        }
+        catch (IllegalArgumentException e)
+        {
+          ; // do nothing
+        }
+      }
     }
-  }
 
-  @Override
-  public boolean isReadOnly(ELContext context, Object base, Object property) throws ELException
-  {
-    // only process if running in a portlet request
-    if (!BridgeUtil.isPortletRequest() || base != null)
+    @Override
+    public boolean isReadOnly(ELContext context, Object base, Object property) throws ELException
     {
+      // only process if running in a portlet request
+      if (!BridgeUtil.isPortletRequest() || base != null)
+      {
+        return false;
+      }
+      
+      if (property == null)
+      {
+        throw new PropertyNotFoundException("Null property");
+      }
+      
+      // As these properties aren't writable in either the Faces or JSP resolver
+      // don't distinguish in what context we are running.
+      if (property instanceof String)
+      {
+        try
+        {
+          // If exception not thrown then we had a hit
+          Enum.valueOf(BRIDGE_IMPLICT_OBJECTS_ENUM.class, (String) property);
+          context.setPropertyResolved(true);
+          return true;
+        }
+        catch (IllegalArgumentException e)
+        {
+          return false;
+        }
+      }
+
       return false;
     }
-    
-    if (property == null)
-    {
-      throw new PropertyNotFoundException("Null property");
-    }
-    
-    int index = -1;
-    if (property instanceof String)
-    {
-      index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
-    }
-    if (index >= 0)
-    {
-      context.setPropertyResolved(true);
-      return true;
-    }
-    return false;
-  }
 
-  @Override
-  public Class<?> getType(ELContext context, Object base, Object property) throws ELException
-  {
-    if (property == null)
-    {
-      throw new PropertyNotFoundException("Null property");
-    }
-    
-    // only process if running in a portlet request
-    if (!BridgeUtil.isPortletRequest() || base != null)
+    @Override
+    public Class<?> getType(ELContext context, Object base, Object property) throws ELException
     {
-      return null;
-    }
+      if (property == null)
+      {
+        throw new PropertyNotFoundException("Null property");
+      }
+      
+      // only process if running in a portlet request
+      if (!BridgeUtil.isPortletRequest() || base != null)
+      {
+        return null;
+      }
 
-    int index = -1;
-    if (property instanceof String)
-    {
-      index = Arrays.binarySearch(IMPLICIT_OBJECTS, property);
-    }
-   
-    switch (index)
-    {
-      case RENDER_REQUEST:
-      case RENDER_RESPONSE:
-      case PORTLET_CONFIG:
-      case SESSION_APPLICATION_SCOPE:
-      case SESSION_PORTLET_SCOPE:
-      case PORTLET_PREFERENCES:
+      int index = -1;
+      // As these properties aren't writable in either the Faces or JSP resolver
+      // don't distinguish in what context we are running.
+      if (property instanceof String)
+      {
+        try
+        {
+          // If exception not thrown then we had a hit
+          Enum.valueOf(BRIDGE_IMPLICT_OBJECTS_ENUM.class, (String) property);
           context.setPropertyResolved(true);
+        }
+        catch (IllegalArgumentException e)
+        {
+          ; // do nothing
+        }
+      }
+     
+      return null;
     }
     
-    return null;
-  }
-  
 
-  @Override
-  public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
-  {
-    if (base != null)
+    @Override
+    public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base)
     {
-      return null;
-    }
-    ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(14);
-    list.add(getFeatureDescriptor("renderRequest", "renderRequest", "renderRequest", false, false,
-                                  true, RenderRequest.class, Boolean.TRUE));
-    list.add(getFeatureDescriptor("renderResponse", "renderResponse", "renderResponse", false, false,
-                                  true, RenderResponse.class, Boolean.TRUE));
-    list.add(getFeatureDescriptor("portletConfig", "portletConfig", "portletConfig", false, false,
-                                  true, PortletConfig.class, Boolean.TRUE));
-    list.add(getFeatureDescriptor("sessionApplicationScope", "sessionApplicationScope",
-                                  "sessionApplicationScope", false, false, true, Map.class,
-                                  Boolean.TRUE));
-    list.add(getFeatureDescriptor("sessionPortletScope", "sessionPortletScope",
-                                  "sessionPortletScope", false, false, true, Map.class,
-                                  Boolean.TRUE));
-    list.add(getFeatureDescriptor("portletPreferences", "portletPreferences",
-                                  "portletPreferences", false, false, true, Map.class,
-                                  Boolean.TRUE));
-
-    return list.iterator();
+      if (base != null)
+      {
+        return null;
+      }
+      ArrayList<FeatureDescriptor> list = new ArrayList<FeatureDescriptor>(9);
+      list.add(getFeatureDescriptor("httpSessionScope", "httpSessionScope",
+                                    "httpSessionScope", false, false, true, Map.class,
+                                    Boolean.TRUE));
+      list.add(getFeatureDescriptor("mutablePortletPreferences", "mutablePortletPreferences",
+                                    "mutablePortletPreferences", false, false, true, Map.class,
+                                    Boolean.TRUE));
+      list.add(getFeatureDescriptor("portletConfig", "portletConfig", "portletConfig", false, false,
+                                    true, PortletConfig.class, Boolean.TRUE));
+      list.add(getFeatureDescriptor("portletPreferences", "portletPreferences", "portletPreferences", false, false,
+                                    true, PortletPreferences.class, Boolean.TRUE));
+      list.add(getFeatureDescriptor("portletPreferencesValues", "portletPreferencesValues", "portletPreferencesValues", false, false,
+                                    true, Map.class, Boolean.TRUE));
+      list.add(getFeatureDescriptor("portletSession", "portletSession", "portletSession", false, false,
+                                    true, PortletSession.class, Boolean.TRUE));
+      list.add(getFeatureDescriptor("portletSessionScope", "portletSessionScope",
+                                    "portletSessionScope", false, false, true, Map.class,
+                                    Boolean.TRUE));
+      list.add(getFeatureDescriptor("renderRequest", "renderRequest", "renderRequest", false, false,
+                                    true, RenderRequest.class, Boolean.TRUE));
+      list.add(getFeatureDescriptor("renderResponse", "renderResponse", "renderResponse", false, false,
+                                    true, RenderResponse.class, Boolean.TRUE));
+ 
+      return list.iterator();
 
-  }
+    }
 
-  @Override
-  public Class<?> getCommonPropertyType(ELContext context, Object base)
-  {
-    if (base != null)
+    @Override
+    public Class<?> getCommonPropertyType(ELContext context, Object base)
     {
-      return null;
+      if (base != null)
+      {
+        return null;
+      }
+      return String.class;
     }
-    return String.class;
-  }
 
-  private FeatureDescriptor getFeatureDescriptor(String name, String displayName, String desc,
-                                                 boolean expert, boolean hidden, boolean preferred,
-                                                 Object type, Boolean designTime)
-  {
-
-    FeatureDescriptor fd = new FeatureDescriptor();
-    fd.setName(name);
-    fd.setDisplayName(displayName);
-    fd.setShortDescription(desc);
-    fd.setExpert(expert);
-    fd.setHidden(hidden);
-    fd.setPreferred(preferred);
-    fd.setValue(ELResolver.TYPE, type);
-    fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, designTime);
-    return fd;
-  }
+    private FeatureDescriptor getFeatureDescriptor(String name, String displayName, String desc,
+                                                   boolean expert, boolean hidden, boolean preferred,
+                                                   Object type, Boolean designTime)
+    {
 
-  @SuppressWarnings("unchecked")
-  private Map<String, String> getPreferencesValueMap(ExternalContext extCtx)
-  {
-    Map<String, String> m;
+      FeatureDescriptor fd = new FeatureDescriptor();
+      fd.setName(name);
+      fd.setDisplayName(displayName);
+      fd.setShortDescription(desc);
+      fd.setExpert(expert);
+      fd.setHidden(hidden);
+      fd.setPreferred(preferred);
+      fd.setValue(ELResolver.TYPE, type);
+      fd.setValue(ELResolver.RESOLVABLE_AT_DESIGN_TIME, designTime);
+      return fd;
+    }
 
-    PortletRequest portletRequest = (PortletRequest) extCtx.getRequest();
-    Enumeration<String> e = portletRequest.getPreferences().getNames();
-    
-    if (e.hasMoreElements())
+    @SuppressWarnings("unchecked")
+    private Map<String, String> getPreferencesValueMap(ExternalContext extCtx)
     {
-      m = new HashMap<String, String>();
-      while (e.hasMoreElements())
+      Map<String, String> m;
+
+      PortletRequest portletRequest = (PortletRequest) extCtx.getRequest();
+      Enumeration<String> e = portletRequest.getPreferences().getNames();
+      
+      if (e.hasMoreElements())
       {
-        String name = e.nextElement();
-        String value = portletRequest.getPreferences().getValue(name, null);
-        if (value != null)
+        m = new HashMap<String, String>();
+        while (e.hasMoreElements())
         {
-          m.put(name, value);
+          String name = e.nextElement();
+          String value = portletRequest.getPreferences().getValue(name, null);
+          if (value != null)
+          {
+            m.put(name, value);
+          }
         }
       }
+      else
+      {
+        m = Collections.emptyMap();
+      }
+      
+      return m;
     }
-    else
+    
+    private Map<String, Preference> getPreferenceMap(PortletPreferences prefs)
     {
-      m = Collections.emptyMap();
+      
+      Map <String, Preference> m;
+      
+      // construct a Map of Preference objects for each preference
+      Enumeration<String> e = prefs.getNames();
+      
+      if (e.hasMoreElements())
+      {
+        m = new HashMap<String, Preference>();
+        while (e.hasMoreElements())
+        {
+          String name = e.nextElement();
+          m.put(name, new PreferenceImpl(prefs, name));
+        }
+      }
+      else
+      {
+        m = Collections.emptyMap();
+      }
+      
+      return m;
     }
     
-    return m;
-  }
-  
-  private Map<String, Preference> getPreferenceMap(PortletPreferences prefs)
-  {
-    
-    Map <String, Preference> m;
-    
-    // construct a Map of Preference objects for each preference
-    Enumeration<String> e = prefs.getNames();
-    
-    if (e.hasMoreElements())
+    private Map<String, Object> getHttpSessionMap(ExternalContext extCtx, PortletELContextImpl bridgeContext)
     {
-      m = new HashMap<String, Preference>();
-      while (e.hasMoreElements())
+
+      Map<String, Object> sessionMap = bridgeContext.getHttpSessionMap();
+      if (sessionMap == null)
       {
-        String name = e.nextElement();
-        m.put(name, new PreferenceImpl(prefs, name));
+        sessionMap = 
+            new PortletSessionMap(extCtx.getRequest(), PortletSession.APPLICATION_SCOPE);
+        bridgeContext.setHttpSessionMap(sessionMap);
       }
+      return sessionMap;
     }
-    else
+    
+    private Map getMutablePortletPreferencesValues(ExternalContext extCtx, PortletELContextImpl bridgeContext)
     {
-      m = Collections.emptyMap();
+
+      Map<String, Preference> preferencesValuesMap = 
+        bridgeContext.getMutablePortletPreferencesMap();
+      if (preferencesValuesMap == null)
+      {
+        preferencesValuesMap = 
+            getPreferenceMap(((PortletRequest) extCtx.getRequest()).getPreferences());
+        bridgeContext.setMutablePortletPreferencesMap(preferencesValuesMap);
+      }
+      return preferencesValuesMap;
     }
-    
-    return m;
-  }
 
 }
\ No newline at end of file

Added: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/FacesVersionUtil.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/FacesVersionUtil.java?rev=783484&view=auto
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/FacesVersionUtil.java (added)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/util/FacesVersionUtil.java Wed Jun 10 20:11:32 2009
@@ -0,0 +1,129 @@
+/* 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.util;
+
+import java.io.IOException;
+
+import java.net.URL;
+
+import java.util.Enumeration;
+import java.util.jar.Manifest;
+
+/**
+ * <a href="FacesUtil.java.html"><b><i>View Source</i></b></a>
+ * 
+ * @author Atul Patel
+ * @author Neil Griffin
+ * 
+ */
+public class FacesVersionUtil
+{
+
+  public static final String FACES_IMPL_NAME_MOJARRA = "mojarra";
+  public static final String FACES_IMPL_NAME_SUN = "sun";
+  public static final String FACES_IMPL_NAME_MYFACES = "myfaces";
+
+  private static final String JSF_IMPL_TITLE = "Implementation-Title";
+  private static final String JSF_IMPL_VERSION = "Implementation-Version";
+
+  private static String mFacesImplTitle;
+  private static int mFacesImplMajorVersion = -1;
+  private static int mFacesImplMinorVersion = -1;
+  private static int mFacesImplPatchVersion = -1;
+  private static FACES_TYPE mFacesType = FACES_TYPE.UNKNOWN;
+
+  public static enum FACES_TYPE
+  {
+    MOJARRA, // Sun RI
+    MYFACES, // Apache Faces
+    UNKNOWN  // couldn't determine
+  }
+
+  static {
+    try
+    {
+      Class c = Class.forName("javax.faces.webapp.FacesServlet");
+      mFacesImplTitle = c.getPackage().getImplementationTitle();
+
+      // Try and determine the FACES_TYPE based on the Title
+      if (mFacesImplTitle != null)
+      {
+        String title = mFacesImplTitle.toLowerCase();
+        if (title.indexOf(FACES_IMPL_NAME_MYFACES) >= 0)
+        {
+          mFacesType = FACES_TYPE.MYFACES;
+        } else if (title.indexOf(FACES_IMPL_NAME_MOJARRA) >= 0 || 
+                   title.indexOf(FACES_IMPL_NAME_SUN) >= 0)
+        {
+          mFacesType = FACES_TYPE.MOJARRA;
+        }
+        // Otherwise -- unknown
+      }
+
+      // Try and determine the Impl version number.
+      String implVersion = c.getPackage().getImplementationVersion();
+
+      if (implVersion != null)
+      {
+        String[] versions = implVersion.split("[\\-_\\.a-z]");
+        try {
+          mFacesImplMajorVersion = (versions.length < 1? -1: Integer.parseInt(versions[0]));
+          mFacesImplMinorVersion = (versions.length < 1? -2: Integer.parseInt(versions[1]));
+          // return -1 if a patch version can not be determined
+          mFacesImplPatchVersion = (versions.length < 3? -1: Integer.parseInt(versions[2]));
+        } 
+        catch (NumberFormatException e)
+        {
+          // do nothing -- can't parse the version
+        }
+      }
+    }
+    catch (ClassNotFoundException e)
+    {
+      // Do nothing -- can't determine the impl/version
+    }
+  }
+
+  public static int getFacesImplMajorVersion()
+  {
+    return mFacesImplMajorVersion;
+  }
+
+  public static int getFacesImplMinorVersion()
+  {
+    return mFacesImplMinorVersion;
+  }
+
+  public static String getFacesImplName()
+  {
+    return mFacesImplTitle;
+  }
+
+  public static int getFacesImplPatchVersion()
+  {
+    return mFacesImplPatchVersion;
+  }
+  
+  public static FACES_TYPE getFacesType()
+  {
+    return mFacesType;
+  }
+
+}