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 2009/08/28 02:50:12 UTC

svn commit: r808697 - in /myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets: ./ tag/composite/ tag/jsf/

Author: lu4242
Date: Fri Aug 28 00:50:12 2009
New Revision: 808697

URL: http://svn.apache.org/viewvc?rev=808697&view=rev
Log:
MYFACES-2324 Add ViewDeclarationLanguage.retargetAttachedObjects and ViewDeclarationLanguage.retargetMethodExpressions

Added:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java   (with props)
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java   (with props)
Modified:
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ConverterTagHandlerDelegate.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java?rev=808697&r1=808696&r2=808697&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/FaceletViewDeclarationLanguage.java Fri Aug 28 00:50:12 2009
@@ -91,6 +91,7 @@
 import org.apache.myfaces.view.facelets.impl.DefaultResourceResolver;
 import org.apache.myfaces.view.facelets.impl.ResourceResolver;
 import org.apache.myfaces.view.facelets.tag.TagDecorator;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
 import org.apache.myfaces.view.facelets.tag.composite.CompositeLibrary;
 import org.apache.myfaces.view.facelets.tag.composite.CompositeResourceLibrary;
 import org.apache.myfaces.view.facelets.tag.ui.UIDebug;
@@ -395,7 +396,7 @@
                         // its tag handler is applied.
                         if (UIComponent.isCompositeComponent(component))
                         {
-                            // TODO: How we obtain the list of AttachedObjectHandler for
+                            // How we obtain the list of AttachedObjectHandler for
                             // the current composite component? It should be a component
                             // attribute or retrieved by a key inside component.getAttributes
                             // map. Since api does not specify any attribute, we suppose
@@ -403,6 +404,16 @@
                             // from component attribute map.
                             // But this is only the point of the iceberg, because we should
                             // define how we register attached object handlers in this list.
+                            // ANS: see CompositeComponentResourceTagHandler.
+                            // The current handler should be added to the list, to be chained.
+                            // Note that the inner component should have a target with the same name
+                            // as "for" attribute
+                            CompositeComponentResourceTagHandler.addAttachedObjectHandler(component, currentHandler);
+                            
+                            List<AttachedObjectHandler> handlers = (List<AttachedObjectHandler>) 
+                                component.getAttributes().get(CompositeComponentResourceTagHandler.ATTACHED_OBJECT_HANDLERS_KEY);
+                            
+                            retargetAttachedObjects(context, component, handlers);
                         }
                         else
                         {
@@ -426,14 +437,12 @@
                             // its tag handler is applied.
                             if (UIComponent.isCompositeComponent(component))
                             {
-                                // TODO: How we obtain the list of AttachedObjectHandler for
-                                // the current composite component? It should be a component
-                                // attribute or retrieved by a key inside component.getAttributes
-                                // map. Since api does not specify any attribute, we suppose
-                                // this is an implementation detail and it should be retrieved
-                                // from component attribute map.
-                                // But this is only the point of the iceberg, because we should
-                                // define how we register attached object handlers in this list.
+                                CompositeComponentResourceTagHandler.addAttachedObjectHandler(component, currentHandler);
+                                
+                                List<AttachedObjectHandler> handlers = (List<AttachedObjectHandler>) 
+                                    component.getAttributes().get(CompositeComponentResourceTagHandler.ATTACHED_OBJECT_HANDLERS_KEY);
+                                
+                                retargetAttachedObjects(context, component, handlers);
                             }
                             else
                             {

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java?rev=808697&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java Fri Aug 28 00:50:12 2009
@@ -0,0 +1,169 @@
+/*
+ * 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.view.facelets.tag.composite;
+
+import java.beans.BeanDescriptor;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.faces.component.UIComponent;
+import javax.faces.view.AttachedObjectTarget;
+import javax.faces.view.facelets.FaceletContext;
+import javax.faces.view.facelets.FaceletHandler;
+import javax.faces.view.facelets.TagAttribute;
+import javax.faces.view.facelets.TagConfig;
+import javax.faces.view.facelets.TagHandler;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
+
+/**
+ * composite:actionSource, composite:valueHolder and composite:editableValueHolder
+ * do the same: register an AttachedObjectTarget on the "targetList" mentioned on
+ * ViewDeclarationLanguage.retargetAttachedObjects. AttachedObjectTargetHandler group the
+ * common behavior
+ * 
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+@JSFFaceletTag
+public abstract class AttachedObjectTargetHandler<T extends AttachedObjectTarget> 
+    extends TagHandler implements InterfaceDescriptorCreator
+{
+
+    private static final Log log = LogFactory.getLog(AttachedObjectTargetHandler.class);
+    
+    /**
+     * 
+     */
+    @JSFFaceletAttribute(name="name",
+            className="javax.el.ValueExpression",
+            deferredValueType="java.lang.String")
+    protected final TagAttribute _name;
+
+    /**
+     * 
+     */
+    @JSFFaceletAttribute(name="targets",
+            className="javax.el.ValueExpression",
+            deferredValueType="java.lang.String")
+    protected final TagAttribute _targets;
+
+    /**
+     * Check if the PropertyDescriptor instance created by this handler
+     * can be cacheable or not. 
+     */
+    private boolean _cacheable;
+    
+    private AttachedObjectTarget _target;
+
+    public AttachedObjectTargetHandler(TagConfig config)
+    {
+        super(config);
+        _name = getRequiredAttribute("name");
+        _targets = getAttribute("targets");
+        if (_name.isLiteral())
+        {
+            _cacheable = true;
+        }
+        else
+        {
+            _cacheable = false;
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void apply(FaceletContext ctx, UIComponent parent)
+            throws IOException
+    {
+        CompositeComponentBeanInfo beanInfo = 
+            (CompositeComponentBeanInfo) parent.getAttributes()
+            .get(UIComponent.BEANINFO_KEY);
+        
+        if (beanInfo == null)
+        {
+            if (log.isErrorEnabled())
+            {
+                log.error("Cannot found composite bean descriptor UIComponent.BEANINFO_KEY ");
+            }
+            return;
+        }
+        
+        BeanDescriptor beanDescriptor = beanInfo.getBeanDescriptor(); 
+        
+        //1. Obtain the list mentioned as "targetList" on ViewDeclarationLanguage.retargetAttachedObjects
+        List<AttachedObjectTarget> targetList = (List<AttachedObjectTarget>)
+            beanDescriptor.getValue(
+                    AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY);
+        
+        if (targetList == null)
+        {
+            //2. If not found create it and set
+            targetList = new ArrayList<AttachedObjectTarget>();
+            beanDescriptor.setValue(
+                    AttachedObjectTarget.ATTACHED_OBJECT_TARGETS_KEY,
+                    targetList);
+        }
+        
+        //3. Create the instance of AttachedObjectTarget
+        if (isCacheable())
+        {
+            if (_target == null)
+            {
+                _target = createAttachedObjectTarget(ctx);
+            }
+            targetList.add(_target);
+        }
+        else
+        {
+            AttachedObjectTarget target = createAttachedObjectTarget(ctx);
+            targetList.add(target);
+        }
+        
+        this.nextHandler.apply(ctx, parent);
+    }
+    
+    public boolean isCacheable()
+    {
+        return _cacheable;
+    }
+    
+    public void setCacheable(boolean cacheable)
+    {
+        _cacheable = cacheable;
+    }
+    
+    @Override
+    public FaceletHandler getNextHandler()
+    {
+        return nextHandler;
+    }
+
+    /**
+     * Create a new AttachedObjectTarget instance to be added on the 
+     * target list.
+     * 
+     * @return
+     */
+    protected abstract T createAttachedObjectTarget(FaceletContext ctx);    
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetHandler.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Added: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java?rev=808697&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java (added)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java Fri Aug 28 00:50:12 2009
@@ -0,0 +1,122 @@
+/*
+ * 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.view.facelets.tag.composite;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.el.ValueExpression;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.view.AttachedObjectTarget;
+
+import org.apache.myfaces.shared_impl.util.StringUtils;
+
+/**
+ * 
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+public class AttachedObjectTargetImpl implements AttachedObjectTarget, Serializable
+{    
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -7214478234269252354L;
+    
+    protected ValueExpression _name;
+    
+    protected ValueExpression _targets;
+
+    public AttachedObjectTargetImpl()
+    {
+    }
+
+    @Override
+    public String getName()
+    {
+        if (_name != null)
+        {
+            return (String) _name.getValue(FacesContext.getCurrentInstance().getELContext());
+        }        
+        return null;
+    }
+
+    @Override
+    public List<UIComponent> getTargets(UIComponent topLevelComponent)
+    {
+        FacesContext facesContext = FacesContext.getCurrentInstance();
+        String [] targetsArray = getTargets(facesContext);
+        
+        if (targetsArray.length > 0)
+        {
+            List<UIComponent> targetsList = new ArrayList<UIComponent>(targetsArray.length);
+            for (String target : targetsArray)
+            {
+                UIComponent innerComponent = topLevelComponent.findComponent(target);
+                
+                if (innerComponent != null)
+                {
+                    targetsList.add(innerComponent);
+                }
+            }
+            return targetsList;
+        }
+        else
+        {
+            // composite:actionSource/valueHolder/editableValueHolder
+            // "name" description says if targets is not set, name is 
+            // the component id of the target component where
+            // it should be mapped to
+            String name = getName();
+            if (name != null)
+            {
+                UIComponent innerComponent = topLevelComponent.findComponent(getName());
+                if (innerComponent != null)
+                {
+                    List<UIComponent> targetsList = new ArrayList<UIComponent>(1);
+                    targetsList.add(innerComponent);
+                    return targetsList;
+                }
+            }
+            return Collections.emptyList();
+        }
+    }
+    
+    public String [] getTargets(FacesContext context)
+    {
+        if (_targets != null)
+        {
+            return StringUtils.splitShortString((String) _targets.getValue(context.getELContext()), ' ');
+        }
+        return org.apache.myfaces.shared_impl.util.ArrayUtils.EMPTY_STRING_ARRAY;
+    }
+    
+    public void setName(ValueExpression ve)
+    {
+        _name = ve;
+    }
+    
+    public void setTargets(ValueExpression ve)
+    {
+        _targets = ve;
+    }
+}

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/AttachedObjectTargetImpl.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java?rev=808697&r1=808696&r2=808697&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentResourceTagHandler.java Fri Aug 28 00:50:12 2009
@@ -21,6 +21,8 @@
 import java.beans.BeanInfo;
 import java.beans.PropertyDescriptor;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.el.ValueExpression;
 import javax.el.VariableMapper;
@@ -32,6 +34,7 @@
 import javax.faces.component.UIPanel;
 import javax.faces.component.ValueHolder;
 import javax.faces.context.FacesContext;
+import javax.faces.view.AttachedObjectHandler;
 import javax.faces.view.ViewDeclarationLanguage;
 import javax.faces.view.facelets.ComponentConfig;
 import javax.faces.view.facelets.ComponentHandler;
@@ -59,6 +62,17 @@
 public class CompositeComponentResourceTagHandler extends ComponentHandler
     implements ComponentBuilderHandler
 {
+    /**
+     * This key is used to keep the list of AttachedObjectHandlers
+     * created when a composite component is created. Tag handlers
+     * exposing attached objects should call 
+     * addAttachedObjectHandler(UIComponent, AttachedObjectHandler)
+     * that uses this key to save this list on component attribute
+     * map.  
+     */
+    public final static String ATTACHED_OBJECT_HANDLERS_KEY = 
+            "org.apache.myfaces.ATTACHED_OBJECT_HANDLERS_KEY";    
+    
     private final Resource _resource;
     
     private Metadata _mapper;
@@ -120,6 +134,7 @@
         return component;
     }
 
+    @SuppressWarnings("unchecked")
     @Override
     public void applyNextHandler(FaceletContext ctx, UIComponent c)
             throws IOException
@@ -133,9 +148,18 @@
         ViewDeclarationLanguage vdl = facesContext.getApplication().getViewHandler().
             getViewDeclarationLanguage(facesContext, facesContext.getViewRoot().getViewId());
         
-        // TODO: This method should be called from here, but we have to retrieve
-        // its handlers from somewhere.
-        //vdl.retargetAttachedObjects(facesContext, c, handlers)
+        List<AttachedObjectHandler> handlers = (List<AttachedObjectHandler>) 
+            c.getAttributes().get(ATTACHED_OBJECT_HANDLERS_KEY);
+        
+        if (handlers != null)
+        {
+            vdl.retargetAttachedObjects(facesContext, c, handlers);
+            
+            // Since handlers list is not serializable and it is not necessary to
+            // keep them anymore on attribute map, it is better to remove it from
+            // component attribute map
+            c.getAttributes().remove(ATTACHED_OBJECT_HANDLERS_KEY);
+        }
         
         vdl.retargetMethodExpressions(facesContext, c);
         
@@ -169,6 +193,32 @@
             faceletContext.setVariableMapper(orig);
         }
     }
+    
+    /**
+     * Add to the composite component parent this handler, so it will be processed later when
+     * ViewDeclarationLanguage.retargetAttachedObjects is called (see applyNextHandler method).
+     * 
+     * Tag Handlers exposing attached objects should call this method to expose them when the
+     * parent to be applied is a composite components.
+     * 
+     * @param compositeComponentParent
+     * @param handler
+     */
+    @SuppressWarnings("unchecked")
+    public static void addAttachedObjectHandler(UIComponent compositeComponentParent, AttachedObjectHandler handler)
+    {
+        List<AttachedObjectHandler> list = (List<AttachedObjectHandler>) 
+            compositeComponentParent.getAttributes().get(
+                ATTACHED_OBJECT_HANDLERS_KEY);
+        
+        if (list == null)
+        {
+            list = new ArrayList<AttachedObjectHandler>();
+            compositeComponentParent.getAttributes().put(ATTACHED_OBJECT_HANDLERS_KEY, list);
+        }
+        
+        list.add(handler);
+    }
 
     @Override
     public void setAttributes(FaceletContext ctx, Object instance)

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ConverterTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ConverterTagHandlerDelegate.java?rev=808697&r1=808696&r2=808697&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ConverterTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ConverterTagHandlerDelegate.java Fri Aug 28 00:50:12 2009
@@ -25,7 +25,8 @@
 import javax.faces.component.ValueHolder;
 import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
-import javax.faces.view.AttachedObjectHandler;
+import javax.faces.view.ValueHolderAttachedObjectHandler;
+import javax.faces.view.facelets.ComponentHandler;
 import javax.faces.view.facelets.ConverterHandler;
 import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.MetaRuleset;
@@ -34,6 +35,9 @@
 import javax.faces.view.facelets.TagHandlerDelegate;
 
 import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
+
+import com.sun.beans.ObjectHandler;
 
 /**
  * Handles setting a Converter instance on a ValueHolder. Will wire all attributes set to the Converter instance
@@ -46,7 +50,7 @@
  *
  * @since 2.0
  */
-public class ConverterTagHandlerDelegate extends TagHandlerDelegate implements AttachedObjectHandler
+public class ConverterTagHandlerDelegate extends TagHandlerDelegate implements ValueHolderAttachedObjectHandler
 {
     private ConverterHandler _delegate;
     
@@ -74,16 +78,23 @@
     @Override
     public void apply(FaceletContext ctx, UIComponent parent) throws IOException
     {
-        if (parent == null || !(parent instanceof ValueHolder))
+        // only process if it's been created
+        if (!ComponentHandler.isNew(parent))
         {
-            throw new TagException(_delegate.getTag(), "Parent not an instance of ValueHolder: " + parent);
+            return;
         }
-
-        // only process if it's been created
-        if (parent.getParent() == null)
+        if (parent instanceof ValueHolder)
         {
             applyAttachedObject(ctx.getFacesContext(), parent);
-        }        
+        }
+        else if (UIComponent.isCompositeComponent(parent))
+        {
+            CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, _delegate);
+        }
+        else
+        {
+            throw new TagException(_delegate.getTag(), "Parent not composite component or an instance of ValueHolder: " + parent);
+        }      
     }
 
     /**

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java?rev=808697&r1=808696&r2=808697&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/ValidatorTagHandlerDelegate.java Fri Aug 28 00:50:12 2009
@@ -25,7 +25,8 @@
 import javax.faces.component.UIComponent;
 import javax.faces.context.FacesContext;
 import javax.faces.validator.Validator;
-import javax.faces.view.AttachedObjectHandler;
+import javax.faces.view.EditableValueHolderAttachedObjectHandler;
+import javax.faces.view.facelets.ComponentHandler;
 import javax.faces.view.facelets.FaceletContext;
 import javax.faces.view.facelets.MetaRuleset;
 import javax.faces.view.facelets.TagAttribute;
@@ -34,6 +35,7 @@
 import javax.faces.view.facelets.ValidatorHandler;
 
 import org.apache.myfaces.view.facelets.tag.MetaRulesetImpl;
+import org.apache.myfaces.view.facelets.tag.composite.CompositeComponentResourceTagHandler;
 
 /**
  * Handles setting a Validator instance on a EditableValueHolder. Will wire all attributes set to the Validator instance
@@ -46,7 +48,7 @@
  *
  * @since 2.0
  */
-public class ValidatorTagHandlerDelegate extends TagHandlerDelegate implements AttachedObjectHandler
+public class ValidatorTagHandlerDelegate extends TagHandlerDelegate implements EditableValueHolderAttachedObjectHandler
 {
     private ValidatorHandler _delegate;
     
@@ -58,17 +60,22 @@
     @Override
     public void apply(FaceletContext ctx, UIComponent parent) throws IOException
     {
-
-        if (parent == null || !(parent instanceof EditableValueHolder))
+        if (!ComponentHandler.isNew(parent))
         {
-            throw new TagException(_delegate.getTag(), "Parent not an instance of EditableValueHolder: " + parent);
+            return;
         }
-
-        // only process if it's been created
-        if (parent.getParent() == null)
+        if (parent instanceof EditableValueHolder)
         {
             applyAttachedObject(ctx.getFacesContext(), parent);
         }
+        else if (UIComponent.isCompositeComponent(parent))
+        {
+            CompositeComponentResourceTagHandler.addAttachedObjectHandler(parent, _delegate);
+        }
+        else
+        {
+            throw new TagException(_delegate.getTag(), "Parent not composite component or an instance of EditableValueHolder: " + parent);
+        }
     }
 
     /**