jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From mreut...@apache.org
Subject svn commit: r691603 - in /jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core: state/ChildNodeEntries.java state/NameSet.java state/NodeState.java util/EmptyLinkedMap.java
Date Wed, 03 Sep 2008 13:10:25 GMT
Author: mreutegg
Date: Wed Sep  3 06:10:23 2008
New Revision: 691603

URL: http://svn.apache.org/viewvc?rev=691603&view=rev
Log:
JCR-1705: Reduce memory usage of transient nodes

Added:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java
  (with props)
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ChildNodeEntries.java
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeState.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ChildNodeEntries.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ChildNodeEntries.java?rev=691603&r1=691602&r2=691603&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ChildNodeEntries.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/ChildNodeEntries.java
Wed Sep  3 06:10:23 2008
@@ -20,6 +20,7 @@
 import org.apache.commons.collections.MapIterator;
 import org.apache.commons.collections.OrderedMapIterator;
 import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.util.EmptyLinkedMap;
 import org.apache.jackrabbit.spi.Name;
 
 import java.util.List;
@@ -29,6 +30,7 @@
 import java.util.Iterator;
 import java.util.Collection;
 import java.util.ListIterator;
+import java.util.Map;
 
 /**
  * <code>ChildNodeEntries</code> represents an insertion-ordered
@@ -40,15 +42,26 @@
  */
 class ChildNodeEntries implements List, Cloneable {
 
-    // insertion-ordered map of entries (key=NodeId, value=entry)
+    /**
+     * Insertion-ordered map of entries
+     * (key=NodeId, value=entry)
+     */
     private LinkedMap entries;
-    // map used for lookup by name
-    // (key=name, value=either a single entry or a list of sns entries)
-    private HashMap nameMap;
+
+    /**
+     * Map used for lookup by name
+     * (key=name, value=either a single entry or a list of sns entries)
+     */
+    private Map nameMap;
+
+    /**
+     * Indicates whether the entries and nameMap are shared with another
+     * ChildNodeEntries instance.
+     */
+    private boolean shared;
 
     ChildNodeEntries() {
-        entries = new LinkedMap();
-        nameMap = new HashMap();
+        init();
     }
 
     ChildNodeEntry get(NodeId id) {
@@ -94,6 +107,7 @@
     }
 
     ChildNodeEntry add(Name nodeName, NodeId id) {
+        ensureModifiable();
         List siblings = null;
         int index = 0;
         Object obj = nameMap.get(nodeName);
@@ -143,6 +157,7 @@
             throw new IllegalArgumentException("index is 1-based");
         }
 
+        ensureModifiable();
         Object obj = nameMap.get(nodeName);
         if (obj == null) {
             return null;
@@ -223,8 +238,7 @@
      * Removes all child node entries
      */
     public void removeAll() {
-        nameMap.clear();
-        entries.clear();
+        init();
     }
 
     /**
@@ -434,6 +448,7 @@
     }
 
     //------------------------------------------------< Cloneable support >
+
     /**
      * Returns a shallow copy of this <code>ChildNodeEntries</code> instance;
      * the entries themselves are not cloned.
@@ -441,19 +456,50 @@
      * @return a shallow copy of this instance.
      */
     protected Object clone() {
-        ChildNodeEntries clone = new ChildNodeEntries();
-        clone.entries = (LinkedMap) entries.clone();
-        clone.nameMap = new HashMap(nameMap.size());
-        for (Iterator it = nameMap.keySet().iterator(); it.hasNext();) {
-            Object key = it.next();
-            Object obj = nameMap.get(key);
-            if (obj instanceof ArrayList) {
-                // clone List
-                obj = ((ArrayList) obj).clone();
+        try {
+            ChildNodeEntries clone = (ChildNodeEntries) super.clone();
+            if (nameMap != Collections.EMPTY_MAP) {
+                clone.shared = true;
+                shared = true;
+            }
+            return clone;
+        } catch (CloneNotSupportedException e) {
+            // never happens, this class is cloneable
+            throw new InternalError();
+        }
+    }
+
+    //-------------------------------------------------------------< internal >
+
+    /**
+     * Initializes the name and entries map with unmodifiable empty instances.
+     */
+    private void init() {
+        nameMap = Collections.EMPTY_MAP;
+        entries = EmptyLinkedMap.INSTANCE;
+        shared = false;
+    }
+
+    /**
+     * Ensures that the {@link #nameMap} and {@link #entries} map are
+     * modifiable.
+     */
+    private void ensureModifiable() {
+        if (nameMap == Collections.EMPTY_MAP) {
+            nameMap = new HashMap();
+            entries = new LinkedMap();
+        } else if (shared) {
+            entries = (LinkedMap) entries.clone();
+            nameMap = (Map) ((HashMap) nameMap).clone();
+            for (Iterator it = nameMap.entrySet().iterator(); it.hasNext(); ) {
+                Map.Entry entry = (Map.Entry) it.next();
+                Object value = entry.getValue();
+                if (value instanceof ArrayList) {
+                    entry.setValue(((ArrayList) value).clone());
+                }
             }
-            clone.nameMap.put(key, obj);
+            shared = false;
         }
-        return clone;
     }
 
     //----------------------------------------------------< inner classes >

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java?rev=691603&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java
Wed Sep  3 06:10:23 2008
@@ -0,0 +1,352 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.state;
+
+import org.apache.jackrabbit.spi.Name;
+
+import java.util.Set;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * <code>NameSet</code> implements a collection of unique {@link Name}s. The
+ * methods exposed via the {@link Set} interface are for read only access, which
+ * means this implementation will throw a {@link UnsupportedOperationException}
+ * for all modifying methods specified by the {@link Set} interface.
+ */
+final class NameSet implements Set, Cloneable {
+
+    /**
+     * The name set cache instance.
+     */
+    private static final NameSetCache CACHE = new NameSetCache();
+
+    /**
+     * The maximum number of names in a set that are cached.
+     */
+    private static final int NUM_NAMES_THRESHOLD = 5;
+
+    /**
+     * The set of property {@link Name}s.
+     */
+    private HashSet names = CACHE.getEmptySet();
+
+    /**
+     * Flag indicating whether the {@link #names} set is shared with another
+     * {@link NameSet} instance. The initial value is <code>true</code> because
+     * {@link #names} is initialized with an empty set from the cache.
+     */
+    private boolean shared = true;
+
+    /**
+     * Adds a <code>name</code>.
+     *
+     * @param name the name to add.
+     * @return <code>true</code> if the name is already present,
+     *         <code>false</code> otherwise.
+     */
+    boolean add(Name name) {
+        if (names.size() > NUM_NAMES_THRESHOLD) {
+            ensureModifiable();
+            return names.add(name);
+        } else {
+            int size = names.size();
+            // get a cached set
+            names = CACHE.get(names, name, !shared);
+            // a set from the cache is always shared
+            shared = true;
+            return names.size() != size;
+        }
+    }
+
+    /**
+     * Removes a <code>name</code>.
+     *
+     * @param name the name to remove.
+     * @return <code>true</code> if the name was removed, <code>false</code>
+     *         if the name was unknown.
+     */
+    boolean remove(Name name) {
+        ensureModifiable();
+        return names.remove(name);
+    }
+
+    /**
+     * Removes all names from this {@link NameSet}.
+     */
+    void removeAll() {
+        ensureModifiable();
+        names.clear();
+    }
+
+    /**
+     * Removes all names currently present and adds all names from
+     * <code>c</code>.
+     *
+     * @param c the {@link Name}s to add.
+     */
+    void replaceAll(Collection c) {
+        if (c instanceof NameSet) {
+            NameSet propNames = (NameSet) c;
+            names = propNames.names;
+            shared = true;
+            propNames.shared = true;
+        } else if (c instanceof HashSet) {
+            names = CACHE.get((HashSet) c);
+            shared = true;
+        } else {
+            ensureModifiable();
+            names.clear();
+            names.addAll(c);
+        }
+    }
+
+    //------------------------------------------------< unmodifiable Set view >
+
+    /**
+     * {@inheritDoc}
+     */
+    public int size() {
+        return names.size();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isEmpty() {
+        return names.isEmpty();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean contains(Object o) {
+        return names.contains(o);
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * The returned iterator will throw a {@link UnsupportedOperationException}
+     * on {@link Iterator#remove()}.
+     */
+    public Iterator iterator() {
+        return new Iterator() {
+            Iterator i = names.iterator();
+
+            public boolean hasNext() {
+                return i.hasNext();
+            }
+
+            public Object next() {
+                return i.next();
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object[] toArray() {
+        return names.toArray();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object[] toArray(Object[] a) {
+        return names.toArray(a);
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public boolean add(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public boolean remove(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean containsAll(Collection c) {
+        return names.containsAll(c);
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public boolean addAll(Collection c) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public boolean retainAll(Collection c) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public boolean removeAll(Collection c) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    //----------------------------------------------------< Cloneable support >
+
+    /**
+     * Returns a clone of this <code>PropertyNames</code> instance.
+     *
+     * @return a clone of this <code>PropertyNames</code> instance.
+     */
+    public Object clone() {
+        try {
+            NameSet propNames = (NameSet) super.clone();
+            shared = true;
+            propNames.shared = true;
+            return propNames;
+        } catch (CloneNotSupportedException e) {
+            // will never happen
+            throw new InternalError();
+        }
+    }
+
+    //-------------------------------------------------------------< internal >
+
+    /**
+     * Ensures that {@link #names} can be modified (-> not shared).
+     */
+    private void ensureModifiable() {
+        if (shared) {
+            names = (HashSet) names.clone();
+            shared = false;
+        }
+    }
+
+    /**
+     * Implements a simple <code>HashSet&lt;Name></code> cache.
+     * <p/>
+     * Please note that this cache does not ensures that the sets are immutable!
+     * It is the responsibility of the caller to make sure that sets passed to
+     * {@link #get} are not modified by multiple threads. Modifying a cached
+     * set is not a problem in general because it will only cause cache misses.
+     */
+    private static final class NameSetCache {
+
+        /**
+         * Size of the cache (must be a power of two). Note that this is the
+         * maximum number of objects kept in the cache, but due to hashing it
+         * can well be that only a part of the cache array is filled even if
+         * many more distinct objects are being accessed.
+         */
+        private static final int SIZE_POWER_OF_2 = 1024;
+
+        /**
+         * Array of cached hash sets, indexed by their hash codes
+         * (module size of the array).
+         */
+        private final HashSet[] array = new HashSet[SIZE_POWER_OF_2];
+
+        /**
+         * Returns a set that contains all elements from <code>set</code> and
+         * <code>obj</code>. If a cached copy of the set already exists, then
+         * this method returns that copy. Otherwise <code>obj</code> is added
+         * to the given <code>set</code>, the <code>set</code> is
cached and
+         * then returned.
+         *
+         * @param set the initial set.
+         * @param obj the object to add to <code>set</code>.
+         * @param modifiable <code>true</code> if <code>set</code>
may be modified.
+         * @return a cached set that contains all elements from <code>set</code>
+         *         and <code>obj</code>.
+         */
+        public HashSet get(HashSet set, Object obj, boolean modifiable) {
+            if (set.contains(obj)) {
+                return set;
+            }
+            int position = (set.hashCode() + obj.hashCode()) & (SIZE_POWER_OF_2 - 1);
+            HashSet previous = array[position];
+            if (previous != null &&
+                    previous.size() == set.size() + 1 &&
+                    previous.containsAll(set) &&
+                    previous.contains(obj)) {
+                return previous;
+            } else {
+                if (modifiable) {
+                    set.add(obj);
+                } else {
+                    set = (HashSet) set.clone();
+                    set.add(obj);
+                }
+                array[position] = set;
+                return set;
+            }
+        }
+
+        /**
+         * If a cached copy of the given set already exists, then this method
+         * returns that copy. Otherwise the given set is cached and returned.
+         *
+         * @param set set to return from the cache
+         * @return the given set or a previously cached copy
+         */
+        public HashSet get(HashSet set) {
+            int position = set.hashCode() & (SIZE_POWER_OF_2 - 1);
+            HashSet previous = array[position];
+            if (set.equals(previous)) {
+                return previous;
+            } else {
+                array[position] = set;
+                return set;
+            }
+        }
+
+        /**
+         * Returns a cached copy of an empty set.
+         *
+         * @return a cached copy of an empty set.
+         */
+        public HashSet getEmptySet() {
+            HashSet set = array[0];
+            if (set == null || !set.isEmpty()) {
+                set = new HashSet();
+                array[0] = set;
+            }
+            return set;
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NameSet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeState.java?rev=691603&r1=691602&r2=691603&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeState.java
(original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/state/NodeState.java
Wed Sep  3 06:10:23 2008
@@ -42,7 +42,7 @@
     /**
      * the names of this node's mixin types
      */
-    private Set mixinTypeNames = Collections.EMPTY_SET;
+    private NameSet mixinTypeNames = new NameSet();
 
     /**
      * the id of this node.
@@ -66,21 +66,9 @@
     private ChildNodeEntries childNodeEntries = new ChildNodeEntries();
 
     /**
-     * Set to <code>true</code> if {@link #childNodeEntries} are shared between
-     * different <code>NodeState</code> instance.
-     */
-    private boolean sharedChildNodeEntries = false;
-
-    /**
      * set of property names (Name objects)
      */
-    private HashSet propertyNames = new HashSet();
-
-    /**
-     * Set to <code>true</code> if {@link #propertyNames} is shared between
-     * different <code>NodeState</code> instances.
-     */
-    private boolean sharedPropertyNames = false;
+    private NameSet propertyNames = new NameSet();
 
     /**
      * Shared set, consisting of the parent ids of this shareable node. This
@@ -138,14 +126,10 @@
             id = nodeState.id;
             parentId = nodeState.parentId;
             nodeTypeName = nodeState.nodeTypeName;
-            mixinTypeNames = nodeState.mixinTypeNames;
+            mixinTypeNames = (NameSet) nodeState.mixinTypeNames.clone();
             defId = nodeState.defId;
-            propertyNames = nodeState.propertyNames;
-            sharedPropertyNames = true;
-            nodeState.sharedPropertyNames = true;
-            childNodeEntries = nodeState.childNodeEntries;
-            sharedChildNodeEntries = true;
-            nodeState.sharedChildNodeEntries = true;
+            propertyNames = (NameSet) nodeState.propertyNames.clone();
+            childNodeEntries = (ChildNodeEntries) nodeState.childNodeEntries.clone();
             if (syncModCount) {
                 setModCount(state.getModCount());
             }
@@ -214,7 +198,7 @@
      * @return a set of the names of this node's mixin types.
      */
     public synchronized Set getMixinTypeNames() {
-        return Collections.unmodifiableSet(mixinTypeNames);
+        return mixinTypeNames;
     }
 
     /**
@@ -223,11 +207,7 @@
      * @param names set of names of mixin types
      */
     public synchronized void setMixinTypeNames(Set names) {
-        if (names instanceof HashSet) {
-            mixinTypeNames = (Set) ((HashSet) names).clone();
-        } else {
-            mixinTypeNames = new HashSet(names);
-        }
+        mixinTypeNames.replaceAll(names);
     }
 
     /**
@@ -367,10 +347,6 @@
      */
     public synchronized ChildNodeEntry addChildNodeEntry(Name nodeName,
                                                          NodeId id) {
-        if (sharedChildNodeEntries) {
-            childNodeEntries = (ChildNodeEntries) childNodeEntries.clone();
-            sharedChildNodeEntries = false;
-        }
         ChildNodeEntry entry = childNodeEntries.add(nodeName, id);
         notifyNodeAdded(entry);
         return entry;
@@ -387,10 +363,6 @@
      */
     public synchronized boolean renameChildNodeEntry(Name oldName, int index,
                                                      Name newName) {
-        if (sharedChildNodeEntries) {
-            childNodeEntries = (ChildNodeEntries) childNodeEntries.clone();
-            sharedChildNodeEntries = false;
-        }
         ChildNodeEntry oldEntry = childNodeEntries.remove(oldName, index);
         if (oldEntry != null) {
             ChildNodeEntry newEntry =
@@ -411,10 +383,6 @@
      *         in the list of child node entries and could be removed.
      */
     public synchronized boolean removeChildNodeEntry(Name nodeName, int index) {
-        if (sharedChildNodeEntries) {
-            childNodeEntries = (ChildNodeEntries) childNodeEntries.clone();
-            sharedChildNodeEntries = false;
-        }
         ChildNodeEntry entry = childNodeEntries.remove(nodeName, index);
         if (entry != null) {
             notifyNodeRemoved(entry);
@@ -430,10 +398,6 @@
      *         in the list of child node entries and could be removed.
      */
     public synchronized boolean removeChildNodeEntry(NodeId id) {
-        if (sharedChildNodeEntries) {
-            childNodeEntries = (ChildNodeEntries) childNodeEntries.clone();
-            sharedChildNodeEntries = false;
-        }
         ChildNodeEntry entry = childNodeEntries.remove(id);
         if (entry != null) {
             notifyNodeRemoved(entry);
@@ -445,10 +409,6 @@
      * Removes all <code>ChildNodeEntry</code>s.
      */
     public synchronized void removeAllChildNodeEntries() {
-        if (sharedChildNodeEntries) {
-            childNodeEntries = (ChildNodeEntries) childNodeEntries.clone();
-            sharedChildNodeEntries = false;
-        }
         childNodeEntries.removeAll();
         notifyNodesReplaced();
     }
@@ -464,14 +424,8 @@
             // optimization
             ChildNodeEntries entries = (ChildNodeEntries) nodeEntries;
             childNodeEntries = (ChildNodeEntries) entries.clone();
-            sharedChildNodeEntries = false;
         } else {
-            if (sharedChildNodeEntries) {
-                childNodeEntries = new ChildNodeEntries();
-                sharedChildNodeEntries = false;
-            } else {
-                childNodeEntries.removeAll();
-            }
+            childNodeEntries.removeAll();
             childNodeEntries.addAll(nodeEntries);
 
         }
@@ -487,7 +441,7 @@
      * @see #removePropertyName
      */
     public synchronized Set getPropertyNames() {
-        return Collections.unmodifiableSet(propertyNames);
+        return propertyNames;
     }
 
     /**
@@ -496,10 +450,6 @@
      * @param propName <code>Name</code> object specifying the property name
      */
     public synchronized void addPropertyName(Name propName) {
-        if (sharedPropertyNames) {
-            propertyNames = (HashSet) propertyNames.clone();
-            sharedPropertyNames = false;
-        }
         propertyNames.add(propName);
     }
 
@@ -511,10 +461,6 @@
      *         in the list of property name entries and could be removed.
      */
     public synchronized boolean removePropertyName(Name propName) {
-        if (sharedPropertyNames) {
-            propertyNames = (HashSet) propertyNames.clone();
-            sharedPropertyNames = false;
-        }
         return propertyNames.remove(propName);
     }
 
@@ -522,12 +468,7 @@
      * Removes all property name entries.
      */
     public synchronized void removeAllPropertyNames() {
-        if (sharedPropertyNames) {
-            propertyNames = new HashSet();
-            sharedPropertyNames = false;
-        } else {
-            propertyNames.clear();
-        }
+        propertyNames.removeAll();
     }
 
     /**
@@ -536,19 +477,7 @@
      * @param propNames set of {@link Name}s.
      */
     public synchronized void setPropertyNames(Set propNames) {
-        if (propNames instanceof HashSet) {
-            HashSet names = (HashSet) propNames;
-            propertyNames = (HashSet) names.clone();
-            sharedPropertyNames = false;
-        } else {
-            if (sharedPropertyNames) {
-                propertyNames = new HashSet();
-                sharedPropertyNames = false;
-            } else {
-                propertyNames.clear();
-            }
-            propertyNames.addAll(propNames);
-        }
+        propertyNames.replaceAll(propNames);
     }
 
     /**
@@ -667,7 +596,7 @@
      */
     public synchronized Set getAddedPropertyNames() {
         if (!hasOverlayedState()) {
-            return Collections.unmodifiableSet(propertyNames);
+            return propertyNames;
         }
 
         NodeState other = (NodeState) getOverlayedState();

Added: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java?rev=691603&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java
(added)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java
Wed Sep  3 06:10:23 2008
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.core.util;
+
+import org.apache.commons.collections.map.LinkedMap;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * <code>EmptyLinkedMap</code> implements an empty unmodifiable {@link LinkedMap}.
+ */
+public class EmptyLinkedMap extends LinkedMap {
+
+    private static final long serialVersionUID = -9165910643562370800L;
+
+    /**
+     * The only instance of this class.
+     */
+    public static final LinkedMap INSTANCE = new EmptyLinkedMap();
+
+    private EmptyLinkedMap() {
+        super();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public Object remove(int i) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public Object put(Object o, Object o1) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public void putAll(Map map) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @throws UnsupportedOperationException always.
+     */
+    public Object remove(Object o) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Returns an unmodifiable empty set.
+     *
+     * @return an unmodifiable empty set.
+     */
+    public Set entrySet() {
+        return Collections.EMPTY_SET;
+    }
+
+    /**
+     * Returns an unmodifiable empty set.
+     *
+     * @return an unmodifiable empty set.
+     */
+    public Set keySet() {
+        return Collections.EMPTY_SET;
+    }
+
+    /**
+     * Returns an unmodifiable empty collection.
+     *
+     * @return an unmodifiable empty collection.
+     */
+    public Collection values() {
+        return Collections.EMPTY_LIST;
+    }
+
+    //----------------------------------------------------< Cloneable support >
+
+    /**
+     * Returns the single instance of this class.
+     *
+     * @return {@link #INSTANCE}.
+     */
+    public Object clone() {
+        return INSTANCE;
+    }
+
+    //-------------------------------------------------< Serializable support >
+
+    /**
+     * Returns the single instance of this class.
+     *
+     * @return {@link #INSTANCE}.
+     */
+    private Object readResolve() {
+        return INSTANCE;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/util/EmptyLinkedMap.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message