[jbosscache-commits] JBoss Cache SVN: r6377 - in core/trunk/src/main/java/org/jboss/cache: buddyreplication and 6 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Jul 23 10:23:32 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-07-23 10:23:32 -0400 (Wed, 23 Jul 2008)
New Revision: 6377

Added:
   core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java
   core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java
   core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/Fqn.java
   core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
   core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
   core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
   core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java
   core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
   core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
   core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java
Log:
Implemented efficient custom collections in place of immutable and defensively copied collections

Modified: core/trunk/src/main/java/org/jboss/cache/Fqn.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Fqn.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/Fqn.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -8,6 +8,7 @@
 
 
 import net.jcip.annotations.Immutable;
+import org.jboss.cache.util.ImmutableListCopy;
 
 import java.io.Externalizable;
 import java.io.IOException;
@@ -112,13 +113,9 @@
    {
       if (names != null)
       {
+         assertNoWhiteSpace(names);
          // if not safe make a defensive copy
-         elements = safe ? names : new ArrayList<Object>(names);
-         if (elements.size() > 0)
-         {
-            if (SEPARATOR.equals(elements.get(0))) elements.remove(0);
-            if ("".equals(elements.get(0))) elements.remove(0);
-         }
+         elements = safe ? names : new ImmutableListCopy<Object>(names);
          size = elements.size();
       }
       else
@@ -128,12 +125,15 @@
       }
    }
 
+   private void assertNoWhiteSpace(List<Object> l)
+   {
+      if (l.contains("") || l.contains(SEPARATOR))
+         throw new IllegalArgumentException("Fqn list cannot contain whitespace or the [" + SEPARATOR + "] character!");
+   }
+
    protected Fqn(Fqn base, List<Object> relative)
    {
-      List<Object> elements = new ArrayList<Object>(base.elements.size() + relative.size());
-      elements.addAll(base.elements);
-      elements.addAll(relative);
-      this.elements = elements;
+      elements = new ImmutableListCopy<Object>(base.elements, relative);
       size = elements.size();
    }
 
