Author: nbelaevski
Date: 2010-03-17 21:20:53 -0400 (Wed, 17 Mar 2010)
New Revision: 16593
Added:
root/framework/trunk/api/src/main/java/org/richfaces/component/PartiallyEncodedComponent.java
root/framework/trunk/api/src/main/java/org/richfaces/renderkit/
root/framework/trunk/api/src/main/java/org/richfaces/renderkit/PartialEncodingRenderer.java
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/component/visit/
root/framework/trunk/impl/src/test/java/org/richfaces/context/
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java
Modified:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextFactoryImpl.java
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java
Log:
Partial updates for sub-component parts implemented in draft
Added:
root/framework/trunk/api/src/main/java/org/richfaces/component/PartiallyEncodedComponent.java
===================================================================
---
root/framework/trunk/api/src/main/java/org/richfaces/component/PartiallyEncodedComponent.java
(rev 0)
+++
root/framework/trunk/api/src/main/java/org/richfaces/component/PartiallyEncodedComponent.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -0,0 +1,40 @@
+/*
+ * 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.component;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface PartiallyEncodedComponent {
+
+ // TODO document this method
+ public void encodePartially(VisitContext context, VisitCallback callback,
+ Collection<String> subComponentIdentifiers) throws IOException;
+
+}
Added:
root/framework/trunk/api/src/main/java/org/richfaces/renderkit/PartialEncodingRenderer.java
===================================================================
---
root/framework/trunk/api/src/main/java/org/richfaces/renderkit/PartialEncodingRenderer.java
(rev 0)
+++
root/framework/trunk/api/src/main/java/org/richfaces/renderkit/PartialEncodingRenderer.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -0,0 +1,40 @@
+/*
+ * 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.renderkit;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface PartialEncodingRenderer {
+
+ // TODO document this method
+ public void encodePartially(UIComponent component, VisitContext context,
VisitCallback callback,
+ Collection<String> subComponentIdentifiers) throws IOException;
+}
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialRenderingVisitContext.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -0,0 +1,55 @@
+/*
+ * 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/PartialViewContextFactoryImpl.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextFactoryImpl.java 2010-03-18
00:53:35 UTC (rev 16592)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextFactoryImpl.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -21,13 +21,14 @@
package org.richfaces.context;
-import org.ajax4jsf.renderkit.AjaxRendererUtils;
+import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextFactory;
-import java.util.Map;
+import org.ajax4jsf.renderkit.AjaxRendererUtils;
+
/**
* @author Nick Belaevski
* @since 4.0
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-03-18
00:53:35 UTC (rev 16592)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/PartialViewContextImpl.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -21,13 +21,18 @@
*/
package org.richfaces.context;
-import org.ajax4jsf.component.AjaxOutput;
-import org.ajax4jsf.context.AjaxContext;
-import org.ajax4jsf.renderkit.AjaxRendererUtils;
import static org.ajax4jsf.renderkit.AjaxRendererUtils.ALL;
-import org.richfaces.log.RichfacesLogger;
-import org.slf4j.Logger;
+import java.io.IOException;
+import java.io.Writer;
+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;
+
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
@@ -40,16 +45,14 @@
import javax.faces.context.PartialViewContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseId;
-import java.io.IOException;
-import java.io.Writer;
-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;
+import org.ajax4jsf.component.AjaxOutput;
+import org.ajax4jsf.context.AjaxContext;
+import org.ajax4jsf.renderkit.AjaxRendererUtils;
+import org.richfaces.component.PartiallyEncodedComponent;
+import org.richfaces.log.RichfacesLogger;
+import org.slf4j.Logger;
+
/**
* @author Nick Belaevski
* @since 4.0
@@ -310,8 +313,20 @@
// is visited. Note that we use the SKIP_UNRENDERED hint as we
// only want to visit the rendered subtree.
EnumSet<VisitHint> hints = EnumSet.of(VisitHint.SKIP_UNRENDERED);
- VisitContext visitContext = VisitContext.createVisitContext(facesContext,
phaseClientIds, hints);
- PhaseAwareVisitCallback visitCallback = new PhaseAwareVisitCallback(facesContext,
phaseId);
+
+ VisitCallback visitCallback;
+ VisitContext visitContext = VisitContext.createVisitContext(facesContext,
Collections.<String>emptySet(),
+ hints);
+
+ if (PhaseId.RENDER_RESPONSE.equals(phaseId)) {
+ PartialRenderingVisitContext partialRenderingVisitContext = new
PartialRenderingVisitContext(visitContext);
+ visitCallback = new RenderVisitCallback(facesContext,
partialRenderingVisitContext.getIdsToVisit());
+ visitContext = partialRenderingVisitContext;
+ } else {
+ visitCallback = new PhaseAwareExecuteVisitCallback(facesContext, phaseId);
+ }
+
+ visitContext.getIdsToVisit().addAll(phaseClientIds);
component.visitTree(visitContext, visitCallback);
}
@@ -334,19 +349,19 @@
}
private void renderState(FacesContext context) throws IOException {
-
- // Get the view state and write it to the response..
- PartialResponseWriter writer = getPartialResponseWriter();
- writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
- String state = context.getApplication().getStateManager().getViewState(context);
- writer.write(state);
- writer.endUpdate();
-
+ if (!context.getViewRoot().isTransient()) {
+ // Get the view state and write it to the response..
+ PartialResponseWriter writer = getPartialResponseWriter();
+ writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
+ String state =
context.getApplication().getStateManager().getViewState(context);
+ writer.write(state);
+ writer.endUpdate();
+ }
}
/*
* (non-Javadoc)
- *
+ *
* @see javax.faces.context.PartialViewContext#release()
*/
@Override
@@ -422,52 +437,94 @@
facesContext.setResponseWriter(orig);
}
- private static final class PhaseAwareVisitCallback implements VisitCallback {
+ private static final class PhaseAwareExecuteVisitCallback implements VisitCallback {
private PhaseId curPhase;
private FacesContext ctx;
- private PhaseAwareVisitCallback(FacesContext ctx, PhaseId curPhase) {
+ private PhaseAwareExecuteVisitCallback(FacesContext ctx, PhaseId curPhase) {
this.ctx = ctx;
this.curPhase = curPhase;
}
public VisitResult visit(VisitContext context, UIComponent comp) {
- try {
- if (curPhase == PhaseId.APPLY_REQUEST_VALUES) {
+ if (curPhase == PhaseId.APPLY_REQUEST_VALUES) {
- // RELEASE_PENDING handle immediate request(s)
- // If the user requested an immediate request
- // Make sure to set the immediate flag here.
+ // RELEASE_PENDING handle immediate request(s)
+ // If the user requested an immediate request
+ // Make sure to set the immediate flag here.
- comp.processDecodes(ctx);
- } else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
- comp.processValidators(ctx);
- } else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
- comp.processUpdates(ctx);
- } else if (curPhase == PhaseId.RENDER_RESPONSE) {
+ comp.processDecodes(ctx);
+ } else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
+ comp.processValidators(ctx);
+ } else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
+ comp.processUpdates(ctx);
+ } else {
+ throw new IllegalStateException("I18N: Unexpected "
+ + "PhaseId passed to PhaseAwareContextCallback: " +
curPhase.toString());
+ }
- PartialResponseWriter writer =
ctx.getPartialViewContext().getPartialResponseWriter();
+ // Once we visit a component, there is no need to visit
+ // its children, since processDecodes/Validators/Updates and
+ // encodeAll() already traverse the subtree. We return
+ // VisitResult.REJECT to supress the subtree visit.
+ return VisitResult.REJECT;
+ }
- writer.startUpdate(comp.getClientId(ctx));
- try {
- // do the default behavior...
- comp.encodeAll(ctx);
- } catch (Exception ce) {
- if (LOG.isErrorEnabled()) {
- LOG.error(ce.getMessage());
+ }
+
+ private static final class RenderVisitCallback implements VisitCallback {
+
+ private FacesContext ctx;
+
+ private SubcomponentIdsProxiedCollection proxiedIdsCollection;
+
+ private RenderVisitCallback(FacesContext ctx, SubcomponentIdsProxiedCollection
proxiedIdsCollection) {
+ this.ctx = ctx;
+ this.proxiedIdsCollection = proxiedIdsCollection;
+ }
+
+ private void logException(Exception e) {
+ if (LOG.isErrorEnabled()) {
+ LOG.error(e.getMessage());
+ }
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(e.getMessage(), e);
+ }
+ }
+
+ private void encodeUpdateForWholeComponent(UIComponent comp) throws IOException
{
+ 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);
}
- if (LOG.isDebugEnabled()) {
- LOG.debug(ce.getMessage(), ce);
- }
+ } else {
+ encodeUpdateForWholeComponent(comp);
}
- writer.endUpdate();
} else {
- throw new IllegalStateException("I18N: Unexpected "
- + "PhaseId passed to PhaseAwareContextCallback: " +
curPhase.toString());
+ encodeUpdateForWholeComponent(comp);
}
} catch (IOException ex) {
- ex.printStackTrace();
+ LOG.error(ex.getMessage(), ex);
}
// Once we visit a component, there is no need to visit
Added:
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java
===================================================================
---
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java
(rev 0)
+++
root/framework/trunk/impl/src/main/java/org/richfaces/context/SubcomponentIdsProxiedCollection.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -0,0 +1,207 @@
+/*
+ * 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;
+ }
+
+}
Added:
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java
===================================================================
---
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java
(rev 0)
+++
root/framework/trunk/impl/src/test/java/org/richfaces/context/SubcomponentIdsProxiedCollectionTest.java 2010-03-18
01:20:53 UTC (rev 16593)
@@ -0,0 +1,173 @@
+/*
+ * 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"));
+ }
+}