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/08/19 21:07:00 UTC
svn commit: r1159747 - in /myfaces/core/trunk/impl/src:
main/java/org/apache/myfaces/view/facelets/tag/jsf/core/
test/java/org/apache/myfaces/view/facelets/tag/composite/
test/resources/org/apache/myfaces/view/facelets/tag/composite/
test/resources/org...
Author: lu4242
Date: Fri Aug 19 19:07:00 2011
New Revision: 1159747
URL: http://svn.apache.org/viewvc?rev=1159747&view=rev
Log:
MYFACES-3289 Allow f:event listener="#{cc.preRenderViewCallback}" work
Added:
myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/resources/testComposite/simpleFEvent2.xhtml
myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/testSimpleFEvent2.xhtml
Modified:
myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java
myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentTestCase.java
myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeTestComponent.java
Modified: myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java?rev=1159747&r1=1159746&r2=1159747&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java (original)
+++ myfaces/core/trunk/impl/src/main/java/org/apache/myfaces/view/facelets/tag/jsf/core/EventHandler.java Fri Aug 19 19:07:00 2011
@@ -28,11 +28,15 @@ import javax.el.ELException;
import javax.el.MethodExpression;
import javax.el.MethodNotFoundException;
import javax.faces.FacesException;
+import javax.faces.component.NamingContainer;
+import javax.faces.component.PartialStateHolder;
import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.event.ComponentSystemEventListener;
+import javax.faces.event.PostAddToViewEvent;
import javax.faces.event.PreRenderViewEvent;
import javax.faces.view.facelets.ComponentHandler;
import javax.faces.view.facelets.FaceletContext;
@@ -44,10 +48,10 @@ import javax.faces.view.facelets.TagHand
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletAttribute;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFFaceletTag;
-import org.apache.myfaces.config.NamedEventManager;
import org.apache.myfaces.config.RuntimeConfig;
import org.apache.myfaces.view.facelets.FaceletCompositionContext;
import org.apache.myfaces.view.facelets.FaceletViewDeclarationLanguage;
+import org.apache.myfaces.view.facelets.el.CompositeComponentELUtils;
import org.apache.myfaces.view.facelets.tag.jsf.ComponentSupport;
import org.apache.myfaces.view.facelets.util.ReflectionUtil;
@@ -73,11 +77,21 @@ public final class EventHandler extends
deferredValueType="java.lang.String")
private TagAttribute type;
+ private boolean listenerIsCompositeComponentME;
+
public EventHandler (TagConfig tagConfig)
{
super (tagConfig);
listener = getRequiredAttribute("listener");
+ if (!listener.isLiteral())
+ {
+ listenerIsCompositeComponentME = CompositeComponentELUtils.isCompositeComponentExpression(listener.getValue());
+ }
+ else
+ {
+ listenerIsCompositeComponentME = false;
+ }
type = getRequiredAttribute("type");
}
@@ -115,7 +129,18 @@ public final class EventHandler extends
{
// ensure ViewRoot for PreRenderViewEvent
UIViewRoot viewRoot = ComponentSupport.getViewRoot(ctx, parent);
- viewRoot.subscribeToEvent(eventClass, new Listener(methodExpOneArg, methodExpZeroArg));
+ if (listenerIsCompositeComponentME)
+ {
+ // Subscribe after the view is built, so we can calculate a findComponent valid expression, and then use it to
+ // put the expression in context.
+ UIComponent parentCompositeComponent = FaceletCompositionContext.getCurrentInstance(ctx).getCompositeComponentFromStack();
+ parentCompositeComponent.subscribeToEvent(PostAddToViewEvent.class,
+ new SubscribeEventListener(eventClass, methodExpOneArg, methodExpZeroArg, (eventClass == PreRenderViewEvent.class) ? null : parent));
+ }
+ else
+ {
+ viewRoot.subscribeToEvent(eventClass, new Listener(methodExpOneArg, methodExpZeroArg));
+ }
}
else
{
@@ -257,4 +282,211 @@ public final class EventHandler extends
}
}
}
+
+ public static class CompositeComponentRelativeListener implements ComponentSystemEventListener, Serializable
+ {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3822330995358746099L;
+
+ private String _compositeComponentExpression;
+ private MethodExpression methodExpOneArg;
+ private MethodExpression methodExpZeroArg;
+
+ public CompositeComponentRelativeListener()
+ {
+ super();
+ }
+
+ public CompositeComponentRelativeListener(MethodExpression methodExpOneArg,
+ MethodExpression methodExpZeroArg,
+ String compositeComponentExpression)
+ {
+ this.methodExpOneArg = methodExpOneArg;
+ this.methodExpZeroArg = methodExpZeroArg;
+ this._compositeComponentExpression = compositeComponentExpression;
+ }
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ UIComponent cc = facesContext.getViewRoot().findComponent(_compositeComponentExpression);
+
+ if (cc != null)
+ {
+ pushAllComponentsIntoStack(facesContext, cc);
+ cc.pushComponentToEL(facesContext, cc);
+ try
+ {
+ ELContext elContext = facesContext.getELContext();
+ try
+ {
+ // first try to invoke the MethodExpression with one argument
+ this.methodExpOneArg.invoke(elContext, new Object[] { event });
+ }
+ catch (MethodNotFoundException mnfeOneArg)
+ {
+ try
+ {
+ // if that fails try to invoke the MethodExpression with zero arguments
+ this.methodExpZeroArg.invoke(elContext, new Object[0]);
+ }
+ catch (MethodNotFoundException mnfeZeroArg)
+ {
+ // if that fails too rethrow the original MethodNotFoundException
+ throw mnfeOneArg;
+ }
+ }
+ }
+ finally
+ {
+ popAllComponentsIntoStack(facesContext, cc);
+ }
+ }
+ else
+ {
+ throw new NullPointerException("Composite Component associated with expression cannot be found");
+ }
+ }
+
+ private void pushAllComponentsIntoStack(FacesContext facesContext, UIComponent component)
+ {
+ UIComponent parent = component.getParent();
+ if (parent != null)
+ {
+ pushAllComponentsIntoStack(facesContext, parent);
+ }
+ component.pushComponentToEL(facesContext, component);
+ }
+
+ private void popAllComponentsIntoStack(FacesContext facesContext, UIComponent component)
+ {
+ UIComponent parent = component.getParent();
+ component.popComponentFromEL(facesContext);
+ if (parent != null)
+ {
+ popAllComponentsIntoStack(facesContext, parent);
+ }
+ }
+ }
+
+ public static final class SubscribeEventListener implements ComponentSystemEventListener, PartialStateHolder
+ {
+ private MethodExpression methodExpOneArg;
+ private MethodExpression methodExpZeroArg;
+ private Class<? extends ComponentSystemEvent> eventClass;
+ private UIComponent _targetComponent;
+ private String _targetFindComponentExpression;
+
+ private boolean markInitialState;
+
+ public SubscribeEventListener()
+ {
+ }
+
+ public SubscribeEventListener(
+ Class<? extends ComponentSystemEvent> eventClass,
+ MethodExpression methodExpOneArg,
+ MethodExpression methodExpZeroArg,
+ UIComponent targetComponent)
+ {
+ //_listener = listener;
+ this.eventClass = eventClass;
+ this.methodExpOneArg = methodExpOneArg;
+ this.methodExpZeroArg = methodExpZeroArg;
+ this._targetComponent = targetComponent;
+ }
+
+ public void processEvent(ComponentSystemEvent event)
+ {
+ UIComponent parentCompositeComponent = event.getComponent();
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ //Calculate a findComponent expression to locate the right instance so PreRenderViewEvent could be called
+ String findComponentExpression = ComponentSupport.getFindComponentExpression(facesContext, parentCompositeComponent);
+
+ //Note in practice this is only used for PreRenderViewEvent, but in the future it could be more events that
+ //require this hack.
+ if (eventClass == PreRenderViewEvent.class)
+ {
+ // ensure ViewRoot for PreRenderViewEvent
+ UIViewRoot viewRoot = facesContext.getViewRoot();
+ viewRoot.subscribeToEvent(eventClass, new CompositeComponentRelativeListener(methodExpOneArg, methodExpZeroArg, findComponentExpression));
+ }
+ else
+ {
+ if (_targetComponent == null)
+ {
+ if (_targetFindComponentExpression.startsWith(findComponentExpression) )
+ {
+ _targetComponent = ComponentSupport.findComponentChildOrFacetFrom(
+ facesContext, parentCompositeComponent,
+ _targetFindComponentExpression.substring(findComponentExpression.length()));
+ }
+ else
+ {
+ _targetComponent = facesContext.getViewRoot().findComponent(_targetFindComponentExpression);
+ }
+ }
+
+ _targetComponent.subscribeToEvent(eventClass, new CompositeComponentRelativeListener(methodExpOneArg, methodExpZeroArg, findComponentExpression));
+ }
+ }
+
+ public Object saveState(FacesContext context)
+ {
+ if (!initialStateMarked())
+ {
+ Object[] values = new Object[4];
+ values[0] = (String) ( (_targetComponent != null && _targetFindComponentExpression == null) ?
+ ComponentSupport.getFindComponentExpression(context, _targetComponent) :
+ _targetFindComponentExpression );
+ values[1] = eventClass;
+ values[2] = methodExpZeroArg;
+ values[3] = methodExpOneArg;
+ return values;
+ }
+ // If the listener was marked, no need to save anything, because
+ // this object is immutable after that.
+ return null;
+ }
+
+ public void restoreState(FacesContext context, Object state)
+ {
+ if (state == null)
+ {
+ return;
+ }
+ Object[] values = (Object[])state;
+ _targetFindComponentExpression = (String) values[0];
+ eventClass = (Class) values[1];
+ methodExpZeroArg = (MethodExpression) values[2];
+ methodExpOneArg = (MethodExpression) values[3];
+ }
+
+ public boolean isTransient()
+ {
+ return false;
+ }
+
+ public void setTransient(boolean newTransientValue)
+ {
+ // no-op as listener is transient
+ }
+
+ public void clearInitialState()
+ {
+ markInitialState = false;
+ }
+
+ public boolean initialStateMarked()
+ {
+ return markInitialState;
+ }
+
+ public void markInitialState()
+ {
+ markInitialState = true;
+ }
+ }
}
Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentTestCase.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentTestCase.java?rev=1159747&r1=1159746&r2=1159747&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentTestCase.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeComponentTestCase.java Fri Aug 19 19:07:00 2011
@@ -33,6 +33,7 @@ import javax.faces.component.UIViewRoot;
import javax.faces.component.html.HtmlCommandLink;
import javax.faces.component.html.HtmlGraphicImage;
import javax.faces.component.html.HtmlOutputText;
+import javax.faces.event.PreRenderViewEvent;
import org.apache.myfaces.config.NamedEventManager;
import org.apache.myfaces.config.RuntimeConfig;
@@ -695,6 +696,43 @@ public class CompositeComponentTestCase
}
@Test
+ public void testSimpleFEvent2() throws Exception
+ {
+ HelloWorld helloWorld = new HelloWorld();
+
+ facesContext.getExternalContext().getRequestMap().put("helloWorldBean",
+ helloWorld);
+
+ UIViewRoot root = facesContext.getViewRoot();
+ vdl.buildView(facesContext, root, "testSimpleFEvent2.xhtml");
+
+ UIComponent panelGroup1 = root.findComponent("testGroup1");
+ Assert.assertNotNull(panelGroup1);
+ CompositeTestComponent compositeComponent1 = (CompositeTestComponent) panelGroup1.getChildren().get(0);
+ Assert.assertNotNull(compositeComponent1);
+
+ application.publishEvent(facesContext, PreRenderViewEvent.class, root);
+
+ Assert.assertTrue("preRenderViewCallback should be called", (Boolean) compositeComponent1.getAttributes().get("preRenderViewCallback"));
+
+ /*
+ StringWriter sw = new StringWriter();
+ MockResponseWriter mrw = new MockResponseWriter(sw);
+ facesContext.setResponseWriter(mrw);
+
+ compositeComponent1.encodeAll(facesContext);
+
+ sw.flush();
+
+ String resp = sw.toString();
+
+ Assert.assertTrue(resp.contains("HELLO"));
+ Assert.assertTrue(resp.contains("WORLD"));
+ */
+
+ }
+
+ @Test
public void testsCompositeRefVE() throws Exception {
servletContext.addInitParameter(
Modified: myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeTestComponent.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeTestComponent.java?rev=1159747&r1=1159746&r2=1159747&view=diff
==============================================================================
--- myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeTestComponent.java (original)
+++ myfaces/core/trunk/impl/src/test/java/org/apache/myfaces/view/facelets/tag/composite/CompositeTestComponent.java Fri Aug 19 19:07:00 2011
@@ -39,6 +39,11 @@ public class CompositeTestComponent exte
getAttributes().put("postAddToViewCallback", true);
}
+ public void preRenderViewCallback(ComponentSystemEvent event)
+ {
+ getAttributes().put("preRenderViewCallback", true);
+ }
+
protected enum PropertyKeys
{
javaProperty
Added: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/resources/testComposite/simpleFEvent2.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/resources/testComposite/simpleFEvent2.xhtml?rev=1159747&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/resources/testComposite/simpleFEvent2.xhtml (added)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/resources/testComposite/simpleFEvent2.xhtml Fri Aug 19 19:07:00 2011
@@ -0,0 +1,30 @@
+<!--
+ 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.
+
+ $Id: defineInclude.xml 804043 2009-08-13 22:08:44Z lu4242 $
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:composite="http://java.sun.com/jsf/composite">
+<head>
+</head>
+<body>
+<composite:interface componentType="org.apache.myfaces.view.facelets.tag.composite.CompositeTestComponent">
+</composite:interface>
+<composite:implementation>
+ <f:event type="preRenderView" listener="#{cc.preRenderViewCallback}"/>
+</composite:implementation>
+</body>
+</html>
Added: myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/testSimpleFEvent2.xhtml
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/testSimpleFEvent2.xhtml?rev=1159747&view=auto
==============================================================================
--- myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/testSimpleFEvent2.xhtml (added)
+++ myfaces/core/trunk/impl/src/test/resources/org/apache/myfaces/view/facelets/tag/composite/testSimpleFEvent2.xhtml Fri Aug 19 19:07:00 2011
@@ -0,0 +1,29 @@
+<!--
+ 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.
+
+ $Id: defineInclude.xml 804043 2009-08-13 22:08:44Z lu4242 $
+-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://java.sun.com/jsf/html"
+ xmlns:f="http://java.sun.com/jsf/core"
+ xmlns:testComposite="http://java.sun.com/jsf/composite/testComposite">
+<head>
+</head>
+<body>
+<h:panelGroup id="testGroup1">
+<testComposite:simpleFEvent2>
+</testComposite:simpleFEvent2>
+</h:panelGroup>
+</body>
+</html>