Author: nbelaevski
Date: 2010-04-05 09:35:27 -0400 (Mon, 05 Apr 2010)
New Revision: 16718
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java
Removed:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.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/PartialViewContextAjaxOutputTracker.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.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-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/api/src/main/java/org/richfaces/context/ExtendedVisitContext.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -21,6 +21,11 @@
*/
package org.richfaces.context;
+import java.util.Collection;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitContext;
+
/**
* @author Nick Belaevski
*
@@ -31,4 +36,7 @@
public ExtendedVisitContextMode getVisitMode();
+ public Collection<String>getDirectSubtreeIdsToVisit(UIComponent component);
+
+ public VisitContext createDirectChildrenVisitContext(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-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/component/UIDataAdaptor.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -86,6 +86,13 @@
*/
public static final String COMPONENT_TYPE = "org.richfaces.Data";
+ private static final VisitCallback STUB_CALLBACK = new VisitCallback() {
+
+ public VisitResult visit(VisitContext context, UIComponent target) {
+ return VisitResult.ACCEPT;
+ }
+ };
+
private static final Logger LOG = RichfacesLogger.COMPONENTS.getLogger();
/**
@@ -158,7 +165,7 @@
if (isRowAvailable()) {
VisitResult result = VisitResult.ACCEPT;
- if (context instanceof ExtendedVisitContext) {
+ if (visitContext instanceof ExtendedVisitContext) {
result = visitContext.invokeVisitCallback(UIDataAdaptor.this,
callback);
if (VisitResult.COMPLETE.equals(result)) {
visitResult = true;
@@ -1185,12 +1192,28 @@
// Visit children, short-circuiting as necessary
if ((result == VisitResult.ACCEPT) && doVisitChildren(visitContext,
visitRows)) {
-
if (visitFixedChildren(visitContext, callback, visitRows)) {
return true;
}
- // TODO check doVisitChildren() once again
+ if (visitContext instanceof ExtendedVisitContext) {
+ ExtendedVisitContext extendedVisitContext = (ExtendedVisitContext)
visitContext;
+
+ Collection<String> directSubtreeIdsToVisit =
extendedVisitContext.getDirectSubtreeIdsToVisit(this);
+ if (directSubtreeIdsToVisit != VisitContext.ALL_IDS) {
+ if (directSubtreeIdsToVisit.isEmpty()) {
+ return false;
+ } else {
+ VisitContext directChildrenVisitContext =
+
extendedVisitContext.createDirectChildrenVisitContext(this, directSubtreeIdsToVisit);
+
+ if (visitFixedChildren(directChildrenVisitContext,
STUB_CALLBACK, visitRows)) {
+ return false;
+ }
+ }
+ }
+ }
+
if (visitDataChildren(visitContext, callback, visitRows)) {
return true;
}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentMatcherNode.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -0,0 +1,240 @@
+/*
+ * 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.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+final class ComponentMatcherNode {
+
+ private boolean added;
+
+ private boolean patternNode;
+
+ private String source;
+
+ private boolean hasParentPatternNode;
+
+ private int kidPatternNodesCounter = 0;
+
+ private ComponentMatcherNode parentNode;
+
+ private Map<String, ComponentMatcherNode> idChildren;
+
+ private Map<String, ComponentMatcherNode> patternChildren;
+
+ private Set<String> subtreeIds;
+
+ protected Map<String, ComponentMatcherNode> getChildrenMap(boolean isPattern)
{
+ return isPattern ? patternChildren : idChildren;
+ }
+
+ protected Map<String, ComponentMatcherNode> getOrCreateChildrenMap(boolean
isPattern) {
+ if (isPattern) {
+ if (patternChildren == null) {
+ patternChildren = new HashMap<String, ComponentMatcherNode>(1);
+ }
+
+ return patternChildren;
+ } else {
+ if (idChildren == null) {
+ idChildren = new HashMap<String, ComponentMatcherNode>();
+ }
+
+ return idChildren;
+ }
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public void setSource(String source) {
+ this.source = source;
+ }
+
+ public ComponentMatcherNode getParentNode() {
+ return parentNode;
+ }
+
+ public void setParentNode(ComponentMatcherNode parentNode) {
+ this.parentNode = parentNode;
+ }
+
+ public boolean matches(String shortId) {
+ if (isPatternNode()) {
+ //TODO - modify when real patterns will be supported
+ return true;
+ } else {
+ return source.equals(shortId);
+ }
+ }
+
+ public ComponentMatcherNode getMatchedChild(String shortId) {
+ ComponentMatcherNode node = null;
+ if (idChildren != null) {
+ node = idChildren.get(shortId);
+ }
+
+ if (node == null && patternChildren != null) {
+ for (ComponentMatcherNode child : patternChildren.values()) {
+ if (child.matches(shortId)) {
+ node = child;
+ break;
+ }
+ }
+ }
+
+ return node;
+ }
+
+ public ComponentMatcherNode getChild(String key, boolean isPatternNode) {
+ Map<String, ComponentMatcherNode> childrenMap =
getChildrenMap(isPatternNode);
+ if (childrenMap != null) {
+ return childrenMap.get(key);
+ }
+
+ return null;
+ }
+
+ public void addChild(ComponentMatcherNode node) {
+ node.setParentNode(this);
+
+ boolean isPatternNode = node.isPatternNode();
+ Map<String, ComponentMatcherNode> childrenMap =
getOrCreateChildrenMap(isPatternNode);
+ if (childrenMap.put(node.getSource(), node) == null) {
+ if (isPatternNode) {
+ increaseKidPatternNodesCounter();
+ }
+
+ if (isPatternNode || this.hasParentPatternNode()) {
+ node.setHasParentPatternNode(true);
+ }
+ }
+ }
+
+ public void removeChild(ComponentMatcherNode node) {
+ boolean isPatternNode = node.isPatternNode();
+ Map<String, ComponentMatcherNode> childrenMap =
getChildrenMap(isPatternNode);
+ if (childrenMap != null) {
+ if (node.getParentNode() == this) {
+ node.setParentNode(null);
+ node.setHasParentPatternNode(false);
+ if (childrenMap.remove(node.getSource()) != null) {
+ if (isPatternNode) {
+ decreaseKidPatternNodesCounter();
+ }
+ }
+ }
+ }
+ }
+
+ public boolean hasDirectChildren() {
+ return hasDirectIdChildren() || hasDirectPatternChildren();
+ }
+
+ public boolean hasDirectIdChildren() {
+ return idChildren != null && !idChildren.isEmpty();
+ }
+
+ public boolean hasDirectPatternChildren() {
+ return patternChildren != null && !patternChildren.isEmpty();
+ }
+
+ public void increaseKidPatternNodesCounter() {
+ kidPatternNodesCounter++;
+ ComponentMatcherNode parentNode = getParentNode();
+ if (parentNode != null) {
+ parentNode.increaseKidPatternNodesCounter();
+ }
+ }
+
+ public void decreaseKidPatternNodesCounter() {
+ kidPatternNodesCounter--;
+ ComponentMatcherNode parentNode = getParentNode();
+ if (parentNode != null) {
+ parentNode.decreaseKidPatternNodesCounter();
+ }
+ }
+
+ public boolean hasKidPatternNodes() {
+ return kidPatternNodesCounter > 0;
+ }
+
+ public void markAdded() {
+ added = true;
+ }
+
+ public void markRemoved() {
+ added = false;
+ }
+
+ public boolean isAdded() {
+ return added;
+ }
+
+ public void setHasParentPatternNode(boolean hasParentPatternNode) {
+ this.hasParentPatternNode = hasParentPatternNode;
+ }
+
+ public boolean hasParentPatternNode() {
+ return hasParentPatternNode;
+ }
+
+ public Collection<String> getSubtreeIds() {
+ return subtreeIds;
+ }
+
+ public void addSubtreeId(String subtreeId) {
+ if (subtreeIds == null) {
+ subtreeIds = new HashSet<String>();
+ }
+
+ subtreeIds.add(subtreeId);
+ }
+
+ public void removeSubtreeId(String subtreeId) {
+ if (subtreeIds != null) {
+ subtreeIds.remove(subtreeId);
+ }
+ }
+
+ public Map<String, ComponentMatcherNode> getIdChildren() {
+ return idChildren;
+ }
+
+ public Map<String, ComponentMatcherNode> getPatternChildren() {
+ return patternChildren;
+ }
+
+ public boolean isPatternNode() {
+ return patternNode;
+ }
+
+ public void setPatternNode(boolean patternNode) {
+ this.patternNode = patternNode;
+ }
+}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -0,0 +1,676 @@
+/*
+ * 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.EnumSet;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UINamingContainer;
+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.ajax4jsf.component.AjaxOutput;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ExtendedPartialVisitContext extends VisitContext implements
ExtendedVisitContext {
+
+ /**
+ *
+ */
+ private static final int SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER = 2;
+
+ // TODO - make this configurable in web.xml
+ private static final char SUB_COMPONENT_SEPARATOR = '@';
+
+ private static final String ANY_WILDCARD = "*";
+
+ private final class CollectionProxy extends AbstractCollection<String> {
+
+ private CollectionProxy() {
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return directNodesMap.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return directNodesMap.size();
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return new IteratorProxy(directNodesMap.keySet().iterator());
+ }
+
+ @Override
+ public boolean add(String o) {
+ return addNode(o);
+ }
+ }
+ // Little proxy collection implementation. We proxy the id
+ // collection so that we can detect modifications and update
+ // our internal state when ids to visit are added or removed.
+
+ // Little proxy iterator implementation used by CollectionProxy
+ // so that we can catch removes.
+ private final class IteratorProxy implements Iterator<String> {
+
+ private Iterator<String> wrapped;
+
+ private String current = null;
+
+ private IteratorProxy(Iterator<String> wrapped) {
+ this.wrapped = wrapped;
+ }
+
+ public boolean hasNext() {
+ return wrapped.hasNext();
+ }
+
+ public String next() {
+ current = wrapped.next();
+
+ return current;
+ }
+
+ public void remove() {
+ if (current != null) {
+ ComponentMatcherNode node = directNodesMap.get(current);
+ if (node != null) {
+ removeNode(node);
+ }
+
+ current = null;
+ }
+
+ wrapped.remove();
+ }
+ }
+
+ 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;
+
+ // The client ids to visit
+ private Collection<String> clientIds;
+
+ private Collection<String> shortIds;
+
+ // The FacesContext for this request
+ private FacesContext facesContext;
+
+ // Our visit hints
+ private Set<VisitHint> hints;
+
+ private ComponentMatcherNode rootNode;
+
+ private Map<String, ComponentMatcherNode> directNodesMap;
+
+ /**
+ * Creates a PartialVisitorContext instance.
+ *
+ * @param facesContext
+ * the FacesContext for the current request
+ * @param clientIds
+ * the client ids of the components to visit
+ * @throws NullPointerException
+ * if {@code facesContext} is {@code null}
+ */
+ public ExtendedPartialVisitContext(FacesContext facesContext,
Collection<String> clientIds, boolean limitRender) {
+ this(facesContext, clientIds, null, limitRender);
+ }
+
+ /**
+ * Creates a PartialVisitorContext instance with the specified hints.
+ *
+ * @param facesContext
+ * the FacesContext for the current request
+ * @param clientIds
+ * the client ids of the components to visit
+ * @param hints
+ * a the VisitHints for this visit
+ * @throws NullPointerException
+ * if {@code facesContext} is {@code null}
+ */
+ public ExtendedPartialVisitContext(FacesContext facesContext,
Collection<String> clientIds, Set<VisitHint> hints,
+ boolean limitRender) {
+
+ if (facesContext == null) {
+ throw new NullPointerException();
+ }
+
+ this.facesContext = facesContext;
+
+ // Initialize our various collections
+ initializeCollections(clientIds);
+
+ // Copy and store hints - ensure unmodifiable and non-empty
+ EnumSet<VisitHint> hintsEnumSet = ((hints == null) || (hints.isEmpty())) ?
EnumSet.noneOf(VisitHint.class)
+ : EnumSet.copyOf(hints);
+
+ this.hints = Collections.unmodifiableSet(hintsEnumSet);
+
+ this.limitRender = limitRender;
+ }
+
+ private IdParser getIdParser(String id) {
+ if (idParser == null) {
+ idParser = new IdParser(UINamingContainer.getSeparatorChar(facesContext),
SUB_COMPONENT_SEPARATOR);
+ }
+
+ idParser.setId(id);
+
+ 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;
+
+ IdParser idParser = getIdParser(patternId);
+
+ String idSegment;
+ while ((idSegment = idParser.nextSegment()) != null) {
+ boolean isPattern = ANY_WILDCARD.equals(idSegment);
+ ComponentMatcherNode child = node.getChild(idSegment, isPattern);
+ if (child == null) {
+ child = new ComponentMatcherNode();
+
+ child.setPatternNode(isPattern);
+ child.setSource(idSegment);
+
+ node.addChild(child);
+ }
+
+ node = child;
+ }
+
+ node.markAdded();
+
+ return node;
+ }
+
+ private ComponentMatcherNode findMatchingNode(String clientId) {
+ ComponentMatcherNode node = rootNode;
+
+ IdParser idParser = getIdParser(clientId);
+
+ while (node != null) {
+ String idSegment = idParser.nextSegment();
+ if (idSegment != null) {
+ if (idParser.containsSubComponentSeparator()) {
+ node = node.getChild(idSegment, false);
+ } else {
+ node = node.getMatchedChild(idSegment);
+ }
+ } else {
+ break;
+ }
+ }
+
+ return node;
+ }
+
+ private ComponentMatcherNode findAddedNode(String clientId) {
+ ComponentMatcherNode node = findMatchingNode(clientId);
+
+ if (node != null && !node.isAdded()) {
+ node = null;
+ }
+
+ return node;
+ }
+
+ private void removeNode(ComponentMatcherNode nodeToRemove) {
+ nodeToRemove.markRemoved();
+
+ ComponentMatcherNode node = nodeToRemove;
+ while (node != null && !node.hasDirectChildren()) {
+ ComponentMatcherNode parentNode = node.getParentNode();
+ if (parentNode != null) {
+ parentNode.removeChild(node);
+ node = parentNode;
+ } else {
+ break;
+ }
+ }
+ }
+
+ private boolean addNode(String patternId) {
+ ComponentMatcherNode node = directNodesMap.get(patternId);
+ if (node == null) {
+ node = createNode(patternId);
+ directNodesMap.put(patternId, node);
+
+ ComponentMatcherNode n = node;
+ int addedSegmentsCount = 0;
+ while (n != null && addedSegmentsCount !=
SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER) {
+ if (!n.isPatternNode()) {
+ String shortId = n.getSource();
+ if (shortId != null) {
+ int sepIdx = shortId.indexOf(SUB_COMPONENT_SEPARATOR);
+ if (sepIdx > 0) {
+ shortId = shortId.substring(0, sepIdx);
+ }
+
+ addedSegmentsCount++;
+ shortIds.add(shortId);
+ }
+ }
+
+ n = n.getParentNode();
+ }
+
+ n = node;
+ if (!n.hasParentPatternNode()) {
+ n = n.getParentNode();
+
+ while (n != null) {
+ ComponentMatcherNode pNode = n.getParentNode();
+ if (pNode != null) {
+ n.addSubtreeId(patternId);
+ }
+
+ n = pNode;
+ }
+ }
+
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private boolean removeNode(String patternId) {
+ ComponentMatcherNode node = directNodesMap.remove(patternId);
+ if (node != null) {
+ ComponentMatcherNode n = node;
+ if (!n.hasParentPatternNode()) {
+ n = n.getParentNode();
+
+ while (n != null) {
+ ComponentMatcherNode pNode = n.getParentNode();
+ if (pNode != null) {
+ n.removeSubtreeId(patternId);
+ }
+
+ n = pNode;
+ }
+ }
+
+ removeNode(node);
+
+ return true;
+ }
+
+ 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(SUB_COMPONENT_SEPARATOR);
+ 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(SUB_COMPONENT_SEPARATOR);
+ 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
+ public Set<VisitHint> getHints() {
+ return hints;
+ }
+
+ /**
+ * @see VisitContext#getIdsToVisit VisitContext.getIdsToVisit()
+ */
+ @Override
+ public Collection<String> getIdsToVisit() {
+
+ // We just return our clientIds collection. This is
+ // the modifiable (but proxied) collection of all of
+ // the client ids to visit.
+ return clientIds;
+ }
+
+ /**
+ * @see VisitContext#getSubtreeIdsToVisit VisitContext.getSubtreeIdsToVisit()
+ */
+ @Override
+ public Collection<String> getSubtreeIdsToVisit(UIComponent component) {
+
+ // Make sure component is a NamingContainer
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
+ }
+
+ if (!limitRender &&
PartialViewContextAjaxOutputTracker.hasNestedAjaxOutputs(component)) {
+ return VisitContext.ALL_IDS;
+ }
+
+ String clientId = buildExtendedClientId(component);
+
+ ComponentMatcherNode node = findMatchingNode(clientId);
+ if (node != null) {
+ if (node.hasKidPatternNodes()) {
+ return VisitContext.ALL_IDS;
+ } else {
+ Collection<String> subtreeIds = node.getSubtreeIds();
+ if (subtreeIds != null) {
+ return Collections.unmodifiableCollection(subtreeIds);
+ } else {
+ if (node.hasDirectIdChildren()) {
+ return VisitContext.ALL_IDS;
+ } else {
+ return Collections.emptySet();
+ }
+ }
+ }
+ }
+
+ return Collections.emptySet();
+ }
+
+ public Collection<String>getDirectSubtreeIdsToVisit(UIComponent component) {
+ // Make sure component is a NamingContainer
+ if (!(component instanceof NamingContainer)) {
+ throw new IllegalArgumentException("Component is not a NamingContainer:
" + component);
+ }
+
+ Collection<String> result = null;
+ String clientId = component.getClientId(facesContext);
+ 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 (!hasDirectPatternChildren && !limitRender) {
+ Collection<String> ajaxOutputs =
+ PartialViewContextAjaxOutputTracker.getNestedAjaxOutputs(component);
+
+ if (ajaxOutputs != null && !ajaxOutputs.isEmpty()) {
+ if (result == null) {
+ result = new HashSet<String>();
+ }
+
+ result.addAll(ajaxOutputs);
+ }
+ }
+
+ return wrapIntoUnmodifiableCollection(result);
+ }
+
+ /**
+ * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
+ */
+ @Override
+ public VisitResult invokeVisitCallback(UIComponent component, VisitCallback callback)
{
+ if (shortIds.contains(component.getId())) {
+ String clientId = buildExtendedClientId(component);
+ ComponentMatcherNode node = findAddedNode(clientId);
+ if (node != null) {
+ VisitResult visitResult = callback.visit(this, component);
+
+ removeNode(clientId);
+
+ if (clientIds.isEmpty() && limitRender) {
+ return VisitResult.COMPLETE;
+ } else {
+ return visitResult;
+ }
+ }
+ }
+
+ if (!limitRender) {
+ if (component instanceof AjaxOutput) {
+ AjaxOutput ajaxOutput = (AjaxOutput) component;
+ if (ajaxOutput.isAjaxRendered()) {
+
+ // TODO - remove explicit nested IDs from update
+ return callback.visit(this, component);
+ }
+ }
+ }
+
+ return VisitResult.ACCEPT;
+ }
+
+ // Called to initialize our various collections.
+ private void initializeCollections(Collection<String> clientIds) {
+ this.rootNode = new ComponentMatcherNode();
+ this.directNodesMap = new HashMap<String, ComponentMatcherNode>();
+ this.shortIds = new HashSet<String>();
+ this.clientIds = new CollectionProxy();
+ 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 ExtendedVisitContextMode getVisitMode() {
+ //TODO version of this context for "execute"
+ return ExtendedVisitContextMode.RENDER;
+ }
+}
Added: root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java
===================================================================
--- root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java
(rev 0)
+++ root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -0,0 +1,123 @@
+/*
+ * 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;
+
+final class IdParser {
+
+ private boolean isInShortId = true;
+
+ private String id;
+
+ private int start;
+
+ private int idx;
+
+ private boolean containsSubComponentSeparator;
+
+ private final char namingContainerSeparator;
+
+ private final char subComponentSeparator;
+
+ public IdParser(char namingContainerSeparator, char subComponentSeparator) {
+ super();
+ this.namingContainerSeparator = namingContainerSeparator;
+ this.subComponentSeparator = subComponentSeparator;
+ }
+
+ private void reset() {
+ this.id = null;
+ this.start = 0;
+ this.idx = 0;
+ this.containsSubComponentSeparator = false;
+ this.isInShortId = true;
+ }
+
+ private String findNextInShortId() {
+ String segment = null;
+ boolean found = false;
+
+ for (int index = idx; !found && index < id.length(); index++) {
+ char c = id.charAt(index);
+ if (c == subComponentSeparator) {
+ segment = id.substring(start, index);
+ idx = index + 1;
+ isInShortId = false;
+ found = true;
+ } else if (c == namingContainerSeparator) {
+ segment = id.substring(start, index);
+ idx = index + 1;
+ start = idx;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ segment = id.substring(start);
+ this.id = null;
+ }
+
+ return segment;
+ }
+
+ private String findNextInFullId() {
+ String segment = null;
+ int index = id.indexOf(namingContainerSeparator, idx);
+ if (index < 0) {
+ segment = id.substring(start);
+ this.id = null;
+ } else {
+ segment = id.substring(start, index);
+ isInShortId = true;
+ idx = index + 1;
+ start = idx;
+ }
+
+ return segment;
+ }
+
+ public void setId(String id) {
+ reset();
+ this.id = id;
+ }
+
+ public String nextSegment() {
+ if (this.id == null) {
+ reset();
+ return null;
+ }
+
+ containsSubComponentSeparator = !isInShortId;
+
+ String segment = null;
+ if (isInShortId) {
+ segment = findNextInShortId();
+ } else {
+ segment = findNextInFullId();
+ }
+
+ return segment;
+ }
+
+ public boolean containsSubComponentSeparator() {
+ return containsSubComponentSeparator;
+ }
+}
\ No newline at end of file
Deleted:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java 2010-04-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -1,55 +0,0 @@
-/*
- * 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.visit.VisitContext;
-import javax.faces.component.visit.VisitContextWrapper;
-
-/**
- * @author Nick Belaevski
- *
- */
-public class PartialRenderingVisitContext extends VisitContextWrapper {
-
- private VisitContext wrappedVisitContext;
-
- private SubcomponentIdsProxiedCollection proxiedIdsCollection;
-
- public PartialRenderingVisitContext(VisitContext wrappedVisitContext) {
- super();
- this.wrappedVisitContext = wrappedVisitContext;
- }
-
- @Override
- public SubcomponentIdsProxiedCollection getIdsToVisit() {
- if (proxiedIdsCollection == null) {
- proxiedIdsCollection = new
SubcomponentIdsProxiedCollection(getWrapped().getIdsToVisit());
- }
-
- return proxiedIdsCollection;
- }
-
- @Override
- public VisitContext getWrapped() {
- return wrappedVisitContext;
- }
-}
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-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextAjaxOutputTracker.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -21,6 +21,7 @@
package org.richfaces.context;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -60,13 +61,19 @@
component.getAttributes().remove(ATTRIBUTE_NAME);
}
- static boolean hasNestedAjaxOutputs(UIComponent component) {
+ static Collection<String> getNestedAjaxOutputs(UIComponent component) {
if (!isContainerComponent(component)) {
throw new IllegalArgumentException(component.toString());
}
Set<String> trackedChildrenSet = getTrackedChildrenSet(component, false);
+ return trackedChildrenSet;
+ }
+
+ static boolean hasNestedAjaxOutputs(UIComponent component) {
+ Collection<String> trackedChildrenSet = getNestedAjaxOutputs(component);
+
return trackedChildrenSet != null && !trackedChildrenSet.isEmpty();
}
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java 2010-04-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -28,7 +28,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -48,7 +47,6 @@
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
-import org.richfaces.component.PartiallyEncodedComponent;
import org.richfaces.log.RichfacesLogger;
import org.slf4j.Logger;
@@ -69,8 +67,8 @@
private FacesContext facesContext;
private PartialResponseWriter partialResponseWriter;
- private Set<String> executeIds = null;
- private Set<String> renderIds = null;
+ private Collection<String> executeIds = null;
+ private Collection<String> renderIds = null;
private Boolean ajaxRequest = null;
private Boolean partialRequest = null;
@@ -81,6 +79,8 @@
private boolean released = false;
+ private boolean limitRender = false;
+
public PartialViewContextImpl(FacesContext facesContext, String activatorComponentId,
String behaviorEvent) {
super();
@@ -97,8 +97,6 @@
if (executeIds == null) {
executeIds = new LinkedHashSet<String>();
-
- setupExecuteIds(executeIds);
}
return executeIds;
@@ -188,26 +186,31 @@
@Override
public void processPartial(PhaseId phaseId) {
+ PartialViewContext pvc = facesContext.getPartialViewContext();
UIViewRoot viewRoot = facesContext.getViewRoot();
+ Collection<String> executeIds = pvc.getExecuteIds();
+ Collection<String> renderIds = pvc.getRenderIds();
+
+ if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
+ setupExecuteIds(executeIds);
+ }
+
if (phaseId == PhaseId.APPLY_REQUEST_VALUES
|| phaseId == PhaseId.PROCESS_VALIDATIONS
|| phaseId == PhaseId.UPDATE_MODEL_VALUES) {
- Collection<String> ids = getExecuteIds();
-
// Skip this processing if "none" is specified in the render list,
// or there were no execute phase client ids.
- if (ids == null || ids.isEmpty()) {
+ if (executeIds == null || executeIds.isEmpty()) {
// RELEASE_PENDING LOG ERROR OR WARNING
return;
}
try {
- processComponents(viewRoot, phaseId, ids, facesContext);
+ processComponents(viewRoot, phaseId, executeIds, facesContext);
} catch (Exception e) {
- //TODO log exception
- e.printStackTrace();
+ LOG.error(e.getMessage(), e);
}
// If we have just finished APPLY_REQUEST_VALUES phase, install the
@@ -216,15 +219,14 @@
// partial response writer.
//
if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
- PartialResponseWriter writer = getPartialResponseWriter();
+ PartialResponseWriter writer = pvc.getPartialResponseWriter();
facesContext.setResponseWriter(writer);
}
} else if (phaseId == PhaseId.RENDER_RESPONSE) {
- Collection<String> ids = getRenderIds();
- setupRenderIds(ids);
+ setupRenderIds(renderIds);
try {
- PartialResponseWriter writer = getPartialResponseWriter();
+ PartialResponseWriter writer = pvc.getPartialResponseWriter();
ResponseWriter orig = facesContext.getResponseWriter();
facesContext.getAttributes().put(ORIGINAL_WRITER, orig);
facesContext.setResponseWriter(writer);
@@ -242,8 +244,9 @@
// Skip this processing if "none" is specified in the render
list,
// or there were no render phase client ids.
- if (ids != null && !ids.isEmpty()) {
- processComponents(viewRoot, phaseId, ids, facesContext);
+ if ((renderIds != null && !renderIds.isEmpty()) ||
+ (!limitRender &&
PartialViewContextAjaxOutputTracker.hasNestedAjaxOutputs(viewRoot))) {
+ processComponents(viewRoot, phaseId, renderIds, facesContext);
}
renderState(facesContext);
@@ -286,6 +289,7 @@
if (visitActivatorComponent(activatorComponentId, callback)) {
ids.addAll(callback.getComponentIds());
+ limitRender = callback.isLimitRender();
if (!Boolean.TRUE.equals(renderAll) && !ids.contains(ALL)) {
addImplicitRenderIds(ids, callback.isLimitRender());
@@ -314,34 +318,33 @@
EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
VisitCallback visitCallback;
- VisitContext visitContext = VisitContext.createVisitContext(facesContext,
Collections.<String>emptySet(),
- hints);
+ VisitContext visitContext;
if (PhaseId.RENDER_RESPONSE.equals(phaseId)) {
- PartialRenderingVisitContext partialRenderingVisitContext = new
PartialRenderingVisitContext(visitContext);
- visitCallback = new RenderVisitCallback(facesContext,
partialRenderingVisitContext.getIdsToVisit());
- visitContext = partialRenderingVisitContext;
+ visitContext = new ExtendedPartialVisitContext(facesContext, phaseClientIds,
hints, limitRender);
+ visitCallback = new RenderVisitCallback(facesContext);
} else {
+ visitContext = VisitContext.createVisitContext(facesContext, phaseClientIds,
hints);
visitCallback = new PhaseAwareExecuteVisitCallback(facesContext, phaseId);
}
- visitContext.getIdsToVisit().addAll(phaseClientIds);
component.visitTree(visitContext, visitCallback);
}
- private void renderAll(FacesContext context, UIComponent component) throws
IOException {
+ private void renderAll(FacesContext context, UIViewRoot viewRoot) throws IOException
{
// If this is a "render all via ajax" request,
// make sure to wrap the entire page in a <render> elemnt
// with the special id of VIEW_ROOT_ID. This is how the client
// JavaScript knows how to replace the entire document with
// this response.
- PartialResponseWriter writer = getPartialResponseWriter();
+ PartialViewContext pvc = context.getPartialViewContext();
+ PartialResponseWriter writer = pvc.getPartialResponseWriter();
writer.startUpdate(PartialResponseWriter.RENDER_ALL_MARKER);
- Iterator<UIComponent> itr = component.getFacetsAndChildren();
- while (itr.hasNext()) {
- UIComponent kid = itr.next();
- kid.encodeAll(context);
+ if (viewRoot.getChildCount() > 0) {
+ for (UIComponent child : viewRoot.getChildren()) {
+ child.encodeAll(context);
+ }
}
writer.endUpdate();
@@ -350,7 +353,8 @@
private void renderState(FacesContext context) throws IOException {
if (!context.getViewRoot().isTransient()) {
// Get the view state and write it to the response..
- PartialResponseWriter writer = getPartialResponseWriter();
+ PartialViewContext pvc = context.getPartialViewContext();
+ PartialResponseWriter writer = pvc.getPartialResponseWriter();
writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
String state =
context.getApplication().getStateManager().getViewState(context);
writer.write(state);
@@ -378,6 +382,7 @@
ajaxRequest = null;
partialRequest = null;
renderAll = null;
+ limitRender = false;
activatorComponentId = null;
behaviorEvent = null;
@@ -388,7 +393,9 @@
UIViewRoot root = facesContext.getViewRoot();
if (root.getFacetCount() > 0) {
if (root.getFacet(UIViewRoot.METADATA_FACET_NAME) != null) {
+ //TODO nick - does ordering matter?
ids.add(UIViewRoot.METADATA_FACET_NAME);
+ //ids.add(0, UIViewRoot.METADATA_FACET_NAME);
}
}
}
@@ -463,11 +470,8 @@
private FacesContext ctx;
- private SubcomponentIdsProxiedCollection proxiedIdsCollection;
-
- private RenderVisitCallback(FacesContext ctx, SubcomponentIdsProxiedCollection
proxiedIdsCollection) {
+ private RenderVisitCallback(FacesContext ctx) {
this.ctx = ctx;
- this.proxiedIdsCollection = proxiedIdsCollection;
}
private void logException(Exception e) {
@@ -479,38 +483,24 @@
}
}
- private void encodeUpdateForWholeComponent(UIComponent comp) throws IOException
{
+ /* (non-Javadoc)
+ * @see
javax.faces.component.visit.VisitCallback#visit(javax.faces.component.visit.VisitContext,
javax.faces.component.UIComponent)
+ */
+ public VisitResult visit(VisitContext context, UIComponent target) {
PartialResponseWriter writer =
ctx.getPartialViewContext().getPartialResponseWriter();
- writer.startUpdate(comp.getClientId(ctx));
try {
- // do the default behavior...
- comp.encodeAll(ctx);
- } catch (Exception ce) {
- logException(ce);
- }
- writer.endUpdate();
- }
-
- public VisitResult visit(VisitContext context, UIComponent comp) {
- try {
- Collection<String> subComponentIds =
proxiedIdsCollection.getSubComponentIds(comp.getClientId(ctx));
- if (subComponentIds != null && !subComponentIds.isEmpty()) {
- if (comp instanceof PartiallyEncodedComponent) {
- PartiallyEncodedComponent partiallyEncodedComponent =
(PartiallyEncodedComponent) comp;
- try {
- partiallyEncodedComponent.encodePartially(context, this,
subComponentIds);
- } catch (Exception e) {
- logException(e);
- }
- } else {
- encodeUpdateForWholeComponent(comp);
- }
- } else {
- encodeUpdateForWholeComponent(comp);
+ writer.startUpdate(target.getClientId(ctx));
+ try {
+ // do the default behavior...
+ target.encodeAll(ctx);
+ } catch (Exception ce) {
+ logException(ce);
}
- } catch (IOException ex) {
- LOG.error(ex.getMessage(), ex);
+
+ writer.endUpdate();
+ } catch (IOException e) {
+ logException(e);
}
// Once we visit a component, there is no need to visit
@@ -523,8 +513,6 @@
private static final class PartialDelayedInitializationResponseWriter extends
PartialResponseWriter {
- private static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
-
private FacesContext facesContext;
private ResponseWriter responseWriter;
@@ -535,6 +523,9 @@
public PartialDelayedInitializationResponseWriter(FacesContext facesContext) {
super(null);
this.facesContext = facesContext;
+ ExternalContext externalContext = facesContext.getExternalContext();
+ externalContext.setResponseContentType("text/xml");
+
externalContext.setResponseCharacterEncoding(externalContext.getRequestCharacterEncoding());
}
/* (non-Javadoc)
@@ -552,24 +543,23 @@
private ResponseWriter createResponseWriter() {
ExternalContext externalContext = facesContext.getExternalContext();
String characterEncoding = externalContext.getRequestCharacterEncoding();
-
- if (characterEncoding == null) {
- characterEncoding = DEFAULT_CHARACTER_ENCODING;
- }
-
externalContext.setResponseCharacterEncoding(characterEncoding);
Writer outputWriter = null;
try {
- outputWriter =
facesContext.getExternalContext().getResponseOutputWriter();
+ outputWriter = externalContext.getResponseOutputWriter();
} catch (IOException e) {
LOG.error("Error creating partial context response writer: " +
e.getMessage(), e);
}
- ResponseWriter newResponseWriter = facesContext.getRenderKit().
- createResponseWriter(outputWriter, "text/xml",
characterEncoding);
+ if (outputWriter != null) {
+ ResponseWriter newResponseWriter = facesContext.getRenderKit().
+ createResponseWriter(outputWriter, "text/xml",
characterEncoding);
- return newResponseWriter;
+ return newResponseWriter;
+ }
+
+ return null;
}
}
}
Deleted:
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java 2010-04-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -1,207 +0,0 @@
-/*
- * 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.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-
-/**
- * @author Nick Belaevski
- *
- */
-class SubcomponentIdsProxiedCollection extends AbstractCollection<String> {
-
- private static final char METADATA_CHAR = '@';
-
- private static final Collection<String> WHOLE_COMPONENT = Collections
- .unmodifiableCollection(new HashSet<String>(0));
-
- private Collection<String> clientdIdsCollection;
-
- private Map<String, Collection<String>> subIdsMap = new
HashMap<String, Collection<String>>();
-
- public SubcomponentIdsProxiedCollection(Collection<String> idsCollection) {
- super();
- this.clientdIdsCollection = idsCollection;
- }
-
- private int getMetadataCharPosition(String s) {
- int idx = s.indexOf(METADATA_CHAR);
-
- // check for (idx == 0): if "s" starts with metadata char, then we
consider it's JSF-predefined id like "@all"
- if (idx <= 0) {
- idx = s.length();
- }
-
- return idx;
- }
-
- private String getClientId(String s, int metadataCharPosition) {
- return s.substring(0, metadataCharPosition);
- }
-
- private String getSubComponentId(String s, int metadataCharPosition) {
- if (s.length() != metadataCharPosition) {
- return s.substring(metadataCharPosition + 1);
- } else {
- return null;
- }
- }
-
- private boolean addSubComponentId(String clientId, String subComponentId) {
- boolean result = clientdIdsCollection.add(clientId);
-
- if (subComponentId != null) {
- Collection<String> subIdsSet = subIdsMap.get(clientId);
- if (subIdsSet == null) {
- subIdsSet = new HashSet<String>();
- subIdsMap.put(clientId, subIdsSet);
- }
-
- if (subIdsSet != WHOLE_COMPONENT) {
- result = subIdsSet.add(subComponentId);
- }
- } else {
- result = (subIdsMap.put(clientId, WHOLE_COMPONENT) != WHOLE_COMPONENT);
- }
-
- return result;
- }
-
- private boolean removeSubComponentId(String clientId, String subComponentId) {
- boolean result = false;
-
- if (subComponentId != null) {
- Collection<String> subIdsSet = subIdsMap.get(clientId);
- if (subIdsSet != null) {
- result = subIdsSet.remove(subComponentId);
- if (subIdsSet.isEmpty()) {
- subIdsMap.remove(clientId);
- clientdIdsCollection.remove(clientId);
- }
- }
- } else {
- subIdsMap.remove(clientId);
- result = clientdIdsCollection.remove(clientId);
- }
-
- return result;
- }
-
- @Override
- public boolean add(String e) {
- int charPosition = getMetadataCharPosition(e);
- String clientId = getClientId(e, charPosition);
- String subComponentId = getSubComponentId(e, charPosition);
-
- return addSubComponentId(clientId, subComponentId);
- }
-
- @Override
- public boolean remove(Object o) {
- if (!(o instanceof String)) {
- return false;
- }
-
- String e = (String) o;
- int charPosition = getMetadataCharPosition(e);
- String clientId = getClientId(e, charPosition);
- String subComponentId = getSubComponentId(e, charPosition);
-
- return removeSubComponentId(clientId, subComponentId);
- }
-
- @Override
- public boolean contains(Object o) {
- if (!(o instanceof String)) {
- return false;
- }
-
- String e = (String) o;
- int charPosition = getMetadataCharPosition(e);
- String clientId = getClientId(e, charPosition);
- String subComponentId = getSubComponentId(e, charPosition);
-
- if (subComponentId != null) {
- Collection<String> subIdsSet = subIdsMap.get(clientId);
- return (subIdsSet != null && subIdsSet != WHOLE_COMPONENT &&
subIdsSet.contains(subComponentId));
- } else {
- return clientdIdsCollection.contains(clientId);
- }
- }
-
- @Override
- public Iterator<String> iterator() {
- return new Iterator<String>() {
-
- private Iterator<String> delegateIterator =
clientdIdsCollection.iterator();
-
- private String nextElement = null;
-
- public boolean hasNext() {
- return delegateIterator.hasNext();
- }
-
- public String next() {
- nextElement = delegateIterator.next();
- return nextElement;
- }
-
- public void remove() {
- delegateIterator.remove();
- subIdsMap.remove(nextElement);
- nextElement = null;
- }
- };
- }
-
- @Override
- public boolean isEmpty() {
- return clientdIdsCollection.isEmpty();
- }
-
- @Override
- public int size() {
- return clientdIdsCollection.size();
- }
-
- @Override
- public void clear() {
- clientdIdsCollection.clear();
- subIdsMap.clear();
- }
-
- public Collection<String> getSubComponentIds(String clientId) {
- Collection<String> subIds = subIdsMap.get(clientId);
- if (subIds != WHOLE_COMPONENT) {
- return subIds;
- }
-
- return null;
- }
-
-}
Deleted:
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java 2010-04-05
13:11:49 UTC (rev 16717)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java 2010-04-05
13:35:27 UTC (rev 16718)
@@ -1,173 +0,0 @@
-/*
- * 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.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-
-/**
- * @author Nick Belaevski
- *
- */
-public class SubcomponentIdsProxiedCollectionTest {
-
- private Collection<String> delegateCollection;
-
- private SubcomponentIdsProxiedCollection proxiedIdsCollection;
-
- @Before
- public void setUp() throws Exception {
- delegateCollection = new LinkedHashSet<String>();
- proxiedIdsCollection = new SubcomponentIdsProxiedCollection(delegateCollection);
- }
-
- @After
- public void tearDown() throws Exception {
- delegateCollection = null;
- proxiedIdsCollection = null;
- }
-
- @Test
- public void testAddClientId() throws Exception {
- assertTrue(proxiedIdsCollection.add("form"));
- assertFalse(proxiedIdsCollection.add("form"));
-
- assertTrue(delegateCollection.contains("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
-
- assertTrue(proxiedIdsCollection.add("form:table"));
- assertFalse(proxiedIdsCollection.add("form:table"));
-
- assertTrue(delegateCollection.contains("form"));
- assertTrue(delegateCollection.contains("form:table"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
-
- assertTrue(proxiedIdsCollection.add("form:grid@body"));
- assertFalse(proxiedIdsCollection.add("form:grid@body"));
-
- assertTrue(delegateCollection.contains("form"));
- assertTrue(delegateCollection.contains("form:table"));
- assertTrue(delegateCollection.contains("form:grid"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
- assertNotNull(proxiedIdsCollection.getSubComponentIds("form:grid"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:grid").contains("body"));
-
- assertTrue(proxiedIdsCollection.add("form:grid@header"));
- assertFalse(proxiedIdsCollection.add("form:grid@header"));
-
- assertTrue(delegateCollection.contains("form"));
- assertTrue(delegateCollection.contains("form:table"));
- assertTrue(delegateCollection.contains("form:grid"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
- assertNotNull(proxiedIdsCollection.getSubComponentIds("form:grid"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:grid").contains("body"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:grid").contains("header"));
-
- assertTrue(proxiedIdsCollection.add("form:grid"));
- assertFalse(proxiedIdsCollection.add("form:grid"));
- assertTrue(delegateCollection.contains("form"));
- assertTrue(delegateCollection.contains("form:table"));
- assertTrue(delegateCollection.contains("form:grid"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:grid"));
- }
-
- @Test
- public void testRemove() throws Exception {
- proxiedIdsCollection.add("form");
- proxiedIdsCollection.add("form:table");
- proxiedIdsCollection.add("form:grid@body");
- proxiedIdsCollection.add("form:tab@label");
- proxiedIdsCollection.add("form:tab@content");
-
- assertTrue(delegateCollection.contains("form"));
- assertTrue(delegateCollection.contains("form:table"));
- assertTrue(delegateCollection.contains("form:grid"));
- assertTrue(delegateCollection.contains("form:tab"));
- assertNotNull(proxiedIdsCollection.getSubComponentIds("form:grid"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:grid").contains("body"));
- assertNotNull(proxiedIdsCollection.getSubComponentIds("form:tab"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:tab").contains("label"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:tab").contains("content"));
-
- assertTrue(proxiedIdsCollection.remove("form"));
- assertFalse(delegateCollection.contains("form"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form"));
- assertFalse(proxiedIdsCollection.remove("form"));
-
- assertTrue(proxiedIdsCollection.remove("form:table"));
- assertFalse(delegateCollection.contains("form:table"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
- assertFalse(proxiedIdsCollection.remove("form:table"));
-
- assertTrue(proxiedIdsCollection.remove("form:grid"));
- assertFalse(delegateCollection.contains("form:grid"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:grid"));
- assertFalse(proxiedIdsCollection.remove("form:grid"));
-
- assertTrue(proxiedIdsCollection.remove("form:tab@label"));
- assertTrue(delegateCollection.contains("form:tab"));
- assertNotNull(proxiedIdsCollection.getSubComponentIds("form:tab"));
-
assertTrue(proxiedIdsCollection.getSubComponentIds("form:tab").contains("content"));
- assertFalse(proxiedIdsCollection.remove("form:tab@label"));
-
- assertTrue(proxiedIdsCollection.remove("form:tab@content"));
- assertFalse(delegateCollection.contains("form:tab"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:tab"));
- assertFalse(proxiedIdsCollection.remove("form:tab@content"));
- }
-
- @Test
- public void testIterator() throws Exception {
- proxiedIdsCollection.add("form");
- proxiedIdsCollection.add("form:table@footer");
- proxiedIdsCollection.add("form:table@header");
-
- Iterator<String> iterator = proxiedIdsCollection.iterator();
- assertTrue(iterator.hasNext());
- assertEquals("form", iterator.next());
-
- assertTrue(iterator.hasNext());
- assertEquals("form:table", iterator.next());
- iterator.remove();
-
- assertTrue(delegateCollection.contains("form"));
- assertFalse(delegateCollection.contains("form:table"));
- assertNull(proxiedIdsCollection.getSubComponentIds("form:table"));
- }
-}