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 2013/09/27 13:29:32 UTC

svn commit: r1526853 - in /myfaces/core/trunk: api/src/main/java/javax/faces/component/ impl/src/main/java/org/apache/myfaces/application/ impl/src/test/java/org/apache/myfaces/application/

Author: lu4242
Date: Fri Sep 27 11:29:32 2013
New Revision: 1526853

URL: http://svn.apache.org/r1526853
Log:
MYFACES-3785 RendererWrapper logic (@ListenerFor and @ResourceDependency)

Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java
    myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
    myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplAnnotationTest.java

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java?rev=1526853&r1=1526852&r2=1526853&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.java Fri Sep 27 11:29:32 2013
@@ -54,6 +54,7 @@ import javax.faces.event.SystemEvent;
 import javax.faces.event.SystemEventListener;
 import javax.faces.event.SystemEventListenerHolder;
 import javax.faces.render.Renderer;
+import javax.faces.render.RendererWrapper;
 
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent;
 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
@@ -1501,6 +1502,7 @@ public abstract class UIComponent
         private boolean _initialStateMarked;
 
         private int listenerCapability;
+        private transient UIComponent _component;
 
         private static final int LISTENER_SAVE_STATE_HOLDER = 1;
         private static final int LISTENER_SAVE_PARTIAL_STATE_HOLDER = 2;
@@ -1537,7 +1539,7 @@ public abstract class UIComponent
 
             this.componentClass = component.getClass();
             this.listener = listener;
-
+            this._component = component;
             initListenerCapability();
         }
 
@@ -1676,14 +1678,26 @@ public abstract class UIComponent
                 //Full restore
                 listenerCapability = (Integer) values[2];
 
+                _component = UIComponent.getCurrentComponent(context);
                 if ((listenerCapability & LISTENER_TYPE_COMPONENT) != 0)
                 {
-                    listener = UIComponent.getCurrentComponent(context);
+                    listener = _component;
                 }
                 else if ((listenerCapability & LISTENER_TYPE_RENDERER) != 0)
                 {
-                    listener = (ComponentSystemEventListener)
-                            UIComponent.getCurrentComponent(context).getRenderer(context);
+                    //listener = (ComponentSystemEventListener)
+                    //        UIComponent.getCurrentComponent(context).getRenderer(context);
+                    Renderer renderer = _component.getRenderer(context);
+                    Integer i = (Integer) values[1];
+                    if (i != null && i >= 0)
+                    {
+                        while (i > 0)
+                        {
+                            renderer = ((RendererWrapper) renderer).getWrapped();
+                            i--;
+                        }
+                    }
+                    listener = (ComponentSystemEventListener) renderer;
                 }
                 else
                 {
@@ -1721,7 +1735,38 @@ public abstract class UIComponent
                 }
                 else
                 {
-                    state[1] = null;
+                    if ( (listenerCapability & LISTENER_TYPE_RENDERER) != 0)
+                    {
+                        UIComponent componentRef = _component != null ? _component : getCurrentComponent(context);
+                        Renderer renderer = componentRef.getRenderer(context);
+                        int i = 0;
+                        while (renderer != null && !renderer.getClass().equals(listener.getClass()))
+                        {
+                            if (renderer instanceof RendererWrapper)
+                            {
+                                renderer = ((RendererWrapper) renderer).getWrapped();
+                                i++;
+                            }
+                            else
+                            {
+                                renderer = null;
+                                i = -1;
+                            }
+                        }
+                        if (i != -1)
+                        {
+                            // Store the number so we can get the right wrapper to invoke the method.
+                            state[1] = i;
+                        }
+                        else
+                        {
+                            state[1] = null;
+                        }
+                    }
+                    else
+                    {
+                        state[1] = null;
+                    }
                 }
                 state[2] = (Integer) listenerCapability;
                 return state;

Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java?rev=1526853&r1=1526852&r2=1526853&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/application/ApplicationImpl.java Fri Sep 27 11:29:32 2013
@@ -81,6 +81,7 @@ import javax.faces.event.SystemEventList
 import javax.faces.flow.FlowHandler;
 import javax.faces.render.ClientBehaviorRenderer;
 import javax.faces.render.Renderer;
