tapestry-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kao...@apache.org
Subject svn commit: r1157207 - in /tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5: annotations/ internal/model/ internal/pageload/ internal/transform/ model/ services/
Date Fri, 12 Aug 2011 18:36:25 GMT
Author: kaosko
Date: Fri Aug 12 18:36:24 2011
New Revision: 1157207

URL: http://svn.apache.org/viewvc?rev=1157207&view=rev
Log:
TAP5-1606: EmbeddedMixin, applying the patch from Dragan Sahpaski

Added:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/EmbeddedMixin.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/EmbeddedMixinWorker.java
Modified:
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableComponentModelImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java
    tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/EmbeddedMixin.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/EmbeddedMixin.java?rev=1157207&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/EmbeddedMixin.java
(added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/annotations/EmbeddedMixin.java
Fri Aug 12 18:36:24 2011
@@ -0,0 +1,48 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.tapestry5.ioc.annotations.AnnotationUseContext.MIXIN;
+
+import org.apache.tapestry5.ioc.annotations.UseWith;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Allows embedding mixins in other mixins. This annotation may be placed only on a mixin
field in a mixin class. The
+ * embedded mixin is applied to embedded components of the component the parent mixin is
applied to.
+ * 
+ * @since 5.3
+ */
+@Target(FIELD)
+@Documented
+@Retention(RUNTIME)
+@UseWith(MIXIN)
+public @interface EmbeddedMixin
+{
+    String value();
+
+    /**
+     * Defines an ordering constraint for when the embedded mixin should be applied in relation
to other embedded
+     * mixins. The string is analogous exactly to the strings used to define ordered contributions.
Eg:
+     * 
+     * @EmbeddedMixin(order={"before:mixina","after:mixinb" ).
+     */
+    String[] order() default {};
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableComponentModelImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableComponentModelImpl.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableComponentModelImpl.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/model/MutableComponentModelImpl.java
Fri Aug 12 18:36:24 2011
@@ -59,8 +59,14 @@ public final class MutableComponentModel
 
     private List<String> mixinClassNames;
 
+    private List<String> embeddedMixinClassNames;
+
     private Map<String, String[]> mixinOrders;
 
+    private Map<String, String[]> embeddedMixinOrders;
+
+    private Map<String, String> embeddedMixinToComponentId;
+
     private boolean informalParametersSupported;
 
     private boolean mixinAfter;
@@ -278,6 +284,52 @@ public final class MutableComponentModel
         return result;
     }
 
+    public void addEmbeddedMixinClassName(String mixinClassName, String embeddedComponentId,
String... order)
+    {
+        if (embeddedMixinClassNames == null)
+            embeddedMixinClassNames = CollectionFactory.newList();
+        
+        if (embeddedMixinToComponentId == null)
+            embeddedMixinToComponentId = CollectionFactory.newMap();
+
+        embeddedMixinClassNames.add(mixinClassName);
+        embeddedMixinToComponentId.put(mixinClassName, embeddedComponentId);
+        if (order != null && order.length > 0)
+        {
+            if (embeddedMixinOrders == null)
+                embeddedMixinOrders = CollectionFactory.newCaseInsensitiveMap();
+            embeddedMixinOrders.put(mixinClassName, order);
+        }
+    }
+    
+    public List<String> getEmbeddedMixinClassNames()
+    {
+        List<String> result = CollectionFactory.newList();
+        
+        if (embeddedMixinClassNames != null)
+            result.addAll(embeddedMixinClassNames);
+
+        if (parentModel != null)
+            result.addAll(parentModel.getEmbeddedMixinClassNames());
+
+        return result;
+    }
+    
+    public String[] getOrderForEmbeddedMixin(String mixinClassName)
+    {
+        return InternalUtils.get(embeddedMixinOrders, mixinClassName);
+    }
+
+    public String getComponentIdForEmbeddedMixin(String mixinClassName)
+    {
+        String componentId = InternalUtils.get(embeddedMixinToComponentId, mixinClassName);
+        
+        if(parentModel == null)
+            return componentId;
+        
+        return parentModel.getComponentIdForEmbeddedMixin(mixinClassName);
+    }
+    
     public void enableSupportsInformalParameters()
     {
         informalParametersSupported = true;

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/EmbeddedComponentAssemblerImpl.java
Fri Aug 12 18:36:24 2011
@@ -29,6 +29,7 @@ import org.apache.tapestry5.services.Com
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -43,7 +44,7 @@ public class EmbeddedComponentAssemblerI
     private final ComponentModel componentModel;
 
     private final Location location;
-
+    
     private final Map<String, Instantiator> mixinIdToInstantiator = CollectionFactory.newCaseInsensitiveMap();
     private final Map<String, String[]> mixinsIdToOrderConstraints = CollectionFactory.newCaseInsensitiveMap();
 
@@ -59,6 +60,8 @@ public class EmbeddedComponentAssemblerI
 
     private Map<String, Boolean> bound;
 
+    private List<String> mixinClassNames;
+    
     /**
      * @param assemblerSource
      * @param instantiatorSource
@@ -88,11 +91,15 @@ public class EmbeddedComponentAssemblerI
 
         componentModel = getModel(componentClassName);
 
-        // Add the implementation mixins defined by the component model.
+        mixinClassNames = CollectionFactory.newList();
 
+        // Add the implementation mixins defined by the component model.
+        
         for (String className : componentModel.getMixinClassNames())
         {
             addMixin(className, componentModel.getOrderForMixin(className));
+            
+            mixinClassNames.add(className);
         }
 
         // If there's an embedded model (i.e., there was an @Component annotation)
@@ -103,6 +110,8 @@ public class EmbeddedComponentAssemblerI
             for (String className : embeddedModel.getMixinClassNames())
             {
                 addMixin(className, embeddedModel.getConstraintsForMixin(className));
+                
+                mixinClassNames.add(className);
             }
         }
 
@@ -114,8 +123,10 @@ public class EmbeddedComponentAssemblerI
             String className = componentClassResolver.resolveMixinTypeToClassName(order.getId());
 
             addMixin(className, order.getConstraints());
-        }
-
+            
+            mixinClassNames.add(className);
+        }        
+        
         informalParametersMixinId = prescanMixins();
 
     }
@@ -222,7 +233,7 @@ public class EmbeddedComponentAssemblerI
         if (componentModel.getSupportsInformalParameters())
             return new ParameterBinderImpl(null, parameterName, null);
 
-        // Otherwise, informal parameter and not supported by the component or any mixin.
+       // Otherwise, informal parameter and not supported by the component or any mixin.
 
         return null;
     }
@@ -260,4 +271,9 @@ public class EmbeddedComponentAssemblerI
     {
         return new HashSet<String>(componentModel.getParameterNames());
     }
+
+    public List<String> getMixinClassNames()
+    {
+        return mixinClassNames;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/pageload/PageLoaderImpl.java
Fri Aug 12 18:36:24 2011
@@ -44,6 +44,7 @@ import org.apache.tapestry5.services.Inv
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -113,6 +114,8 @@ public class PageLoaderImpl implements P
     };
 
     private final Map<Key, ComponentAssembler> cache = CollectionFactory.newConcurrentMap();
+    
+    private Map<String, List<String>> componentIdToMixins = CollectionFactory.newConcurrentMap();
 
     private final ComponentInstantiatorSource instantiatorSource;
 
@@ -869,12 +872,21 @@ public class PageLoaderImpl implements P
                 // ... which is why we can find it via peek() here. And it's our responsibility
                 // to clean it up.
 
-                ComponentPageElement embeddedElement = pageAssembly.createdElement.peek();
+                final ComponentPageElement embeddedElement = pageAssembly.createdElement.peek();
 
                 // Add the new element to the template of its container.
 
                 pageAssembly.addRenderCommand(embeddedElement);
-
+                
+                // Add defered actions for applying embedded mixins
+                pageAssembly.deferred.add(new PageAssemblyAction()
+                {
+                    public void execute(PageAssembly pageAssembly)
+                    {
+                        addEmbeddedMixins(embeddedElement, (EmbeddedComponentAssemblerImpl)
embeddedAssembler);
+                    }
+                });
+                
                 // And redirect any futher content from this component's template to go into
                 // the body of the embedded element.
 
@@ -887,6 +899,46 @@ public class PageLoaderImpl implements P
         });
     }
 
+    private void addEmbeddedMixins(ComponentPageElement newElement, EmbeddedComponentAssemblerImpl
embeddedAssembler)
+    {
+        // for all mixins in this component's embeddedAssembler
+        for (String mixinClass : embeddedAssembler.getMixinClassNames())
+        {
+            if (!componentIdToMixins.containsKey(newElement.getCompleteId()))
+                componentIdToMixins.put(newElement.getCompleteId(), new ArrayList<String>());
+            
+            componentIdToMixins.get(newElement.getCompleteId()).add(mixinClass);
+        }
+
+        ComponentPageElement container = newElement.getContainerElement();
+        String newElementId = newElement.getId();
+        while (container != null)
+        {
+            /*
+             * search in all containing components if they contain embedded mixins that apply
to the current component
+             */
+            if (componentIdToMixins.containsKey(container.getCompleteId()))
+            {
+                // for all the container components mixins
+                for (String mixinClass : componentIdToMixins.get(container.getCompleteId()))
+                {  
+                    ComponentModel mixinModel = instantiatorSource.getInstantiator(mixinClass).getModel();
+                    // for all the container component mixins embedded mixins
+                    for (String embeddedMixinClass : mixinModel.getEmbeddedMixinClassNames())
+                    {
+                        Instantiator mixinsInstantiator = instantiatorSource.getInstantiator(embeddedMixinClass);
+                        String componentId = mixinModel.getComponentIdForEmbeddedMixin(embeddedMixinClass);
+                        // does the embedded mixin apply to the current component 
+                        if (componentId.equalsIgnoreCase(newElementId))
+                            newElement.addMixin(embeddedMixinClass, mixinsInstantiator);
+                    }
+                }
+            }
+            newElementId = container.getId() + "." + newElementId;
+            container = container.getContainerElement();
+        }
+    }
+    
     private void attribute(AssemblerContext context) {
         final AttributeToken token = context.next(AttributeToken.class);
 

Added: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/EmbeddedMixinWorker.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/EmbeddedMixinWorker.java?rev=1157207&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/EmbeddedMixinWorker.java
(added)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/internal/transform/EmbeddedMixinWorker.java
Fri Aug 12 18:36:24 2011
@@ -0,0 +1,88 @@
+// Copyright 2011 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.internal.transform;
+
+import org.apache.tapestry5.ComponentResources;
+import org.apache.tapestry5.annotations.EmbeddedMixin;
+import org.apache.tapestry5.internal.InternalComponentResources;
+import org.apache.tapestry5.model.MutableComponentModel;
+import org.apache.tapestry5.plastic.ComputedValue;
+import org.apache.tapestry5.plastic.FieldConduit;
+import org.apache.tapestry5.plastic.InstanceContext;
+import org.apache.tapestry5.plastic.PlasticClass;
+import org.apache.tapestry5.plastic.PlasticField;
+import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
+import org.apache.tapestry5.services.transform.TransformationSupport;
+
+/**
+ * Supports the {@link org.apache.tapestry5.annotations.EmbeddedMixin} annotation, which
allows a mixin to be embedded
+ * in another mixin. The annotation is applied to a field, which will become read-only, and
contain a reference
+ * to the mixin instance.
+ */
+public class EmbeddedMixinWorker implements ComponentClassTransformWorker2
+{
+    public void transform(PlasticClass plasticClass, TransformationSupport support, MutableComponentModel
model)
+    {
+        for (PlasticField field : plasticClass.getFieldsWithAnnotation(EmbeddedMixin.class))
+        {
+            replaceFieldWithMixin(model, field);
+        }
+    }
+
+    private void replaceFieldWithMixin(MutableComponentModel model, PlasticField field)
+    {
+        EmbeddedMixin annotation = field.getAnnotation(EmbeddedMixin.class);
+
+        field.claim(annotation);
+        
+        String embeddedComponentId = annotation.value();
+
+        String[] order = annotation.order();
+
+        String mixinClassName = field.getTypeName();
+
+        model.addEmbeddedMixinClassName(mixinClassName, embeddedComponentId, order);
+
+        replaceFieldAccessWithMixin(field, mixinClassName);
+    }
+
+    private void replaceFieldAccessWithMixin(PlasticField field, String mixinClassName)
+    {
+        ComputedValue<FieldConduit<Object>> provider = createMixinFieldProvider(field.getName(),
mixinClassName);
+
+        field.setComputedConduit(provider);
+    }
+
+    private ComputedValue<FieldConduit<Object>> createMixinFieldProvider(final
String fieldName,
+            final String mixinClassName)
+    {
+        return new ComputedValue<FieldConduit<Object>>()
+        {
+            public FieldConduit<Object> get(InstanceContext context)
+            {
+                ComponentResources resources = context.get(ComponentResources.class);
+                final InternalComponentResources icr = (InternalComponentResources) resources;
+
+                return new ReadOnlyComponentFieldConduit(resources, fieldName)
+                {
+                    public Object get(Object instance, InstanceContext context)
+                    {
+                        return icr.getMixinByClassName(mixinClassName);
+                    }
+                };
+            }
+        };
+    }
+}

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/ComponentModel.java
Fri Aug 12 18:36:24 2011
@@ -190,4 +190,29 @@ public interface ComponentModel
      * @since 5.2.0
      */
     String[] getOrderForMixin(String mixinClassName);
+    
+    /**
+     * Relevant for mixins only. Returns a list of the class names of embedded mixins defined

+     * in this mixin.
+     * 
+     * @since 5.3
+     */
+    List<String> getEmbeddedMixinClassNames();
+    
+    /**
+     * @param mixinClassName class name of the embedded mixin for which the ordering is desired
+     * @return the ordering constraint(s) for the embedded mixin, potentially null.
+     * @since 5.3
+     */
+    String[] getOrderForEmbeddedMixin(String mixinClassName);
+    
+    /**
+     * Relevant for mixins only. Returns a list of the embedded component ids for the embedded
mixins defined 
+     * in this mixin.
+     * @param mixinClassName class name of the mixin for which the componentId is desired
+     * @return the componentId for the mixin.
+     * 
+     * @since 5.3
+     */
+    String getComponentIdForEmbeddedMixin(String mixinClassName);
 }

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/model/MutableComponentModel.java
Fri Aug 12 18:36:24 2011
@@ -87,6 +87,14 @@ public interface MutableComponentModel e
      * @since 5.2.0.0
      */
     void addMixinClassName(String mixinClassName, String... order);
+    
+    /**
+     * Relevant for mixins only. Adds an embedded mixin to the component's implementation,

+     * optionally specifying ordering constraints, as per OrderedConfiguration.
+     * 
+     * @since 5.3
+     */
+    void addEmbeddedMixinClassName(String mixinClassName, String embeddedComponentId, String...
order);
 
     /**
      * Sets the internal flag to indicate that this model (and all models that extend from
it) support informal

Modified: tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java?rev=1157207&r1=1157206&r2=1157207&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
(original)
+++ tapestry/tapestry5/trunk/tapestry-core/src/main/java/org/apache/tapestry5/services/TapestryModule.java
Fri Aug 12 18:36:24 2011
@@ -576,6 +576,7 @@ public final class TapestryModule
 
         configuration.add("Component", new ComponentWorker(resolver));
         configuration.add("Mixin", new MixinWorker(resolver));
+        configuration.add("EmbeddedMixin", new EmbeddedMixinWorker());
         configuration.addInstance("InjectPage", InjectPageWorker.class);
         configuration.addInstance("InjectComponent", InjectComponentWorker.class);
         configuration.addInstance("InjectContainer", InjectContainerWorker.class);



Mime
View raw message