[infinispan-commits] Infinispan SVN: r423 - in trunk/core/src: main/java/org/infinispan/commands and 10 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Wed Jun 10 09:46:04 EDT 2009
Author: galder.zamarreno at jboss.com
Date: 2009-06-10 09:46:03 -0400 (Wed, 10 Jun 2009)
New Revision: 423
Added:
trunk/core/src/main/java/org/infinispan/commands/read/EntrySetCommand.java
trunk/core/src/main/java/org/infinispan/commands/read/KeySetCommand.java
trunk/core/src/main/java/org/infinispan/commands/read/ValuesCommand.java
Modified:
trunk/core/src/main/java/org/infinispan/Cache.java
trunk/core/src/main/java/org/infinispan/CacheDelegate.java
trunk/core/src/main/java/org/infinispan/commands/AbstractVisitor.java
trunk/core/src/main/java/org/infinispan/commands/CommandsFactory.java
trunk/core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java
trunk/core/src/main/java/org/infinispan/commands/Visitor.java
trunk/core/src/main/java/org/infinispan/container/DataContainer.java
trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java
trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java
trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java
trunk/core/src/main/java/org/infinispan/container/entries/CacheEntry.java
trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java
trunk/core/src/main/java/org/infinispan/util/Immutables.java
trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java
trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java
trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java
trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java
trunk/core/src/test/java/org/infinispan/test/TestingUtil.java
Log:
[ISPN-94] (Implement Map.keySet(), Map.values() and Map.entrySet() methods) Done.
Modified: trunk/core/src/main/java/org/infinispan/Cache.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/Cache.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/Cache.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -30,7 +30,9 @@
import org.infinispan.notifications.Listenable;
import org.infinispan.util.concurrent.NotifyingFuture;
+import java.util.Collection;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
@@ -90,6 +92,7 @@
*
* @author Mircea.Markus at jboss.com
* @author Manik Surtani
+ * @author Galder Zamarreño
* @see CacheManager
* @see DefaultCacheManager
* @see <a href="http://www.jboss.org/infinispan/docs">Infinispan documentation</a>
@@ -540,4 +543,47 @@
void compact();
ComponentStatus getStatus();
+
+ /**
+ * Returns a set view of the keys contained in this cache. This set is immutable, so it cannot be modified
+ * and changes to the cache won't be reflected in the set. When this method is called on a cache configured with
+ * distribution mode, the set returned only contains the keys locally available in the cache instance. To avoid
+ * memory issues, there will be not attempt to bring keys from other nodes.
+ * <p/>
+ * This method should only be used for debugging purpouses such as to verify that the cache contains all the keys
+ * entered. Any other use involving execution of this method on a production system is not recommended.
+ * <p/>
+ *
+ * @return a set view of the keys contained in this cache.
+ */
+ Set<K> keySet();
+
+ /**
+ * Returns a collection view of the keys contained in this cache. This collection is immutable, so it cannot be modified
+ * and changes to the cache won't be reflected in the set. When this method is called on a cache configured with
+ * distribution mode, the collection returned only contains the values locally available in the cache instance. To avoid
+ * memory issues, there is not attempt to bring values from other nodes.
+ * <p/>
+ * This method should only be used for testing or debugging purpouses such as to verify that the cache contains all the
+ * values entered. Any other use involving execution of this method on a production system is not recommended.
+ * <p/>
+ *
+ * @return a collection view of the values contained in this map.
+ */
+ Collection<V> values();
+
+ /**
+ * Returns a set view of the mappings contained in this cache. This set is immutable, so it cannot be modified
+ * and changes to the cache won't be reflected in the set. Besides, each element in the returned set is an immutable
+ * {@link Map.Entry}. When this method is called on a cache configured with distribution mode, the set returned only
+ * contains the mappings locally available in the cache instance. To avoid memory issues, there will be not attempt
+ * to bring mappings from other nodes.
+ * <p/>
+ * This method should only be used for debugging purpouses such as to verify that the cache contains all the mappings
+ * entered. Any other use involving execution of this method on a production system is not recommended.
+ * <p/>
+ *
+ * @return a set view of the mappings contained in this cache.
+ */
+ Set<Map.Entry<K, V>> entrySet();
}
Modified: trunk/core/src/main/java/org/infinispan/CacheDelegate.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/CacheDelegate.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/CacheDelegate.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -27,8 +27,11 @@
import org.infinispan.batch.BatchContainer;
import org.infinispan.commands.CommandsFactory;
import org.infinispan.commands.LockControlCommand;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.SizeCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.write.ClearCommand;
import org.infinispan.commands.write.EvictCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
@@ -75,6 +78,7 @@
/**
* @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
* @since 4.0
*/
@NonVolatile
@@ -152,7 +156,7 @@
public final int size() {
SizeCommand command = commandsFactory.buildSizeCommand();
- return (Integer) invoker.invoke(getInvocationContext(), command);
+ return (Integer) invoker.invoke(icc.createNonTxInvocationContext(), command);
}
public final boolean isEmpty() {
@@ -188,15 +192,18 @@
}
public Set<K> keySet() {
- throw new UnsupportedOperationException("TODO implement me"); // TODO implement me
+ KeySetCommand command = commandsFactory.buildKeySetCommand();
+ return (Set<K>) invoker.invoke(icc.createNonTxInvocationContext(), command);
}
public Collection<V> values() {
- throw new UnsupportedOperationException("TODO implement me"); // TODO implement me
+ ValuesCommand command = commandsFactory.buildValuesCommand();
+ return (Collection<V>) invoker.invoke(icc.createNonTxInvocationContext(), command);
}
public Set<Map.Entry<K, V>> entrySet() {
- throw new UnsupportedOperationException("TODO implement me"); // TODO implement me
+ EntrySetCommand command = commandsFactory.buildEntrySetCommand();
+ return (Set<Map.Entry<K, V>>) invoker.invoke(icc.createNonTxInvocationContext(), command);
}
public final void putForExternalRead(K key, V value) {
Modified: trunk/core/src/main/java/org/infinispan/commands/AbstractVisitor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/AbstractVisitor.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/commands/AbstractVisitor.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -21,8 +21,11 @@
*/
package org.infinispan.commands;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.SizeCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.tx.CommitCommand;
import org.infinispan.commands.tx.PrepareCommand;
import org.infinispan.commands.tx.RollbackCommand;
@@ -43,6 +46,7 @@
*
* @author Mircea.Markus at jboss.com
* @author Manik Surtani
+ * @author Galder Zamarreño
* @since 4.0
*/
public abstract class AbstractVisitor implements Visitor {
@@ -82,6 +86,18 @@
return handleDefault(ctx, command);
}
+ public Object visitKeySetCommand(InvocationContext ctx, KeySetCommand command) throws Throwable {
+ return handleDefault(ctx, command);
+ }
+
+ public Object visitValuesCommand(InvocationContext ctx, ValuesCommand command) throws Throwable {
+ return handleDefault(ctx, command);
+ }
+
+ public Object visitEntrySetCommand(InvocationContext ctx, EntrySetCommand command) throws Throwable {
+ return handleDefault(ctx, command);
+ }
+
// tx commands
public Object visitPrepareCommand(TxInvocationContext ctx, PrepareCommand command) throws Throwable {
Modified: trunk/core/src/main/java/org/infinispan/commands/CommandsFactory.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/CommandsFactory.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/commands/CommandsFactory.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -22,8 +22,11 @@
package org.infinispan.commands;
import org.infinispan.commands.control.StateTransferControlCommand;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.SizeCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.remote.ClusteredGetCommand;
import org.infinispan.commands.remote.MultipleRpcCommand;
import org.infinispan.commands.remote.SingleRpcCommand;
@@ -48,6 +51,7 @@
/**
* @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
* @since 4.0
*/
@Scope(Scopes.NAMED_CACHE)
@@ -66,6 +70,12 @@
SizeCommand buildSizeCommand();
GetKeyValueCommand buildGetKeyValueCommand(Object key);
+
+ KeySetCommand buildKeySetCommand();
+
+ ValuesCommand buildValuesCommand();
+
+ EntrySetCommand buildEntrySetCommand();
PutMapCommand buildPutMapCommand(Map map, long lifespanMillis, long maxIdleTimeMillis);
Modified: trunk/core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/commands/CommandsFactoryImpl.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -23,8 +23,11 @@
import org.infinispan.Cache;
import org.infinispan.commands.control.StateTransferControlCommand;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.SizeCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.remote.ClusteredGetCommand;
import org.infinispan.commands.remote.MultipleRpcCommand;
import org.infinispan.commands.remote.SingleRpcCommand;
@@ -57,6 +60,7 @@
/**
* @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
* @since 4.0
*/
public class CommandsFactoryImpl implements CommandsFactory {
@@ -68,6 +72,9 @@
// some stateless commands can be reused so that they aren't constructed again all the time.
SizeCommand cachedSizeCommand;
+ KeySetCommand cachedKeySetCommand;
+ ValuesCommand cachedValuesCommand;
+ EntrySetCommand cachedEntrySetCommand;
private InterceptorChain interceptorChain;
private DistributionManager distributionManager;
private InvocationContextContainer icc;
@@ -120,7 +127,28 @@
}
return cachedSizeCommand;
}
+
+ public KeySetCommand buildKeySetCommand() {
+ if (cachedKeySetCommand == null) {
+ cachedKeySetCommand = new KeySetCommand(dataContainer);
+ }
+ return cachedKeySetCommand;
+ }
+
+ public ValuesCommand buildValuesCommand() {
+ if (cachedValuesCommand == null) {
+ cachedValuesCommand = new ValuesCommand(dataContainer);
+ }
+ return cachedValuesCommand;
+ }
+ public EntrySetCommand buildEntrySetCommand() {
+ if (cachedEntrySetCommand == null) {
+ cachedEntrySetCommand = new EntrySetCommand(dataContainer);
+ }
+ return cachedEntrySetCommand;
+ }
+
public GetKeyValueCommand buildGetKeyValueCommand(Object key) {
return new GetKeyValueCommand(key, notifier);
}
Modified: trunk/core/src/main/java/org/infinispan/commands/Visitor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/Visitor.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/commands/Visitor.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -21,8 +21,11 @@
*/
package org.infinispan.commands;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.read.SizeCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.tx.CommitCommand;
import org.infinispan.commands.tx.PrepareCommand;
import org.infinispan.commands.tx.RollbackCommand;
@@ -38,6 +41,7 @@
/**
* @author Mircea.Markus at jboss.com
+ * @author Galder Zamarreño
* @since 4.0
*/
@@ -61,6 +65,12 @@
Object visitSizeCommand(InvocationContext ctx, SizeCommand command) throws Throwable;
Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable;
+
+ Object visitKeySetCommand(InvocationContext ctx, KeySetCommand command) throws Throwable;
+
+ Object visitValuesCommand(InvocationContext ctx, ValuesCommand command) throws Throwable;
+
+ Object visitEntrySetCommand(InvocationContext ctx, EntrySetCommand command) throws Throwable;
// tx commands
Added: trunk/core/src/main/java/org/infinispan/commands/read/EntrySetCommand.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/read/EntrySetCommand.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/commands/read/EntrySetCommand.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -0,0 +1,71 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.infinispan.commands.read;
+
+import java.util.Set;
+
+import org.infinispan.commands.VisitableCommand;
+import org.infinispan.commands.Visitor;
+import org.infinispan.container.DataContainer;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.util.Immutables;
+
+/**
+ * EntrySetCommand.
+ *
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class EntrySetCommand implements VisitableCommand {
+ private final DataContainer container;
+
+ public EntrySetCommand(DataContainer container) {
+ this.container = container;
+ }
+
+ public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable {
+ return visitor.visitEntrySetCommand(ctx, this);
+ }
+
+ public Set perform(InvocationContext ctx) throws Throwable {
+ return Immutables.immutableSetWrap(container.entrySet());
+ }
+
+ public byte getCommandId() {
+ return 0; // no-op
+ }
+
+ public Object[] getParameters() {
+ return new Object[0]; // no-op
+ }
+
+ public void setParameters(int commandId, Object[] parameters) {
+ // no-op
+ }
+
+ @Override
+ public String toString() {
+ return "EntrySetCommand{" +
+ "set=" + container.entrySet() +
+ '}';
+ }
+}
Added: trunk/core/src/main/java/org/infinispan/commands/read/KeySetCommand.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/read/KeySetCommand.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/commands/read/KeySetCommand.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.infinispan.commands.read;
+
+import java.util.Set;
+
+import org.infinispan.commands.VisitableCommand;
+import org.infinispan.commands.Visitor;
+import org.infinispan.container.DataContainer;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.util.Immutables;
+
+/**
+ * KeySetCommand.
+ *
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class KeySetCommand implements VisitableCommand {
+ private final DataContainer container;
+
+ public KeySetCommand(DataContainer container) {
+ this.container = container;
+ }
+
+ public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable {
+ return visitor.visitKeySetCommand(ctx, this);
+ }
+
+ public Set perform(InvocationContext ctx) throws Throwable {
+ return Immutables.immutableSetWrap(container.keySet());
+ }
+
+ public byte getCommandId() {
+ return 0; // no-op
+ }
+
+ public Object[] getParameters() {
+ return new Object[0]; // no-op
+ }
+
+ public void setParameters(int commandId, Object[] parameters) {
+ // no-op
+ }
+
+ @Override
+ public String toString() {
+ return "KeySetCommand{" +
+ "set=" + container.keySet() +
+ '}';
+ }
+
+}
Added: trunk/core/src/main/java/org/infinispan/commands/read/ValuesCommand.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/commands/read/ValuesCommand.java (rev 0)
+++ trunk/core/src/main/java/org/infinispan/commands/read/ValuesCommand.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -0,0 +1,72 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file 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.infinispan.commands.read;
+
+import java.util.Collection;
+
+import org.infinispan.commands.VisitableCommand;
+import org.infinispan.commands.Visitor;
+import org.infinispan.container.DataContainer;
+import org.infinispan.context.InvocationContext;
+import org.infinispan.util.Immutables;
+
+/**
+ * ValuesCommand.
+ *
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class ValuesCommand implements VisitableCommand {
+ private final DataContainer container;
+
+ public ValuesCommand(DataContainer container) {
+ this.container = container;
+ }
+
+ public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable {
+ return visitor.visitValuesCommand(ctx, this);
+ }
+
+ public Collection perform(InvocationContext ctx) throws Throwable {
+ return Immutables.immutableCollectionWrap(container.values());
+ }
+
+ public byte getCommandId() {
+ return 0; // no-op
+ }
+
+ public Object[] getParameters() {
+ return new Object[0]; // no-op
+ }
+
+ public void setParameters(int commandId, Object[] parameters) {
+ // no-op
+ }
+
+ @Override
+ public String toString() {
+ return "ValuesCommand{" +
+ "values=" + container.values() +
+ '}';
+ }
+
+}
Modified: trunk/core/src/main/java/org/infinispan/container/DataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/DataContainer.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/container/DataContainer.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -25,12 +25,15 @@
import org.infinispan.factories.scopes.Scope;
import org.infinispan.factories.scopes.Scopes;
+import java.util.Collection;
+import java.util.Map;
import java.util.Set;
/**
* The main internal data structure which stores entries
*
* @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @author Galder Zamarreño
* @since 4.0
*/
@Scope(Scopes.NAMED_CACHE)
@@ -83,6 +86,23 @@
Set<Object> keySet();
/**
+ * @return a set of values contained in the container
+ */
+ Collection<Object> values();
+
+ /**
+ * Returns a mutable set of immutable cache entries exposed as immutable Map.Entry instances. Clients
+ * of this method such as Cache.entrySet() operation implementors are free to convert the set into an
+ * immutable set if needed, which is the most common use case.
+ *
+ * If a client needs to iterate through a mutable set of mutable cache entries, it should iterate the
+ * container itself rather than iterating through the return of entrySet().
+ *
+ * @return a set of immutable cache entries
+ */
+ Set<Map.Entry> entrySet();
+
+ /**
* Purges entries that have passed their expiry time
*/
void purgeExpired();
Modified: trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/container/FIFODataContainer.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -2,9 +2,13 @@
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.InternalEntryFactory;
+import org.infinispan.util.Immutables;
+import java.util.AbstractCollection;
import java.util.AbstractSet;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.ReentrantLock;
@@ -25,6 +29,7 @@
* <p/>
*
* @author Manik Surtani
+ * @author Galder Zamarreño
* @since 4.0
*/
public class FIFODataContainer implements DataContainer {
@@ -603,7 +608,6 @@
protected final class KeySet extends AbstractSet<Object> {
-
public Iterator<Object> iterator() {
return new KeyIterator();
}
@@ -612,7 +616,27 @@
return FIFODataContainer.this.size();
}
}
+
+ protected final class Values extends AbstractCollection<Object> {
+ public Iterator<Object> iterator() {
+ return new ValueIterator();
+ }
+ public int size() {
+ return FIFODataContainer.this.size();
+ }
+ }
+
+ protected final class EntrySet extends AbstractSet<Map.Entry> {
+ public Iterator<Map.Entry> iterator() {
+ return new ImmutableEntryIterator();
+ }
+
+ public int size() {
+ return FIFODataContainer.this.size();
+ }
+ }
+
protected abstract class LinkedIterator {
LinkedEntry current = head;
@@ -627,17 +651,29 @@
}
}
- protected final class ValueIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
+ protected final class EntryIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
public InternalCacheEntry next() {
return current.e;
}
}
+
+ protected final class ImmutableEntryIterator extends LinkedIterator implements Iterator<Map.Entry> {
+ public Map.Entry next() {
+ return Immutables.immutableEntry(current.e);
+ }
+ }
protected final class KeyIterator extends LinkedIterator implements Iterator<Object> {
public Object next() {
return current.e.getKey();
}
}
+
+ protected final class ValueIterator extends LinkedIterator implements Iterator<Object> {
+ public Object next() {
+ return current.e.getValue();
+ }
+ }
// ----------- PUBLIC API ---------------
@@ -760,6 +796,14 @@
return keySet;
}
+ public Collection<Object> values() {
+ return new Values();
+ }
+
+ public Set<Map.Entry> entrySet() {
+ return new EntrySet();
+ }
+
public void purgeExpired() {
for (InternalCacheEntry ice : this) {
if (ice.isExpired()) remove(ice.getKey());
@@ -767,6 +811,6 @@
}
public Iterator<InternalCacheEntry> iterator() {
- return new ValueIterator();
+ return new EntryIterator();
}
}
Modified: trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/container/SimpleDataContainer.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -4,10 +4,14 @@
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.InternalEntryFactory;
import org.infinispan.factories.annotations.Stop;
+import org.infinispan.util.Immutables;
+import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -22,6 +26,7 @@
* This implementation offers O(1) performance for all operations.
*
* @author Manik Surtani
+ * @author Galder Zamarreño
* @since 4.0
*/
@ThreadSafe
@@ -126,7 +131,15 @@
public Set<Object> keySet() {
return new KeySet();
}
+
+ public Collection<Object> values() {
+ return new Values();
+ }
+ public Set<Map.Entry> entrySet() {
+ return new EntrySet();
+ }
+
public void purgeExpired() {
for (Iterator<InternalCacheEntry> entries = mortalEntries.values().iterator(); entries.hasNext();) {
InternalCacheEntry e = entries.next();
@@ -198,13 +211,24 @@
throw new UnsupportedOperationException();
}
}
+
+ private class EntrySet extends AbstractSet<Map.Entry> {
+ public Iterator<Map.Entry> iterator() {
+ return new ImmutableEntryIterator(immortalEntries.values().iterator(), mortalEntries.values().iterator());
+ }
- private class EntryIterator implements Iterator<InternalCacheEntry> {
+ @Override
+ public int size() {
+ return immortalEntries.size() + mortalEntries.size();
+ }
+ }
+
+ private class MortalInmortalIterator {
Iterator<Iterator<InternalCacheEntry>> metaIterator;
Iterator<InternalCacheEntry> currentIterator;
InternalCacheEntry next;
- private EntryIterator(Iterator<InternalCacheEntry> immortalIterator, Iterator<InternalCacheEntry> mortalIterator) {
+ private MortalInmortalIterator(Iterator<InternalCacheEntry> immortalIterator, Iterator<InternalCacheEntry> mortalIterator) {
metaIterator = Arrays.asList(immortalIterator, mortalIterator).iterator();
if (metaIterator.hasNext()) currentIterator = metaIterator.next();
}
@@ -218,13 +242,51 @@
return hasNext;
}
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private class EntryIterator extends MortalInmortalIterator implements Iterator<InternalCacheEntry> {
+ private EntryIterator(Iterator<InternalCacheEntry> immortalIterator, Iterator<InternalCacheEntry> mortalIterator) {
+ super(immortalIterator, mortalIterator);
+ }
+
@SuppressWarnings("unchecked")
public InternalCacheEntry next() {
return currentIterator.next();
}
+ }
+
+ private class ImmutableEntryIterator extends MortalInmortalIterator implements Iterator<Map.Entry> {
+ private ImmutableEntryIterator(Iterator<InternalCacheEntry> immortalIterator, Iterator<InternalCacheEntry> mortalIterator) {
+ super(immortalIterator, mortalIterator);
+ }
+
+ public Map.Entry next() {
+ return Immutables.immutableEntry(currentIterator.next());
+ }
+ }
+
+ private class Values extends AbstractCollection<Object> {
+ @Override
+ public Iterator<Object> iterator() {
+ return new ValueIterator(immortalEntries.values().iterator(), mortalEntries.values().iterator());
+ }
- public void remove() {
- throw new UnsupportedOperationException();
+ @Override
+ public int size() {
+ return immortalEntries.size() + mortalEntries.size();
+ }
+ }
+
+ private class ValueIterator extends MortalInmortalIterator implements Iterator<Object> {
+ private ValueIterator(Iterator<InternalCacheEntry> immortalIterator, Iterator<InternalCacheEntry> mortalIterator) {
+ super(immortalIterator, mortalIterator);
}
+
+ public Object next() {
+ return currentIterator.next().getValue();
+ }
}
}
Modified: trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -1,11 +1,16 @@
package org.infinispan.container;
import net.jcip.annotations.ThreadSafe;
+
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.entries.InternalEntryFactory;
+import org.infinispan.util.Immutables;
+import java.util.AbstractCollection;
import java.util.AbstractSet;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
@@ -27,6 +32,7 @@
* and due to the nature of these spin locks, they should only be held for a minimal amount of time.
*
* @author Manik Surtani
+ * @author Galder Zamarreño
* @since 4.0
*/
@ThreadSafe
@@ -231,7 +237,15 @@
if (keySet == null) keySet = new KeySet();
return keySet;
}
+
+ public Set<Map.Entry> entrySet() {
+ return new EntrySet();
+ }
+ public Collection<Object> values() {
+ return new Values();
+ }
+
public void purgeExpired() {
for (InternalCacheEntry ice : this) {
if (ice.isExpired()) remove(ice.getKey());
@@ -239,7 +253,7 @@
}
public Iterator<InternalCacheEntry> iterator() {
- return new ValueIterator();
+ return new EntryIterator();
}
// --------------- Internals
@@ -526,7 +540,6 @@
}
protected final class KeySet extends AbstractSet<Object> {
-
public Iterator<Object> iterator() {
return new KeyIterator();
}
@@ -535,7 +548,27 @@
return SpinLockBasedFIFODataContainer.this.size();
}
}
+
+ protected final class Values extends AbstractCollection<Object> {
+ public Iterator<Object> iterator() {
+ return new ValueIterator();
+ }
+
+ public int size() {
+ return SpinLockBasedFIFODataContainer.this.size();
+ }
+ }
+
+ protected final class EntrySet extends AbstractSet<Map.Entry> {
+ public Iterator<Map.Entry> iterator() {
+ return new ImmutableEntryIterator();
+ }
+ public int size() {
+ return SpinLockBasedFIFODataContainer.this.size();
+ }
+ }
+
protected abstract class LinkedIterator {
Aux nextAux = dummyEntry.next;
@@ -548,7 +581,7 @@
}
}
- protected final class ValueIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
+ protected final class EntryIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
public InternalCacheEntry next() {
LinkedEntry le = nextAux.next;
if (le == dummyEntry) return null;
@@ -557,6 +590,15 @@
}
}
+ protected final class ImmutableEntryIterator extends LinkedIterator implements Iterator<Map.Entry> {
+ public Map.Entry next() {
+ LinkedEntry le = nextAux.next;
+ if (le == dummyEntry) return null;
+ nextAux = le.next;
+ return Immutables.immutableEntry(le.entry);
+ }
+ }
+
protected final class KeyIterator extends LinkedIterator implements Iterator<Object> {
public Object next() {
LinkedEntry le = nextAux.next;
@@ -566,6 +608,15 @@
}
}
+ protected final class ValueIterator extends LinkedIterator implements Iterator<Object> {
+ public Object next() {
+ LinkedEntry le = nextAux.next;
+ if (le == dummyEntry) return null;
+ nextAux = le.next;
+ return le.entry.getValue();
+ }
+ }
+
protected static abstract class SpinLock {
final AtomicBoolean l = new AtomicBoolean(false);
Modified: trunk/core/src/main/java/org/infinispan/container/entries/CacheEntry.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/entries/CacheEntry.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/container/entries/CacheEntry.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -1,14 +1,17 @@
package org.infinispan.container.entries;
+import java.util.Map;
+
import org.infinispan.container.DataContainer;
/**
* An entry that is stored in the data container
*
* @author Manik Surtani
+ * @author Galder Zamarreño
* @since 4.0
*/
-public interface CacheEntry {
+public interface CacheEntry extends Map.Entry<Object, Object> {
/**
* Tests whether the entry represents a null value, typically used for repeatable read.
Modified: trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/interceptors/MarshalledValueInterceptor.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -21,18 +21,25 @@
*/
package org.infinispan.interceptors;
+import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
+import org.infinispan.commands.read.KeySetCommand;
+import org.infinispan.commands.read.ValuesCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
import org.infinispan.commands.write.PutMapCommand;
import org.infinispan.commands.write.RemoveCommand;
+import org.infinispan.container.entries.InternalEntryFactory;
import org.infinispan.context.InvocationContext;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.interceptors.base.CommandInterceptor;
import org.infinispan.marshall.MarshalledValue;
import org.infinispan.marshall.Marshaller;
+import org.infinispan.util.Immutables;
import java.io.IOException;
import java.io.NotSerializableException;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -112,7 +119,52 @@
compact(mv);
return processRetVal(retVal);
}
+
+ @Override
+ public Object visitKeySetCommand(InvocationContext ctx, KeySetCommand command) throws Throwable {
+ Set keys = (Set) invokeNextInterceptor(ctx, command);
+ Set copy = new HashSet(keys.size());
+ for (Object key : keys) {
+ if (key instanceof MarshalledValue) {
+ key = ((MarshalledValue) key).get();
+ }
+ copy.add(key);
+ }
+ return Immutables.immutableSetWrap(copy);
+ }
+ @Override
+ public Object visitValuesCommand(InvocationContext ctx, ValuesCommand command) throws Throwable {
+ Collection values = (Collection) invokeNextInterceptor(ctx, command);
+ Collection copy = new ArrayList();
+ for (Object value : values) {
+ if (value instanceof MarshalledValue) {
+ value = ((MarshalledValue) value).get();
+ }
+ copy.add(value);
+ }
+ return Immutables.immutableCollectionWrap(copy);
+ }
+
+ @Override
+ public Object visitEntrySetCommand(InvocationContext ctx, EntrySetCommand command) throws Throwable {
+ Set<Map.Entry> entries = (Set<Map.Entry>) invokeNextInterceptor(ctx, command);
+ Set<Map.Entry> copy = new HashSet<Map.Entry>(entries.size());
+ for (Map.Entry entry : entries) {
+ Object key = entry.getKey();
+ Object value = entry.getValue();
+ if (key instanceof MarshalledValue) {
+ key = ((MarshalledValue) key).get();
+ }
+ if (value instanceof MarshalledValue) {
+ value = ((MarshalledValue) value).get();
+ }
+ Map.Entry newEntry = Immutables.immutableEntry(InternalEntryFactory.create(key, value, -1));
+ copy.add(newEntry);
+ }
+ return Immutables.immutableSetWrap(copy);
+ }
+
private Object compactAndProcessRetVal(Set<MarshalledValue> marshalledValues, Object retVal)
throws IOException, ClassNotFoundException {
if (trace) log.trace("Compacting MarshalledValues created");
Modified: trunk/core/src/main/java/org/infinispan/util/Immutables.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/util/Immutables.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/main/java/org/infinispan/util/Immutables.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -37,6 +37,7 @@
* Factory for generating immutable type wrappers.
*
* @author Jason T. Greene
+ * @author Galder Zamarreño
* @since 4.0
*/
public class Immutables {
@@ -172,6 +173,16 @@
return new ImmutableCollectionWrapper<T>(copy);
}
+
+ /**
+ * Wraps a collection with an immutable collection. There is no copying involved.
+ *
+ * @param collection the collection to wrap
+ * @return an immutable collection wrapper that delegates to the original collection
+ */
+ public static <T> Collection<T> immutableCollectionWrap(Collection<? extends T> collection) {
+ return new ImmutableCollectionWrapper<T>(collection);
+ }
@SuppressWarnings("unchecked")
private static <T> T attemptCopyConstructor(T source, Class<? super T> clazz) {
@@ -194,6 +205,16 @@
return new ImmutableReversibleOrderedSetWrapper<T>(copy);
}
+
+ /**
+ * Wraps a {@link Map.Entry}} with an immutable {@link Map.Entry}}. There is no copying involved.
+ *
+ * @param entry the mapping to wrap.
+ * @return an immutable {@link Map.Entry}} wrapper that delegates to the original mapping.
+ */
+ public static Map.Entry immutableEntry(Map.Entry entry) {
+ return new ImmutableEntry(entry);
+ }
public interface Immutable {
@@ -321,7 +342,7 @@
}
}
- static class ImmutableEntry<K, V> implements Entry<K, V> {
+ static class ImmutableEntry<K, V> implements Entry<K, V>, Immutable {
private K key;
private V value;
private int hash;
Modified: trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/test/java/org/infinispan/api/CacheAPITest.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -8,13 +8,17 @@
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.transaction.lookup.DummyTransactionManagerLookup;
import org.infinispan.transaction.tm.DummyTransactionManager;
+import org.infinispan.util.ObjectDuplicator;
import org.infinispan.util.concurrent.IsolationLevel;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertNull;
import org.testng.annotations.Test;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Tests the {@link org.infinispan.Cache} public API at a high level
@@ -43,8 +47,8 @@
*/
public void testConfiguration() {
Configuration c = cache.getConfiguration();
- assertEquals(Configuration.CacheMode.LOCAL, c.getCacheMode());
- assertEquals(DummyTransactionManagerLookup.class.getName(), c.getTransactionManagerLookupClass());
+ assert Configuration.CacheMode.LOCAL.equals(c.getCacheMode());
+ assert DummyTransactionManagerLookup.class.getName().equals(c.getTransactionManagerLookupClass());
// note that certain values should be immutable. E.g., CacheMode cannot be changed on the fly.
try {
@@ -68,19 +72,31 @@
Map<String, String> data = new HashMap<String, String>();
data.put(key, value);
- assertNull(cache.get(key));
+ assert cache.get(key) == null;
+ assert cache.keySet().isEmpty();
+ assert cache.values().isEmpty();
+ assert cache.entrySet().isEmpty();
cache.put(key, value);
- assertEquals(value, cache.get(key));
+ assert value.equals(cache.get(key));
+ assert 1 == cache.keySet().size() && 1 == cache.values().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
cache.remove(key);
- assertNull(cache.get(key));
+ assert cache.get(key) == null;
+ assert cache.keySet().isEmpty();
+ assert cache.values().isEmpty();
+ assert cache.entrySet().isEmpty();
cache.putAll(data);
- assertEquals(value, cache.get(key));
+ assert value.equals(cache.get(key));
+ assert 1 == cache.keySet().size() && 1 == cache.values().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
}
/**
@@ -88,100 +104,163 @@
*/
public void testEvict() {
String key1 = "keyOne", key2 = "keyTwo", value = "value";
+ int size = 0;
cache.put(key1, value);
cache.put(key2, value);
assert cache.containsKey(key1);
assert cache.containsKey(key2);
- assert cache.size() == 2;
+ size = 2;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key1);
+ assert cache.keySet().contains(key2);
+ assert cache.values().contains(value);
// evict two
cache.evict(key2);
assert cache.containsKey(key1);
assert !cache.containsKey(key2);
- assert cache.size() == 1;
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key1);
+ assert !cache.keySet().contains(key2);
+ assert cache.values().contains(value);
cache.evict(key1);
assert !cache.containsKey(key1);
assert !cache.containsKey(key2);
assert cache.size() == 0;
+ assert !cache.keySet().contains(key1);
+ assert !cache.keySet().contains(key2);
+ assert cache.keySet().isEmpty();
+ assert !cache.values().contains(value);
+ assert cache.values().isEmpty();
+ assert cache.entrySet().isEmpty();
}
public void testStopClearsData() throws Exception {
String key = "key", value = "value";
+ int size = 0;
cache.put(key, value);
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
cache.stop();
cache.start();
assert !cache.containsKey(key);
assert cache.isEmpty();
+ assert !cache.keySet().contains(key);
+ assert cache.keySet().isEmpty();
+ assert !cache.values().contains(value);
+ assert cache.values().isEmpty();
+ assert cache.entrySet().isEmpty();
}
public void testRollbackAfterPut() throws Exception {
- String key = "key", value = "value";
+ String key = "key", value = "value", key2 = "keyTwo", value2="value2";
+ int size = 0;
cache.put(key, value);
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
DummyTransactionManager.getInstance().begin();
- cache.put("key2", "value2");
- assert cache.get("key2").equals("value2");
+ cache.put(key2, value2);
+ assert cache.get(key2).equals(value2);
+ assert !cache.keySet().contains(key2);
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert !cache.values().contains(value2);
DummyTransactionManager.getInstance().rollback();
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
}
public void testRollbackAfterOverwrite() throws Exception {
- String key = "key", value = "value";
+ String key = "key", value = "value", value2= "value2";
+ int size = 0;
cache.put(key, value);
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
DummyTransactionManager.getInstance().begin();
- cache.put(key, "value2");
- assert cache.get(key).equals("value2");
- assert 1 == cache.size();
+ cache.put(key, value2);
+ assert cache.get(key).equals(value2);
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert !cache.values().contains(value2);
DummyTransactionManager.getInstance().rollback();
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
}
public void testRollbackAfterRemove() throws Exception {
String key = "key", value = "value";
+ int size = 0;
cache.put(key, value);
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
DummyTransactionManager.getInstance().begin();
cache.remove(key);
assert cache.get(key) == null;
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
DummyTransactionManager.getInstance().rollback();
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
}
public void testRollbackAfterClear() throws Exception {
String key = "key", value = "value";
+ int size = 0;
cache.put(key, value);
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
DummyTransactionManager.getInstance().begin();
cache.clear();
assert cache.get(key) == null;
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
DummyTransactionManager.getInstance().rollback();
assert cache.get(key).equals(value);
- assert 1 == cache.size();
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
}
public void testConcurrentMapMethods() {
@@ -209,21 +288,31 @@
public void testSizeAndContents() throws Exception {
String key = "key", value = "value";
+ int size = 0;
assert cache.isEmpty();
- assert cache.size() == 0;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
assert !cache.containsKey(key);
+ assert !cache.keySet().contains(key);
+ assert !cache.values().contains(value);
cache.put(key, value);
- assert cache.size() == 1;
+ size = 1;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
assert cache.containsKey(key);
assert !cache.isEmpty();
+ assert cache.containsKey(key);
+ assert cache.keySet().contains(key);
+ assert cache.values().contains(value);
assert cache.remove(key).equals(value);
assert cache.isEmpty();
- assert cache.size() == 0;
+ size = 0;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
assert !cache.containsKey(key);
+ assert !cache.keySet().contains(key);
+ assert !cache.values().contains(value);
Map<String, String> m = new HashMap<String, String>();
m.put("1", "one");
@@ -234,7 +323,8 @@
assert cache.get("1").equals("one");
assert cache.get("2").equals("two");
assert cache.get("3").equals("three");
- assert cache.size() == 3;
+ size = 3;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
m = new HashMap<String, String>();
m.put("1", "newvalue");
@@ -246,6 +336,108 @@
assert cache.get("2").equals("two");
assert cache.get("3").equals("three");
assert cache.get("4").equals("four");
- assert cache.size() == 4;
+ size = 4;
+ assert size == cache.size() && size == cache.keySet().size() && size == cache.values().size() && size == cache.entrySet().size();
}
+
+ public void testKeyValueEntryCollections() {
+ String key1 = "1", value1 = "one", key2 = "2", value2 = "two", key3 = "3", value3 = "three";
+ Map<String, String> m = new HashMap<String, String>();
+ m.put(key1, value1);
+ m.put(key2, value2);
+ m.put(key3, value3);
+ cache.putAll(m);
+ assert 3 == cache.size() && 3 == cache.keySet().size() && 3 == cache.values().size() && 3 == cache.entrySet().size();
+
+ Set expKeys = new HashSet();
+ expKeys.add(key1);
+ expKeys.add(key2);
+ expKeys.add(key3);
+
+ Set expValues = new HashSet();
+ expValues.add(value1);
+ expValues.add(value2);
+ expValues.add(value3);
+
+ Set expKeyEntries = ObjectDuplicator.duplicateSet(expKeys);
+ Set expValueEntries = ObjectDuplicator.duplicateSet(expValues);
+
+ Set<String> keys = cache.keySet();
+ for (String key : keys) assert expKeys.remove(key);
+ assert expKeys.isEmpty() : "Did not see keys " + expKeys + " in iterator!";
+
+ Collection<String> values = cache.values();
+ for (String value : values) assert expValues.remove(value);
+ assert expValues.isEmpty() : "Did not see keys " + expValues + " in iterator!";
+
+ Set<Map.Entry> entries = cache.entrySet();
+ for (Map.Entry entry : entries) {
+ assert expKeyEntries.remove(entry.getKey());
+ assert expValueEntries.remove(entry.getValue());
+ }
+ assert expKeyEntries.isEmpty() : "Did not see keys " + expKeyEntries + " in iterator!";
+ assert expValueEntries.isEmpty() : "Did not see keys " + expValueEntries + " in iterator!";
+ }
+
+ public void testImmutabilityOfKeyValueEntryCollections() {
+ final String key1 = "1", value1 = "one", key2 = "2", value2 = "two", key3 = "3", value3 = "three";
+ Map<String, String> m = new HashMap<String, String>();
+ m.put(key1, value1);
+ m.put(key2, value2);
+ m.put(key3, value3);
+ cache.putAll(m);
+
+ Set<String> keys = cache.keySet();
+ Collection<String> values = cache.values();
+ Set<Map.Entry> entries = cache.entrySet();
+ Collection[] collections = new Collection[]{keys, values, entries};
+ Object newObj = new Object();
+ List newObjCol = new ArrayList();
+ newObjCol.add(newObj);
+ for (Collection col : collections) {
+ try {
+ col.add(newObj);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ col.addAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.clear();
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.remove(key1);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.removeAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.retainAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ }
+
+ for (Map.Entry entry : entries) {
+ try {
+ entry.setValue(newObj);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ }
+ }
+
}
Modified: trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/test/java/org/infinispan/container/SimpleDataContainerTest.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -5,11 +5,13 @@
import org.infinispan.container.entries.MortalCacheEntry;
import org.infinispan.container.entries.TransientCacheEntry;
import org.infinispan.container.entries.TransientMortalCacheEntry;
+import org.infinispan.util.Immutables;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
@Test(groups = "unit", testName = "container.SimpleDataContainerTest")
@@ -137,7 +139,7 @@
assert expected.isEmpty() : "Did not see keys " + expected + " in iterator!";
}
- public void testEntrySet() {
+ public void testContainerIteration() {
dc.put("k1", "v", 6000000, -1);
dc.put("k2", "v", -1, -1);
dc.put("k3", "v", -1, 6000000);
@@ -155,4 +157,55 @@
assert expected.isEmpty() : "Did not see keys " + expected + " in iterator!";
}
+
+ public void testKeys() {
+ dc.put("k1", "v1", 6000000, -1);
+ dc.put("k2", "v2", -1, -1);
+ dc.put("k3", "v3", -1, 6000000);
+ dc.put("k4", "v4", 6000000, 6000000);
+
+ Set expected = new HashSet();
+ expected.add("k1");
+ expected.add("k2");
+ expected.add("k3");
+ expected.add("k4");
+
+ for (Object o : dc.keySet()) assert expected.remove(o);
+
+ assert expected.isEmpty() : "Did not see keys " + expected + " in iterator!";
+ }
+
+ public void testValues() {
+ dc.put("k1", "v1", 6000000, -1);
+ dc.put("k2", "v2", -1, -1);
+ dc.put("k3", "v3", -1, 6000000);
+ dc.put("k4", "v4", 6000000, 6000000);
+
+ Set expected = new HashSet();
+ expected.add("v1");
+ expected.add("v2");
+ expected.add("v3");
+ expected.add("v4");
+
+ for (Object o : dc.values()) assert expected.remove(o);
+
+ assert expected.isEmpty() : "Did not see keys " + expected + " in iterator!";
+ }
+
+ public void testEntrySet() {
+ dc.put("k1", "v1", 6000000, -1);
+ dc.put("k2", "v2", -1, -1);
+ dc.put("k3", "v3", -1, 6000000);
+ dc.put("k4", "v4", 6000000, 6000000);
+
+ Set expected = new HashSet();
+ expected.add(Immutables.immutableEntry(dc.get("k1")));
+ expected.add(Immutables.immutableEntry(dc.get("k2")));
+ expected.add(Immutables.immutableEntry(dc.get("k3")));
+ expected.add(Immutables.immutableEntry(dc.get("k4")));
+
+ for (Map.Entry o : dc.entrySet()) assert expected.remove(o);
+
+ assert expected.isEmpty() : "Did not see keys " + expected + " in iterator!";
+ }
}
Modified: trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/test/java/org/infinispan/distribution/DistSyncFuncTest.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -1,10 +1,16 @@
package org.infinispan.distribution;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
import org.infinispan.Cache;
import org.infinispan.commands.write.ClearCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
import org.infinispan.commands.write.RemoveCommand;
import org.infinispan.commands.write.ReplaceCommand;
+import org.infinispan.test.TestingUtil;
+import org.infinispan.util.ObjectDuplicator;
import org.testng.annotations.Test;
@Test(groups = "functional", testName = "distribution.DistSyncFuncTest")
@@ -154,4 +160,39 @@
for (Cache<Object, String> c : caches) assert c.isEmpty();
}
+
+ public void testKeyValueEntryCollections() {
+ c1.put("1", "one");
+ asyncWait("1", PutKeyValueCommand.class, getNonOwnersExcludingSelf("1", addressOf(c1)));
+ c2.put("2", "two");
+ asyncWait("2", PutKeyValueCommand.class, getNonOwnersExcludingSelf("2", addressOf(c2)));
+ c3.put("3", "three");
+ asyncWait("3", PutKeyValueCommand.class, getNonOwnersExcludingSelf("3", addressOf(c3)));
+ c4.put("4", "four");
+ asyncWait("4", PutKeyValueCommand.class, getNonOwnersExcludingSelf("4", addressOf(c4)));
+
+ for (Cache c : caches) {
+ Set expKeys = TestingUtil.getInternalKeys(c);
+ Collection expValues = TestingUtil.getInternalValues(c);
+
+ Set expKeyEntries = ObjectDuplicator.duplicateSet(expKeys);
+ Collection expValueEntries = ObjectDuplicator.duplicateCollection(expValues);
+
+ Set keys = c.keySet();
+ for (Object key : keys) assert expKeys.remove(key);
+ assert expKeys.isEmpty() : "Did not see keys " + expKeys + " in iterator!";
+
+ Collection values = c.values();
+ for (Object value : values) assert expValues.remove(value);
+ assert expValues.isEmpty() : "Did not see keys " + expValues + " in iterator!";
+
+ Set<Map.Entry> entries = c.entrySet();
+ for (Map.Entry entry : entries) {
+ assert expKeyEntries.remove(entry.getKey());
+ assert expValueEntries.remove(entry.getValue());
+ }
+ assert expKeyEntries.isEmpty() : "Did not see keys " + expKeyEntries + " in iterator!";
+ assert expValueEntries.isEmpty() : "Did not see keys " + expValueEntries + " in iterator!";
+ }
+ }
}
Modified: trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/test/java/org/infinispan/marshall/MarshalledValueTest.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -18,6 +18,7 @@
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
import org.infinispan.test.MultipleCacheManagersTest;
import org.infinispan.test.TestingUtil;
+import org.infinispan.util.ObjectDuplicator;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@@ -28,7 +29,13 @@
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Tests implicit marshalled values
@@ -196,6 +203,92 @@
assertSerialized(mv);
assertSerializationCounts(2, 1);
}
+
+ public void testKeySetValuesEntrySetCollectionReferences() {
+ Pojo key1 = new Pojo(), value1 = new Pojo(), key2 = new Pojo(), value2 = new Pojo();
+ String key3 = "3", value3 = "three";
+ cache1.put(key1, value1);
+ cache1.put(key2, value2);
+ cache1.put(key3, value3);
+
+ Set expKeys = new HashSet();
+ expKeys.add(key1);
+ expKeys.add(key2);
+ expKeys.add(key3);
+
+ Set expValues = new HashSet();
+ expValues.add(value1);
+ expValues.add(value2);
+ expValues.add(value3);
+
+ Set expKeyEntries = ObjectDuplicator.duplicateSet(expKeys);
+ Set expValueEntries = ObjectDuplicator.duplicateSet(expValues);
+
+ Set keys = cache2.keySet();
+ for (Object key : keys) assert expKeys.remove(key);
+ assert expKeys.isEmpty() : "Did not see keys " + expKeys + " in iterator!";
+
+ Collection values = cache2.values();
+ for (Object key : values) assert expValues.remove(key);
+ assert expValues.isEmpty() : "Did not see keys " + expValues + " in iterator!";
+
+ Set<Map.Entry> entries = cache2.entrySet();
+ for (Map.Entry entry : entries) {
+ assert expKeyEntries.remove(entry.getKey());
+ assert expValueEntries.remove(entry.getValue());
+ }
+ assert expKeyEntries.isEmpty() : "Did not see keys " + expKeyEntries + " in iterator!";
+ assert expValueEntries.isEmpty() : "Did not see keys " + expValueEntries + " in iterator!";
+
+ Collection[] collections = new Collection[]{keys, values, entries};
+ Object newObj = new Object();
+ List newObjCol = new ArrayList();
+ newObjCol.add(newObj);
+ for (Collection col : collections) {
+ try {
+ col.add(newObj);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ try {
+ col.addAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.clear();
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.remove(key1);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.removeAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+
+ try {
+ col.retainAll(newObjCol);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ }
+
+ for (Map.Entry entry : entries) {
+ try {
+ entry.setValue(newObj);
+ assert false : "Should have thrown a UnsupportedOperationException";
+ } catch (UnsupportedOperationException uoe) {
+ }
+ }
+ }
public void testEqualsAndHashCode() throws Exception {
Pojo pojo = new Pojo();
Modified: trunk/core/src/test/java/org/infinispan/test/TestingUtil.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/test/TestingUtil.java 2009-06-10 12:37:21 UTC (rev 422)
+++ trunk/core/src/test/java/org/infinispan/test/TestingUtil.java 2009-06-10 13:46:03 UTC (rev 423)
@@ -30,11 +30,14 @@
import javax.transaction.TransactionManager;
import java.io.File;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
+import java.util.Set;
public class TestingUtil {
private static Random random = new Random();
@@ -634,4 +637,22 @@
builder.append("]");
return builder.toString();
}
+
+ public static Set getInternalKeys(Cache cache) {
+ DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class);
+ Set keys = new HashSet();
+ for (CacheEntry entry : dataContainer) {
+ keys.add(entry.getKey());
+ }
+ return keys;
+ }
+
+ public static Collection getInternalValues(Cache cache) {
+ DataContainer dataContainer = TestingUtil.extractComponent(cache, DataContainer.class);
+ Collection values = new ArrayList();
+ for (CacheEntry entry : dataContainer) {
+ values.add(entry.getValue());
+ }
+ return values;
+ }
}
More information about the infinispan-commits
mailing list