+import javax.faces.render.RendererWrapper;
 import javax.faces.validator.Validator;
 import javax.faces.view.ViewDeclarationLanguage;
 import javax.naming.Context;
@@ -2148,7 +2149,37 @@ public class ApplicationImpl extends App
 
         _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
     }
-    
+
+    private void _handleRendererAnnotations(FacesContext context, Renderer inspected, UIComponent component)
+    {   
+        // determine the ProjectStage setting via the given FacesContext
+        // note that a local getProjectStage() could cause problems in wrapped environments
+        boolean isProduction = context.isProjectStage(ProjectStage.Production);
+        Renderer innerRenderer = inspected;
+        while (innerRenderer != null)
+        {
+            if (innerRenderer instanceof RendererWrapper)
+            {
+                Class<?> inspectedClass = innerRenderer.getClass();
+                _handleListenerForAnnotations(context, innerRenderer, inspectedClass, component, isProduction);
+
+                _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
+                
+                // get the inner wrapper
+                innerRenderer = ((RendererWrapper)innerRenderer).getWrapped();
+            }
+            else
+            {
+                Class<?> inspectedClass = innerRenderer.getClass();
+                _handleListenerForAnnotations(context, innerRenderer, inspectedClass, component, isProduction);
+
+                _handleResourceDependencyAnnotations(context, inspectedClass, component, isProduction);
+                
+                innerRenderer = null;
+            }
+        }
+    }
+
     private void _handleListenerForAnnotations(FacesContext context, Object inspected, Class<?> inspectedClass,
                                                UIComponent component, boolean isProduction)
     {
@@ -2473,7 +2504,7 @@ public class ApplicationImpl extends App
              * except the Renderer for the component to be returned must be inspected for the annotations mentioned in
              * createComponent(ValueExpression, FacesContext, String) as specified in the documentation for that method.
              */
-            _handleAnnotations(context, renderer, component);
+            _handleRendererAnnotations(context, renderer, component);
         }
     }
 

Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplAnnotationTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplAnnotationTest.java?rev=1526853&r1=1526852&r2=1526853&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplAnnotationTest.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/application/ApplicationImplAnnotationTest.java Fri Sep 27 11:29:32 2013
@@ -29,12 +29,16 @@ import javax.faces.component.UIComponent
 import javax.faces.component.UIComponentBase;
 import javax.faces.component.UIOutput;
 import javax.faces.component.UIPanel;
+import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.DateTimeConverter;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
 import javax.faces.event.ListenerFor;
 import javax.faces.event.PostAddToViewEvent;
 import javax.faces.render.RenderKitFactory;
 import javax.faces.render.Renderer;
+import javax.faces.render.RendererWrapper;
 
 import org.apache.myfaces.component.ComponentResourceContainer;
 import org.apache.myfaces.config.RuntimeConfig;
@@ -139,10 +143,78 @@ public class ApplicationImplAnnotationTe
     @ListenerFor(systemEventClass=PostAddToViewEvent.class,
             sourceClass=UIComponentBase.class)
     @ResourceDependency(library = "testLib", name = "testResource.js")
