You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ma...@apache.org on 2009/05/22 08:58:41 UTC

svn commit: r777406 - in /myfaces/trinidad/branches/1.2.11.3-branch: src/site/xdoc/installation.xml trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java

Author: matzew
Date: Fri May 22 06:58:40 2009
New Revision: 777406

URL: http://svn.apache.org/viewvc?rev=777406&view=rev
Log:
TRINIDAD-1482 - Facelets: cannot use "facelets.VIEW_MAPPINGS" with logical view handled by PageResolver

Thanks to Max Starets for his patch and the added documentation.

Modified:
    myfaces/trinidad/branches/1.2.11.3-branch/src/site/xdoc/installation.xml
    myfaces/trinidad/branches/1.2.11.3-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java

Modified: myfaces/trinidad/branches/1.2.11.3-branch/src/site/xdoc/installation.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.3-branch/src/site/xdoc/installation.xml?rev=777406&r1=777405&r2=777406&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.3-branch/src/site/xdoc/installation.xml (original)
+++ myfaces/trinidad/branches/1.2.11.3-branch/src/site/xdoc/installation.xml Fri May 22 06:58:40 2009
@@ -159,7 +159,10 @@
   </context-param>
 
   <context-param>
-    <param-name>facelets.VIEW_MAPPINGS</param-name>
+    <!--Unfortunately, Facelets provides no hook for plugging the PageResolver into the logic 
+      handling "facelets.VIEW_MAPPINGS". You should leave "facelets.VIEW_MAPPINGS" 
+      unset and use "org.apache.myfaces.trinidad.FACELETS_VIEW_MAPPINGS" instead.-->
+    <param-name>org.apache.myfaces.trinidad.FACELETS_VIEW_MAPPINGS</param-name>
     <param-value>*.xhtml</param-value>
   </context-param>
 ]]></source>

Modified: myfaces/trinidad/branches/1.2.11.3-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/branches/1.2.11.3-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java?rev=777406&r1=777405&r2=777406&view=diff
==============================================================================
--- myfaces/trinidad/branches/1.2.11.3-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java (original)
+++ myfaces/trinidad/branches/1.2.11.3-branch/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/facelets/TrinidadFaceletViewHandler.java Fri May 22 06:58:40 2009
@@ -5,12 +5,17 @@
 
 import java.io.IOException;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import javax.faces.FacesException;
 import javax.faces.application.ViewHandler;
 import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 
 import org.apache.myfaces.trinidad.change.ChangeManager;
+import org.apache.myfaces.trinidad.context.PageResolver;
 import org.apache.myfaces.trinidad.context.RequestContext;
 
 /**
@@ -19,11 +24,28 @@
 public class TrinidadFaceletViewHandler
   extends FaceletViewHandler
 {
+  
+  // A context parameter for controlling which views should be handled by Facelets 
+  // based on the supplied extensions and prefixes.
+  // We process this parameter exactly like Facelets does with "facelets.VIEW_MAPPINGS" 
+  // with the exception that we get a physical view Id from the PageResolver before checking
+  // its extension/prefix.
+  //
+  // Unfortunately, Facelets provides no hook for plugging the PageResolver into the logic
+  // handling "facelets.VIEW_MAPPINGS". We will recommend that our users leave "facelets.VIEW_MAPPINGS" 
+  // unset and use "org.apache.myfaces.trinidad.FACELETS_VIEW_MAPPINGS" instead.
+  static public final String FACELETS_VIEW_MAPPINGS =
+                            "org.apache.myfaces.trinidad.FACELETS_VIEW_MAPPINGS";
+  
   public TrinidadFaceletViewHandler(ViewHandler parent)
   {
     super(parent);
+    _parent = parent;
   }
   
+  /**
+   * Overridden to apply changes from the ChangeManager
+   */
   @Override
   protected void buildView(FacesContext context, UIViewRoot viewToRender)
     throws IOException, FacesException 
@@ -31,8 +53,192 @@
     super.buildView(context, viewToRender);
     
     // Apply changes once we have a stable view tree built. This is the earliest 
-    //  opportunity, the document was just attached to the view root.
+    // opportunity, the document was just attached to the view root.
     ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
     cm.applyComponentChangesForCurrentView(FacesContext.getCurrentInstance());
   }
