Author: nbelaevski
Date: 2010-04-30 14:59:59 -0400 (Fri, 30 Apr 2010)
New Revision: 16861
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolverNode.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTest.java
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTestBean.java
root/framework/trunk/impl/src/test/resources/org/richfaces/context/
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.config.xml
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.xhtml
Modified:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.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
root/framework/trunk/pom.xml
Log:
test-base module removed
https://jira.jboss.org/jira/browse/RF-7856
Modified:
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java 2010-04-30
18:41:32 UTC (rev 16860)
+++
root/framework/trunk/impl/src/main/java/org/ajax4jsf/renderkit/RendererUtils.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -23,11 +23,8 @@
package org.ajax4jsf.renderkit;
-import static
org.richfaces.component.MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR;
-
import java.io.IOException;
import java.lang.reflect.Array;
-import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -44,7 +41,6 @@
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
-import javax.faces.component.UINamingContainer;
import javax.faces.component.UIParameter;
import javax.faces.component.UIViewRoot;
import javax.faces.component.ValueHolder;
@@ -60,10 +56,7 @@
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.util.HtmlDimensions;
-import org.richfaces.component.AjaxContainer;
-import org.richfaces.component.MetaComponentResolver;
-import org.richfaces.log.RichfacesLogger;
-import org.slf4j.Logger;
+import org.richfaces.context.ComponentIdResolver;
/**
* Util class for common render operations - render passthru html attributes,
@@ -77,8 +70,6 @@
public static final String DUMMY_FORM_ID = ":_form";
- private static final Logger LOGGER = RichfacesLogger.RENDERKIT.getLogger();
-
// we'd better use this instance multithreadly quickly
private static final RendererUtils INSTANCE = new RendererUtils();
@@ -87,12 +78,10 @@
*/
private static Map<String, String> substitutions = new HashMap<String,
String>();
private static Set<String> requiredAttributes = new HashSet<String>();
- private static Map<String, String> metaComponentSubstitutions = new
HashMap<String, String>();
static {
substitutions.put(HTML.CLASS_ATTRIBUTE, "styleClass");
requiredAttributes.add(HTML.ALT_ATTRIBUTE);
- metaComponentSubstitutions.put(AjaxContainer.META_COMPONENT_ID,
AjaxContainer.DEFAULT_RENDER_ID);
Arrays.sort(HTML.PASS_THRU);
Arrays.sort(HTML.PASS_THRU_EVENTS);
@@ -920,134 +909,24 @@
return false;
}
- private static int findNextIdx(String string, char c, int startIdx) {
- int result = string.indexOf(c, startIdx);
+ public String getPredefinedMetaComponentId(FacesContext facesContext, UIComponent
component, String id) {
- if (result < 0) {
- result = string.length();
- }
-
- return result;
- }
-
- private static UIComponent findParentContainer(UIComponent component) {
- UIComponent c = component;
-
- do {
- c = c.getParent();
- } while (!(c instanceof NamingContainer) && c != null);
-
- return c;
- }
-
- private static String computeClientId(FacesContext context,
- UIComponent component, String cleanedId, String id) {
-
- StringBuilder builder = new StringBuilder(id.length());
-
- char separatorChar = UINamingContainer.getSeparatorChar(context);
-
- int nameSegmentsCounter = 1;
- int idx = 0;
-
- //TODO nick - here hack is used - implement correct findComponent(...) method
- while ((idx = cleanedId.indexOf(separatorChar, idx) + 1) > 0) {
- nameSegmentsCounter++;
- }
-
- UIComponent container = component;
-
- for (int i = 0; i < nameSegmentsCounter && container != null; i++) {
- container = findParentContainer(container);
- }
-
- if (container != null) {
- String clientId = container.getContainerClientId(context);
- if (clientId.length() != 0) {
- builder.append(clientId);
- builder.append(separatorChar);
- }
- }
-
- builder.append(id);
-
- return builder.toString();
- }
-
- private static String cleanupId(char separatorChar, String id) {
- if (id == null || id.length() == 0) {
- return id;
- }
-
- StringBuilder sb = new StringBuilder();
-
- boolean appendSeparator = false;
- int lastIdx = 0;
- int idx = 0;
-
- do {
- idx = findNextIdx(id, separatorChar, lastIdx);
- //TODO nick - extract constants
- if (idx == lastIdx || (id.charAt(lastIdx) != '[' &&
id.charAt(idx - 1) != ']')) {
- //TODO nick - review this code for '*' selectors handling
- if (idx - lastIdx != 1 || id.charAt(lastIdx) != '*') {
- if (appendSeparator) {
- sb.append(separatorChar);
- } else {
- appendSeparator = true;
- }
-
- sb.append(id.substring(lastIdx, idx));
- }
- }
-
- lastIdx = idx + 1;
- } while (idx != id.length());
-
- return sb.toString();
- }
-
- private static String resolveMetaComponentId(FacesContext context, UIComponent
component, String metaComponentId) {
- UIComponent c = component;
- while (c != null) {
- if (c instanceof MetaComponentResolver) {
- MetaComponentResolver metaComponentResolver = (MetaComponentResolver) c;
-
- String resolvedId = metaComponentResolver.resolveClientId(context,
component, metaComponentId);
-
- if (resolvedId != null) {
- return resolvedId;
- }
- }
-
- c = c.getParent();
- }
-
- return metaComponentSubstitutions.get(metaComponentId);
- }
-
- private boolean addPredefinedMetaComponentId(FacesContext facesContext, UIComponent
component,
- Set<String> ids, String id) {
-
if (AjaxRendererUtils.ALL.equals(id)) {
- ids.clear();
- ids.add(AjaxRendererUtils.ALL);
- return true;
+ return AjaxRendererUtils.ALL;
} else if (AjaxRendererUtils.NONE.equals(id)) {
- ids.clear();
- return true;
+ return AjaxRendererUtils.NONE;
} else if (AjaxRendererUtils.THIS.equals(id)) {
- ids.add(component.getClientId(facesContext));
- return true;
+ return component.getClientId(facesContext);
} else if (AjaxRendererUtils.FORM.equals(id)) {
UIForm nestingForm = getNestingForm(facesContext, component);
if (nestingForm != null) {
- ids.add(nestingForm.getClientId(facesContext));
+ return nestingForm.getClientId(facesContext);
+ } else {
+ //TODO nick - log warning for missing form
}
- return true;
}
- return false;
+ return null;
}
/**
@@ -1065,81 +944,31 @@
Set<String> result = new LinkedHashSet<String>(shortIds.size());
if (checkKeyword(shortIds, AjaxRendererUtils.ALL)) {
- result.clear();
result.add(AjaxRendererUtils.ALL);
} else if (checkKeyword(shortIds, AjaxRendererUtils.NONE)) {
//do nothing, use empty set
} else {
- for (String id : shortIds) {
- if (id.length() == 0) {
- continue;
- }
+ ComponentIdResolver locator = new ComponentIdResolver(context);
- if (addPredefinedMetaComponentId(context, component, result, id)) {
- continue;
- }
-
- char separatorChar = UINamingContainer.getSeparatorChar(context);
- if (id.charAt(0) == separatorChar) {
- //TODO nick - how to handle meta-component IDs attached to client
IDs?
- result.add(id.substring(1));
- continue;
- }
-
- String componentId;
- String metaComponentId;
-
- int idx = id.indexOf(META_COMPONENT_SEPARATOR_CHAR);
- if (idx >= 0) {
- componentId = id.substring(0, idx);
- metaComponentId = id.substring(idx + 1);
- } else {
- componentId = id;
- metaComponentId = null;
- }
-
- UIComponent baseComponent = null;
- String cleanedId = null;
- if (!isEmpty(componentId)) {
- cleanedId = cleanupId(separatorChar, componentId);
- baseComponent = findComponentFor(component, cleanedId);
-
- if (baseComponent == null) {
- LOGGER.warn(MessageFormat.format(
- "''{0}'' cannot be resolved in the
current context", cleanedId));
+ for (String id : shortIds) {
+ String predefinedMetaComponentId = getPredefinedMetaComponentId(context,
component, id);
+ if (predefinedMetaComponentId != null) {
+ if
(AjaxRendererUtils.GLOBAL_META_COMPONENTS.contains(predefinedMetaComponentId)) {
+ result.clear();
+ result.add(predefinedMetaComponentId);
+ break;
+ } else {
+ result.add(predefinedMetaComponentId);
+ continue;
}
}
- if (!isEmpty(metaComponentId)) {
- if (isEmpty(componentId)) {
- baseComponent = component;
- }
+ locator.addId(id);
+ }
- if (baseComponent != null) {
- String convertedId = resolveMetaComponentId(context,
baseComponent, metaComponentId);
- if (addPredefinedMetaComponentId(context, baseComponent, result,
convertedId)) {
- if
(AjaxRendererUtils.GLOBAL_META_COMPONENTS.contains(convertedId)) {
- break;
- }
- } else {
- if (convertedId == null) {
- convertedId = computeClientId(context, baseComponent,
cleanedId, id);
- }
+ locator.resolve(component);
- result.add(convertedId);
- }
- } else {
- result.add(id);
- }
- } else {
- if (baseComponent != null) {
- String computedId = computeClientId(context, baseComponent,
cleanedId, id);
- result.add(computedId);
- } else {
- result.add(id);
- }
- }
- }
+ result.addAll(locator.getResolvedIds());
}
return result;
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolver.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,480 @@
+/*
+ * 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.richfaces.component.MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+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.context.FacesContext;
+
+import org.ajax4jsf.renderkit.AjaxRendererUtils;
+import org.richfaces.component.AjaxContainer;
+import org.richfaces.component.MetaComponentResolver;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public final class ComponentIdResolver {
+
+ private static Map<String, String> metaComponentSubstitutions = new
HashMap<String, String>();
+
+ static {
+ metaComponentSubstitutions.put(AjaxContainer.META_COMPONENT_ID,
AjaxContainer.DEFAULT_RENDER_ID);
+ }
+
+ private Set<String> resolvedIds;
+
+ private Set<String> unresolvedIds;
+
+ private Set<String> absoluteIds = null;
+
+ private UIComponent containerTopMatchComponent;
+
+ private LinkedList<UIComponent> componentsStack = null;
+
+ private IdParser idParser;
+
+ private char namingContainerSeparator;
+
+ private FacesContext facesContext;
+
+ private ComponentIdResolverNode rootNode;
+
+ public ComponentIdResolver(FacesContext facesContext) {
+ super();
+
+ this.facesContext = facesContext;
+
+ this.resolvedIds = new HashSet<String>();
+ this.unresolvedIds = new HashSet<String>();
+ this.rootNode = new ComponentIdResolverNode(null, null);
+ this.namingContainerSeparator =
UINamingContainer.getSeparatorChar(facesContext);
+ this.idParser = new IdParser(namingContainerSeparator,
MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR);
+ }
+
+ private static boolean isNotEmpty(Collection<?> c) {
+ return c != null && !c.isEmpty();
+ }
+
+ private static boolean isRoot(UIComponent component) {
+ return component.getParent() == null;
+ }
+
+ private static UIComponent findRoot(UIComponent component) {
+ UIComponent c = component;
+
+ while (c != null && !isRoot(c)) {
+ c = c.getParent();
+ }
+
+ return c;
+ }
+
+ private static UIComponent findContainerOrRoot(UIComponent component) {
+ UIComponent c = component;
+
+ while (c != null && c.getParent() != null) {
+ if (c instanceof NamingContainer) {
+ break;
+ }
+ c = c.getParent();
+ }
+
+ return c;
+ }
+
+ private static String resolveMetaComponentId(FacesContext context, UIComponent
component, String metaComponentId) {
+ UIComponent c = component;
+ while (c != null) {
+ if (c instanceof MetaComponentResolver) {
+ MetaComponentResolver metaComponentResolver = (MetaComponentResolver) c;
+
+ String resolvedId = metaComponentResolver.resolveClientId(context,
component, metaComponentId);
+
+ if (resolvedId != null) {
+ return resolvedId;
+ }
+ }
+
+ c = c.getParent();
+ }
+
+ return metaComponentSubstitutions.get(metaComponentId);
+ }
+
+ private String computeClientId(FacesContext context,
+ UIComponent topMatchComponent, String id) {
+
+ UIComponent container = findContainerOrRoot(topMatchComponent.getParent());
+
+ String containerClientId = null;
+
+ if (container instanceof NamingContainer) {
+ containerClientId = container.getContainerClientId(context);
+ }
+
+ if (containerClientId != null && containerClientId.length() != 0) {
+ StringBuilder builder = new StringBuilder(containerClientId.length() + 1 /*
separator */ + id.length());
+ builder.append(containerClientId);
+ builder.append(namingContainerSeparator);
+ builder.append(id);
+ return builder.toString();
+ } else {
+ return id;
+ }
+ }
+
+ protected void addIdImmediately(String id) {
+ idParser.setId(id);
+
+ ComponentIdResolverNode node = rootNode;
+
+ while (idParser.findNext()) {
+ String componentId = idParser.getComponentId();
+
+ if (componentId.length() == 0) {
+ continue;
+ }
+
+ if (ExtendedPartialVisitContext.ANY_WILDCARD.equals(componentId)) {
+ continue;
+ }
+
+ if (componentId.length() > 2 && componentId.charAt(0) ==
'[' &&
+ componentId.charAt(componentId.length() - 1) == ']') {
+
+ continue;
+ }
+
+ node = node.getOrCreateChild(componentId);
+ }
+
+ unresolvedIds.add(id);
+ node.addFullId(id);
+ }
+
+ public void addId(String id) {
+ if (isAbsolute(id)) {
+ if (absoluteIds == null) {
+ absoluteIds = new HashSet<String>();
+ }
+
+ absoluteIds.add(id.substring(1));
+ } else {
+ addIdImmediately(id);
+ }
+ }
+
+ public Set<String> getResolvedIds() {
+ return resolvedIds;
+ }
+
+ private ComponentIdResolverNode buildInversedTreeForNode(ComponentIdResolverNode
directNode) {
+ ComponentIdResolverNode localNode = directNode;
+ ComponentIdResolverNode localInversedNode = rootNode;
+
+ while (localNode != null) {
+ ComponentIdResolverNode parent = localNode.getParent();
+ if (parent != null) {
+ localInversedNode =
localInversedNode.getOrCreateChild(localNode.getId());
+ }
+
+ localNode = parent;
+ }
+
+ return localInversedNode;
+ }
+
+ private boolean isAbsolute(String id) {
+ return id.charAt(0) == namingContainerSeparator;
+ }
+
+ private void buildInversedFilteredTreeRecursively(ComponentIdResolverNode directNode)
{
+ Set<String> fullIds = directNode.getFullIds();
+ if (isNotEmpty(fullIds)) {
+ ComponentIdResolverNode inversedNode = null;
+ for (String fullId : fullIds) {
+ if (isAbsolute(fullId)) {
+ continue;
+ }
+
+ if (inversedNode == null) {
+ inversedNode = buildInversedTreeForNode(directNode);
+ }
+
+ inversedNode.addFullId(fullId);
+ }
+ }
+
+ Collection<ComponentIdResolverNode> children =
directNode.getChildren().values();
+ for (ComponentIdResolverNode node : children) {
+ buildInversedFilteredTreeRecursively(node);
+ }
+ }
+
+ protected void clearAllUnresolvedIds() {
+ rootNode.clearChildren();
+ absoluteIds = null;
+ }
+
+ protected boolean hasUnresolvedIds() {
+ return rootNode.hasChildren();
+ }
+
+ protected boolean findComponentsInContainerRecursively(UIComponent component,
ComponentIdResolverNode node) {
+ if (!hasUnresolvedIds()) {
+ return true;
+ }
+
+ if (component.getChildCount() > 0) {
+ for (UIComponent child : component.getChildren()) {
+ if (findComponentsInContainer(child, node, false)) {
+ return true;
+ }
+ }
+ }
+
+ if (component.getFacetCount() > 0) {
+ for (UIComponent child : component.getFacets().values()) {
+ if (findComponentsInContainer(child, node, false)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean resolveId(ComponentIdResolverNode node, UIComponent topMatch,
UIComponent bottomMatch) {
+ boolean shouldStop = false;
+ Set<String> fullIds = node.getFullIds();
+ if (isNotEmpty(fullIds)) {
+ for (String fullId : fullIds) {
+ unresolvedIds.remove(fullId);
+
+ String metaComponentId;
+
+ int idx = fullId.indexOf(META_COMPONENT_SEPARATOR_CHAR);
+ if (idx >= 0) {
+ metaComponentId = fullId.substring(idx + 1);
+ } else {
+ metaComponentId = null;
+ }
+
+ String resolvedId = null;
+
+ if (metaComponentId != null && metaComponentId.length() != 0) {
+ resolvedId = resolveMetaComponentId(facesContext, bottomMatch,
metaComponentId);
+ }
+
+ if (AjaxRendererUtils.GLOBAL_META_COMPONENTS.contains(resolvedId)) {
+ resolvedIds.clear();
+ resolvedIds.add(resolvedId);
+
+ shouldStop = true;
+ break;
+ } else {
+ if (resolvedId != null) {
+ resolvedIds.add(resolvedId);
+ } else {
+ String computedId = computeClientId(facesContext, topMatch,
fullId);
+ resolvedIds.add(computedId);
+ }
+ }
+ }
+ node.resetFullIds();
+ }
+
+ if (shouldStop) {
+ clearAllUnresolvedIds();
+ }
+
+ return shouldStop;
+ }
+
+ protected boolean findComponentsInContainer(UIComponent component,
ComponentIdResolverNode node, boolean resolveNCChildren) {
+ ComponentIdResolverNode matchedChild = node.getChild(component.getId());
+ if (matchedChild != null) {
+ try {
+ if (rootNode.equals(node)) {
+ containerTopMatchComponent = component;
+ }
+
+ if (resolveId(matchedChild, containerTopMatchComponent, component)) {
+ return true;
+ }
+
+ if (matchedChild.hasChildren()) {
+ if (component instanceof NamingContainer) {
+ if (findComponentsInContainerRecursively(component,
matchedChild)) {
+ return true;
+ }
+ }
+ } else {
+ matchedChild.remove();
+ if (!hasUnresolvedIds()) {
+ return true;
+ }
+ }
+ } finally {
+ if (rootNode.equals(node)) {
+ containerTopMatchComponent = null;
+ }
+ }
+ }
+
+ if (!(component instanceof NamingContainer) || resolveNCChildren) {
+ return findComponentsInContainerRecursively(component, node);
+ }
+
+ return false;
+ }
+
+ protected void matchStackedComponents() {
+ UIComponent bottomMatchComponent = componentsStack.getFirst();
+ if (rootNode.getChild(bottomMatchComponent.getId()) != null) {
+ Iterator<UIComponent> iterator = componentsStack.iterator();
+ ComponentIdResolverNode node = rootNode;
+
+ while (iterator.hasNext() && node != null) {
+ UIComponent component = iterator.next();
+
+ node = node.getChild(component.getId());
+
+ if (node != null) {
+ if (resolveId(node, component, bottomMatchComponent)) {
+ break;
+ }
+
+ if (!node.hasChildren()) {
+ node.remove();
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean findComponentsBelowRecursively(UIComponent component) {
+ if (component.getChildCount() > 0) {
+ for (UIComponent child : component.getChildren()) {
+ if (findComponentsBelow(child)) {
+ return true;
+ }
+ }
+ }
+ if (component.getFacetCount() > 0) {
+ for (UIComponent facet : component.getFacets().values()) {
+ if (findComponentsBelow(facet)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ protected boolean findComponentsBelow(UIComponent component) {
+ if (componentsStack == null) {
+ componentsStack = new LinkedList<UIComponent>();
+ }
+
+ componentsStack.addFirst(component);
+ matchStackedComponents();
+
+ boolean result;
+ boolean componentRemoved = false;
+
+ if (hasUnresolvedIds()) {
+ if (!(component instanceof NamingContainer)) {
+ componentRemoved = true;
+ componentsStack.removeFirst();
+ }
+
+ result = findComponentsBelowRecursively(component);
+ } else {
+ result = true;
+ }
+
+ if (!componentRemoved) {
+ componentsStack.removeFirst();
+ }
+
+ return result;
+ }
+
+ public void resolve(UIComponent component) {
+ assert component != null;
+
+ UIComponent c = component;
+
+ //meta-components-only IDs like "@region" are handled by this line
+ resolveId(rootNode, c, c);
+
+ if (hasUnresolvedIds()) {
+ boolean resolutionResult = false;
+
+ while (!isRoot(c) && !resolutionResult) {
+ c = findContainerOrRoot(c);
+
+ resolutionResult = findComponentsInContainer(c, rootNode, true);
+
+ c = c.getParent();
+ }
+ }
+
+ UIComponent root = findRoot(c);
+
+ if (isNotEmpty(absoluteIds)) {
+ for (String absoluteId : absoluteIds) {
+ addIdImmediately(absoluteId);
+ }
+
+ absoluteIds.clear();
+ }
+
+ if (hasUnresolvedIds()) {
+ findComponentsInContainer(root, rootNode, true);
+ }
+
+ if (hasUnresolvedIds()) {
+ ComponentIdResolverNode directTreeRootNode = rootNode;
+ rootNode = new ComponentIdResolverNode(null, null);
+ buildInversedFilteredTreeRecursively(directTreeRootNode);
+
+ findComponentsBelow(root);
+ }
+
+ //TODO nick - LOG here?
+ resolvedIds.addAll(unresolvedIds);
+ }
+}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolverNode.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolverNode.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ComponentIdResolverNode.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,106 @@
+/*
+ * 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.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+final class ComponentIdResolverNode {
+
+ private Set<String> fullIds;
+
+ private String id;
+
+ private ComponentIdResolverNode parent;
+
+ private Map<String, ComponentIdResolverNode> children = new HashMap<String,
ComponentIdResolverNode>(2);
+
+ public ComponentIdResolverNode(ComponentIdResolverNode parent, String id) {
+ this.parent = parent;
+ this.id = id;
+ }
+
+ public ComponentIdResolverNode getChild(String name) {
+ return children.get(name);
+ }
+
+ public ComponentIdResolverNode getOrCreateChild(String name) {
+ ComponentIdResolverNode child = children.get(name);
+ if (child == null) {
+ child = new ComponentIdResolverNode(this, name);
+ children.put(name, child);
+ }
+
+ return child;
+ }
+
+ public boolean hasChildren() {
+ return !children.isEmpty();
+ }
+
+ public Map<String, ComponentIdResolverNode> getChildren() {
+ return children;
+ }
+
+ protected void removeNode(String id) {
+ children.remove(id);
+ }
+
+ public void remove() {
+ if (parent != null) {
+ parent.removeNode(id);
+ if (!parent.hasChildren()) {
+ parent.remove();
+ }
+ }
+ }
+
+ public Set<String> getFullIds() {
+ return fullIds;
+ }
+
+ public void addFullId(String fullId) {
+ if (fullIds == null) {
+ fullIds = new HashSet<String>();
+ }
+
+ fullIds.add(fullId);
+ }
+
+ public void resetFullIds() {
+ this.fullIds = null;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public ComponentIdResolverNode getParent() {
+ return parent;
+ }
+
+ public void clearChildren() {
+ children.clear();
+ }
+}
\ No newline at end of file
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-30
18:41:32 UTC (rev 16860)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/ExtendedPartialVisitContext.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -21,8 +21,6 @@
*/
package org.richfaces.context;
-import static
org.richfaces.component.MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR;
-
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Collections;
@@ -44,6 +42,7 @@
import javax.faces.context.FacesContext;
import org.ajax4jsf.component.AjaxOutput;
+import org.richfaces.component.MetaComponentResolver;
/**
* @author Nick Belaevski
@@ -51,13 +50,10 @@
*/
public class ExtendedPartialVisitContext extends ExtendedVisitContext {
- /**
- *
- */
+ static final String ANY_WILDCARD = "*";
+
private static final int SHORT_ID_IN_CLIENTID_SEGMENTS_NUMBER = 2;
- private static final String ANY_WILDCARD = "*";
-
private final class CollectionProxy extends AbstractCollection<String> {
private CollectionProxy() {
@@ -249,7 +245,7 @@
private IdParser setupIdParser(String id) {
if (idParser == null) {
idParser = new
IdParser(UINamingContainer.getSeparatorChar(getFacesContext()),
- META_COMPONENT_SEPARATOR_CHAR);
+ MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR);
}
idParser.setId(id);
Modified: root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java
===================================================================
--- root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java 2010-04-30
18:41:32 UTC (rev 16860)
+++ root/framework/trunk/impl/src/main/java/org/richfaces/context/IdParser.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -21,6 +21,7 @@
*/
package org.richfaces.context;
+
/**
* Helper class for parsing ids.
*
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTest.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTest.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTest.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,218 @@
+/*
+ * 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 java.util.HashSet;
+import java.util.Set;
+
+import javax.faces.application.ViewHandler;
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.view.ViewDeclarationLanguage;
+
+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;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ComponentIdResolverTest {
+
+ private FacesEnvironment environment;
+
+ private FacesRequest facesRequest;
+
+ private FacesContext facesContext;
+
+ private UIViewRoot viewRoot;
+
+ @Before
+ public void setUp() throws Exception {
+ environment = FacesEnvironment.createEnvironment();
+
+ environment.withResource("/test.xhtml", getClass().getResource(
+ "/org/richfaces/context/ComponentIdResolver.xhtml"));
+
+ environment.withResource("/WEB-INF/faces-config.xml",
getClass().getResource(
+ "/org/richfaces/context/ComponentIdResolver.config.xml"));
+
+ environment.start();
+
+ facesRequest = environment.createFacesRequest();
+ facesRequest.start();
+
+ facesContext = FacesContext.getCurrentInstance();
+ viewRoot = facesContext.getViewRoot();
+
+ ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
+ ViewDeclarationLanguage vdl =
viewHandler.getViewDeclarationLanguage(facesContext, viewRoot.getViewId());
+ vdl.buildView(facesContext, viewRoot);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ viewRoot = null;
+ facesContext = null;
+
+ facesRequest.release();
+ facesRequest = null;
+
+ environment.release();
+ environment = null;
+ }
+
+ private <T> Set<T> asSet(T... elements) {
+ Set<T> set = new HashSet<T>();
+
+ for (T element : elements) {
+ set.add(element);
+ }
+
+ return set;
+ }
+
+ private ComponentIdResolver createComponentIdResolver() {
+ return new ComponentIdResolver(facesContext);
+ }
+
+ private UIComponent evaluateComponentExpression(String expression) {
+ return (UIComponent) facesContext.getApplication().
+ evaluateExpressionGet(facesContext, expression, UIComponent.class);
+ }
+
+ @Test
+ public void testFindBySimpleId() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("input");
+ resolver.addId("column");
+ resolver.addId("header");
+ resolver.resolve(viewRoot);
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:input", "form:table:header",
"form:table:column"), resolvedIds);
+ }
+
+ @Test
+ public void testFindBySimpleIdInContext() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("input");
+ resolver.addId("column");
+ resolver.addId("header");
+
+ resolver.resolve(evaluateComponentExpression("#{testBean.table}"));
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:input", "form:table:header",
"form:table:column"), resolvedIds);
+ }
+
+ @Test
+ public void testFindByWildcardId() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("table:*:input");
+ resolver.addId("table:[*]:header");
+ resolver.addId("table:[1 2]:column");
+
+ resolver.resolve(evaluateComponentExpression("#{testBean.table}"));
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:*:input",
"form:table:[*]:header", "form:table:[1 2]:column"), resolvedIds);
+ }
+
+ @Test
+ public void testFindByMetaComponentId() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("input@text");
+ resolver.addId("table:[*]:header@head");
+ resolver.addId("table:[*]:header@footer");
+
+ resolver.resolve(viewRoot);
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:[*]:header@footer",
"form:table:[*]:header@head", "form:table:input@text"), resolvedIds);
+ }
+
+ @Test
+ public void testFindWithNoParentContainer() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("form:table:[*]:column");
+
+ resolver.resolve(evaluateComponentExpression("#{testBean.table}"));
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:[*]:column"), resolvedIds);
+ }
+
+ @Test
+ public void testFindNonExistent() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("nonExistentId");
+ resolver.addId("xForm:nonExistentId");
+ resolver.addId(":ySubview:nonExistentId");
+
+ resolver.resolve(viewRoot);
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("nonExistentId", "xForm:nonExistentId",
"ySubview:nonExistentId"), resolvedIds);
+ }
+
+ @Test
+ public void testFindViaMetadataResolverInContext() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("@region");
+
+
resolver.resolve(evaluateComponentExpression("#{testBean.outputInRegion}"));
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("firstRegion"), resolvedIds);
+ }
+
+ @Test
+ public void testFindViaMetadataResolverOutContext() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId("@region");
+
+
resolver.resolve(evaluateComponentExpression("#{testBean.outputOutRegion}"));
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("@all"), resolvedIds);
+ }
+
+ @Test
+ public void testAbsoluteIds() throws Exception {
+ ComponentIdResolver resolver = createComponentIdResolver();
+ resolver.addId(":form:table:input");
+ resolver.addId(":form:table:column@head");
+ resolver.addId(":form:table:[1]:column");
+
+ resolver.resolve(viewRoot);
+
+ Set<String> resolvedIds = resolver.getResolvedIds();
+ assertEquals(asSet("form:table:input",
"form:table:column@head", "form:table:[1]:column"), resolvedIds);
+ }
+}
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTestBean.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTestBean.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/ComponentIdResolverTestBean.java 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,96 @@
+/*
+ * 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.UIComponentBase;
+import javax.faces.context.FacesContext;
+
+import org.richfaces.component.MetaComponentResolver;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class ComponentIdResolverTestBean {
+
+ private static class UIRegion extends UIComponentBase implements
MetaComponentResolver {
+
+ public String resolveClientId(FacesContext facesContext, UIComponent
contextComponent, String metaComponentId) {
+ if ("region".equals(metaComponentId)) {
+ return getClientId(facesContext);
+ }
+ return null;
+ }
+
+ @Override
+ public String getFamily() {
+ return null;
+ }
+ }
+
+ private String[] data = {"1", "2", "3"};
+
+ private UIComponent table;
+
+ private UIComponent firstRegion = new UIRegion();
+
+ private UIComponent outputInRegion;
+
+ private UIComponent outputOutRegion;
+
+ public Object getData() {
+ return data;
+ }
+
+ public UIComponent getTable() {
+ return table;
+ }
+
+ public void setTable(UIComponent table) {
+ this.table = table;
+ }
+
+ public UIComponent getFirstRegion() {
+ return firstRegion;
+ }
+
+ public void setFirstRegion(UIComponent firstRegion) {
+ this.firstRegion = firstRegion;
+ }
+
+ public UIComponent getOutputInRegion() {
+ return outputInRegion;
+ }
+
+ public void setOutputInRegion(UIComponent inputInRegion) {
+ this.outputInRegion = inputInRegion;
+ }
+
+ public UIComponent getOutputOutRegion() {
+ return outputOutRegion;
+ }
+
+ public void setOutputOutRegion(UIComponent outputOutRegion) {
+ this.outputOutRegion = outputOutRegion;
+ }
+}
\ No newline at end of file
Added:
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.config.xml
===================================================================
---
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.config.xml
(rev 0)
+++
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.config.xml 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
+ version="2.0">
+
+ <managed-bean>
+ <managed-bean-name>testBean</managed-bean-name>
+ <managed-bean-class>org.richfaces.context.ComponentIdResolverTestBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+
+</faces-config>
\ No newline at end of file
Added:
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.xhtml
===================================================================
---
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.xhtml
(rev 0)
+++
root/framework/trunk/impl/src/test/resources/org/richfaces/context/ComponentIdResolver.xhtml 2010-04-30
18:59:59 UTC (rev 16861)
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html
xmlns="http://www.w3.org/1999/xhtml"
+
xmlns:f="http://java.sun.com/jsf/core"
+
xmlns:h="http://java.sun.com/jsf/html"
+
xmlns:ui="http://java.sun.com/jsf/facelets">
+<f:view>
+ <h:head>
+ </h:head>
+ <h:body>
+ <h:form id="form">
+ <h:dataTable value="#{testBean.data}" id="table"
binding="#{testBean.table}">
+ <h:column id="column">
+ <h:inputText id="input" />
+
+ <f:facet name="header">
+ <h:outputText id="header" />
+ </f:facet>
+ </h:column>
+ </h:dataTable>
+ </h:form>
+
+ <ui:fragment binding="#{testBean.firstRegion}"
id="firstRegion">
+ <h:outputText binding="#{testBean.outputInRegion}"
id="outputInRegion" />
+ </ui:fragment>
+
+ <h:outputText binding="#{testBean.outputOutRegion}"
id="outputOutRegion" />
+ </h:body>
+</f:view>
+</html>
\ No newline at end of file
Modified: root/framework/trunk/pom.xml
===================================================================
--- root/framework/trunk/pom.xml 2010-04-30 18:41:32 UTC (rev 16860)
+++ root/framework/trunk/pom.xml 2010-04-30 18:59:59 UTC (rev 16861)
@@ -29,7 +29,6 @@
<module>commons</module>
<module>api</module>
<module>impl</module>
- <module>test-base</module>
</modules>
<dependencyManagement>