-    public static class TestRendererA extends Renderer
+    public static class TestRendererA extends Renderer implements ComponentSystemEventListener
     {
+        public void processEvent(ComponentSystemEvent event)
+        {
+            FacesContext.getCurrentInstance().getAttributes().put("oam.test.TestRendererA", Boolean.TRUE);
+        }
+    }
+    
+    public static class FakeTestRendererWrapper extends RendererWrapper implements ComponentSystemEventListener
+    {
+        private Renderer delegate;
+        
+        public FakeTestRendererWrapper(Renderer delegate)
+        {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Renderer getWrapped()
+        {
+            return delegate;
+        }
+
+        public void processEvent(ComponentSystemEvent event)
+        {
+            // Note there is no @ListenerFor annotation, so this should not happen, but the interesting thing
+            // here is the wrapper should not stop an inner renderer to be notified about an event. So, if
+            // the delegate renderer implements ComponentSystemEventListener and has @ListenerFor annotations,
+            // it should be notified anyway
+            FacesContext.getCurrentInstance().getAttributes().put("oam.test.FakeTestRendererWrapper", Boolean.TRUE);
+        }
+    }
+    
+    @ListenerFor(systemEventClass=PostAddToViewEvent.class,
+            sourceClass=UIComponentBase.class)
+    public static class TestRendererWrapper extends RendererWrapper implements ComponentSystemEventListener
+    {
+        private Renderer delegate;
+        
+        public TestRendererWrapper(Renderer delegate)
+        {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Renderer getWrapped()
+        {
+            return delegate;
+        }
 
+        public void processEvent(ComponentSystemEvent event)
+        {
+            FacesContext.getCurrentInstance().getAttributes().put("oam.test.TestRendererWrapper", Boolean.TRUE);
+        }
     }
+    
+    public static class TestRendererWrapper2 extends RendererWrapper
+    {
+        private Renderer delegate;
+        
+        public TestRendererWrapper2(Renderer delegate)
+        {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Renderer getWrapped()
+        {
+            return delegate;
+        }
+    }
+
 
     @Test
     public void testCreateComponentRenderer() throws Exception
@@ -166,6 +238,245 @@ public class ApplicationImplAnnotationTe
         Assert.assertEquals("testResource.js",attrMap.get("name"));
         Assert.assertEquals("testLib",attrMap.get("library"));
     }
+    
+    /**
+     * This test has a RendererWrapper that implement ComponentSystemEventListener, but it does not
+     * have a @ListenerFor annotation, in this case the listener that receive the event is the 
+     * inner renderer, and the outer wrapper should not be notified about the event
+     * 
+     * @throws Exception 
+     */
+    @Test
+    public void testCreateComponentRendererWrapper1() throws Exception
+    {
+        facesContext.getViewRoot().setRenderKitId(
+                MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.getRenderKit().addRenderer(
+                UITestComponentA.COMPONENT_FAMILY,
+                UITestComponentA.DEFAULT_RENDERER_TYPE, new FakeTestRendererWrapper(new TestRendererA()));
+
+        application.addComponent(UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.class.getName());
+        
+        UITestComponentA comp = (UITestComponentA) application.createComponent(facesContext, 
+                UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.DEFAULT_RENDERER_TYPE);
+        
+        List<UIComponent> componentResources = facesContext.getViewRoot().getComponentResources(facesContext, "head");
+        Assert.assertEquals(1,componentResources.size());
+        Map<String,Object> attrMap = componentResources.get(0).getAttributes();
+        Assert.assertEquals("testResource.js",attrMap.get("name"));
+        Assert.assertEquals("testLib",attrMap.get("library"));
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+        
+        facesContext.getAttributes().remove("oam.test.TestRendererWrapper");
+        facesContext.getAttributes().remove("oam.test.TestRendererA");
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        Object state = comp.saveState(facesContext);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        UITestComponentA comp2 = new UITestComponentA();
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        comp2.restoreState(facesContext, state);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        facesContext.getViewRoot().getChildren().clear();
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp2);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+    }
+    
+    /**
+     * This test has a RendererWrapper that does not implement ComponentSystemEventListener, in this case
+     * the listener is the wrapped Renderer (TestRendererA).
+     * 
+     * @throws Exception 
+     */
+    @Test
+    public void testCreateComponentRendererWrapper2() throws Exception
+    {
+        facesContext.getViewRoot().setRenderKitId(
+                MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.getRenderKit().addRenderer(
+                UITestComponentA.COMPONENT_FAMILY,
+                UITestComponentA.DEFAULT_RENDERER_TYPE, new TestRendererWrapper2(new TestRendererA()));
+
+        application.addComponent(UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.class.getName());
+        
+        UITestComponentA comp = (UITestComponentA) application.createComponent(facesContext, 
+                UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.DEFAULT_RENDERER_TYPE);
+        
+        List<UIComponent> componentResources = facesContext.getViewRoot().getComponentResources(facesContext, "head");
+        Assert.assertEquals(1,componentResources.size());
+        Map<String,Object> attrMap = componentResources.get(0).getAttributes();
+        Assert.assertEquals("testResource.js",attrMap.get("name"));
+        Assert.assertEquals("testLib",attrMap.get("library"));
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp);
+        
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+        
+        facesContext.getAttributes().remove("oam.test.TestRendererA");
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        Object state = comp.saveState(facesContext);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        UITestComponentA comp2 = new UITestComponentA();
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        comp2.restoreState(facesContext, state);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        facesContext.getViewRoot().getChildren().clear();
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp2);
+        
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+    }
+    
+    /**
+     * 
+     * @throws Exception 
+     */
+    @Test
+    public void testCreateComponentRendererWrapper3() throws Exception
+    {
+        facesContext.getViewRoot().setRenderKitId(
+                MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.getRenderKit().addRenderer(
+                UITestComponentA.COMPONENT_FAMILY,
+                UITestComponentA.DEFAULT_RENDERER_TYPE, 
+                    new FakeTestRendererWrapper(new TestRendererWrapper2(new TestRendererA())));
+
+        application.addComponent(UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.class.getName());
+        
+        UITestComponentA comp = (UITestComponentA) application.createComponent(facesContext, 
+                UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.DEFAULT_RENDERER_TYPE);
+        
+        List<UIComponent> componentResources = facesContext.getViewRoot().getComponentResources(facesContext, "head");
+        Assert.assertEquals(1,componentResources.size());
+        Map<String,Object> attrMap = componentResources.get(0).getAttributes();
+        Assert.assertEquals("testResource.js",attrMap.get("name"));
+        Assert.assertEquals("testLib",attrMap.get("library"));
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+        
+        facesContext.getAttributes().remove("oam.test.TestRendererWrapper");
+        facesContext.getAttributes().remove("oam.test.TestRendererA");
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        Object state = comp.saveState(facesContext);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        UITestComponentA comp2 = new UITestComponentA();
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        comp2.restoreState(facesContext, state);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        facesContext.getViewRoot().getChildren().clear();
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp2);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+    }
+    
+    /**
+     * 
+     * @throws Exception 
+     */
+    @Test
+    public void testCreateComponentRendererWrapper4() throws Exception
+    {
+        facesContext.getViewRoot().setRenderKitId(
+                MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
+        facesContext.getRenderKit().addRenderer(
+                UITestComponentA.COMPONENT_FAMILY,
+                UITestComponentA.DEFAULT_RENDERER_TYPE, 
+                    new TestRendererWrapper(new FakeTestRendererWrapper(
+                        new TestRendererWrapper2(new TestRendererA()))) );
+
+        application.addComponent(UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.class.getName());
+        
+        UITestComponentA comp = (UITestComponentA) application.createComponent(facesContext, 
+                UITestComponentA.COMPONENT_TYPE,
+                UITestComponentA.DEFAULT_RENDERER_TYPE);
+        
+        List<UIComponent> componentResources = facesContext.getViewRoot().getComponentResources(facesContext, "head");
+        Assert.assertEquals(1,componentResources.size());
+        Map<String,Object> attrMap = componentResources.get(0).getAttributes();
+        Assert.assertEquals("testResource.js",attrMap.get("name"));
+        Assert.assertEquals("testLib",attrMap.get("library"));
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+        
+        facesContext.getAttributes().remove("oam.test.TestRendererWrapper");
+        facesContext.getAttributes().remove("oam.test.TestRendererA");
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        Object state = comp.saveState(facesContext);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        UITestComponentA comp2 = new UITestComponentA();
+        
+        facesContext.getViewRoot().pushComponentToEL(facesContext, facesContext.getViewRoot());
+        comp.pushComponentToEL(facesContext, comp);
+        comp2.restoreState(facesContext, state);
+        comp.popComponentFromEL(facesContext);
+        facesContext.getViewRoot().popComponentFromEL(facesContext);
+        
+        facesContext.getViewRoot().getChildren().clear();
+        
+        // Invoke PostAddToViewEvent
+        facesContext.getViewRoot().getChildren().add(comp2);
+        
+        Assert.assertFalse(facesContext.getAttributes().containsKey("oam.test.FakeTestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererWrapper"));
+        Assert.assertTrue(facesContext.getAttributes().containsKey("oam.test.TestRendererA"));
+    }
 
     @ResourceDependency(name = "testResource.js")
     public static class UITestComponentB extends UIComponentBase