+  
+  
+  /**
+   * Overridden to check wthether the physical viewId (as determined by PageResolver)
+   * should be handled by Facelets
+   */
+  @Override
+  public UIViewRoot restoreView(FacesContext context, String viewId)
+  {
+    _initMappings(context);
+    
+    if (_handledByFacelets(viewId))
+    {
+      return super.restoreView(context, viewId);
+    }
+    else
+    {
+      return _parent.restoreView(context, viewId);
+    }
+  }
+  
+  /**
+   * Overridden to check wthether the physical viewId (as determined by PageResolver)
+   * should be handled by Facelets
+   */
+   @Override
+  public void renderView(FacesContext context, UIViewRoot viewToRender)
+    throws IOException
+  {
+    if (!viewToRender.isRendered()) 
+    {
+      return;
+    }
+    
+    _initMappings(context);
+    
+    if (_handledByFacelets(viewToRender.getViewId())) 
+    {
+      super.renderView(context, viewToRender);
+    }
+    else
+    {
+      _parent.renderView(context, viewToRender);
+    }
+  }
+  
+  /**
+   * Overridden to check wthether the physical viewId (as determined by PageResolver)
+   * should be handled by Facelets
+   */
+  @Override
+  public void writeState(FacesContext context) 
+    throws IOException
+  {
+    _initMappings(context);
+    
+    if (_handledByFacelets(context.getViewRoot().getViewId()))
+    {
+      super.writeState(context);
+    }
+    else
+    {
+      _parent.writeState(context);
+    }
+  }
+  
+  /**
+   * This method uses double-check locking (DLC) to avoid synchronization
+   * when accessing _extensionMappings and _prefixMappings
+   * Note that _mappingsInitialized, _extensionMappings and _prefixMappings
+   * are declared 'volatile', and _extensionMappings/_prefixMappings are not modified
+   * since they are constructed. 
+   * JDK5 and later extends the semantics for volatile so 
+   * that the system will not allow a write of a volatile to be reordered with respect 
+   * to any previous read or write, and a read of a volatile cannot be reordered with 
+   * respect to any following read or write
+   */
+  private void _initMappings(FacesContext context)
+  {
+    if (_mappingsInitialized)
+    {
+      return;
+    }
+    synchronized(this)
+    {
+      if (!_mappingsInitialized)
+      {
+        ExternalContext external = context.getExternalContext();
+        String viewMappings = external.getInitParameter(FACELETS_VIEW_MAPPINGS);
+        if ((viewMappings != null) && (viewMappings.length() > 0)) 
+        {
+          String[] mappingsArray = viewMappings.split(";");
+          
+          Set<String> extensionMappings = new HashSet<String>(mappingsArray.length);
+          Set<String> prefixMappings = new HashSet<String>(mappingsArray.length);
+          
+          for (int i = 0; i < mappingsArray.length; i++) 
+          {
+            String mapping = mappingsArray[i].trim();
+            int mappingLength = mapping.length();
+            if (mappingLength <= 1) 
+            {
+              continue;
+            }
+      
+            if (mapping.charAt(0) == '*') 
+            {
+              extensionMappings.add(mapping.substring(1));
+            } 
+            else if (mapping.charAt(mappingLength - 1) == '*') 
+            {
+              prefixMappings.add(mapping.substring(0, mappingLength - 1));
+            }
+          }
+          
+          if (extensionMappings.size() > 0)
+          {
+            _extensionMappings = new HashSet<String>(extensionMappings);
+          }
+          
+          if (prefixMappings.size() > 0)
+          {
+            _prefixMappings = new HashSet<String>(prefixMappings);
+          }
+        }
+       
+        _mappingsInitialized = true;
+      }
+    }
+  }
+  
+  private boolean _handledByFacelets(String viewId) 
+  {
+    // If there's no extension or prefixe mappings, then
+    // just make Facelets handle everything
+    if ((_extensionMappings == null) && (_prefixMappings == null)) 
+    {
+      return true;
+    }
+    
+    // Since extension/prefix mappings apply to physical URIs, we need
+    // to get a physical viewId. It is assumed that getPhysicalURI() lookup is
+    // relatively cheap
+    RequestContext afc = RequestContext.getCurrentInstance();
+    if (afc != null)
+    {
+      viewId = afc.getPageResolver().getPhysicalURI(viewId);
+    }
+    
+    if (_extensionMappings != null) 
+    {
+      for (String extension: _extensionMappings) 
+      {
+        if (viewId.endsWith(extension)) 
+        {
+          return true;
+        }
+      }
+    }
+    
+    if (_prefixMappings != null) 
+    {
+      for (String prefix: _prefixMappings) 
+      {
+        if (viewId.startsWith(prefix)) 
+        {
+            return true;
+        }
+      }
+    }
+    
+    return false;
+  }
+  
+  
+  private final ViewHandler _parent;
+  
+  // Set of viewId extensions that should be handled by Facelets
+  private volatile Set<String> _extensionMappings;
+
+  // Set of viewId prefixes that should be handled by Facelets
+  private volatile Set<String> _prefixMappings;
+  
+  private volatile boolean _mappingsInitialized = false;
 }