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