@@ -235,12 +235,12 @@
    @SuppressWarnings("unchecked")
    public static Fqn fromString(String stringRepresentation)
    {
-      if (stringRepresentation == null || stringRepresentation.equals(SEPARATOR))
-      {
+      if (stringRepresentation == null || stringRepresentation.equals(SEPARATOR) || stringRepresentation.equals(""))
          return root();
-      }
-      List elements = Arrays.asList(stringRepresentation.split("/"));
-      return new Fqn(elements, false);
+
+      String toMatch = stringRepresentation.startsWith(SEPARATOR) ? stringRepresentation.substring(1) : stringRepresentation;
+      Object[] el = toMatch.split("/");
+      return new Fqn(new ImmutableListCopy(el), true);
    }
 
    /**
@@ -434,7 +434,7 @@
     */
    public boolean isDirectChildOf(Fqn parentFqn)
    {
-      return size == parentFqn.size() - 1 && isChildOf(parentFqn);
+      return size == parentFqn.size() + 1 && isChildOf(parentFqn);
    }
 
    /**

Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -16,8 +16,8 @@
 import org.jboss.cache.marshall.MarshalledValue;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.util.ImmutableSetCopy;
 
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -417,7 +417,7 @@
       {
          return Collections.emptySet();
       }
-      return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
+      return new ImmutableSetCopy<K>(data.keySet());
    }
 
    public boolean removeChild(Object childName)
@@ -567,7 +567,7 @@
       {
          if (children != null && !children.isEmpty())
          {
-            return Collections.unmodifiableSet(new HashSet<NodeSPI<K, V>>((Collection) children.values()));
+            return new ImmutableSetCopy(children.values());
          }
          else
          {

Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyGroup.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -7,12 +7,11 @@
 package org.jboss.cache.buddyreplication;
 
 import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.util.ImmutableListCopy;
 import org.jgroups.Address;
 
 import java.io.Serializable;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Vector;
@@ -66,7 +65,7 @@
    public List<Address> getBuddies()
    {
       // defensive copy and immutable.
-      return Collections.unmodifiableList(new ArrayList<Address>(buddies));
+      return new ImmutableListCopy<Address>(buddies);
    }
 
    protected void addBuddies(Collection<Address> buddies)

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -4,7 +4,7 @@
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
 
 /**
  * Implements functionality defined by {@link org.jboss.cache.Cache#getData(org.jboss.cache.Fqn)}
@@ -37,7 +37,7 @@
    {
       NodeSPI n = ctx.lookUpNode(fqn);
       if (n == null || n.isDeleted()) return null;
-      return new MapCopy(n.getDataDirect());
+      return new ImmutableMapCopy(n.getDataDirect());
    }
 
    public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/AbstractInvocationContext.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -14,9 +14,9 @@
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionContext;
 import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ImmutableListCopy;
 
 import javax.transaction.Transaction;
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -118,7 +118,7 @@
    {
       // first check transactional scope
       if (transactionContext != null) return transactionContext.getLocks();
-      return invocationLocks == null || invocationLocks.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList(invocationLocks));
+      return invocationLocks == null || invocationLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(invocationLocks);
    }
 
    @SuppressWarnings("unchecked")

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -40,12 +40,12 @@
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ImmutableSetCopy;
 import org.jgroups.Address;
 
 import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -543,7 +543,7 @@
       GetChildrenNamesCommand command = commandsFactory.buildGetChildrenNamesCommand(fqn);
       Set<Object> retval = (Set<Object>) invoker.invoke(ctx, command);
       if (retval != null)
-         retval = Collections.unmodifiableSet(new HashSet<Object>(retval));
+         retval = new ImmutableSetCopy<Object>(retval);
       else
          retval = Collections.emptySet();
       return retval;

Modified: core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -20,7 +20,7 @@
 import org.jboss.cache.marshall.NodeData;
 import org.jboss.cache.marshall.NodeDataExceptionMarker;
 import org.jboss.cache.marshall.NodeDataMarker;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
 
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
@@ -64,7 +64,7 @@
       }
 
       // JBCACHE-769 -- make a defensive copy
-      Map<Object, Object> attrs = (attributes == null ? null : new MapCopy<Object, Object>(attributes));
+      Map<Object, Object> attrs = (attributes == null ? null : new ImmutableMapCopy<Object, Object>(attributes));
       put(fqn, attrs);
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AsyncCacheLoader.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -9,7 +9,7 @@
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Modification;
 import org.jboss.cache.config.CacheLoaderConfig.IndividualCacheLoaderConfig;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -182,7 +182,7 @@
       if (config.getUseAsyncPut())
       {
          // JBCACHE-769 -- make a defensive copy
-         Map attrs = (attributes == null ? null : new MapCopy(attributes));
+         Map attrs = (attributes == null ? null : new ImmutableMapCopy(attributes));
          Modification mod = new Modification(Modification.ModificationType.PUT_DATA, name, attrs);
          enqueue(mod);
       }

Modified: core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -24,7 +24,7 @@
 import org.jboss.cache.notifications.annotation.*;
 import org.jboss.cache.notifications.event.*;
 import static org.jboss.cache.notifications.event.Event.Type.*;
-import org.jboss.cache.util.MapCopy;
+import org.jboss.cache.util.ImmutableMapCopy;
 import org.jgroups.View;
 
 import javax.transaction.Transaction;
@@ -539,7 +539,7 @@
       if (data == null) return null;
       if (data.isEmpty()) return Collections.emptyMap();
       if (safe(data)) return useMarshalledValueMaps ? new MarshalledValueMap(data) : data;
-      Map defensivelyCopiedData = new MapCopy(data);
+      Map defensivelyCopiedData = new ImmutableMapCopy(data);
       return useMarshalledValueMaps ? new MarshalledValueMap(defensivelyCopiedData) : defensivelyCopiedData;
    }
 
@@ -566,7 +566,7 @@
     * A map is deemed 'safe' to be passed as-is to a listener, if either of the following are true:
     * <ul>
     * <li>It is null</li>
-    * <li>It is an instance of {@link org.jboss.cache.util.MapCopy}, which is immutable</li>
+    * <li>It is an instance of {@link org.jboss.cache.util.ImmutableMapCopy}, which is immutable</li>
     * <li>It is an instance of {@link java.util.Collections#emptyMap()}, which is also immutable</li>
     * <li>It is an instance of {@link java.util.Collections#singletonMap(Object,Object)}, which is also immutable</li>
     * </ul>
@@ -576,7 +576,7 @@
     */
    private static boolean safe(Map map)
    {
-      return map == null || map instanceof MapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
+      return map == null || map instanceof ImmutableMapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
    }
 
    /**

Modified: core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -13,6 +13,7 @@
 import org.jboss.cache.commands.WriteCommand;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
+import org.jboss.cache.util.ImmutableListCopy;
 
 import javax.transaction.RollbackException;
 import javax.transaction.SystemException;
@@ -170,7 +171,7 @@
    @SuppressWarnings("unchecked")
    public List getLocks()
    {
-      return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(new ArrayList(transactionLocks));
+      return transactionLocks == null || transactionLocks.isEmpty() ? Collections.emptyList() : new ImmutableListCopy(transactionLocks);
    }
 
 

Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableListCopy.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,428 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.lang.reflect.Array;
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A lightweight, read-only copy of a List.  Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableList(new ArrayList( myInternalList ));
+ * </code>
+ * <p/>
+ * a it is far more efficient than making a defensive copy and then wrapping the defensive copy in a read-only wrapper.
+ * <p/>
+ * Also used whenever a read-only reference List is needed (such as in Fqns).
+ * <p/>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableListCopy<E> extends AbstractList<E>
+{
+   private final E[] elements;
+   private final int size;
+
+   /**
+    * Only one copy constructor since the list is immutable.
+    *
+    * @param c collection to copy from
+    */
+   @SuppressWarnings("unchecked")
+   public ImmutableListCopy(Collection<? extends E> c)
+   {
+      size = c.size();
+      Object[] el = new Object[size]; // no room for growth;
+      el = c.toArray(el);
+      elements = (E[]) el;
+   }
+
+   /**
+    * Assumes that the array passed in is "safe", i.e., is not referenced from elsewhere.  Use with care!
+    *
+    * @param array to reference
+    */
+   public ImmutableListCopy(E[] array)
+   {
+      size = array.length;
+      elements = array;
+   }
+
+   /**
+    * Utility constructors to allow combining collections
+    *
+    * @param collection1 collection to copy from
+    * @param collection2 collection to copy from
+    */
+   @SuppressWarnings("unchecked")
+   public ImmutableListCopy(Collection<? extends E> collection1, Collection<? extends E> collection2)
+   {
+      size = collection1.size() + collection2.size();
+      elements = (E[]) new Object[size]; // no room for growth;
+      Object[] c1 = new Object[collection1.size()];
+      Object[] c2 = new Object[collection2.size()];
+      c1 = collection1.toArray(c1);
+      c2 = collection2.toArray(c2);
+      System.arraycopy(c1, 0, elements, 0, c1.length);
+      System.arraycopy(c2, 0, elements, c1.length, c2.length);
+   }
+
+   @Override
+   public final int size()
+   {
+      return size;
+   }
+
+   @Override
+   public final boolean isEmpty()
+   {
+      return size == 0;
+   }
+
+   @Override
+   public final boolean contains(Object o)
+   {
+      return indexOf(o) >= 0;
+   }
+
+   @Override
+   public final Iterator<E> iterator()
+   {
+      return new ImmutableIterator();
+   }
+
+   @Override
+   public final Object[] toArray()
+   {
+      Object[] result = new Object[size];
+      System.arraycopy(elements, 0, result, 0, size);
+      return result;
+   }
+
+   @Override
+   @SuppressWarnings("unchecked")
+   public final <T> T[] toArray(T[] a)
+   {
+      if (a.length < size)
+      {
+         a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
+      }
+      System.arraycopy(elements, 0, a, 0, size);
+      if (a.length > size) a[size] = null;
+      return a;
+   }
+
+   @Override
+   public final boolean add(E o)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final boolean remove(Object o)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final boolean addAll(Collection<? extends E> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final boolean addAll(int index, Collection<? extends E> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final boolean removeAll(Collection<?> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final boolean retainAll(Collection<?> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public final E get(int index)
+   {
+      assertIndexInRange(index);
+      return elements[index];
+   }
+
+   @Override
+   public final int indexOf(Object o)
+   {
+      if (o == null)
+      {
+         for (int i = 0; i < size; i++)
+         {
+            if (elements[i] == null) return i;
+         }
+      }
+      else
+      {
+         for (int i = 0; i < size; i++)
+         {
+            if (o.equals(elements[i])) return i;
+         }
+      }
+      return -1;
+   }
+
+   @Override
+   public final int lastIndexOf(Object o)
+   {
+      if (o == null)
+      {
+         for (int i = size - 1; i >= 0; i--)
+         {
+            if (elements[i] == null) return i;
+         }
+      }
+      else
+      {
+         for (int i = size - 1; i >= 0; i--)
+         {
+            if (o.equals(elements[i])) return i;
+         }
+      }
+      return -1;
+   }
+
+   @Override
+   public final ListIterator<E> listIterator()
+   {
+      return listIterator(0);
+   }
+
+   @Override
+   public final ListIterator<E> listIterator(int index)
+   {
+      assertIndexInRange(index);
+      return new ImmutableIterator(index);
+   }
+
+   @Override
+   public final List<E> subList(int fromIndex, int toIndex)
+   {
+      return new ImmutableSubList<E>(fromIndex, toIndex);
+   }
+
+   private void assertIndexInRange(int index)
+   {
+      if (index >= size || index < 0) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
+   }
+
+   private class ImmutableIterator implements ListIterator<E>
+   {
+      int cursor = 0;
+
+      ImmutableIterator(int index)
+      {
+         cursor = index;
+      }
+
+      ImmutableIterator()
+      {
+
+      }
+
+      public boolean hasNext()
+      {
+         return cursor != size;
+      }
+
+      public E next()
+      {
+         try
+         {
+            return get(cursor++);
+         }
+         catch (IndexOutOfBoundsException e)
+         {
+            throw new NoSuchElementException();
+         }
+      }
+
+      public void remove()
+      {
+         throw new UnsupportedOperationException();
+      }
+
+      public boolean hasPrevious()
+      {
+         return cursor != 0;
+      }
+
+      public E previous()
+      {
+         try
+         {
+            return get(--cursor);
+         }
+         catch (IndexOutOfBoundsException e)
+         {
+            throw new NoSuchElementException();
+         }
+      }
+
+      public int nextIndex()
+      {
+         return cursor;
+      }
+
+      public int previousIndex()
+      {
+         return cursor - 1;
+      }
+
+      public void set(E o)
+      {
+         throw new UnsupportedOperationException();
+      }
+
+      public void add(E o)
+      {
+         throw new UnsupportedOperationException();
+      }
+   }
+
+   private class ImmutableSubList<E> extends AbstractList<E>
+   {
+      private int offset;
+      private int size;
+
+      ImmutableSubList(int fromIndex, int toIndex)
+      {
+         assertIndexInRange(fromIndex);
+         assertIndexInRange(toIndex - 1);
+         if (fromIndex > toIndex)
+            throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+         offset = fromIndex;
+         size = toIndex - fromIndex;
+      }
+
+      @SuppressWarnings("unchecked")
+      public final E get(int index)
+      {
+         rangeCheck(index);
+         return (E) ImmutableListCopy.this.get(index + offset);
+      }
+
+      private void rangeCheck(int index)
+      {
+         if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ",Size: " + size);
+      }
+
+      public final int size()
+      {
+         return size;
+      }
+
+      @Override
+      protected final void removeRange(int fromIndex, int toIndex)
+      {
+         throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public final boolean addAll(Collection<? extends E> c)
+      {
+         throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public final boolean addAll(int index, Collection<? extends E> c)
+      {
+         throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public final Iterator<E> iterator()
+      {
+         return listIterator();
+      }
+
+      @Override
+      public final ListIterator<E> listIterator(final int index)
+      {
+         rangeCheck(index);
+
+         return new ListIterator<E>()
+         {
+            private ListIterator i = ImmutableListCopy.this.listIterator(index + offset);
+
+            public boolean hasNext()
+            {
+               return nextIndex() < size;
+            }
+
+            @SuppressWarnings("unchecked")
+            public E next()
+            {
+               if (hasNext())
+                  return (E) i.next();
+               else
+                  throw new NoSuchElementException();
+            }
+
+            public boolean hasPrevious()
+            {
+               return previousIndex() >= 0;
+            }
+
+            @SuppressWarnings("unchecked")
+            public E previous()
+            {
+               if (hasPrevious())
+                  return (E) i.previous();
+               else
+                  throw new NoSuchElementException();
+            }
+
+            public int nextIndex()
+            {
+               return i.nextIndex() - offset;
+            }
+
+            public int previousIndex()
+            {
+               return i.previousIndex() - offset;
+            }
+
+            public void remove()
+            {
+               throw new UnsupportedOperationException();
+            }
+
+            public void set(E o)
+            {
+               throw new UnsupportedOperationException();
+            }
+
+            public void add(E o)
+            {
+               throw new UnsupportedOperationException();
+            }
+         };
+      }
+
+      @Override
+      public final List<E> subList(int fromIndex, int toIndex)
+      {
+         return new ImmutableSubList<E>(offset + fromIndex, offset + toIndex);
+      }
+   }
+}

Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableMapCopy.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,95 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Along the lines of ImmutableListCopy and ImmutableSetCopy.  This lightweight wrapper primarily meant for iteration.
+ * performance of get() and containsKey() are not as efficient as that of a {@link java.util.HashMap}, but iteration is
+ * fast since the entry table is a fixed size immutable array.
+ * <p/>
+ * Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableMap(new HashMap( myInternalMap ));
+ * </code>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableMapCopy<K, V> extends AbstractMap<K, V>
+{
+   private final Entry<K, V>[] table;
+   private final int size;
+
+   @SuppressWarnings("unchecked")
+   public ImmutableMapCopy(Map<K, V> map)
+   {
+      size = map.size();
+      table = new ImmutableEntry[size];
+      int i = 0;
+      for (Map.Entry<K, V> me : map.entrySet())
+      {
+         table[i++] = new ImmutableEntry<K, V>(me);
+      }
+   }
+
+   @Override
+   public int size()
+   {
+      return size;
+   }
+
+   @Override
+   public final V remove(Object key)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final void putAll(Map<? extends K, ? extends V> t)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public final void clear()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public final Set<Entry<K, V>> entrySet()
+   {
+      return new ImmutableSetCopy<Map.Entry<K, V>>(table);
+   }
+
+   private class ImmutableEntry<K, V> implements Map.Entry<K, V>
+   {
+      K k;
+      V v;
+
+      private ImmutableEntry(Map.Entry<K, V> entry)
+      {
+         k = entry.getKey();
+         v = entry.getValue();
+      }
+
+      public K getKey()
+      {
+         return k;
+      }
+
+      public V getValue()
+      {
+         return v;
+      }
+
+      public V setValue(V value)
+      {
+         throw new UnsupportedOperationException();
+      }
+   }
+}

Added: core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/util/ImmutableSetCopy.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -0,0 +1,109 @@
+package org.jboss.cache.util;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This is based on an ImmutableListCopy, with the assumption that the set passed in would ensure uniqueness of elements.
+ * <p/>
+ * The constructor takes in a collection so the onus is on the caller to ensure that the collection passed in adheres to
+ * Set semantics.
+ * <p/>
+ * Typically used in place of the common idiom:
+ * <code>
+ * return Collections.unmodifiableSet(new HashSet( myInternalSet ));
+ * </code>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @see org.jboss.cache.util.ImmutableListCopy
+ * @since 3.0
+ */
+ at Immutable
+public class ImmutableSetCopy<E> extends AbstractSet<E>
+{
+   private final E[] elements;
+   private final int size;
+
+   @SuppressWarnings("unchecked")
+   public ImmutableSetCopy(Collection<E> set)
+   {
+      size = set.size();
+      E[] tempElements = (E[]) new Object[size]; // no room for growth
+      elements = set.toArray(tempElements);
+   }
+
+   /**
+    * Assumes that the array passed in is "safe", i.e., is not referenced from elsewhere.  Also assumes the array contains
+    * elements such that the uniqueness required by a set is adhered to.  Use with care!
+    *
+    * @param array to reference
+    */
+   public ImmutableSetCopy(E[] array)
+   {
+      elements = array;
+      size = elements.length;
+   }
+
+   @Override
+   public boolean remove(Object o)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public boolean addAll(Collection<? extends E> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public boolean retainAll(Collection<?> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public boolean removeAll(Collection<?> c)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   @Override
+   public void clear()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public Iterator<E> iterator()
+   {
+      return new Iterator<E>()
+      {
+         int cursor = 0;
+
+         public boolean hasNext()
+         {
+            return cursor < size;
+         }
+
+         public E next()
+         {
+            if (cursor >= size) throw new NoSuchElementException();
+            return elements[cursor++];
+         }
+
+         public void remove()
+         {
+            throw new UnsupportedOperationException();
+         }
+      };
+   }
+
+   public int size()
+   {
+      return size;
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java	2008-07-23 13:46:30 UTC (rev 6376)
+++ core/trunk/src/main/java/org/jboss/cache/util/MapCopy.java	2008-07-23 14:23:32 UTC (rev 6377)
@@ -7,7 +7,7 @@
 import java.util.AbstractMap;
 import java.util.AbstractSet;
 import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -21,8 +21,10 @@
  * {@link UnsupportedOperationException}s.
  *
  * @author Elias Ross
+ * @deprecated see ImmutableMapCopy instead.
  */
 @Immutable
+ at Deprecated
 public class MapCopy<K, V> extends AbstractMap<K, V> implements Serializable
 {
 
@@ -51,7 +53,7 @@
 
    public MapCopy()
    {
-      this(new HashMap<K, V>(0));
+      this((Map<K, V>) Collections.emptyMap());
    }
 
    /**




More information about the jbosscache-commits mailing list