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 2011/06/03 21:11:58 UTC
svn commit: r1131148 - in /myfaces/core/trunk/api/src:
main/java/javax/faces/component/UIComponent.java
test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java
Author: lu4242
Date: Fri Jun 3 19:11:58 2011
New Revision: 1131148
URL: http://svn.apache.org/viewvc?rev=1131148&view=rev
Log:
MYFACES-3167 UIComponent EventListenerWrapper optimizations
Added:
myfaces/core/trunk/api/src/test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java
Modified:
myfaces/core/trunk/api/src/main/java/javax/faces/component/UIComponent.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=1131148&r1=1131147&r2=1131148&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 Jun 3 19:11:58 2011
@@ -1211,6 +1211,16 @@ public abstract class UIComponent implem
private Class<?> componentClass;
private ComponentSystemEventListener listener;
+ private boolean _initialStateMarked;
+
+ private int listenerCapability;
+
+ private static final int LISTENER_SAVE_STATE_HOLDER = 1;
+ private static final int LISTENER_SAVE_PARTIAL_STATE_HOLDER = 2;
+ private static final int LISTENER_TYPE_COMPONENT = 4;
+ private static final int LISTENER_TYPE_RENDERER = 8;
+ private static final int LISTENER_TYPE_OTHER = 16;
+
public EventListenerWrapper()
{
//need a no-arg constructor for state saving purposes
@@ -1224,7 +1234,9 @@ public abstract class UIComponent implem
* it because we need to point to the real component, but we can assume the instance
* is the same because UIComponent.subscribeToEvent says so. Also take into account
* this case is the reason why we need a wrapper for UIComponent.subscribeToEvent
- * 2. listener is an instance of ComponentSystemEventListener but not from UIComponent.
+ * 2. listener is an instance of Renderer. In this case we can assume the same renderer
+ * used by the source component is the one used by the listener (ListenerFor).
+ * 3. listener is an instance of ComponentSystemEventListener but not from UIComponent.
* In this case, the instance could implement StateHolder, PartialStateHolder or do
* implement anything, so we have to deal with that case as usual.
*
@@ -1237,6 +1249,36 @@ public abstract class UIComponent implem
this.componentClass = component.getClass();
this.listener = listener;
+
+ initListenerCapability();
+ }
+
+ private void initListenerCapability()
+ {
+ this.listenerCapability = 0;
+ if (this.listener instanceof UIComponent)
+ {
+ this.listenerCapability = LISTENER_TYPE_COMPONENT;
+ }
+ else if (this.listener instanceof Renderer)
+ {
+ this.listenerCapability = LISTENER_TYPE_RENDERER;
+ }
+ else
+ {
+ if (this.listener instanceof PartialStateHolder)
+ {
+ this.listenerCapability = LISTENER_TYPE_OTHER | LISTENER_SAVE_PARTIAL_STATE_HOLDER;
+ }
+ else if (this.listener instanceof StateHolder)
+ {
+ this.listenerCapability = LISTENER_TYPE_OTHER | LISTENER_SAVE_STATE_HOLDER;
+ }
+ else
+ {
+ this.listenerCapability = LISTENER_TYPE_OTHER;
+ }
+ }
}
@Override
@@ -1284,32 +1326,40 @@ public abstract class UIComponent implem
public void clearInitialState()
{
- if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ if ( (listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
{
((PartialStateHolder)listener).clearInitialState();
}
+ _initialStateMarked = false;
}
public boolean initialStateMarked()
{
- if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ if ( (listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
{
return ((PartialStateHolder)listener).initialStateMarked();
}
- return false;
+ //return false;
+ return _initialStateMarked;
}
public void markInitialState()
{
- if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ //if (!(listener instanceof UIComponent) && listener instanceof PartialStateHolder)
+ if ( (listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
{
((PartialStateHolder)listener).markInitialState();
}
+ _initialStateMarked = true;
}
public boolean isTransient()
{
- if (listener instanceof StateHolder)
+ //if ( listener instanceof StateHolder)
+ if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0 ||
+ (listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0 )
{
return ((StateHolder)listener).isTransient();
}
@@ -1330,9 +1380,26 @@ public abstract class UIComponent implem
}
else
{
+ //Full restore
+ listenerCapability = (Integer) values[2];
+
+ if ( (listenerCapability & LISTENER_TYPE_COMPONENT) != 0 )
+ {
+ listener = UIComponent.getCurrentComponent(context);
+ }
+ else if ( (listenerCapability & LISTENER_TYPE_RENDERER) != 0)
+ {
+ listener = (ComponentSystemEventListener) UIComponent.getCurrentComponent(context).getRenderer(context);
+ }
+ else
+ {
+ listener = (ComponentSystemEventListener) UIComponentBase.restoreAttachedState(context, values[1]);
+ }
+ /*
listener = values[1] == null ?
UIComponent.getCurrentComponent(context) :
(ComponentSystemEventListener) UIComponentBase.restoreAttachedState(context, values[1]);
+ */
}
}
@@ -1340,6 +1407,7 @@ public abstract class UIComponent implem
{
if (!initialStateMarked())
{
+ /*
Object[] state = new Object[2];
state[0] = componentClass;
if (!(listener instanceof UIComponent))
@@ -1347,21 +1415,67 @@ public abstract class UIComponent implem
state[1] = UIComponentBase.saveAttachedState(context, listener);
}
return state;
+ */
+ Object[] state = new Object[3];
+ state[0] = componentClass;
+ //If this is not a component or a renderer, save it calling UIComponent.saveAttachedState
+ if (!( (listenerCapability & LISTENER_TYPE_COMPONENT) != 0 ||
+ (listenerCapability & LISTENER_TYPE_RENDERER) != 0 ) )
+ {
+ state[1] = UIComponentBase.saveAttachedState(context, listener);
+ }
+ else
+ {
+ state[1] = null;
+ }
+ state[2] = (Integer) listenerCapability;
+ return state;
}
else
{
+ // If initialStateMarked() == true means two things:
+ // 1. PSS is being used
+ if ( (listenerCapability & LISTENER_TYPE_COMPONENT) != 0)
+ {
+ return null;
+ }
+ else if ( (listenerCapability & LISTENER_TYPE_RENDERER) != 0)
+ {
+ return null;
+ }
+ else
+ {
+ if ( (listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0 ||
+ (listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0)
+ {
+ Object listenerSaved = ((StateHolder) listener).saveState(context);
+ if (listenerSaved == null)
+ {
+ return null;
+ }
+ return new Object[]{componentClass, new _AttachedDeltaWrapper(listener.getClass(), listenerSaved)};
+ }
+ else
+ {
+ //This is not necessary, because the instance is considered serializable!
+ return null;
+ }
+ }
+ /*
Object listenerSaved = ((StateHolder) listener).saveState(context);
if (listenerSaved == null)
{
return null;
}
return new Object[]{componentClass, new _AttachedDeltaWrapper(listener.getClass(), listenerSaved)};
+ */
}
}
public void setTransient(boolean newTransientValue)
{
- if (listener instanceof StateHolder)
+ if ((listenerCapability & LISTENER_SAVE_PARTIAL_STATE_HOLDER) != 0 ||
+ (listenerCapability & LISTENER_SAVE_STATE_HOLDER) != 0 )
{
((StateHolder)listener).setTransient(newTransientValue);
}
Added: myfaces/core/trunk/api/src/test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java?rev=1131148&view=auto
==============================================================================
--- myfaces/core/trunk/api/src/test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java (added)
+++ myfaces/core/trunk/api/src/test/java/javax/faces/component/UIComponentEventListenerWrapperTest.java Fri Jun 3 19:11:58 2011
@@ -0,0 +1,662 @@
+/*
+ * 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 javax.faces.component;
+
+import javax.faces.component.UIComponent.EventListenerWrapper;
+import javax.faces.context.FacesContext;
+import javax.faces.event.ComponentSystemEvent;
+import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.render.Renderer;
+
+public class UIComponentEventListenerWrapperTest extends AbstractComponentTest
+{
+
+ public UIComponentEventListenerWrapperTest(String arg0)
+ {
+ super(arg0);
+ }
+
+ public void testUIComponentListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, component);
+
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testUIComponentListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, component);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be null
+ assertNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, component);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testUIComponentListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, component);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, component);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public static class MyCustomRenderer extends Renderer implements ComponentSystemEventListener {
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+
+ }
+ }
+
+ public void testRendererListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ MyCustomRenderer renderer = new MyCustomRenderer();
+ component.setRendererType("org.apache.myfaces.MyCustomRenderer");
+ renderKit.addRenderer("javax.faces.Output", "org.apache.myfaces.MyCustomRenderer", renderer);
+ //This case happens when @ListenerFor is attached on the renderer class like h:outputScript or h:outputStylesheet
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, renderer);
+
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testRendererListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ MyCustomRenderer renderer = new MyCustomRenderer();
+ component.setRendererType("org.apache.myfaces.MyCustomRenderer");
+ renderKit.addRenderer("javax.faces.Output", "org.apache.myfaces.MyCustomRenderer", renderer);
+ //This case happens when @ListenerFor is attached on the renderer class like h:outputScript or h:outputStylesheet
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, renderer);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be null
+ assertNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, renderer);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testRendererListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ MyCustomRenderer renderer = new MyCustomRenderer();
+ component.setRendererType("org.apache.myfaces.MyCustomRenderer");
+ renderKit.addRenderer("javax.faces.Output", "org.apache.myfaces.MyCustomRenderer", renderer);
+ //This case happens when @ListenerFor is attached on the renderer class like h:outputScript or h:outputStylesheet
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, renderer);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, renderer);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public static class MyNonSerializableListener implements ComponentSystemEventListener {
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return obj instanceof MyNonSerializableListener;
+ }
+
+ }
+
+ public void testNonSerializableListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyNonSerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testNonSerializableListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyNonSerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be null
+ assertNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testNonSerializableListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyNonSerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public static class MySerializableListener implements ComponentSystemEventListener {
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return obj instanceof MySerializableListener;
+ }
+
+ }
+
+ public void testSerializableListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MySerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testSerializableListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MySerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be null
+ assertNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testSerializableListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MySerializableListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public static class MyStateHolderListener implements ComponentSystemEventListener, StateHolder {
+
+ private Integer i = 1;
+
+ public void setI(int value)
+ {
+ i = value;
+ }
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof MyStateHolderListener)
+ {
+ return (this.i == ((MyStateHolderListener)obj).i);
+ }
+ return false;
+ }
+
+ public Object saveState(FacesContext context)
+ {
+ return i;
+ }
+
+ public void restoreState(FacesContext context, Object state)
+ {
+ i = (Integer) state;
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void setTransient(boolean newTransientValue)
+ {
+ }
+
+ }
+
+ public void testStateHolderListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ MyStateHolderListener listener = new MyStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ listener.setI(2);
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testStateHolderListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be not null, because it implements StateHolder
+ assertNotNull(state);
+
+ MyStateHolderListener listener2 = new MyStateHolderListener();
+ listener2.setI(2);
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener2);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testStateHolderListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public static class MyPartialStateHolderListener implements ComponentSystemEventListener, PartialStateHolder {
+
+ private Integer i = 1;
+
+ private boolean markInitialState;
+
+ public MyPartialStateHolderListener()
+ {
+ }
+
+ public void setI(int value)
+ {
+ i = value;
+ }
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof MyPartialStateHolderListener)
+ {
+ return (this.i == ((MyPartialStateHolderListener)obj).i);
+ }
+ return false;
+ }
+
+ public Object saveState(FacesContext context)
+ {
+ if (!initialStateMarked())
+ {
+ return i;
+ }
+ else
+ {
+ return i == 1 ? null : i;
+ }
+ }
+
+ public void restoreState(FacesContext context, Object state)
+ {
+ if (state == null)
+ {
+ return;
+ }
+ i = (Integer) state;
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void setTransient(boolean newTransientValue)
+ {
+ }
+
+ public void clearInitialState()
+ {
+ markInitialState = false;
+ }
+
+ public boolean initialStateMarked()
+ {
+ return markInitialState;
+ }
+
+ public void markInitialState()
+ {
+ markInitialState = true;
+ }
+
+ }
+
+ public void testPartialStateHolderListenerNormalState()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyPartialStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testPartialStateHolderListenerWithPSS()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyPartialStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be null
+ assertNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testPartialStateHolderListenerWithPSS2()
+ {
+ UIComponent component = new UIOutput();
+ MyPartialStateHolderListener listener = new MyPartialStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+
+ listener.setI(2);
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should be not null, because something changed inside the listener
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, new MyPartialStateHolderListener());
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+
+ public void testPartialStateHolderListenerWithPSSFull()
+ {
+ UIComponent component = new UIOutput();
+ ComponentSystemEventListener listener = new MyPartialStateHolderListener();
+ //This case happens when @ListenerFor is attached on the component class
+ EventListenerWrapper wrapper = new EventListenerWrapper(component, listener);
+
+ wrapper.markInitialState();
+
+ wrapper.clearInitialState();
+ Object state = wrapper.saveState(facesContext);
+
+ //In this case state should not be null, because state should be saved fully
+ assertNotNull(state);
+
+ EventListenerWrapper wrapper2 = new EventListenerWrapper(component, listener);
+ wrapper.markInitialState();
+ //For restore we need to setup the context first
+ component.pushComponentToEL(facesContext, component);
+ wrapper2.restoreState(facesContext, state);
+ component.popComponentFromEL(facesContext);
+
+ assertNotNull(wrapper2.getComponentSystemEventListener());
+ assertEquals(wrapper.getComponentSystemEventListener(), wrapper2.getComponentSystemEventListener());
+ }
+}