You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2012/03/29 06:27:03 UTC

svn commit: r1306710 - in /myfaces/core/branches/2.0.x: api/src/main/java/javax/faces/component/ impl/src/main/java/org/apache/myfaces/view/facelets/ impl/src/main/java/org/apache/myfaces/view/facelets/impl/ impl/src/main/java/org/apache/myfaces/view/f...

Author: lu4242
Date: Thu Mar 29 04:27:03 2012
New Revision: 1306710

URL: http://svn.apache.org/viewvc?rev=1306710&view=rev
Log:
MYFACES-3515 Duplicate id using a facet and multiple <c:if> blocks in a composite component

Modified:
    myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIData.java
    myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIForm.java
    myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UINamingContainer.java
    myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIViewRoot.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java
    myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java

Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIData.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIData.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIData.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIData.java Thu Mar 29 04:27:03 2012
@@ -1063,15 +1063,17 @@ public class UIData extends UIComponentB
     {
         StringBuilder bld = __getSharedStringBuilder(context);
 
-        Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
-        uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
-        getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
-        // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot. 
+        // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX,
+        // and will be unique within this UIViewRoot.
         if(seed==null)
         {
+            Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
+            uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+            getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
         }
-        // Optionally, a unique seed value can be supplied by component creators which should be included in the generated unique id.
+        // Optionally, a unique seed value can be supplied by component creators
+        // which should be included in the generated unique id.
         else
         {
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();

Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIForm.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIForm.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIForm.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIForm.java Thu Mar 29 04:27:03 2012
@@ -89,13 +89,13 @@ public class UIForm extends UIComponentB
             bld = __getSharedStringBuilder(context);
         }
 
-        Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
-        uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
-        getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
         // Generate an identifier for a component. The identifier will be prefixed with
         // UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
         if(seed==null)
         {
+            Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
+            uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+            getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
         }
         // Optionally, a unique seed value can be supplied by component creators

Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UINamingContainer.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UINamingContainer.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UINamingContainer.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UINamingContainer.java Thu Mar 29 04:27:03 2012
@@ -73,15 +73,17 @@ public class UINamingContainer extends U
     {
         StringBuilder bld = __getSharedStringBuilder(context);
 
-        Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
-        uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
-        getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
-        // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot. 
+        // Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX,
+        // and will be unique within this UIViewRoot.
         if(seed==null)
         {
+            Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
+            uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+            getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
         }
-        // Optionally, a unique seed value can be supplied by component creators which should be included in the generated unique id.
+        // Optionally, a unique seed value can be supplied by component creators
+        // which should be included in the generated unique id.
         else
         {
             return bld.append(UIViewRoot.UNIQUE_ID_PREFIX).append(seed).toString();
@@ -142,47 +144,56 @@ public class UINamingContainer extends U
                 setCachedFacesContext(context.getFacesContext());
             }
             
-            if (!isVisitable(context)) {
+            if (!isVisitable(context))
+            {
                 return false;
             }
     
             pushComponentToEL(context.getFacesContext(), this);
-            try {
+            try
+            {
                 VisitResult res = context.invokeVisitCallback(this, callback);
-                switch (res) {
-                //we are done nothing has to be processed anymore
-                case COMPLETE:
-                    return true;
-    
-                case REJECT:
-                    return false;
-    
-                //accept
-                default:
-                    // Take advantage of the fact this is a NamingContainer
-                    // and we can know if there are ids to visit inside it 
-                    Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
-                    
-                    if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
-                    {
-                        if (getFacetCount() > 0) {
-                            for (UIComponent facet : getFacets().values()) {
-                                if (facet.visitTree(context, callback)) {
-                                    return true;
+                switch (res)
+                {
+                    //we are done nothing has to be processed anymore
+                    case COMPLETE:
+                        return true;
+
+                    case REJECT:
+                        return false;
+
+                    //accept
+                    default:
+                        // Take advantage of the fact this is a NamingContainer
+                        // and we can know if there are ids to visit inside it
+                        Collection<String> subtreeIdsToVisit = context.getSubtreeIdsToVisit(this);
+
+                        if (subtreeIdsToVisit != null && !subtreeIdsToVisit.isEmpty())
+                        {
+                            if (getFacetCount() > 0)
+                            {
+                                for (UIComponent facet : getFacets().values())
+                                {
+                                    if (facet.visitTree(context, callback))
+                                    {
+                                        return true;
+                                    }
                                 }
                             }
-                        }
-                        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
-                            UIComponent child = getChildren().get(i);
-                            if (child.visitTree(context, callback)) {
-                                return true;
+                            for (int i = 0, childCount = getChildCount(); i < childCount; i++)
+                            {
+                                UIComponent child = getChildren().get(i);
+                                if (child.visitTree(context, callback))
+                                {
+                                    return true;
+                                }
                             }
                         }
-                    }
-                    return false;
+                        return false;
                 }
             }
-            finally {
+            finally
+            {
                 //all components must call popComponentFromEl after visiting is finished
                 popComponentFromEL(context.getFacesContext());
             }

Modified: myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIViewRoot.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIViewRoot.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIViewRoot.java (original)
+++ myfaces/core/branches/2.0.x/api/src/main/java/javax/faces/component/UIViewRoot.java Thu Mar 29 04:27:03 2012
@@ -339,13 +339,13 @@ public class UIViewRoot extends UICompon
     {
         StringBuilder bld = __getSharedStringBuilder(context);
 
-        Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
-        uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
-        getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
         // Generate an identifier for a component. The identifier will be prefixed with
         // UNIQUE_ID_PREFIX, and will be unique within this UIViewRoot.
         if(seed==null)
         {
+            Long uniqueIdCounter = (Long) getStateHelper().get(PropertyKeys.uniqueIdCounter);
+            uniqueIdCounter = (uniqueIdCounter == null) ? 0 : uniqueIdCounter;
+            getStateHelper().put(PropertyKeys.uniqueIdCounter, (uniqueIdCounter+1L));
             return bld.append(UNIQUE_ID_PREFIX).append(uniqueIdCounter).toString();    
         }
         // Optionally, a unique seed value can be supplied by component creators which

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletCompositionContext.java Thu Mar 29 04:27:03 2012
@@ -572,4 +572,9 @@ abstract public class FaceletComposition
     {
        return isRefreshingTransientBuild() ||  (!isBuildingViewMetadata() && isInMetadataSection());
     }
+    
+    public StringBuilder getSharedStringBuilder()
+    {
+        return new StringBuilder();
+    }
 }

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/impl/FaceletCompositionContextImpl.java Thu Mar 29 04:27:03 2012
@@ -137,6 +137,8 @@ public class FaceletCompositionContextIm
     private SectionUniqueIdCounter _sectionUniqueComponentMetadataIdCounter;
     private SectionUniqueIdCounter _sectionUniqueComponentNormalIdCounter;
     
+    private StringBuilder _sharedStringBuilder;
+    
     public FaceletCompositionContextImpl(FaceletFactory factory, FacesContext facesContext)
     {
         super();
@@ -172,6 +174,7 @@ public class FaceletCompositionContextIm
         _uniqueIdsIterator = null;
         _level = 0;
         _isInMetadataSection = 0;
+        _sharedStringBuilder = null;
     }
     
     @Override
@@ -232,7 +235,12 @@ public class FaceletCompositionContextIm
         _validationGroupsStack = null;
         _componentsMarkedForDeletion = null;
         _sectionUniqueIdCounter = null;
+        _sectionUniqueNormalIdCounter = null;
+        _sectionUniqueMetadataIdCounter = null;
         _sectionUniqueComponentIdCounter = null;
+        _sectionUniqueComponentNormalIdCounter = null;
+        _sectionUniqueComponentMetadataIdCounter = null;
+        _sharedStringBuilder = null;
     }
    
     @Override
@@ -945,6 +953,20 @@ public class FaceletCompositionContextIm
        return isRefreshingTransientBuild() ||  (!isBuildingViewMetadata() && isInMetadataSection());
     }
     
+    @Override
+    public StringBuilder getSharedStringBuilder()
+    {
+        if (_sharedStringBuilder == null)
+        {
+            _sharedStringBuilder = new StringBuilder();
+        }
+        else
+        {
+            _sharedStringBuilder.setLength(0);
+        }
+        return _sharedStringBuilder;
+    }
+    
     private static class KeyEntryIterator<K, V> implements Iterator<K>
     {
         private Iterator<Map.Entry<K, V>> _delegateIterator;

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java Thu Mar 29 04:27:03 2012
@@ -331,7 +331,11 @@ public class CompositeComponentResourceT
             {
                 // UIViewRoot implements UniqueIdVendor, so there is no need to cast to UIViewRoot
                 // and call createUniqueId()
-                String uid = uniqueIdVendor.createUniqueId(faceletContext.getFacesContext(),null);
+                String uid = uniqueIdVendor.createUniqueId(faceletContext.getFacesContext(),
+                        mctx.getSharedStringBuilder()
+                        .append(compositeComponentBase.getId())
+                        .append("__f_")
+                        .append("cc_facet").toString());
                 compositeFacetPanel.setId(uid);
             }            
         }

Modified: myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java
URL: http://svn.apache.org/viewvc/myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java?rev=1306710&r1=1306709&r2=1306710&view=diff
==============================================================================
--- myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java (original)
+++ myfaces/core/branches/2.0.x/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ComponentSupport.java Thu Mar 29 04:27:03 2012
@@ -30,6 +30,7 @@ import javax.faces.component.UIComponent
 import javax.faces.component.UINamingContainer;
 import javax.faces.component.UIPanel;
 import javax.faces.component.UIViewRoot;
+import javax.faces.component.UniqueIdVendor;
 import javax.faces.context.FacesContext;
 import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.TagAttribute;
@@ -365,10 +366,44 @@ public final class ComponentSupport
      * @param facesContext
      * @return
      */
-    private static UIComponent createFacetUIPanel(FacesContext facesContext)
+    private static UIComponent createFacetUIPanel(FaceletContext ctx, UIComponent parent, String facetName)
     {
+        FacesContext facesContext = ctx.getFacesContext();
         UIComponent panel = facesContext.getApplication().createComponent(UIPanel.COMPONENT_TYPE);
-        panel.setId(facesContext.getViewRoot().createUniqueId());
+        
+        // The panel created by this method is special. To be restored properly and do not
+        // create duplicate ids or any other unwanted conflicts, it requires an unique id.
+        // This code is usually called when more than one component is added to a facet and
+        // it is necessary to create a shared container.
+        // Use FaceletCompositionContext.generateUniqueComponentId() is not possible, because
+        // <c:if> blocks inside a facet will make component ids unstable. Use UniqueIdVendor
+        // is feasible but also will be affected by <c:if> blocks inside a facet.
+        // The only solution that will generate real unique ids is use the parent id and the
+        // facet name and derive an unique id that cannot be generated by SectionUniqueIdCounter,
+        // doing the same trick as with metadata: use a double __ and add a prefix (f).
+        // Note this id will never be printed into the response, because this is just a container.
+        FaceletCompositionContext mctx = FaceletCompositionContext.getCurrentInstance(ctx);
+        UniqueIdVendor uniqueIdVendor = mctx.getUniqueIdVendorFromStack();
+        if (uniqueIdVendor == null)
+        {
+            uniqueIdVendor = ComponentSupport.getViewRoot(ctx, parent);
+        }
+        if (uniqueIdVendor != null)
+        {
+            // UIViewRoot implements UniqueIdVendor, so there is no need to cast to UIViewRoot
+            // and call createUniqueId(). See ComponentTagHandlerDelegate
+            int index = facetName.indexOf('.');
+            String cleanFacetName = facetName;
+            if (index >= 0)
+            {
+                cleanFacetName = facetName.replace('.', '_');
+            }
+            panel.setId(uniqueIdVendor.createUniqueId(facesContext, 
+                    mctx.getSharedStringBuilder()
+                      .append(parent.getId())
+                      .append("__f_")
+                      .append(cleanFacetName).toString()));
+        }
         panel.getAttributes().put(FACET_CREATED_UIPANEL_MARKER, Boolean.TRUE);
         return panel;
     }
@@ -387,7 +422,7 @@ public final class ComponentSupport
         {
             // there is a facet, but it is not an instance of UIPanel
             UIComponent child = facet;
-            facet = createFacetUIPanel(ctx.getFacesContext());
+            facet = createFacetUIPanel(ctx, parent, facetName);
             facet.getChildren().add(child);
             facet.getChildren().add(c);
             parent.getFacets().put(facetName, facet);
@@ -405,7 +440,7 @@ public final class ComponentSupport
                 // the facet is an instance of UIPanel, but it is not marked,
                 // so we have to create a new UIPanel and store this one in it
                 UIComponent oldPanel = facet;
-                facet = createFacetUIPanel(ctx.getFacesContext());
+                facet = createFacetUIPanel(ctx, parent, facetName);
                 facet.getChildren().add(oldPanel);
                 facet.getChildren().add(c);
                 parent.getFacets().put(facetName, facet);