/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2014 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.component;
import com.sun.faces.mock.MockExternalContext;
import com.sun.faces.mock.MockValueBinding;
import junit.framework.Test;
import junit.framework.TestSuite;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import javax.faces.event.*;
import javax.faces.validator.ValidatorException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
* <p>
* Base unit tests for all {@link UIComponentBase} subclasses.</p>
*/
public class UIComponentBaseTestCase extends UIComponentTestCase {
// ------------------------------------------------------ Instance Variables
// Mock object instances for our tests
// ------------------------------------------------------------ Constructors
/**
* Construct a new instance of this test case.
*
* @param name Name of the test case
*/
public UIComponentBaseTestCase(String name) {
super(name);
}
// ---------------------------------------------------- Overall Test Methods
// Set up instance variables required by this test case.
@Override
public void setUp() throws Exception {
// Set up the component under test
super.setUp();
component = new ComponentTestImpl(expectedId);
}
// Return the tests included in this test case.
public static Test suite() {
return (new TestSuite(UIComponentBaseTestCase.class));
}
// Tear down instance variables required by ths test case
@Override
public void tearDown() throws Exception {
externalContext.setRequestParameterMap(null);
super.tearDown();
}
// ------------------------------------------------- Individual Test Methods
// Test lifecycle management methods
public void testLifecycleManagement() {
checkLifecycleParentRendered();
checkLifecycleParentUnrendered();
checkLifecycleSelfRendered();
checkLifecycleSelfUnrendered();
}
public void testComponentToFromELBackwardCompatible() {
final String key = UIComponent.CURRENT_COMPONENT;
((MockExternalContext) this.facesContext.getExternalContext()).addInitParameter(UIComponent.HONOR_CURRENT_COMPONENT_ATTRIBUTES_PARAM_NAME, "true");
ComponentTestImpl c = new ComponentTestImpl();
facesContext.getAttributes().clear();
assertNull(facesContext.getAttributes().get(key));
c.pushComponentToEL(facesContext, null);
assertTrue(facesContext.getAttributes().get(key) == c);
c.popComponentFromEL(facesContext);
assertNull(facesContext.getAttributes().get(key));
}
public void testComponentToFromEL() {
final String key = UIComponent.CURRENT_COMPONENT;
ComponentTestImpl c = new ComponentTestImpl();
facesContext.getAttributes().clear();
assertNull(facesContext.getAttributes().get(key));
c.pushComponentToEL(facesContext, null);
assertFalse(facesContext.getAttributes().get(key) == c);
c.popComponentFromEL(facesContext);
assertNull(facesContext.getAttributes().get(key));
}
public void testComponentToFromEL2() throws Exception {
final String key = UIComponent.CURRENT_COMPONENT;
final FacesContext ctx = facesContext;
ComponentTestImpl c = new ComponentTestImpl();
ComponentTestImpl c2 = new ComponentTestImpl();
UIComponent eeo = new UIComponentOverrideEncodeEnd();
ComponentTestImpl c3 = new ComponentTestImpl();
UIComponent ebo = new UIComponentOverrideEncodeBegin();
c.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c);
c2.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c2);
c2.encodeEnd(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c);
c.encodeEnd(ctx);
assertNull(UIComponent.getCurrentComponent(ctx));
// sanity check for the case where a component overrides
// encodeBegin() without calling super or pushComponentToEL
c.encodeBegin(ctx);
c2.encodeBegin(ctx);
ebo.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c2);
ebo.encodeEnd(ctx); // if the component wasn't pushed
// it shouldn't be popped.
assertEquals(UIComponent.getCurrentComponent(ctx), c2);
c2.encodeEnd(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c);
c.encodeEnd(ctx);
assertNull(UIComponent.getCurrentComponent(ctx));
// sanity check for the case where a component overrides
// encodeEnd() without calling super or popComponentFromEL
c.encodeBegin(ctx);
c2.encodeBegin(ctx);
eeo.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
eeo.encodeEnd(ctx);
// this is ugly. Because of a component not doing calling
// super() or popComponentFromEL, c2 won't be visible
// as the current component.
assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
c2.encodeEnd(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c);
c.encodeEnd(ctx);
assertNull(UIComponent.getCurrentComponent(ctx));
UIComponent eeo2 = new UIComponentOverrideEncodeEnd();
c.encodeBegin(ctx);
c2.encodeBegin(ctx);
eeo.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
c3.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c3);
eeo2.encodeBegin(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
eeo2.encodeEnd(ctx);
// this is ugly.
assertEquals(UIComponent.getCurrentComponent(ctx), eeo2);
c3.encodeEnd(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
eeo.encodeEnd(ctx);
// this is ugly.
assertEquals(UIComponent.getCurrentComponent(ctx), eeo);
c2.encodeEnd(ctx);
assertEquals(UIComponent.getCurrentComponent(ctx), c);
c.encodeEnd(ctx);
assertNull(UIComponent.getCurrentComponent(ctx));
}
public void testEncodeChildren() throws Exception {
ComponentTestImpl.trace(null);
UIComponent comp1 = new ComponentTestImpl("one");
UIComponent comp2 = new ComponentTestImpl("two");
UIComponent comp3 = new ComponentTestImpl("three");
UIComponent comp4 = new ComponentTestImpl("four");
comp1.getChildren().add(comp2);
comp1.getChildren().add(comp3);
comp1.getChildren().add(comp4);
comp1.encodeChildren(facesContext);
System.out.println("Actual: " + ComponentTestImpl.trace());
System.out.println("Expected: " + "/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four");
assertEquals("/eC-one/eB-two/eE-two/eB-three/eE-three/eB-four/eE-four", ComponentTestImpl.trace());
}
// Test recursive adding and removing child trees with ids
public void testChildrenRecursive() {
// Create the components we will need
UIComponent testComponent = new ComponentTestImpl();
UIComponent child1 = new ComponentTestImpl("child1");
UIComponent child2 = new ComponentTestImpl("child2");
UIComponent child3 = new ComponentTestImpl("child3");
// Prepare ancestry tree before adding to base component
child1.getChildren().add(child2);
child2.getChildren().add(child3);
// Verify that no child ids are visible yet
assertNull(testComponent.findComponent("child1"));
assertNull(testComponent.findComponent("child2"));
assertNull(testComponent.findComponent("child3"));
// Add the entire tree
testComponent.getChildren().add(child1);
// Verify that all named children get added
assertEquals(child1, testComponent.findComponent("child1"));
assertEquals(child2, testComponent.findComponent("child2"));
assertEquals(child3, testComponent.findComponent("child3"));
// Remove the entire tree
testComponent.getChildren().remove(child1);
// Verify that child ids are no longer visible
assertNull(testComponent.findComponent("child1"));
assertNull(testComponent.findComponent("child2"));
assertNull(testComponent.findComponent("child3"));
}
public void testChildrenAndFacetsWithNullGetParent() throws Exception {
ComponentTestImpl child = new ComponentTestImpl() {
@Override
public UIComponent getParent() {
return null;
}
};
component.getChildren().add(child);
assertNull(component.getChildren().get(0).getParent());
ComponentTestImpl facet = new ComponentTestImpl() {
@Override
public UIComponent getParent() {
return null;
}
};
component.getFacets().put("nullParent", facet);
assertNull(component.getFacets().get("nullParent").getParent());
}
// Test reconnecting a child or facet to a different component
public void testComponentReconnect() {
UIComponent parent1 = new ComponentTestImpl();
UIComponent parent2 = new ComponentTestImpl();
// Reconnect an existing child as a child
checkChildCount(parent1, 0);
checkChildCount(parent2, 0);
parent1.getChildren().add(component);
checkChildCount(parent1, 1);
checkChildCount(parent2, 0);
checkChildPresent(parent1, component, 0);
parent2.getChildren().add(component);
checkChildCount(parent1, 0);
checkChildCount(parent2, 1);
checkChildPresent(parent2, component, 0);
parent2.getChildren().clear();
checkChildCount(parent1, 0);
checkChildCount(parent2, 0);
// Reconnect an existing child as a facet
checkChildCount(parent1, 0);
checkFacetCount(parent2, 0);
parent1.getChildren().add(component);
checkChildCount(parent1, 1);
checkFacetCount(parent2, 0);
checkChildPresent(parent1, component, 0);
parent2.getFacets().put("facet", component);
checkChildCount(parent1, 0);
checkFacetCount(parent2, 1);
checkFacetPresent(parent2, "facet", component);
parent2.getFacets().clear();
checkChildCount(parent1, 0);
checkFacetCount(parent2, 0);
// Reconnect an existing facet as a child
checkFacetCount(parent1, 0);
checkChildCount(parent2, 0);
parent1.getFacets().put("facet", component);
checkFacetCount(parent1, 1);
checkChildCount(parent2, 0);
checkFacetPresent(parent1, "facet", component);
parent2.getChildren().add(component);
checkFacetCount(parent1, 0);
checkChildCount(parent2, 1);
checkChildPresent(parent2, component, 0);
parent2.getChildren().clear();
checkFacetCount(parent1, 0);
checkChildCount(parent2, 0);
}
// Test removing components from our naming container.
public void testComponentRemoval() {
UIComponent testComponent = new ComponentTestImpl();
UIComponent child1 = new ComponentTestImpl("child1");
UIComponent child2 = new ComponentTestImpl("child2");
UIComponent child3 = new ComponentTestImpl("child3");
UIComponent child = null;
//adding children to naming container
testComponent.getChildren().add(child1);
testComponent.getChildren().add(child2);
testComponent.getChildren().add(child3);
// make sure children are stored in naming container properly
Iterator kidItr = null;
kidItr = testComponent.getFacetsAndChildren();
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child1));
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child2));
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child3));
//make sure child is removed from component and naming container
//pass in a component to remove method
testComponent.getChildren().remove(child1);
kidItr = testComponent.getFacetsAndChildren();
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child2));
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child3));
//make sure child is removed from component and naming container
//pass an index to remove method
testComponent.getChildren().remove(0);
kidItr = testComponent.getFacetsAndChildren();
child = (UIComponent) kidItr.next();
assertTrue(child.equals(child3));
//make sure child is removed from component and naming container
//remove all children
testComponent.getChildren().clear();
kidItr = testComponent.getFacetsAndChildren();
assertTrue(!kidItr.hasNext());
}
public void testStateHolder() throws Exception {
// Set up the components we will need
UIComponent parent = new ComponentTestImpl("root");
UIComponent preSave = createComponent();
UIComponent facet1 = createComponent();
facet1.setId("facet1");
preSave.getFacets().put("facet1 key", facet1);
UIComponent facet2 = createComponent();
facet2.setId("facet2");
preSave.getFacets().put("facet2 key", facet2);
parent.getChildren().add(preSave);
populateComponent(preSave);
UIComponent postSave = createComponent();
// Save and restore state and compare the results
Object state = preSave.saveState(facesContext);
assertNotNull(state);
postSave.restoreState(facesContext, state);
checkComponents(preSave, postSave);
checkValueBindings(preSave, postSave);
checkComponentListeners(preSave, postSave);
}
public void testStateHolder2() throws Exception {
UIComponent c = new UIComponentListener();
c.subscribeToEvent(PostAddToViewEvent.class, (ComponentSystemEventListener) c);
Object state = c.saveState(facesContext);
c = new UIComponentListener();
c.pushComponentToEL(facesContext, c);
c.restoreState(facesContext, state);
c.popComponentFromEL(facesContext);
assertTrue(c.getListenersForEventClass(PostAddToViewEvent.class).size() == 1);
}
public void testValueBindings() {
UIComponentBase test = (UIComponentBase) component;
// generic attributes
request.setAttribute("foo", "bar");
Object result = test.getAttributes().get("childCount");
test.getAttributes().clear();
assertNull(test.getAttributes().get("baz"));
test.setValueBinding("baz", application.createValueBinding("#{foo}"));
assertEquals("bar", test.getAttributes().get("baz"));
test.getAttributes().put("baz", "bop");
assertEquals("bop", test.getAttributes().get("baz"));
test.getAttributes().remove("baz");
assertEquals("bar", test.getAttributes().get("baz"));
test.setValueBinding("baz", null);
assertNull(test.getAttributes().get("baz"));
// "id" property
try {
test.setValueBinding("id",
application.createValueBinding("#{foo}"));
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected response
}
// "parent" property
try {
test.setValueBinding("parent",
application.createValueBinding("#{foo}"));
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected response
}
// "rendered" property
request.setAttribute("foo", Boolean.FALSE);
boolean initial = test.isRendered();
if (initial) {
request.setAttribute("foo", Boolean.FALSE);
} else {
request.setAttribute("foo", Boolean.TRUE);
}
test.setValueBinding("rendered", application.createValueBinding("#{foo}"));
assertEquals(!initial, test.isRendered());
test.setRendered(initial);
assertEquals(initial, test.isRendered());
assertNotNull(test.getValueBinding("rendered"));
// "rendererType" property
request.setAttribute("foo", "bar");
test.setRendererType(null);
assertNull(test.getRendererType());
test.setValueBinding("rendererType", application.createValueBinding("#{foo}"));
assertNotNull(test.getValueBinding("rendererType"));
assertEquals("bar", test.getRendererType());
test.setRendererType("baz");
assertEquals("baz", test.getRendererType());
test.setRendererType(null);
assertEquals("bar", test.getRendererType());
test.setValueBinding("rendererType", null);
assertNull(test.getValueBinding("rendererType"));
assertNull(test.getRendererType());
}
public void testValueExpressions() throws Exception {
UIComponentBase test = (UIComponentBase) component;
// generic attributes
request.setAttribute("foo", "bar");
test.getAttributes().clear();
assertNull(test.getAttributes().get("baz"));
test.setValueExpression("baz", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
assertEquals("bar", test.getAttributes().get("baz"));
test.getAttributes().put("baz", "bop");
assertEquals("bop", test.getAttributes().get("baz"));
test.getAttributes().remove("baz");
assertEquals("bar", test.getAttributes().get("baz"));
test.setValueExpression("baz", null);
assertNull(test.getAttributes().get("baz"));
// "id" property
try {
test.setValueExpression("id",
application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected response
}
// "parent" property
try {
test.setValueExpression("parent",
application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", UIComponent.class));
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException e) {
// Expected response
}
// "rendered" property
request.setAttribute("foo", Boolean.FALSE);
test.setValueExpression("rendered", null);
boolean initial = test.isRendered();
if (initial) {
request.setAttribute("foo", Boolean.FALSE);
} else {
request.setAttribute("foo", Boolean.TRUE);
}
test.setValueExpression("rendered", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", Boolean.class));
assertEquals(!initial, test.isRendered());
test.setRendered(initial);
assertEquals(initial, test.isRendered());
assertNotNull(test.getValueExpression("rendered"));
// "rendererType" property
request.setAttribute("foo", "bar");
test.setRendererType(null);
assertNull(test.getRendererType());
test.setValueExpression("rendererType", application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class));
assertNotNull(test.getValueExpression("rendererType"));
assertEquals("bar", test.getRendererType());
test.setRendererType("baz");
assertEquals("baz", test.getRendererType());
test.setRendererType(null);
assertEquals("bar", test.getRendererType());
test.setValueExpression("rendererType", null);
assertNull(test.getValueExpression("rendererType"));
assertNull(test.getRendererType());
}
public void testValueExpressionValueBindingIdempotency() throws Exception {
UIComponentBase test = (UIComponentBase) component;
request.setAttribute("foo", "bar");
test.getAttributes().clear();
assertNull(test.getAttributes().get("baz"));
ValueBinding binding = null;
ValueExpression expression = null;
binding = application.createValueBinding("#{foo}");
test.setValueBinding("baz", binding);
expression = test.getValueExpression("baz");
assertEquals(binding.getExpressionString(),
expression.getExpressionString());
test.setValueBinding("baz", null);
expression = application.getExpressionFactory().createValueExpression(facesContext.getELContext(), "#{foo}", String.class);
test.setValueExpression("baz", expression);
binding = test.getValueBinding("baz");
assertEquals(binding.getExpressionString(),
expression.getExpressionString());
test.setValueBinding("baz", null);
}
public void testMethodBindingAdapterBaseException() throws Exception {
IllegalThreadStateException itse = new IllegalThreadStateException("The root cause!");
AbortProcessingException ape = new CustomAbortProcessingException(itse);
InvocationTargetException ite1 = new InvocationTargetException(ape);
InvocationTargetException ite2 = new InvocationTargetException(ite1);
InvocationTargetException ite3 = new InvocationTargetException(ite2);
MethodBindingValueChangeListener mbvcl
= new MethodBindingValueChangeListener();
Throwable expected
= mbvcl.getExpectedCause(AbortProcessingException.class, ite3);
assertEquals(expected, ape);
ValidatorException ve = new ValidatorException(new FacesMessage(),
itse);
ite1 = new InvocationTargetException(ve);
ite2 = new InvocationTargetException(ite1);
ite3 = new InvocationTargetException(ite2);
MethodBindingValidator mbv = new MethodBindingValidator();
expected
= mbv.getExpectedCause(ValidatorException.class, ite3);
assertEquals(expected, ve);
}
// --------------------------------------------------------- support Methods
// Check that the attributes on the specified components are equal
protected void checkAttributes(UIComponent comp1, UIComponent comp2) {
assertEquals(comp1.getAttributes(), comp2.getAttributes());
}
// Check that the specified components are equal
protected void checkComponents(UIComponent comp1, UIComponent comp2) {
checkAttributes(comp1, comp2);
// checkFacets(comp1, comp2); // Not saved and restored by component
checkProperties(comp1, comp2);
}
// Check lifecycle processing when parent "rendered" property is "true"
private void checkLifecycleParentRendered() {
// Put our component under test in a tree under a UIViewRoot
component.getAttributes().clear();
component.getChildren().clear();
component.getFacets().clear();
component.setRendered(true);
UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
UIPanel panel = new UIPanel();
panel.setRendered(true);
root.getChildren().add(panel);
panel.getChildren().add(component);
// Establish a view with multiple facets and children
UIComponent facet1 = new ComponentTestImpl("f1");
UIComponent facet2 = new ComponentTestImpl("f2");
UIComponent facet3 = new ComponentTestImpl("f3");
component.getFacets().put("f1", facet1);
component.getFacets().put("f2", facet2);
component.getFacets().put("f3", facet3);
checkFacetCount(component, 3);
UIComponent child1 = new ComponentTestImpl("c1");
UIComponent child2 = new ComponentTestImpl("c2");
UIComponent child3 = new ComponentTestImpl("c3");
component.getChildren().add(child1);
component.getChildren().add(child2);
component.getChildren().add(child3);
checkChildCount(component, 3);
UIComponent child2a = new ComponentTestImpl("c2a");
UIComponent child2b = new ComponentTestImpl("c2b");
child2.getChildren().add(child2a);
child2.getChildren().add(child2b);
checkChildCount(child2, 2);
// Enqueue a single FacesEvent for each component
component.queueEvent(new EventTestImpl(component));
component.queueEvent(new EventTestImpl(facet1));
component.queueEvent(new EventTestImpl(facet2));
component.queueEvent(new EventTestImpl(facet3));
component.queueEvent(new EventTestImpl(child1));
component.queueEvent(new EventTestImpl(child2));
component.queueEvent(new EventTestImpl(child3));
component.queueEvent(new EventTestImpl(child2a));
component.queueEvent(new EventTestImpl(child2b));
// Test processDecodes()
ComponentTestImpl.trace(null);
component.processDecodes(facesContext);
assertEquals("processDecodes",
lifecycleTrace("pD", "d"),
ComponentTestImpl.trace());
// Test processValidators()
ComponentTestImpl.trace(null);
component.processValidators(facesContext);
assertEquals("processValidators",
lifecycleTrace("pV", null),
ComponentTestImpl.trace());
// Test processUpdates()
ComponentTestImpl.trace(null);
component.processUpdates(facesContext);
assertEquals("processUpdates",
lifecycleTrace("pU", null),
ComponentTestImpl.trace());
}
// Check lifecycle processing when parent "rendered" property is "false"
private void checkLifecycleParentUnrendered() {
// Put our component under test in a tree under a UIViewRoot
component.getAttributes().clear();
component.getChildren().clear();
component.getFacets().clear();
component.setRendered(true);
UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
UIPanel panel = new UIPanel();
panel.setRendered(false);
root.getChildren().add(panel);
panel.getChildren().add(component);
// Establish a view with multiple facets and children
UIComponent facet1 = new ComponentTestImpl("f1");
UIComponent facet2 = new ComponentTestImpl("f2");
UIComponent facet3 = new ComponentTestImpl("f3");
component.getFacets().put("f1", facet1);
component.getFacets().put("f2", facet2);
component.getFacets().put("f3", facet3);
checkFacetCount(component, 3);
UIComponent child1 = new ComponentTestImpl("c1");
UIComponent child2 = new ComponentTestImpl("c2");
UIComponent child3 = new ComponentTestImpl("c3");
component.getChildren().add(child1);
component.getChildren().add(child2);
component.getChildren().add(child3);
checkChildCount(component, 3);
UIComponent child2a = new ComponentTestImpl("c2a");
UIComponent child2b = new ComponentTestImpl("c2b");
child2.getChildren().add(child2a);
child2.getChildren().add(child2b);
checkChildCount(child2, 2);
// Enqueue a single FacesEvent for each component
component.queueEvent(new EventTestImpl(component));
component.queueEvent(new EventTestImpl(facet1));
component.queueEvent(new EventTestImpl(facet2));
component.queueEvent(new EventTestImpl(facet3));
component.queueEvent(new EventTestImpl(child1));
component.queueEvent(new EventTestImpl(child2));
component.queueEvent(new EventTestImpl(child3));
component.queueEvent(new EventTestImpl(child2a));
component.queueEvent(new EventTestImpl(child2b));
// Test processDecodes()
ComponentTestImpl.trace(null);
component.processDecodes(facesContext);
assertEquals("processDecodes",
lifecycleTrace("pD", "d"),
ComponentTestImpl.trace());
// Test processValidators()
ComponentTestImpl.trace(null);
component.processValidators(facesContext);
assertEquals("processValidators",
lifecycleTrace("pV", null),
ComponentTestImpl.trace());
// Test processUpdates()
ComponentTestImpl.trace(null);
component.processUpdates(facesContext);
assertEquals("processUpdates",
lifecycleTrace("pU", null),
ComponentTestImpl.trace());
}
// Check lifecycle processing when our "rendered" property is "true"
private void checkLifecycleSelfRendered() {
// Put our component under test in a tree under a UIViewRoot
component.getAttributes().clear();
component.getChildren().clear();
component.getFacets().clear();
component.setRendered(true);
UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
root.getChildren().add(component);
// Establish a view with multiple facets and children
UIComponent facet1 = new ComponentTestImpl("f1");
UIComponent facet2 = new ComponentTestImpl("f2");
UIComponent facet3 = new ComponentTestImpl("f3");
component.getFacets().put("f1", facet1);
component.getFacets().put("f2", facet2);
component.getFacets().put("f3", facet3);
checkFacetCount(component, 3);
UIComponent child1 = new ComponentTestImpl("c1");
UIComponent child2 = new ComponentTestImpl("c2");
UIComponent child3 = new ComponentTestImpl("c3");
component.getChildren().add(child1);
component.getChildren().add(child2);
component.getChildren().add(child3);
checkChildCount(component, 3);
UIComponent child2a = new ComponentTestImpl("c2a");
UIComponent child2b = new ComponentTestImpl("c2b");
child2.getChildren().add(child2a);
child2.getChildren().add(child2b);
checkChildCount(child2, 2);
// Enqueue a single FacesEvent for each component
component.queueEvent(new EventTestImpl(component));
component.queueEvent(new EventTestImpl(facet1));
component.queueEvent(new EventTestImpl(facet2));
component.queueEvent(new EventTestImpl(facet3));
component.queueEvent(new EventTestImpl(child1));
component.queueEvent(new EventTestImpl(child2));
component.queueEvent(new EventTestImpl(child3));
component.queueEvent(new EventTestImpl(child2a));
component.queueEvent(new EventTestImpl(child2b));
// Test processDecodes()
ComponentTestImpl.trace(null);
component.processDecodes(facesContext);
assertEquals("processDecodes",
lifecycleTrace("pD", "d"),
ComponentTestImpl.trace());
// Test processValidators()
ComponentTestImpl.trace(null);
component.processValidators(facesContext);
assertEquals("processValidators",
lifecycleTrace("pV", null),
ComponentTestImpl.trace());
// Test processUpdates()
ComponentTestImpl.trace(null);
component.processUpdates(facesContext);
assertEquals("processUpdates",
lifecycleTrace("pU", null),
ComponentTestImpl.trace());
}
// Check lifecycle processing when our "rendered" property is "false"
private void checkLifecycleSelfUnrendered() {
// Put our component under test in a tree under a UIViewRoot
component.getAttributes().clear();
component.getChildren().clear();
component.getFacets().clear();
component.setRendered(false);
UIViewRoot root = facesContext.getApplication().getViewHandler().createView(facesContext, null);
root.getChildren().add(component);
// Establish a view with multiple facets and children
UIComponent facet1 = new ComponentTestImpl("f1");
UIComponent facet2 = new ComponentTestImpl("f2");
UIComponent facet3 = new ComponentTestImpl("f3");
component.getFacets().put("f1", facet1);
component.getFacets().put("f2", facet2);
component.getFacets().put("f3", facet3);
checkFacetCount(component, 3);
UIComponent child1 = new ComponentTestImpl("c1");
UIComponent child2 = new ComponentTestImpl("c2");
UIComponent child3 = new ComponentTestImpl("c3");
component.getChildren().add(child1);
component.getChildren().add(child2);
component.getChildren().add(child3);
checkChildCount(component, 3);
UIComponent child2a = new ComponentTestImpl("c2a");
UIComponent child2b = new ComponentTestImpl("c2b");
child2.getChildren().add(child2a);
child2.getChildren().add(child2b);
checkChildCount(child2, 2);
// Enqueue a single FacesEvent for each component
component.queueEvent(new EventTestImpl(component));
component.queueEvent(new EventTestImpl(facet1));
component.queueEvent(new EventTestImpl(facet2));
component.queueEvent(new EventTestImpl(facet3));
component.queueEvent(new EventTestImpl(child1));
component.queueEvent(new EventTestImpl(child2));
component.queueEvent(new EventTestImpl(child3));
component.queueEvent(new EventTestImpl(child2a));
component.queueEvent(new EventTestImpl(child2b));
// Test processDecodes()
ComponentTestImpl.trace(null);
component.processDecodes(facesContext);
assertEquals("processDecodes",
lifecycleTrace("pD", "d"),
ComponentTestImpl.trace());
// Test processValidators()
ComponentTestImpl.trace(null);
component.processValidators(facesContext);
assertEquals("processValidators",
lifecycleTrace("pV", null),
ComponentTestImpl.trace());
// Test processUpdates()
ComponentTestImpl.trace(null);
component.processUpdates(facesContext);
assertEquals("processUpdates",
lifecycleTrace("pU", null),
ComponentTestImpl.trace());
}
// Check that the properties on the specified components are equal
protected void checkProperties(UIComponent comp1, UIComponent comp2) {
assertEquals(comp1.getClientId(facesContext),
comp2.getClientId(facesContext));
assertEquals(comp1.getId(), comp2.getId());
assertEquals(comp1.isRendered(), comp2.isRendered());
assertEquals(comp1.getRendererType(), comp2.getRendererType());
assertEquals(comp1.getRendersChildren(), comp2.getRendersChildren());
}
// Check that the configured ValueBindings got restored
protected void checkValueBindings(UIComponent comp1, UIComponent comp2) {
ValueBinding vb1, vb2;
vb1 = comp1.getValueBinding("baz");
vb2 = comp2.getValueBinding("baz");
assertEquals(((MockValueBinding) vb1).ref(),
((MockValueBinding) vb2).ref());
vb1 = comp1.getValueBinding("bop");
vb2 = comp2.getValueBinding("bop");
assertEquals(((MockValueBinding) vb1).ref(),
((MockValueBinding) vb2).ref());
}
protected void checkComponentListeners(UIComponent control, UIComponent toValidate) {
List<SystemEventListener> lc = control.getListenersForEventClass(PostAddToViewEvent.class);
List<SystemEventListener> tvl = toValidate.getListenersForEventClass(PostAddToViewEvent.class);
List<SystemEventListener> lc2 = control.getListenersForEventClass(PostConstructViewMapEvent.class);
List<SystemEventListener> tvl2 = toValidate.getListenersForEventClass(PostConstructViewMapEvent.class);
assertTrue(lc.size() == tvl.size());
assertTrue(lc2.size() == tvl2.size());
}
// Create a pristine component of the type to be used in state holder tests
protected UIComponent createComponent() {
return (new ComponentTestImpl());
}
// Populate a pristine component to be used in state holder tests
protected void populateComponent(UIComponent component) {
component.getAttributes().put("foo", "foo value");
component.getAttributes().put("bar", "bar value");
component.setId("componentId");
component.getClientId(facesContext); // Forces evaluation
component.setRendered(false);
component.setRendererType(null); // Since we have no renderers
component.setValueBinding("baz",
application.createValueBinding("baz.value"));
component.setValueBinding("bop",
application.createValueBinding("bop.value"));
component.subscribeToEvent(PostAddToViewEvent.class,
new ComponentListener());
component.subscribeToEvent(PostAddToViewEvent.class,
new ComponentListener());
component.subscribeToEvent(PostConstructViewMapEvent.class,
new ComponentListener());
}
/**
* Construct and return a lifecycle method call trace for the specified
* method names.
*
* @param lmethod Name of the lifecycle method under test
* @param cmethod Name of the component method that corresponds
* @return
*/
protected String lifecycleTrace(String lmethod, String cmethod) {
StringBuffer sb = new StringBuffer();
lifecycleTrace(lmethod, cmethod, component, sb);
return (sb.toString());
}
protected void lifecycleTrace(String lmethod, String cmethod,
UIComponent component, StringBuffer sb) {
// Append the call for this lifecycle method
String id = component.getId();
sb.append("/").append(lmethod).append("-").append(id);
if (!component.isRendered()) {
return;
}
// Append the calls for each facet
Iterator names = component.getFacets().keySet().iterator();
while (names.hasNext()) {
String name = (String) names.next();
sb.append("/").append(lmethod).append("-").append(name);
if ((cmethod != null)
&& ((UIComponent) component.getFacets().get(name)).isRendered()) {
sb.append("/").append(cmethod).append("-").append(name);
}
}
// Append the calls for each child
Iterator kids = component.getChildren().iterator();
while (kids.hasNext()) {
UIComponent kid = (UIComponent) kids.next();
lifecycleTrace(lmethod, cmethod, kid, sb);
}
// Append the call for this component's component method
if ((cmethod != null) && component.isRendered()) {
sb.append("/").append(cmethod).append("-").append(id);
}
}
public void testGetFacetsAndChildren() {
UIComponent testComponent = new ComponentTestImpl();
UIComponent child1 = new ComponentTestImpl("child1");
UIComponent child2 = new ComponentTestImpl("child2");
UIComponent child3 = new ComponentTestImpl("child3");
UIComponent facet1 = new ComponentTestImpl("facet1");
UIComponent facet2 = new ComponentTestImpl("facet2");
UIComponent facet3 = new ComponentTestImpl("facet3");
testComponent.getChildren().add(child1);
testComponent.getChildren().add(child2);
testComponent.getChildren().add(child3);
testComponent.getFacets().put("facet1", facet1);
testComponent.getFacets().put("facet2", facet2);
testComponent.getFacets().put("facet3", facet3);
Iterator iter = testComponent.getFacetsAndChildren();
Object cur = null;
boolean exceptionThrown = false;
assertTrue(iter.hasNext());
try {
iter.remove();
} catch (UnsupportedOperationException e) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
// facets are returned in an undefined order.
cur = iter.next();
assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
cur = iter.next();
assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
cur = iter.next();
assertTrue(cur == facet1 || cur == facet2 || cur == facet3);
// followed by components, in the order added
cur = iter.next();
assertTrue(cur == child1);
cur = iter.next();
assertTrue(cur == child2);
cur = iter.next();
assertTrue(cur == child3);
assertTrue(!iter.hasNext());
}
private Object foundComponent = null;
/**
* <p>
* Build a tree with the following layout.</p>
* <code><pre>
* root: id: root
* <p/>
* form1: id: form1
* <p/>
* panel1: id: panel
* <p/>
* input1: id: input1
* <p/>
* input2: id: input2
* <p/>
* form2: id: form2
* <p/>
* panel2: id: panel
* <p/>
* input3: id: input1
* <p/>
* input4: id: input2
* </pre></code>
*
* @return a Map<String, UIComponent>. The key is the string before the
* first : in the above layout. The value is the component instance. Note
* that the keys in the map are <b>not</b> the ids.
*/
private Map<String, UIComponent> setupInvokeOnComponentTree() {
UIViewRoot root = new UIViewRoot();
UIForm form1 = new UIForm();
UIPanel panel1 = new UIPanel();
UIInput input1 = new UIInput();
UIInput input2 = new UIInput();
UIForm form2 = new UIForm();
UIPanel panel2 = new UIPanel();
UIInput input3 = new UIInput();
UIInput input4 = new UIInput();
root.setId("root");
form1.setId("form1");
panel1.setId("panel");
input1.setId("input1");
input2.setId("input2");
form2.setId("form2");
panel2.setId("panel");
input3.setId("input1");
input4.setId("input2");
root.getChildren().add(form1);
form1.getChildren().add(panel1);
panel1.getChildren().add(input1);
panel1.getChildren().add(input2);
root.getChildren().add(form2);
form2.getChildren().add(panel2);
panel2.getChildren().add(input3);
panel2.getChildren().add(input4);
Map<String, UIComponent> result = new HashMap<String, UIComponent>();
result.put("root", root);
result.put("form1", form1);
result.put("panel1", panel1);
result.put("input1", input1);
result.put("input2", input2);
result.put("form2", form2);
result.put("panel2", panel2);
result.put("input3", input3);
result.put("input4", input4);
return result;
}
public void testInvokeOnComponentPositive() throws Exception {
Map<String, UIComponent> tree = setupInvokeOnComponentTree();
UIViewRoot root = (UIViewRoot) tree.get("root");
UIInput input1 = (UIInput) tree.get("input1");
foundComponent = null;
boolean result = false;
assertNull(UIComponent.getCurrentComponent(facesContext));
result = root.invokeOnComponent(facesContext,
input1.getClientId(facesContext),
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
assertEquals("getCurrentComponent does not return the current component during"
+ "invokeOnComponent", UIComponent.getCurrentComponent(context), component);
foundComponent = component;
}
});
assertEquals(input1, foundComponent);
assertTrue(result);
assertNull(UIComponent.getCurrentComponent(facesContext));
}
public void testInvokeOnComponentNegative() throws Exception {
Map<String, UIComponent> tree = setupInvokeOnComponentTree();
UIViewRoot root = (UIViewRoot) tree.get("root");
UIInput input4 = (UIInput) tree.get("input4");
foundComponent = null;
boolean result = false;
boolean exceptionThrown = false;
// Negative case 0, null pointers
exceptionThrown = false;
FacesContext nullContext = null;
ContextCallback nullCallback = null;
try {
root.invokeOnComponent(nullContext, "form:input7",
nullCallback);
} catch (NullPointerException npe) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
exceptionThrown = false;
try {
root.invokeOnComponent(facesContext, null,
nullCallback);
} catch (NullPointerException npe) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
exceptionThrown = false;
try {
root.invokeOnComponent(nullContext, null,
nullCallback);
} catch (NullPointerException npe) {
exceptionThrown = true;
}
assertTrue(exceptionThrown);
// Negative case 1, not found component.
result = root.invokeOnComponent(facesContext,
"form:input7",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
}
});
assertNull(foundComponent);
assertTrue(!result);
// Negative case 2A, callback throws exception with found component
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"form2:input2",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
// When else am I going to get the chance to throw this exception?
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertTrue(exceptionThrown);
assertEquals(foundComponent, input4);
assertTrue(!result);
// Negative case 2B, callback throws exception with not found component
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"form2:input6",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
// When else am I going to get the chance to throw this exception?
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertTrue(!exceptionThrown);
assertNull(foundComponent);
assertTrue(!result);
}
public void testInvokeOnComponentWithPrependId() throws Exception {
Map<String, UIComponent> tree = setupInvokeOnComponentTree();
UIViewRoot root = (UIViewRoot) tree.get("root");
UIForm truePrependIdForm = (UIForm) tree.get("form1");
UIForm falsePrependIdForm = (UIForm) tree.get("form2");
UIInput truePrependIdInput = (UIInput) tree.get("input2");
UIInput falsePrependIdInput = (UIInput) tree.get("input3");
truePrependIdForm.setPrependId(true);
falsePrependIdForm.setPrependId(false);
foundComponent = null;
boolean result = false;
boolean exceptionThrown = false;
// Case 1, positive find with prependId == true
result = root.invokeOnComponent(facesContext,
"form1:input2",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
}
});
assertEquals(truePrependIdInput, foundComponent);
assertTrue(result);
// Case 2, negative find with prependId == true
foundComponent = null;
result = false;
result = root.invokeOnComponent(facesContext,
"form9:input5",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
}
});
assertNull(foundComponent);
assertTrue(!result);
// Case 3, exception positive find with prependId == true
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"form1:input2",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertEquals(truePrependIdInput, foundComponent);
assertTrue(!result);
assertTrue(exceptionThrown);
// Case 4, exception negative find with prependId == true
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"formFozzy:inputKermit",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertNull(foundComponent);
assertTrue(!result);
assertTrue(!exceptionThrown);
// Case 5, positive find with prependId == false
result = root.invokeOnComponent(facesContext,
"input1",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
}
});
assertEquals(falsePrependIdInput, foundComponent);
assertTrue(result);
// Case 6, negative find with prependId == false
foundComponent = null;
result = false;
result = root.invokeOnComponent(facesContext,
"input99",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
}
});
assertNull(foundComponent);
assertTrue(!result);
// Case 3, exception positive find with prependId == false
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"input1",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertEquals(falsePrependIdInput, foundComponent);
assertTrue(!result);
assertTrue(exceptionThrown);
// Case 4, exception negative find with prependId == false
foundComponent = null;
result = false;
exceptionThrown = false;
try {
result = root.invokeOnComponent(facesContext,
"inputKermit",
new ContextCallback() {
@Override
public void invokeContextCallback(FacesContext context, UIComponent component) {
foundComponent = component;
throw new IllegalStateException();
}
});
} catch (FacesException e) {
assertTrue(e.getCause() instanceof IllegalStateException);
exceptionThrown = true;
}
assertNull(foundComponent);
assertTrue(!result);
assertTrue(!exceptionThrown);
}
public void testChildrenListAfterAddPublish() {
Listener listener = new Listener();
application.subscribeToEvent(PostAddToViewEvent.class, listener);
UIComponent c1 = createComponent();
c1.setInView(true);
UIComponent c2 = createComponent();
c2.setInView(true);
UIComponent c3 = createComponent();
c3.setInView(true);
c1.getChildren().add(c2);
SystemEvent e = listener.getEvent();
assertNotNull(e);
assertTrue(e.getSource() == c2);
assertTrue(((UIComponent) e.getSource()).getParent() == c1);
listener.reset();
c2.getChildren().add(c3);
e = listener.getEvent();
assertNotNull(e);
assertTrue(e.getSource() == c3);
assertTrue(((UIComponent) e.getSource()).getParent() == c2);
//ensure events are re-published if the event is added
listener.reset();
c2.getChildren().remove(c3);
c1.getChildren().add(c3);
e = listener.getEvent();
assertNotNull(e);
assertTrue(e.getSource() == c3);
assertTrue(((UIComponent) e.getSource()).getParent() == c1);
application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
}
public void testFacetMapAfterAddViewPublish() {
QueueingListener listener = new QueueingListener();
application.subscribeToEvent(PostAddToViewEvent.class, listener);
UIComponent c1 = createComponent();
UIComponent c2 = createComponent();
UIComponent c3 = createComponent();
List<SystemEvent> e = listener.getEvents();
Map<String, UIComponent> facets = c1.getFacets();
facets.put("c2", c2);
assertTrue("Expected Event queue size of 0, found: " + e.size(), e.isEmpty());
UIViewRoot root = new UIViewRoot();
root.getChildren().add(c1);
assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
assertTrue(e.get(0).getSource() == c1);
assertTrue(e.get(1).getSource() == c2);
// remove c1 from the root and add c3 as a facet to c1 - no events should be
// published
e.clear();
root.getChildren().remove(c1);
facets = c1.getFacets();
facets.put("c3", c3);
assertTrue("Expected Event queue size of 0, found: " + e.size(), e.isEmpty());
// reorganize the facet structure to ensure nested facets work
facets.remove("c3");
c2.getFacets().put("c3", c3);
root.getChildren().add(c1);
assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);
assertTrue(e.get(0).getSource() == c1);
assertTrue(e.get(1).getSource() == c2);
assertTrue(e.get(2).getSource() == c3);
e.clear();
// ensure clear() method disconnects the facets from the view
facets.clear();
c2.getFacets().remove("c3");
c2.getFacets().put("c3", c3);
assertTrue("Expected Event queue size of 0, found: " + e.size(), e.isEmpty());
application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
}
public void testChildrenListAfterAddViewPublish() {
QueueingListener listener = new QueueingListener();
application.subscribeToEvent(PostAddToViewEvent.class, listener);
UIComponent c1 = createComponent();
UIComponent c2 = createComponent();
UIComponent c3 = createComponent();
UIComponent c4 = createComponent();
c1.getChildren().add(c2);
List<SystemEvent> e = listener.getEvents();
assertTrue(e.isEmpty());
c2.getChildren().add(c3);
assertTrue(e.isEmpty());
UIViewRoot root = new UIViewRoot();
root.getChildren().add(c1);
// sub-tree has been added to the view. Ensure that subsequent additions
// to that sub-tree cause the PostAddToViewEvent to fire.
c2.getChildren().add(c4);
assertTrue("Expected Event queue size of 4, found: " + e.size(), e.size() == 4);
UIComponent[] comps = {
c1, c2, c3, c4
};
for (int i = 0; i < comps.length; i++) {
assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps[i]);
}
// remove c1 and it's children from the subview, then remove and
// re-add one of the children in the sub-tree. No event should
// be fired
e.clear();
root.getChildren().remove(c1);
c2.getChildren().remove(c4);
c2.getChildren().add(c4);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
c2.getChildren().remove(c4);
c1.getChildren().add(c4);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
// re-wire c1 as a child of root and ensure all children get re-notified
root.getChildren().add(c1);
assertTrue("Expected Event queue size of 4, found: " + e.size(), e.size() == 4);
for (int i = 0; i < comps.length; i++) {
assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps[i]);
}
// validate clearing c1's children (effectively removing them from the view
// will result in no events being fired of components are added to any of
// the disconnected children.
// At this point in the test, c2 and c4 are children of c1, and c3
// is a child of c2.
c1.getChildren().clear();
UIComponent temp = createComponent();
e.clear();
c2.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
c2.getChildren().remove(temp);
c3.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
c3.getChildren().remove(temp);
c4.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
c4.getChildren().remove(temp);
// now add c2 and c4 as children of c1. This should cause three
// events to fire
c1.getChildren().add(c2);
c1.getChildren().add(c4);
assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);
UIComponent[] comps2 = {
c2, c3, c4
};
for (int i = 0; i < comps2.length; i++) {
assertTrue("Index " + i + " invalid", e.get(i).getSource() == comps2[i]);
}
// validate add(int, UIComponent) fires events
e.clear();
c1.getChildren().remove(c4);
c1.getChildren().add(0, c4);
assertTrue(c1.getChildren().get(0) == c4);
assertTrue(c1.getChildren().get(1) == c2);
assertTrue("Expected Event queue size of 1, found: " + e.size(), e.size() == 1);
assertTrue(e.get(0).getSource() == c4);
// validate addAll(Collection<UIComponent>) fires events
e.clear();
c1.getChildren().clear();
List<UIComponent> children = new ArrayList<UIComponent>(2);
Collections.addAll(children, c2, c4);
c1.getChildren().addAll(children);
assertTrue(c1.getChildren().get(0) == c2);
assertTrue(c1.getChildren().get(1) == c4);
assertTrue("Expected Event queue size of 3, found: " + e.size(), e.size() == 3);
assertTrue(e.get(0).getSource() == c2);
assertTrue(e.get(2).getSource() == c4);
// validate addAll(int, Collection<UIComponent>) fires events
e.clear();
children = new ArrayList<UIComponent>(2);
UIComponent t1 = createComponent();
UIComponent t2 = createComponent();
Collections.addAll(children, t1, t2);
c1.getChildren().addAll(0, children);
assertTrue(c1.getChildren().get(0) == t1);
assertTrue(c1.getChildren().get(1) == t2);
assertTrue(c1.getChildren().get(2) == c2);
assertTrue(c1.getChildren().get(3) == c4);
assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
assertTrue(e.get(0).getSource() == t1);
assertTrue(e.get(1).getSource() == t2);
// validate retainAll(Collection<UIComponent> properly disconnects
// the components from the view such that events aren't fired
// if children are added to them
e.clear();
List<UIComponent> retained = new ArrayList<UIComponent>(2);
Collections.addAll(retained, c2, c4);
c1.getChildren().retainAll(retained);
assertTrue(c1.getChildren().size() == 2);
assertTrue(c1.getChildren().get(0) == c2);
assertTrue(c1.getChildren().get(1) == c4);
t1.getChildren().add(t2);
assertTrue("Expected Event queue size of 0, found: " + e.size(), e.isEmpty());
// test set(int, UIComponent) properly fires an event if the parent
// the component is being added to is wired to the view
e.clear();
c1.getChildren().set(0, t1);
assertTrue(c1.getChildren().size() == 2);
assertTrue(c1.getChildren().get(0) == t1);
assertTrue(c1.getChildren().get(1) == c4);
assertTrue("Expected Event queue size of 2, found: " + e.size(), e.size() == 2);
assertTrue(e.get(0).getSource() == t1);
assertTrue(e.get(1).getSource() == t2);
// c2 was removed by the set operation, so ensure it's marked as
// having been removed from the view by ensuring events aren't fired.
e.clear();
UIComponent t3 = createComponent();
c2.getChildren().add(t3);
assertTrue("Expected Event queue size of 0, found: " + e.size(), e.isEmpty());
application.unsubscribeFromEvent(PostAddToViewEvent.class, listener);
// validate Iterator.remove() over c1's children correctly disconnects
// the children from the view
for (Iterator<UIComponent> i = c1.getChildren().iterator(); i.hasNext();) {
i.next();
i.remove();
}
// at this point, t1 and c4 should be disconnected meaning adding children
// to t1, t2, or c4 should result in no events being fired
e.clear();
t1.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
t1.getChildren().remove(temp);
t2.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
t2.getChildren().remove(temp);
c4.getChildren().add(temp);
assertTrue("AfterAddToView events queued after a sub-tree was removed from the view, and a child added to the sub-view",
e.isEmpty());
c4.getChildren().remove(temp);
}
public void testEncodeBeginPublish() throws Exception {
Listener listener = new Listener();
application.subscribeToEvent(PreRenderComponentEvent.class, listener);
UIComponent c1 = createComponent();
c1.encodeBegin(facesContext);
SystemEvent e = listener.getEvent();
assertNotNull(e);
assertTrue(e.getSource() == c1);
listener.reset();
c1.encodeChildren(facesContext);
assertNull(listener.getEvent());
c1.encodeEnd(facesContext);
assertNull(listener.getEvent());
application.unsubscribeFromEvent(PreRenderComponentEvent.class, listener);
}
// --------------------------------------------------------- Private Classes
public static final class Listener implements SystemEventListener {
private SystemEvent event;
@Override
public void processEvent(SystemEvent event)
throws AbortProcessingException {
this.event = event;
}
@Override
public boolean isListenerForSource(Object source) {
return (source instanceof UIComponent);
}
public SystemEvent getEvent() {
return event;
}
public void reset() {
event = null;
}
}
public static final class QueueingListener implements SystemEventListener {
private List<SystemEvent> events = new ArrayList<SystemEvent>();
@Override
public void processEvent(SystemEvent event)
throws AbortProcessingException {
events.add(event);
}
@Override
public boolean isListenerForSource(Object source) {
return (source instanceof UIComponent);
}
public List<SystemEvent> getEvents() {
return events;
}
public void reset() {
events.clear();
}
}
public static final class ComponentListener implements ComponentSystemEventListener {
@Override
public void processEvent(ComponentSystemEvent event)
throws AbortProcessingException {
}
}
public static final class UIComponentListener extends UIComponentBase implements ComponentSystemEventListener {
@Override
public String getFamily() {
return "family";
}
@Override
public void processEvent(ComponentSystemEvent event)
throws AbortProcessingException {
}
}
public static final class UIComponentOverrideEncodeBegin extends UIComponentBase {
@Override
public String getFamily() {
return "UIComponentOverrideEncodeBegin";
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
// no-op
}
}
public static final class UIComponentOverrideEncodeEnd extends UIComponentBase {
@Override
public String getFamily() {
return "UIComponentOverrideEncodeEnd";
}
@Override
public void encodeEnd(FacesContext context) throws IOException {
// no-op
}
}
public static final class CustomAbortProcessingException extends AbortProcessingException {
public CustomAbortProcessingException() {
super();
}
public CustomAbortProcessingException(String message) {
super(message);
}
public CustomAbortProcessingException(Throwable cause) {
super(cause);
}
public CustomAbortProcessingException(String message, Throwable cause) {
super(message, cause);
}
}
}