Author: nbelaevski
Date: 2010-04-09 14:52:56 -0400 (Fri, 09 Apr 2010)
New Revision: 16755
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/NamingContainerVisitContext.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxOutputComponentImpl.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java
Modified:
root/framework/trunk/api/src/main/java/org/richfaces/context/ExtendedVisitContext.java
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextAjaxOutputTracker.java
Log:
https://jira.jboss.org/jira/browse/RF-7856
Modified:
root/framework/trunk/api/src/main/java/org/richfaces/context/ExtendedVisitContext.java
===================================================================
---
root/framework/trunk/api/src/main/java/org/richfaces/context/ExtendedVisitContext.java 2010-04-09
16:28:30 UTC (rev 16754)
+++
root/framework/trunk/api/src/main/java/org/richfaces/context/ExtendedVisitContext.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -21,22 +21,101 @@
*/
package org.richfaces.context;
+import static
org.richfaces.component.MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR;
+
import java.util.Collection;
+import java.util.Map;
import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
/**
* @author Nick Belaevski
*
*/
-public interface ExtendedVisitContext {
+public abstract class ExtendedVisitContext extends VisitContext {
- public static final String SUB_COMPONENT_ID =
"org.richfaces.SubComponentId";
+ public static final String META_COMPONENT_ID =
"org.richfaces.MetaComponentId";
- public ExtendedVisitContextMode getVisitMode();
+ private final FacesContext facesContext;
- public Collection<String>getDirectSubtreeIdsToVisit(UIComponent component);
+ private final ExtendedVisitContextMode visitMode;
- public VisitContext createDirectChildrenVisitContext(UIComponent component,
Collection<String> directIds);
+ protected ExtendedVisitContext(FacesContext facesContext, ExtendedVisitContextMode
visitMode) {
+ super();
+
+ if (facesContext == null) {
+ throw new NullPointerException();
+ }
+
+ this.facesContext = facesContext;
+ this.visitMode = visitMode;
+ }
+
+ public ExtendedVisitContextMode getVisitMode() {
+ return visitMode;
+ }
+
+ public VisitResult invokeMetaComponentVisitCallback(UIComponent component,
VisitCallback callback,
+ String metaComponentId) {
+
+ if (metaComponentId != null) {
+ Map<Object, Object> attributes = getFacesContext().getAttributes();
+ try {
+ attributes.put(META_COMPONENT_ID, metaComponentId);
+ return invokeVisitCallback(component, callback);
+ } finally {
+ attributes.remove(META_COMPONENT_ID);
+ }
+ } else {
+ return invokeVisitCallback(component, callback);
+ }
+ }
+
+ public String buildExtendedClientId(UIComponent component) {
+ String extendedClientId = component.getClientId(facesContext);
+ String subComponentId = (String)
facesContext.getAttributes().get(META_COMPONENT_ID);
+ if (subComponentId != null) {
+ StringBuilder sb = new StringBuilder(extendedClientId.length() + 1 /*
separator length */ +
+ subComponentId.length());
+
+ sb.append(extendedClientId);
+ sb.append(META_COMPONENT_SEPARATOR_CHAR);
+ sb.append(subComponentId);
+
+ extendedClientId = sb.toString();
+ }
+
+ return extendedClientId;
+ }
+
+ public String buildExtendedComponentId(UIComponent component) {
+ String componentId = component.getId();
+ String subComponentId = (String)
facesContext.getAttributes().get(META_COMPONENT_ID);
+ if (subComponentId != null) {
+ StringBuilder sb = new StringBuilder(componentId.length() + 1 /* separator
length */ +
+ subComponentId.length());
+
+ sb.append(componentId);
+ sb.append(META_COMPONENT_SEPARATOR_CHAR);
+ sb.append(subComponentId);
+
+ componentId = sb.toString();
+ }
+
+ return componentId;
+ }
+
+ @Override
+ public FacesContext getFacesContext() {
+ return facesContext;
+ }
+
+ public abstract Collection<String>getDirectSubtreeIdsToVisit(UIComponent
component);
+
+ public abstract VisitContext createNamingContainerVisitContext(UIComponent
component,
+ Collection<String> directIds);
}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java 2010-04-09
16:28:30 UTC (rev 16754)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -1308,7 +1308,7 @@
return false;
} else {
VisitContext directChildrenVisitContext =
-
extendedVisitContext.createDirectChildrenVisitContext(this, directSubtreeIdsToVisit);
+
extendedVisitContext.createNamingContainerVisitContext(this, directSubtreeIdsToVisit);
if (visitFixedChildren(directChildrenVisitContext,
STUB_CALLBACK, visitRows)) {
return false;
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-04-09
16:28:30 UTC (rev 16754)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -48,7 +48,7 @@
* @author Nick Belaevski
*
*/
-public class ExtendedPartialVisitContext extends VisitContext implements
ExtendedVisitContext {
+public class ExtendedPartialVisitContext extends ExtendedVisitContext {
/**
*
@@ -111,9 +111,7 @@
public void remove() {
if (current != null) {
ComponentMatcherNode node = directNodesMap.get(current);
- if (node != null) {
- removeNode(node);
- }
+ removeNode(node);
current = null;
}
@@ -122,117 +120,6 @@
}
}
- private final class DirectSubtreeVisitContext extends VisitContext implements
ExtendedVisitContext {
-
- private final class IdsProxyCollection extends AbstractCollection<String>
{
-
- @Override
- public Iterator<String> iterator() {
- throw new UnsupportedOperationException(
- "iterator() method is not supported by this collection
implementation");
- }
-
- @Override
- public int size() {
- throw new UnsupportedOperationException(
- "size() method is not supported by this collection
implementation");
- }
-
- @Override
- public boolean isEmpty() {
- return ids.isEmpty();
- }
- };
-
- private Collection<String> ids;
-
- private IdsProxyCollection idsToVisit;
-
- private UIComponent startingComponent;
-
- public DirectSubtreeVisitContext(UIComponent component, Collection<String>
ids) {
- super();
-
- this.ids = copyCollection(ids);
- this.idsToVisit = new IdsProxyCollection();
- this.startingComponent = component;
- }
-
- @Override
- public VisitResult invokeVisitCallback(UIComponent component, VisitCallback
callback) {
- // cancel visiting children for nested naming containers
- if (component instanceof NamingContainer &&
!component.equals(startingComponent)) {
- return VisitResult.REJECT;
- }
-
- if (ids == VisitContext.ALL_IDS) {
- return VisitResult.ACCEPT;
- }
-
- String id = buildExtendedComponentId(component);
- if (ids.contains(id)) {
- VisitResult result = callback.visit(this, component);
- ids.remove(id);
-
- if (!ids.isEmpty()) {
- return result;
- } else {
- return VisitResult.COMPLETE;
- }
- }
-
- return VisitResult.ACCEPT;
- }
-
- @Override
- public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
- if (!(component instanceof NamingContainer)) {
- throw new IllegalArgumentException(component.toString());
- }
-
- if (startingComponent.equals(component)) {
- return VisitContext.ALL_IDS;
- }
-
- return Collections.emptySet();
- }
-
- public Collection<String> getDirectSubtreeIdsToVisit(UIComponent component)
{
- if (!(component instanceof NamingContainer)) {
- throw new IllegalArgumentException(component.toString());
- }
-
- if (startingComponent.equals(component)) {
- return Collections.unmodifiableCollection(ids);
- }
-
- return Collections.emptySet();
- }
-
- @Override
- public FacesContext getFacesContext() {
- return ExtendedPartialVisitContext.this.getFacesContext();
- }
-
- @Override
- public Set<VisitHint> getHints() {
- return Collections.emptySet();
- }
-
- @Override
- public Collection<String> getIdsToVisit() {
- return idsToVisit;
- }
-
- public ExtendedVisitContextMode getVisitMode() {
- return ExtendedPartialVisitContext.this.getVisitMode();
- }
-
- public VisitContext createDirectChildrenVisitContext(UIComponent component,
Collection<String> directIds) {
- return
ExtendedPartialVisitContext.this.createDirectChildrenVisitContext(component, directIds);
- }
- }
-
private IdParser idParser;
private boolean limitRender;
@@ -242,9 +129,6 @@
private Collection<String> shortIds;
- // The FacesContext for this request
- private FacesContext facesContext;
-
// Our visit hints
private Set<VisitHint> hints;
@@ -281,12 +165,8 @@
public ExtendedPartialVisitContext(FacesContext facesContext,
Collection<String> clientIds, Set<VisitHint> hints,
boolean limitRender) {
- if (facesContext == null) {
- throw new NullPointerException();
- }
+ super(facesContext, ExtendedVisitContextMode.RENDER);
- this.facesContext = facesContext;
-
// Initialize our various collections
initializeCollections(clientIds);
@@ -301,7 +181,8 @@
private IdParser getIdParser(String id) {
if (idParser == null) {
- idParser = new IdParser(UINamingContainer.getSeparatorChar(facesContext),
META_COMPONENT_SEPARATOR_CHAR);
+ idParser = new
IdParser(UINamingContainer.getSeparatorChar(getFacesContext()),
+ META_COMPONENT_SEPARATOR_CHAR);
}
idParser.setId(id);
@@ -309,30 +190,6 @@
return idParser;
}
- private static Collection<String> copyCollection(Collection<String> r) {
- if (r != VisitContext.ALL_IDS) {
- if (r != null) {
- return new HashSet<String>(r);
- } else {
- return new HashSet<String>();
- }
- }
-
- return r;
- }
-
- private static Collection<String>
wrapIntoUnmodifiableCollection(Collection<String> c) {
- if (c != VisitContext.ALL_IDS) {
- if (c != null && !c.isEmpty()) {
- return Collections.unmodifiableCollection(c);
- } else {
- return Collections.emptySet();
- }
- } else {
- return c;
- }
- }
-
private ComponentMatcherNode createNode(String patternId) {
ComponentMatcherNode node = rootNode;
@@ -476,49 +333,7 @@
return false;
}
- private String buildExtendedClientId(UIComponent component) {
- String extendedClientId = component.getClientId(facesContext);
- String subComponentId = (String)
facesContext.getAttributes().get(SUB_COMPONENT_ID);
- if (subComponentId != null) {
- StringBuilder sb = new StringBuilder(extendedClientId.length() + 1 /*
separator length */ +
- subComponentId.length());
-
- sb.append(extendedClientId);
- sb.append(META_COMPONENT_SEPARATOR_CHAR);
- sb.append(subComponentId);
-
- extendedClientId = sb.toString();
- }
-
- return extendedClientId;
- }
-
- private String buildExtendedComponentId(UIComponent component) {
- String componentId = component.getId();
- String subComponentId = (String)
facesContext.getAttributes().get(SUB_COMPONENT_ID);
- if (subComponentId != null) {
- StringBuilder sb = new StringBuilder(componentId.length() + 1 /* separator
length */ +
- subComponentId.length());
-
- sb.append(componentId);
- sb.append(META_COMPONENT_SEPARATOR_CHAR);
- sb.append(subComponentId);
-
- componentId = sb.toString();
- }
-
- return componentId;
- }
-
/**
- * @see VisitContext#getFacesContext VisitContext.getFacesContext()
- */
- @Override
- public FacesContext getFacesContext() {
- return facesContext;
- }
-
- /**
* @see VisitContext#getHints VisitContext.getHints
*/
@Override
@@ -564,6 +379,7 @@
if (subtreeIds != null) {
return Collections.unmodifiableCollection(subtreeIds);
} else {
+ //TODO nick - this code addresses the case of parent pattern nodes,
and can be optimized
if (node.hasDirectIdChildren()) {
return VisitContext.ALL_IDS;
} else {
@@ -582,37 +398,36 @@
throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
}
- Collection<String> result = null;
- String clientId = component.getClientId(facesContext);
+ String clientId = component.getClientId(getFacesContext());
ComponentMatcherNode node = findMatchingNode(clientId);
- boolean hasDirectPatternChildren = false;
- if (node != null) {
- if (node.hasDirectPatternChildren()) {
- hasDirectPatternChildren = true;
- result = VisitContext.ALL_IDS;
- } else {
- if (node.hasDirectIdChildren()) {
- result = new HashSet<String>();
- result.addAll(node.getIdChildren().keySet());
- }
- }
+ if (node != null && node.hasDirectPatternChildren()) {
+ return VisitContext.ALL_IDS;
}
- if (!hasDirectPatternChildren && !limitRender) {
- Collection<String> ajaxOutputs =
- PartialViewContextAjaxOutputTracker.getNestedAjaxOutputs(component);
+ Set<String> result = null;
+ if (node != null && node.hasDirectIdChildren()) {
+ result = new HashSet<String>();
+ result.addAll(node.getIdChildren().keySet());
+ }
- if (ajaxOutputs != null && !ajaxOutputs.isEmpty()) {
+ if (!limitRender) {
+
+ Collection<String> directChildrenIds =
PartialViewContextAjaxOutputTracker.getDirectChildrenIds(component);
+ if (directChildrenIds != null && !directChildrenIds.isEmpty()) {
if (result == null) {
result = new HashSet<String>();
}
- result.addAll(ajaxOutputs);
+ result.addAll(directChildrenIds);
}
}
- return wrapIntoUnmodifiableCollection(result);
+ if (result != null && !result.isEmpty()) {
+ return Collections.unmodifiableCollection(result);
+ } else {
+ return Collections.emptySet();
+ }
}
/**
@@ -659,17 +474,7 @@
this.clientIds.addAll(clientIds);
}
- public VisitContext createDirectChildrenVisitContext(UIComponent component,
Collection<String> directIds) {
- // Make sure component is a NamingContainer
- if (!(component instanceof NamingContainer)) {
- throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
- }
-
- return new DirectSubtreeVisitContext(component, directIds);
+ public VisitContext createNamingContainerVisitContext(UIComponent component,
Collection<String> directIds) {
+ return new NamingContainerVisitContext(getFacesContext(), getVisitMode(),
component, directIds);
}
-
- public ExtendedVisitContextMode getVisitMode() {
- //TODO version of this context for "execute"
- return ExtendedVisitContextMode.RENDER;
- }
}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/NamingContainerVisitContext.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/NamingContainerVisitContext.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/NamingContainerVisitContext.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -0,0 +1,144 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+
+package org.richfaces.context;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+
+final class NamingContainerVisitContext extends ExtendedVisitContext {
+
+ private final class IdsProxyCollection extends AbstractCollection<String> {
+
+ @Override
+ public Iterator<String> iterator() {
+ throw new UnsupportedOperationException(
+ "iterator() method is not supported by this collection
implementation");
+ }
+
+ @Override
+ public int size() {
+ throw new UnsupportedOperationException(
+ "size() method is not supported by this collection
implementation");
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return ids.isEmpty();
+ }
+ };
+
+ private Set<String> ids;
+
+ private IdsProxyCollection idsToVisit;
+
+ private UIComponent startingComponent;
+
+ public NamingContainerVisitContext(FacesContext facesContext,
ExtendedVisitContextMode visitMode,
+ UIComponent component, Collection<String> ids) {
+
+ super(facesContext, visitMode);
+
+ // Make sure component is a NamingContainer
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
+ }
+
+ this.ids = new HashSet<String>(ids);
+ this.idsToVisit = new IdsProxyCollection();
+ this.startingComponent = component;
+ }
+
+ @Override
+ public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
{
+ VisitResult result = VisitResult.ACCEPT;
+ String id = buildExtendedComponentId(component);
+ if (ids.contains(id)) {
+ result = callback.visit(this, component);
+ ids.remove(id);
+
+ if (ids.isEmpty()) {
+ return VisitResult.COMPLETE;
+ }
+ }
+
+ // cancel visiting children for nested naming containers
+ if (component instanceof NamingContainer &&
!component.equals(startingComponent)) {
+ return VisitResult.REJECT;
+ }
+
+ return result;
+ }
+
+ @Override
+ public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException(component.toString());
+ }
+
+ //TODO nick - check clientId, e.g. to avoid visiting components with client ids
like
+ // "table:0:nested" ("table" is a starting
component)
+ if (startingComponent.equals(component)) {
+ return VisitContext.ALL_IDS;
+ }
+
+ return Collections.emptySet();
+ }
+
+ public Collection<String> getDirectSubtreeIdsToVisit(UIComponent component) {
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException(component.toString());
+ }
+
+ if (startingComponent.equals(component)) {
+ return Collections.unmodifiableCollection(ids);
+ }
+
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<VisitHint> getHints() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Collection<String> getIdsToVisit() {
+ return idsToVisit;
+ }
+
+ public VisitContext createNamingContainerVisitContext(UIComponent component,
Collection<String> directIds) {
+ return new NamingContainerVisitContext(getFacesContext(), getVisitMode(),
component, directIds);
+ }
+}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextAjaxOutputTracker.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextAjaxOutputTracker.java 2010-04-09
16:28:30 UTC (rev 16754)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextAjaxOutputTracker.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -61,20 +61,17 @@
component.getAttributes().remove(ATTRIBUTE_NAME);
}
- static Collection<String> getNestedAjaxOutputs(UIComponent component) {
+ static Collection<String> getDirectChildrenIds(UIComponent component) {
if (!isContainerComponent(component)) {
throw new IllegalArgumentException(component.toString());
}
- Set<String> trackedChildrenSet = getTrackedChildrenSet(component, false);
-
- return trackedChildrenSet;
+ return getTrackedChildrenSet(component, false);
}
static boolean hasNestedAjaxOutputs(UIComponent component) {
- Collection<String> trackedChildrenSet = getNestedAjaxOutputs(component);
-
- return trackedChildrenSet != null && !trackedChildrenSet.isEmpty();
+ Collection<String> childrenIds = getDirectChildrenIds(component);
+ return childrenIds != null && !childrenIds.isEmpty();
}
private static String getId(UIComponent component) {
@@ -120,11 +117,11 @@
UIComponent child = c;
UIComponent parent;
while ((parent = findParentContainerComponent(child)) != null) {
- Set<String> ajaxOutputSet = getTrackedChildrenSet(parent, false);
- if (ajaxOutputSet != null) {
- ajaxOutputSet.remove(getId(child));
+ Set<String> trackingSet = getTrackedChildrenSet(parent, false);
+ if (trackingSet != null) {
+ trackingSet.remove(getId(child));
- if (ajaxOutputSet.isEmpty()) {
+ if (trackingSet.isEmpty()) {
clearTrackedChildrenSet(parent);
} else {
break;
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxOutputComponentImpl.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxOutputComponentImpl.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxOutputComponentImpl.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -0,0 +1,58 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import javax.faces.component.UIOutput;
+
+import org.ajax4jsf.component.AjaxOutput;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class AjaxOutputComponentImpl extends UIOutput implements AjaxOutput {
+
+ private enum PropertyKeys {
+ ajaxRendered
+ }
+
+ public AjaxOutputComponentImpl() {
+ setRendererType("javax.faces.Text");
+ }
+
+ public boolean isAjaxRendered() {
+ return
Boolean.valueOf(String.valueOf(getStateHelper().eval(PropertyKeys.ajaxRendered)));
+ }
+
+ public boolean isKeepTransient() {
+ return false;
+ }
+
+ public void setAjaxRendered(boolean ajaxRendered) {
+ getStateHelper().put(PropertyKeys.ajaxRendered, ajaxRendered);
+ }
+
+ public void setKeepTransient(boolean ajaxRendered) {
+ throw new UnsupportedOperationException();
+ }
+}
+
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/AjaxTableComponentImpl.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -0,0 +1,80 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitResult;
+
+import org.richfaces.component.UISequence;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class AjaxTableComponentImpl extends UISequence {
+
+ private boolean visitMetaComponent(String name, ExtendedVisitContext visitContext,
VisitCallback callback) {
+ UIComponent facet = getFacet(name);
+ if (facet != null) {
+ VisitResult result = visitContext.invokeMetaComponentVisitCallback(this,
callback, name);
+
+ if (result == VisitResult.ACCEPT) {
+ if (facet.visitTree(visitContext, callback)) {
+ result = VisitResult.COMPLETE;
+ }
+ }
+
+ return result == VisitResult.COMPLETE;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected boolean visitFixedChildren(VisitContext visitContext, VisitCallback
callback,
+ boolean resetKeyBeforeVisit) {
+
+ if (visitContext instanceof ExtendedVisitContext) {
+ ExtendedVisitContext extendedVisitContext = (ExtendedVisitContext)
visitContext;
+
+ //TODO - review
+ if (resetKeyBeforeVisit) {
+ setRowKey(visitContext.getFacesContext(), null);
+ }
+
+ if (visitMetaComponent("header", extendedVisitContext, callback))
{
+ return true;
+ }
+
+ if (visitMetaComponent("footer", extendedVisitContext, callback))
{
+ return true;
+ }
+
+ return false;
+ } else {
+ return super.visitFixedChildren(visitContext, callback,
resetKeyBeforeVisit);
+ }
+ }
+
+}
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/ExtendedPartialVisitContextTest.java 2010-04-09
18:52:56 UTC (rev 16755)
@@ -0,0 +1,719 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.context;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.ValueExpression;
+import javax.faces.application.Application;
+import javax.faces.component.UIColumn;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIData;
+import javax.faces.component.UIForm;
+import javax.faces.component.UIOutput;
+import javax.faces.component.UIViewRoot;
+import javax.faces.component.html.HtmlOutputText;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+import javax.faces.component.visit.VisitHint;
+import javax.faces.component.visit.VisitResult;
+import javax.faces.context.FacesContext;
+
+import org.jboss.test.faces.FacesEnvironment;
+import org.jboss.test.faces.FacesEnvironment.FacesRequest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+
+/**
+ * Tested view structure:
+ * <pre>
+ * <h:form id="myForm">
+ * <a4j:outputText id="outerOutput" />
+ *
+ * <h:dataTable id="table" var="item"
value="['Item 0',... ,'Item 1']">
+ * <f:facet name="header">
+ * <h:outputText id="theHeader" />
+ * </f:facet>
+ *
+ * <h:column id="col">
+ * <a4j:outputText id="nestedOutput"
value="#{item}" />
+ *
+ * <h:outputText id="nestedText"
value="#{item}" />
+ *
+ * <a4j:table id="nestedTable"
value="['Nested item 0',... ,'Nested item 2']"
var="nestedItem">
+ * <f:facet name="footer">
+ * <h:outputText id="nestedTableFooter"
value="#{item}" />
+ * </f:facet>
+ *
+ * <h:outputText id="nestedTableText"
value="#{nestedItem}" />
+ * </a4j:table>
+ * </h:column>
+ * </h:dataTable>
+ * </h:form>
+ * </pre>
+ *
+ *
+ * @author Nick Belaevski
+ *
+ */
+public class ExtendedPartialVisitContextTest {
+
+ private class TrackingVisitCallback implements VisitCallback {
+
+ private List<String> visitedIds = new ArrayList<String>();
+
+ public VisitResult visit(VisitContext context, UIComponent target) {
+ if (context instanceof ExtendedVisitContext) {
+ visitedIds.add(((ExtendedVisitContext)
context).buildExtendedClientId(target));
+ } else {
+ visitedIds.add(target.getClientId(context.getFacesContext()));
+ }
+
+
+ return VisitResult.REJECT;
+ }
+
+ public List<String> getVisitedIds() {
+ return visitedIds;
+ }
+
+ public void reset() {
+ visitedIds.clear();
+ }
+ }
+
+ private FacesEnvironment environment;
+
+ private FacesRequest facesRequest;
+
+ private FacesContext facesContext;
+
+ private Application application;
+
+ private UIViewRoot viewRoot;
+
+ private UIForm form;
+
+ private AjaxOutputComponentImpl outerOutput;
+
+ private UIData table;
+
+ private UIColumn column;
+
+ private UIOutput dataHeader;
+
+ private AjaxOutputComponentImpl nestedOutput;
+
+ private UIOutput nestedText;
+
+ private List<String> tableData;
+
+ private ExtendedPartialVisitContext renderingContext;
+
+ private TrackingVisitCallback trackingVisitCallback;
+
+ private ArrayList<String> nestedTableData;
+
+ private AjaxTableComponentImpl nestedTable;
+
+ private UIOutput nestedTableText;
+
+ private UIOutput nestedTableFooter;
+
+ private static void assertEqualSets(Collection<?> expected, Collection<?>
actual) {
+ assertEquals(asSet(expected), asSet(actual));
+ }
+
+ private static <T> Set<T> asSet(Collection<T> c) {
+ if (c instanceof Set) {
+ return (Set) c;
+ } else {
+ if (c != null) {
+ return new HashSet<T>(c);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static <T> Set<T> asSet(T... args) {
+ Set<T> set = new HashSet<T>();
+ for (T argItem : args) {
+ set.add(argItem);
+ }
+
+ return set;
+ }
+
+ private void createVisitContext(boolean limitRender) {
+ renderingContext = new ExtendedPartialVisitContext(facesContext,
Collections.<String>emptySet(),
+ EnumSet.<VisitHint>of(VisitHint.SKIP_UNRENDERED), limitRender);
+ }
+
+ private void createNestedTableData() {
+ nestedTableData = new ArrayList<String>();
+ for (int i = 0; i < 3; i++) {
+ nestedTableData.add(MessageFormat.format("Nested item {0}", i));
+ }
+ }
+
+ private void createTableData() {
+ tableData = new ArrayList<String>();
+ for (int i = 0; i < 2; i++) {
+ tableData.add(MessageFormat.format("Item {0}", i));
+ }
+ }
+
+ private ValueExpression createTableVarValueExpression() {
+ ExpressionFactory expressionFactory = application.getExpressionFactory();
+ ELContext elContext = facesContext.getELContext();
+
+ return expressionFactory.createValueExpression(elContext, "#{item}",
String.class);
+ }
+
+ private ValueExpression createNestedTableVarValueExpression() {
+ ExpressionFactory expressionFactory = application.getExpressionFactory();
+ ELContext elContext = facesContext.getELContext();
+
+ return expressionFactory.createValueExpression(elContext,
"#{nestedItem}", String.class);
+ }
+
+ private void createNestedText() {
+ nestedText = (UIOutput)
application.createComponent(HtmlOutputText.COMPONENT_TYPE);
+ nestedText.setId("nestedText");
+ nestedText.setValueExpression("value",
createTableVarValueExpression());
+
+ column.getChildren().add(nestedText);
+ }
+
+ private void createNestedOutput() {
+ nestedOutput = new AjaxOutputComponentImpl();
+ nestedOutput.setAjaxRendered(true);
+ nestedOutput.setId("nestedOutput");
+ nestedOutput.setValueExpression("value",
createTableVarValueExpression());
+
+ column.getChildren().add(nestedOutput);
+ }
+
+ private void createOuterOutput() {
+ outerOutput = new AjaxOutputComponentImpl();
+ outerOutput.setAjaxRendered(true);
+ outerOutput.setId("outerOutput");
+
+ form.getChildren().add(outerOutput);
+ }
+
+ private void createTableHeader() {
+ dataHeader = (UIOutput)
application.createComponent(HtmlOutputText.COMPONENT_TYPE);
+ dataHeader.setId("theHeader");
+
+ table.getFacets().put("header", dataHeader);
+ }
+
+ private void createTableColumn() {
+ column = (UIColumn) application.createComponent(UIColumn.COMPONENT_TYPE);
+ column.setId("col");
+
+ table.getChildren().add(column);
+ createNestedOutput();
+ createNestedText();
+ createNestedTable();
+ }
+
+ private void createNestedTable() {
+ nestedTable = new AjaxTableComponentImpl();
+ nestedTable.setId("nestedTable");
+ nestedTable.setVar("nestedItem");
+
+ createNestedTableData();
+ nestedTable.setValue(nestedTableData);
+
+ column.getChildren().add(nestedTable);
+
+ createNestedTableText();
+ createNestedTableFooter();
+ }
+
+ private void createNestedTableFooter() {
+ nestedTableFooter = (UIOutput)
application.createComponent(HtmlOutputText.COMPONENT_TYPE);
+ nestedTableFooter.setId("nestedTableFooter");
+ nestedTableFooter.setValueExpression("value",
createTableVarValueExpression());
+
+ nestedTable.getFacets().put("footer", nestedTableFooter);
+ }
+
+ private void createNestedTableText() {
+ nestedTableText = (UIOutput)
application.createComponent(HtmlOutputText.COMPONENT_TYPE);
+ nestedTableText.setId("nestedTableText");
+ nestedTableText.setValueExpression("value",
createNestedTableVarValueExpression());
+
+ nestedTable.getChildren().add(nestedTableText);
+ }
+
+ private void createTable() {
+ table = (UIData) application.createComponent(UIData.COMPONENT_TYPE);
+ table.setId("table");
+ table.setVar("item");
+
+ createTableData();
+ table.setValue(tableData);
+
+ form.getChildren().add(table);
+ createTableColumn();
+ createTableHeader();
+ }
+
+ private void createForm() {
+ form = (UIForm) application.createComponent(UIForm.COMPONENT_TYPE);
+ form.setId("myForm");
+
+ viewRoot.getChildren().add(form);
+
+ createOuterOutput();
+ createTable();
+ }
+
+ private void createView() {
+ viewRoot = (UIViewRoot) application.createComponent(UIViewRoot.COMPONENT_TYPE);
+
+ createForm();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ environment = FacesEnvironment.createEnvironment();
+ environment.start();
+
+ facesRequest = environment.createFacesRequest();
+ facesRequest.start();
+
+ facesContext = FacesContext.getCurrentInstance();
+ application = facesContext.getApplication();
+
+ createView();
+
+ trackingVisitCallback = new TrackingVisitCallback();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ renderingContext = null;
+ trackingVisitCallback = null;
+
+ facesContext = null;
+ application = null;
+
+ column = null;
+ table = null;
+ dataHeader = null;
+ form = null;
+ nestedOutput = null;
+ nestedTable = null;
+ nestedTableData = null;
+ nestedTableFooter = null;
+ nestedTableText = null;
+ nestedText = null;
+ outerOutput = null;
+ tableData = null;
+ viewRoot = null;
+
+ facesRequest.release();
+ facesRequest = null;
+
+ environment.release();
+ environment = null;
+ }
+
+ @Test
+ public void testCollectionProxy() throws Exception {
+ createVisitContext(false);
+
+ Iterator<String> iterator;
+
+ Collection<String> idsToVisit = renderingContext.getIdsToVisit();
+ assertTrue(idsToVisit.isEmpty());
+ assertTrue(idsToVisit.size() == 0);
+
+ iterator = idsToVisit.iterator();
+ assertNotNull(iterator);
+ assertFalse(iterator.hasNext());
+
+ Set<String> idsToAdd = asSet("someIds",
"thisIs:evenBetter", "id:*:x");
+ idsToVisit.addAll(idsToAdd);
+
+ assertFalse(idsToVisit.isEmpty());
+ assertTrue(idsToVisit.size() == 3);
+
+ iterator = idsToVisit.iterator();
+
+ while (iterator.hasNext()) {
+ String nextId = iterator.next();
+
+ assertTrue(idsToAdd.remove(nextId));
+
+ iterator.remove();
+ }
+
+ assertTrue(idsToVisit.isEmpty());
+ assertTrue(idsToVisit.size() == 0);
+ assertTrue(idsToAdd.isEmpty());
+
+ iterator = idsToVisit.iterator();
+
+ try {
+ iterator.remove();
+
+ fail();
+ } catch (IllegalStateException e) {
+ //ignore
+ }
+
+ idsToVisit.add("testId");
+ assertFalse(idsToVisit.isEmpty());
+
+ iterator = idsToVisit.iterator();
+
+ try {
+ iterator.remove();
+
+ fail();
+ } catch (IllegalStateException e) {
+ //ignore
+ }
+ }
+
+ @Test
+ public void testSubtreeIdsToForAjaxOutputs() throws Exception {
+ createVisitContext(false);
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(asSet("table", "outerOutput"),
renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(table));
+ assertEqualSets(asSet("nestedOutput"),
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(nestedTable).isEmpty());
+ assertTrue(renderingContext.getDirectSubtreeIdsToVisit(nestedTable).isEmpty());
+ }
+
+ @Test
+ public void testSubtreeIdsForEmptyIdsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(form).isEmpty());
+ assertTrue(renderingContext.getDirectSubtreeIdsToVisit(form).isEmpty());
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(table).isEmpty());
+ assertTrue(renderingContext.getDirectSubtreeIdsToVisit(table).isEmpty());
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(nestedTable).isEmpty());
+ assertTrue(renderingContext.getDirectSubtreeIdsToVisit(nestedTable).isEmpty());
+ }
+
+ @Test
+ public void testSubtreeIdsForOuterOutputWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ renderingContext.getIdsToVisit().add("myForm:outerOutput");
+
+ assertEqualSets(asSet("myForm:outerOutput"),
renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(asSet("outerOutput"),
renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(table).isEmpty());
+ assertTrue(renderingContext.getDirectSubtreeIdsToVisit(table).isEmpty());
+ }
+
+ @Test
+ public void testSubtreeIdsForNestedComponentsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ renderingContext.getIdsToVisit().add("myForm:outerOutput");
+ renderingContext.getIdsToVisit().add("myForm:table:theHeader");
+ renderingContext.getIdsToVisit().add("myForm:table:1:nestedOutput");
+ renderingContext.getIdsToVisit().add("myForm:table:0:nestedText");
+ renderingContext.getIdsToVisit().add("myForm:table:0:nestedTable:1");
+
renderingContext.getIdsToVisit().add("myForm:table:0:nestedTable:nestedFooter");
+
+ Set<String> formClientIds = asSet("myForm:outerOutput",
"myForm:table:0:nestedText",
+ "myForm:table:1:nestedOutput", "myForm:table:theHeader",
"myForm:table:0:nestedTable:1",
+ "myForm:table:0:nestedTable:nestedFooter");
+
+ Set<String> formIds = asSet("table", "outerOutput");
+
+ assertEqualSets(formClientIds, renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(formIds, renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ Set<String> tableClientIds = asSet("myForm:table:0:nestedText",
"myForm:table:1:nestedOutput",
+ "myForm:table:theHeader", "myForm:table:0:nestedTable:1",
"myForm:table:0:nestedTable:nestedFooter");
+ Set<String> tableIds = asSet("0", "1",
"theHeader");
+
+ assertEqualSets(tableClientIds, renderingContext.getSubtreeIdsToVisit(table));
+ assertEqualSets(tableIds, renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ table.setRowIndex(0);
+
+ Set<String> nestedTableClientIds =
asSet("myForm:table:0:nestedTable:1",
+ "myForm:table:0:nestedTable:nestedFooter");
+
+ Set<String> nestedTableIds = asSet("nestedFooter",
"1");
+ assertEqualSets(nestedTableClientIds,
renderingContext.getSubtreeIdsToVisit(nestedTable));
+ assertEqualSets(nestedTableIds,
renderingContext.getDirectSubtreeIdsToVisit(nestedTable));
+
+ table.setRowIndex(-1);
+ }
+
+ @Test
+ public void testSubtreeIdsForWildcardIds() throws Exception {
+ createVisitContext(false);
+ renderingContext.getIdsToVisit().add("myForm:table:*:nestedText");
+ renderingContext.getIdsToVisit().add("myForm:table:*:nestedTable:0");
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(asSet("table", "outerOutput"),
renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(table));
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ for (int i = 0; i < tableData.size(); i++) {
+ table.setRowIndex(i);
+
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getSubtreeIdsToVisit(table));
+ assertEqualSets(asSet("nestedText", "nestedTable",
"nestedOutput"),
+ renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getSubtreeIdsToVisit(nestedTable));
+ assertEqualSets(asSet("0"),
renderingContext.getDirectSubtreeIdsToVisit(nestedTable));
+ }
+
+ table.setRowIndex(-1);
+ }
+
+ @Test
+ public void testSubtreeIdsForWildcardIdsWithLimitRender() throws Exception {
+ createVisitContext(true);
+ renderingContext.getIdsToVisit().add("myForm:table:*:nestedText");
+ renderingContext.getIdsToVisit().add("myForm:table:*:nestedTable:0");
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(asSet("table"),
renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(table));
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ for (int i = 0; i < tableData.size(); i++) {
+ table.setRowIndex(i);
+
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getSubtreeIdsToVisit(table));
+ assertEqualSets(asSet("nestedText", "nestedTable"),
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getSubtreeIdsToVisit(nestedTable));
+ assertEqualSets(asSet("0"),
renderingContext.getDirectSubtreeIdsToVisit(nestedTable));
+ }
+
+ table.setRowIndex(-1);
+ }
+
+ @Test
+ public void testSubtreeIdsForWildcardIds2WithLimitRender() throws Exception {
+ createVisitContext(true);
+ renderingContext.getIdsToVisit().add("myForm:table:*:nestedTable");
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(form));
+ assertEqualSets(asSet("table"),
renderingContext.getDirectSubtreeIdsToVisit(form));
+
+ assertSame(VisitContext.ALL_IDS, renderingContext.getSubtreeIdsToVisit(table));
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ for (int i = 0; i < tableData.size(); i++) {
+ table.setRowIndex(i);
+
+ assertSame(VisitContext.ALL_IDS,
renderingContext.getSubtreeIdsToVisit(table));
+ assertEqualSets(asSet("nestedTable"),
renderingContext.getDirectSubtreeIdsToVisit(table));
+
+ assertTrue(renderingContext.getSubtreeIdsToVisit(nestedTable).isEmpty());
+
assertTrue(renderingContext.getDirectSubtreeIdsToVisit(nestedTable).isEmpty());
+ }
+
+ table.setRowIndex(-1);
+ }
+
+ @Test
+ public void testVisitCallbackForEmptyIds() throws Exception {
+ createVisitContext(false);
+
+ viewRoot.visitTree(renderingContext, trackingVisitCallback);
+
+ assertEquals(Arrays.asList("myForm:outerOutput",
"myForm:table:0:nestedOutput", "myForm:table:1:nestedOutput"),
+ trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testVisitCallbackForEmptyIdsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ viewRoot.visitTree(renderingContext, trackingVisitCallback);
+
+ assertEquals(Arrays.asList(), trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testVisitCallbackForEmptyIdsForFalseAjaxRendered() throws Exception {
+ outerOutput.setAjaxRendered(false);
+ createVisitContext(false);
+
+ viewRoot.visitTree(renderingContext, trackingVisitCallback);
+
+ assertEquals(Arrays.asList("myForm:table:0:nestedOutput",
"myForm:table:1:nestedOutput"),
+ trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testVisitCallback() throws Exception {
+ createVisitContext(false);
+
+ renderingContext.getIdsToVisit().add("myForm:table:1:nestedTable:0");
+
renderingContext.getIdsToVisit().add("myForm:table:1:nestedTable:1:nestedTableText");
+
renderingContext.getIdsToVisit().add("myForm:table:1:nestedTable:nestedTableFooter");
+
+ viewRoot.visitTree(renderingContext, trackingVisitCallback);
+
+ assertEquals(Arrays.asList("myForm:outerOutput",
"myForm:table:0:nestedOutput", "myForm:table:1:nestedOutput",
+ "myForm:table:1:nestedTable:nestedTableFooter",
"myForm:table:1:nestedTable:0",
+ "myForm:table:1:nestedTable:1:nestedTableText"),
trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testVisitMetaComponentsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
renderingContext.getIdsToVisit().add("myForm:table:1:nestedTable@footer");
+
+ boolean visitResult = viewRoot.visitTree(renderingContext,
trackingVisitCallback);
+ assertTrue(visitResult);
+
+ assertEquals(Arrays.asList("myForm:table:1:nestedTable@footer"),
trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testVisitMetaComponentsWithWildcardsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
renderingContext.getIdsToVisit().add("myForm:table:*:nestedTable@footer");
+
+ viewRoot.visitTree(renderingContext, trackingVisitCallback);
+
+ assertEquals(Arrays.asList("myForm:table:0:nestedTable@footer",
"myForm:table:1:nestedTable@footer"),
+ trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testFormVisitContext() throws Exception {
+ createVisitContext(false);
+
+ Collection<String> formDirectIds =
renderingContext.getDirectSubtreeIdsToVisit(form);
+ assertNotSame(VisitContext.ALL_IDS, formDirectIds);
+ ExtendedVisitContext formVisitContext = (ExtendedVisitContext) renderingContext.
+ createNamingContainerVisitContext(form, formDirectIds);
+
+ assertFalse(formVisitContext.getIdsToVisit().isEmpty());
+ assertSame(VisitContext.ALL_IDS, formVisitContext.getSubtreeIdsToVisit(form));
+ assertTrue(formVisitContext.getSubtreeIdsToVisit(table).isEmpty());
+
+ Collection<String> directIds =
formVisitContext.getDirectSubtreeIdsToVisit(form);
+ assertEqualSets(asSet("outerOutput", "table"), directIds);
+ assertTrue(formVisitContext.getDirectSubtreeIdsToVisit(table).isEmpty());
+
+ boolean visitResult = form.visitTree(formVisitContext, trackingVisitCallback);
+ assertTrue(visitResult);
+
+ assertEquals(Arrays.asList("myForm:outerOutput",
"myForm:table"), trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testFormVisitContextWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ renderingContext.getIdsToVisit().add("myForm:table:0");
+
+ Collection<String> formDirectIds =
renderingContext.getDirectSubtreeIdsToVisit(form);
+ assertNotSame(VisitContext.ALL_IDS, formDirectIds);
+ ExtendedVisitContext formVisitContext = (ExtendedVisitContext) renderingContext.
+ createNamingContainerVisitContext(form, formDirectIds);
+
+ assertFalse(formVisitContext.getIdsToVisit().isEmpty());
+ assertSame(VisitContext.ALL_IDS, formVisitContext.getSubtreeIdsToVisit(form));
+ assertTrue(formVisitContext.getSubtreeIdsToVisit(table).isEmpty());
+
+ Collection<String> directIds =
formVisitContext.getDirectSubtreeIdsToVisit(form);
+ assertEqualSets(asSet("table"), directIds);
+ assertTrue(formVisitContext.getSubtreeIdsToVisit(table).isEmpty());
+
+ boolean visitResult = form.visitTree(formVisitContext, trackingVisitCallback);
+ assertTrue(visitResult);
+
+ assertEquals(Arrays.asList("myForm:table"),
trackingVisitCallback.getVisitedIds());
+ }
+
+ @Test
+ public void testFormVisitContextNonexistentIdsWithLimitRender() throws Exception {
+ createVisitContext(true);
+
+ renderingContext.getIdsToVisit().add("myForm:nonExistentId");
+ Collection<String> formDirectIds =
renderingContext.getDirectSubtreeIdsToVisit(form);
+ assertNotSame(VisitContext.ALL_IDS, formDirectIds);
+ ExtendedVisitContext formVisitContext = (ExtendedVisitContext) renderingContext.
+ createNamingContainerVisitContext(form, formDirectIds);
+
+ assertFalse(formVisitContext.getIdsToVisit().isEmpty());
+ assertSame(VisitContext.ALL_IDS, formVisitContext.getSubtreeIdsToVisit(form));
+ assertTrue(formVisitContext.getSubtreeIdsToVisit(table).isEmpty());
+
+ Collection<String> directIds =
formVisitContext.getDirectSubtreeIdsToVisit(form);
+ assertEqualSets(asSet("nonExistentId"), directIds);
+ assertTrue(formVisitContext.getSubtreeIdsToVisit(table).isEmpty());
+
+ boolean visitResult = form.visitTree(formVisitContext, trackingVisitCallback);
+ assertFalse(visitResult);
+
+ assertEquals(Arrays.asList(), trackingVisitCallback.getVisitedIds());
+ }
+}
+