openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r640685 [10/14] - in /openjpa/trunk: ./ openjpa-all/ openjpa-jdbc-5/ openjpa-jdbc/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/java/org/apache/ope...
Date Tue, 25 Mar 2008 03:38:02 GMT
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CacheMap.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CacheMap.java?rev=640685&r1=640684&r2=640685&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CacheMap.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CacheMap.java Mon Mar 24 20:37:56 2008
@@ -1,639 +1,645 @@
-/*
- * 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.openjpa.util;
-
-import java.util.AbstractCollection;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.collections.Predicate;
-import org.apache.commons.collections.iterators.FilterIterator;
-import org.apache.commons.collections.iterators.IteratorChain;
-import org.apache.openjpa.lib.util.LRUMap;
-import org.apache.openjpa.lib.util.ReferenceHashMap;
-import org.apache.openjpa.lib.util.ReferenceMap;
-import org.apache.openjpa.lib.util.SizedMap;
-import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap;
-import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
-import org.apache.openjpa.lib.util.concurrent.ReentrantLock;
-
-/**
- * Fixed-size map that has ability to pin/unpin entries and move overflow to
- * a backing soft map.
- *
- * @author Patrick Linskey
- * @author Abe White
- */
-public class CacheMap
-    implements Map {
-
-    /**
-     * The map for non-expired and non-pinned references.
-     */
-    protected final SizedMap cacheMap;
-
-    /**
-     * The map for expired references.
-     */
-    protected final SizedMap softMap;
-
-    /**
-     * The set of objects pinned into the cache.
-     */
-    protected final Map pinnedMap;
-
-    // number of pinned values (not including keys not mapped to values)
-    private int _pinnedSize = 0;
-
-    private final ReentrantLock _writeLock = new ReentrantLock();
-    private final ReentrantLock _readLock;
-
-    /**
-     * Create a non-LRU (and therefore highly concurrent) cache map with a
-     * size of 1000.
-     */
-    public CacheMap() {
-        this(false, 1000);
-    }
-
-    /**
-     * Create a cache map with the given properties.
-     */
-    public CacheMap(boolean lru, int max) {
-        this(lru, max, max / 2, .75F);
-    }
-
-    /**
-     * Create a cache map with the given properties.
-     */
-    public CacheMap(boolean lru, int max, int size, float load) {
-        if (size < 0)
-            size = 500;
-        if (!lru) {
-            cacheMap = new ConcurrentHashMap(size, load) {
-                public void overflowRemoved(Object key, Object value) {
-                    cacheMapOverflowRemoved(key, value);
-                }
-            };
-            softMap = new ConcurrentReferenceHashMap(ReferenceMap.HARD,
-                ReferenceMap.SOFT, size, load) {
-                public void overflowRemoved(Object key, Object value) {
-                    softMapOverflowRemoved(key, value);
-                }
-
-                public void valueExpired(Object key) {
-                    softMapValueExpired(key);
-                }
-            };
-            pinnedMap = new ConcurrentHashMap();
-            _readLock = null;
-        } else {
-            cacheMap = new LRUMap(size, load) {
-                public void overflowRemoved(Object key, Object value) {
-                    cacheMapOverflowRemoved(key, value);
-                }
-            };
-            softMap = new ReferenceHashMap(ReferenceMap.HARD,
-                ReferenceMap.SOFT, size, load) {
-                public void overflowRemoved(Object key, Object value) {
-                    softMapOverflowRemoved(key, value);
-                }
-
-                public void valueExpired(Object key) {
-                    softMapValueExpired(key);
-                }
-            };
-            pinnedMap = new HashMap();
-            _readLock = _writeLock;
-        }
-        cacheMap.setMaxSize((max < 0) ? Integer.MAX_VALUE : max);
-    }
-
-    /**
-     * Called from {@link SizedMap#overflowRemoved} in the cache map.
-     */
-    protected void cacheMapOverflowRemoved(Object key, Object value) {
-        if (softMap.size() < softMap.getMaxSize())
-            put(softMap, key, value);
-        else
-            entryRemoved(key, value, true);
-    }
-
-    /**
-     * Called from {@link SizedMap#overflowRemoved} in the soft map.
-     */
-    protected void softMapOverflowRemoved(Object key, Object value) {
-        entryRemoved(key, value, true);
-    }
-
-    /**
-     * Called when a value expires from the soft map.
-     */
-    protected void softMapValueExpired(Object key) {
-        entryRemoved(key, null, true);
-    }
-
-    /**
-     * Put the given entry into the given map. Allows subclasses to
-     * take additional actions.
-     */
-    protected Object put(Map map, Object key, Object value) {
-        return map.put(key, value);
-    }
-
-    /**
-     * Remove the given key from the given map. Allows subclasses to
-     * take additional actions.
-     */
-    protected Object remove(Map map, Object key) {
-        return map.remove(key);
-    }
-
-    /**
-     * Acquire read lock.
-     */
-    public void readLock() {
-        if (_readLock != null)
-            _readLock.lock();
-    }
-
-    /**
-     * Release read lock.
-     */
-    public void readUnlock() {
-        if (_readLock != null)
-            _readLock.unlock();
-    }
-
-    /**
-     * Acquire write lock.
-     */
-    public void writeLock() {
-        _writeLock.lock();
-    }
-
-    /**
-     * Release write lock.
-     */
-    public void writeUnlock() {
-        _writeLock.unlock();
-    }
-
-    /**
-     * Whether this cache map uses LRU eviction.
-     */
-    public boolean isLRU() {
-        return _readLock != null;
-    }
-
-    /**
-     * The maximum number of hard references to maintain, or -1 for no limit.
-     */
-    public void setCacheSize(int size) {
-        writeLock();
-        try {
-            cacheMap.setMaxSize((size < 0) ? Integer.MAX_VALUE : size);
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    /**
-     * The maximum number of hard references to maintain, or -1 for no limit.
-     */
-    public int getCacheSize() {
-        int max = cacheMap.getMaxSize();
-        return (max == Integer.MAX_VALUE) ? -1 : max;
-    }
-
-    /**
-     * The maximum number of soft references to maintain, or -1 for no limit.
-     */
-    public void setSoftReferenceSize(int size) {
-        writeLock();
-        try {
-            softMap.setMaxSize((size < 0) ? Integer.MAX_VALUE : size);
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    /**
-     * The maximum number of soft references to maintain, or -1 for no limit.
-     */
-    public int getSoftReferenceSize() {
-        int max = softMap.getMaxSize();
-        return (max == Integer.MAX_VALUE) ? -1 : max;
-    }
-
-    /**
-     * The keys pinned into the map.
-     */
-    public Set getPinnedKeys() {
-        readLock();
-        try {
-            return Collections.unmodifiableSet(pinnedMap.keySet());
-        } finally {
-            readUnlock();
-        }
-    }
-
-    /**
-     * Locks the given key and its value into the map. Objects pinned into
-     * the map are not counted towards the maximum cache size, and are never
-     * evicted implicitly. You may pin keys for which no value is in the map.
-     *
-     * @return true if the givne key's value was pinned; false if no value
-     * for the given key is cached
-     */
-    public boolean pin(Object key) {
-        writeLock();
-        try {
-            // if we don't have a pinned map we need to create one; else if the
-            // pinned map already contains the key, nothing to do
-            if (pinnedMap.containsKey(key))
-                return pinnedMap.get(key) != null;
-
-            // check other maps for key
-            Object val = remove(cacheMap, key);
-            if (val == null)
-                val = remove(softMap, key);
-
-            // pin key
-            put(pinnedMap, key, val);
-            if (val != null) {
-                _pinnedSize++;
-                return true;
-            }
-            return false;
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    /**
-     * Undo a pinning.
-     */
-    public boolean unpin(Object key) {
-        writeLock();
-        try {
-            Object val = remove(pinnedMap, key);
-            if (val != null) {
-                // put back into unpinned cache
-                put(key, val);
-                _pinnedSize--;
-                return true;
-            }
-            return false;
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    /**
-     * Invoked when a key-value pair is evicted from this data
-     * structure. This is invoked with <code>expired</code> set to
-     * <code>true</code> when an object is dropped because of space
-     * requirements or through garbage collection of soft references.
-     * It is invoked with <code>expired</code> set to <code>false</code>
-     * when an object is explicitly removed via the {@link #remove} or
-     * {@link #clear} methods. This may be invoked more than once for a
-     * given entry.
-     *
-     * @param value may be null if the value was a soft reference that has
-     * been GCd
-     * @since 0.2.5.0
-     */
-    protected void entryRemoved(Object key, Object value, boolean expired) {
-    }
-
-    /**
-     * Invoked when an entry is added to the cache. This may be invoked
-     * more than once for an entry.
-     */
-    protected void entryAdded(Object key, Object value) {
-    }
-
-    public Object get(Object key) {
-        readLock();
-        try {
-            Object val = pinnedMap.get(key);
-            if (val != null)
-                return val;
-
-            val = cacheMap.get(key);
-            if (val == null) {
-                // if we find the key in the soft map, move it back into
-                // the primary map
-                val = softMap.get(key);
-                if (val != null)
-                    put(key, val);
-            }
-            return val;
-        } finally {
-            readUnlock();
-        }
-    }
-
-    public Object put(Object key, Object value) {
-        writeLock();
-        try {
-            // if the key is pinned, just interact directly with the pinned map
-            Object val;
-            if (pinnedMap.containsKey(key)) {
-                val = put(pinnedMap, key, value);
-                if (val == null) {
-                    _pinnedSize++;
-                    entryAdded(key, value);
-                } else {
-                    entryRemoved(key, val, false);
-                    entryAdded(key, value);
-                }
-                return val;
-            }
-
-            // if no hard refs, don't put anything
-            if (cacheMap.getMaxSize() == 0)
-                return null;
-
-            // otherwise, put the value into the map and clear it from the
-            // soft map
-            val = put(cacheMap, key, value);
-            if (val == null) {
-                val = remove(softMap, key);
-                if (val == null)
-                    entryAdded(key, value);
-                else {
-                    entryRemoved(key, val, false);
-                    entryAdded(key, value);
-                }
-            } else {
-                entryRemoved(key, val, false);
-                entryAdded(key, value);
-            }
-            return val;
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    public void putAll(Map map) {
-        Map.Entry entry;
-        for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
-            entry = (Map.Entry) itr.next();
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    /**
-     * If <code>key</code> is pinned into the cache, the pin is
-     * cleared and the object is removed.
-     */
-    public Object remove(Object key) {
-        writeLock();
-        try {
-            // if the key is pinned, just interact directly with the
-            // pinned map
-            Object val;
-            if (pinnedMap.containsKey(key)) {
-                // re-put with null value; we still want key pinned
-                val = put(pinnedMap, key, null);
-                if (val != null) {
-                    _pinnedSize--;
-                    entryRemoved(key, val, false);
-                }
-                return val;
-            }
-
-            val = remove(cacheMap, key);
-            if (val == null)
-                val = softMap.remove(key);
-            if (val != null)
-                entryRemoved(key, val, false);
-
-            return val;
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    /**
-     * Removes pinned objects as well as unpinned ones.
-     */
-    public void clear() {
-        writeLock();
-        try {
-            notifyEntryRemovals(pinnedMap.entrySet());
-            pinnedMap.clear();
-            _pinnedSize = 0;
-
-            notifyEntryRemovals(cacheMap.entrySet());
-            cacheMap.clear();
-
-            notifyEntryRemovals(softMap.entrySet());
-            softMap.clear();
-        } finally {
-            writeUnlock();
-        }
-    }
-
-    private void notifyEntryRemovals(Set set) {
-        Map.Entry entry;
-        for (Iterator itr = set.iterator(); itr.hasNext();) {
-            entry = (Map.Entry) itr.next();
-            if (entry.getValue() != null)
-                entryRemoved(entry.getKey(), entry.getValue(), false);
-        }
-    }
-
-    public int size() {
-        readLock();
-        try {
-            return _pinnedSize + cacheMap.size() + softMap.size();
-        } finally {
-            readUnlock();
-        }
-    }
-
-    public boolean isEmpty() {
-        return size() == 0;
-    }
-
-    public boolean containsKey(Object key) {
-        readLock();
-        try {
-            return pinnedMap.get(key) != null
-                || cacheMap.containsKey(key)
-                || softMap.containsKey(key);
-        } finally {
-            readUnlock();
-        }
-    }
-
-    public boolean containsValue(Object val) {
-        readLock();
-        try {
-            return pinnedMap.containsValue(val)
-                || cacheMap.containsValue(val)
-                || softMap.containsValue(val);
-        } finally {
-            readUnlock();
-        }
-    }
-
-    public Set keySet() {
-        return new KeySet();
-    }
-
-    public Collection values() {
-        return new ValueCollection();
-    }
-
-    public Set entrySet() {
-        return new EntrySet();
-    }
-
-    public String toString() {
-        readLock();
-        try {
-            return "CacheMap:" + cacheMap.toString() + "::"
-                + softMap.toString();
-        } finally {
-            readUnlock();
-        }
-    }
-
-    /**
-     * View of the entry set.
-     */
-    private class EntrySet
-        extends AbstractSet {
-
-        public int size() {
-            return CacheMap.this.size();
-        }
-
-        public boolean add(Object o) {
-            Map.Entry entry = (Map.Entry) o;
-            put(entry.getKey(), entry.getValue());
-            return true;
-        }
-
-        public Iterator iterator() {
-            return new EntryIterator(EntryIterator.ENTRY);
-        }
-    }
-
-    /**
-     * View of the key set.
-     */
-    private class KeySet
-        extends AbstractSet {
-
-        public int size() {
-            return CacheMap.this.size();
-        }
-
-        public Iterator iterator() {
-            return new EntryIterator(EntryIterator.KEY);
-        }
-    }
-
-    /**
-     * View of the value collection.
-     */
-    private class ValueCollection
-        extends AbstractCollection {
-
-        public int size() {
-            return CacheMap.this.size();
-        }
-
-        public Iterator iterator() {
-            return new EntryIterator(EntryIterator.VALUE);
-        }
-    }
-
-    /**
-     * Iterator over all entries.
-     */
-    private class EntryIterator
-        implements Iterator, Predicate {
-
-        public static final int ENTRY = 0;
-        public static final int KEY = 1;
-        public static final int VALUE = 2;
-
-        private final IteratorChain _itr = new IteratorChain();
-        private final int _type;
-
-        public EntryIterator(int type) {
-            _type = type;
-            _itr.addIterator(new FilterIterator(getView(pinnedMap), this));
-            _itr.addIterator(getView(cacheMap));
-            _itr.addIterator(getView(softMap));
-        }
-
-        /**
-         * Return an iterator over the appropriate view of the given map.
-         */
-        private Iterator getView(Map m) {
-            if (m == null)
-                return null;
-
-            switch (_type) {
-                case KEY:
-                    return m.keySet().iterator();
-                case VALUE:
-                    return m.values().iterator();
-                default:
-                    return m.entrySet().iterator();
-            }
-        }
-
-        public boolean hasNext() {
-            return _itr.hasNext();
-        }
-
-        public Object next() {
-            return _itr.next();
-        }
-
-        public void remove() {
-            _itr.remove();
-        }
-
-        public boolean evaluate(Object obj) {
-            switch (_type) {
-                case ENTRY:
-                    return ((Map.Entry) obj).getValue() != null;
-			case VALUE:
-				return obj != null;
-			default:
-				return true;
-			}
-		}
-	}
-}
-
+/*
+ * 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.openjpa.util;
+
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.Predicate;
+import org.apache.commons.collections.iterators.FilterIterator;
+import org.apache.commons.collections.iterators.IteratorChain;
+import org.apache.openjpa.lib.util.LRUMap;
+import org.apache.openjpa.lib.util.ReferenceHashMap;
+import org.apache.openjpa.lib.util.ReferenceMap;
+import org.apache.openjpa.lib.util.SizedMap;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
+import org.apache.openjpa.lib.util.concurrent.SizedConcurrentHashMap;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Fixed-size map that has ability to pin/unpin entries and move overflow to
+ * a backing soft map.
+ *
+ * @author Patrick Linskey
+ * @author Abe White
+ */
+public class CacheMap
+    implements Map {
+
+    /**
+     * The map for non-expired and non-pinned references.
+     */
+    protected final SizedMap cacheMap;
+
+    /**
+     * The map for expired references.
+     */
+    protected final SizedMap softMap;
+
+    /**
+     * The set of objects pinned into the cache.
+     */
+    protected final Map pinnedMap;
+
+    // number of pinned values (not including keys not mapped to values)
+    private int _pinnedSize = 0;
+
+    private final ReentrantLock _writeLock = new ReentrantLock();
+    private final ReentrantLock _readLock;
+
+    /**
+     * Create a non-LRU (and therefore highly concurrent) cache map with a
+     * size of 1000.
+     */
+    public CacheMap() {
+        this(false, 1000);
+    }
+
+    /**
+     * Create a cache map with the given properties.
+     */
+    public CacheMap(boolean lru, int max) {
+        this(lru, max, max / 2, .75F);
+    }
+
+    /**
+     * @deprecated use {@link CacheMap#CacheMap(boolean, int, int, float, int)}
+     * instead.
+     */
+    public CacheMap(boolean lru, int max, int size, float load) {
+        this(lru, max, size, load, 16);
+    }
+
+    /**
+     * Create a cache map with the given properties.
+     *
+     * @since 1.1.0
+     */
+    public CacheMap(boolean lru, int max, int size, float load,
+        int concurrencyLevel) {
+        if (size < 0)
+            size = 500;
+
+        softMap = new ConcurrentReferenceHashMap(ReferenceMap.HARD,
+            ReferenceMap.SOFT, size, load) {
+            public void overflowRemoved(Object key, Object value) {
+                softMapOverflowRemoved(key, value);
+            }
+
+            public void valueExpired(Object key) {
+                softMapValueExpired(key);
+            }
+        };
+        pinnedMap = new ConcurrentHashMap();
+
+        if (!lru) {
+            cacheMap = new SizedConcurrentHashMap(size, load, concurrencyLevel){
+                public void overflowRemoved(Object key, Object value) {
+                    cacheMapOverflowRemoved(key, value);
+                }
+            };
+            _readLock = null;
+        } else {
+            cacheMap = new LRUMap(size, load) {
+                public void overflowRemoved(Object key, Object value) {
+                    cacheMapOverflowRemoved(key, value);
+                }
+            };
+            _readLock = _writeLock;
+        }
+        if (max < 0)
+            max = Integer.MAX_VALUE;
+        cacheMap.setMaxSize(max);
+    }
+
+    /**
+     * Called from {@link SizedMap#overflowRemoved} in the cache map.
+     */
+    protected void cacheMapOverflowRemoved(Object key, Object value) {
+        if (softMap.size() < softMap.getMaxSize())
+            put(softMap, key, value);
+        else
+            entryRemoved(key, value, true);
+    }
+
+    /**
+     * Called from {@link SizedMap#overflowRemoved} in the soft map.
+     */
+    protected void softMapOverflowRemoved(Object key, Object value) {
+        entryRemoved(key, value, true);
+    }
+
+    /**
+     * Called when a value expires from the soft map.
+     */
+    protected void softMapValueExpired(Object key) {
+        entryRemoved(key, null, true);
+    }
+
+    /**
+     * Put the given entry into the given map. Allows subclasses to
+     * take additional actions.
+     */
+    protected Object put(Map map, Object key, Object value) {
+        return map.put(key, value);
+    }
+
+    /**
+     * Remove the given key from the given map. Allows subclasses to
+     * take additional actions.
+     */
+    protected Object remove(Map map, Object key) {
+        return map.remove(key);
+    }
+
+    /**
+     * Acquire read lock.
+     */
+    public void readLock() {
+        if (_readLock != null)
+            _readLock.lock();
+    }
+
+    /**
+     * Release read lock.
+     */
+    public void readUnlock() {
+        if (_readLock != null)
+            _readLock.unlock();
+    }
+
+    /**
+     * Acquire write lock.
+     */
+    public void writeLock() {
+        _writeLock.lock();
+    }
+
+    /**
+     * Release write lock.
+     */
+    public void writeUnlock() {
+        _writeLock.unlock();
+    }
+
+    /**
+     * Whether this cache map uses LRU eviction.
+     */
+    public boolean isLRU() {
+        return _readLock != null;
+    }
+
+    /**
+     * The maximum number of hard references to maintain, or -1 for no limit.
+     */
+    public void setCacheSize(int size) {
+        writeLock();
+        try {
+            cacheMap.setMaxSize((size < 0) ? Integer.MAX_VALUE : size);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    /**
+     * The maximum number of hard references to maintain, or -1 for no limit.
+     */
+    public int getCacheSize() {
+        int max = cacheMap.getMaxSize();
+        return (max == Integer.MAX_VALUE) ? -1 : max;
+    }
+
+    /**
+     * The maximum number of soft references to maintain, or -1 for no limit.
+     */
+    public void setSoftReferenceSize(int size) {
+        writeLock();
+        try {
+            softMap.setMaxSize((size < 0) ? Integer.MAX_VALUE : size);
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    /**
+     * The maximum number of soft references to maintain, or -1 for no limit.
+     */
+    public int getSoftReferenceSize() {
+        int max = softMap.getMaxSize();
+        return (max == Integer.MAX_VALUE) ? -1 : max;
+    }
+
+    /**
+     * The keys pinned into the map.
+     */
+    public Set getPinnedKeys() {
+        readLock();
+        try {
+            return Collections.unmodifiableSet(pinnedMap.keySet());
+        } finally {
+            readUnlock();
+        }
+    }
+
+    /**
+     * Locks the given key and its value into the map. Objects pinned into
+     * the map are not counted towards the maximum cache size, and are never
+     * evicted implicitly. You may pin keys for which no value is in the map.
+     *
+     * @return true if the givne key's value was pinned; false if no value
+     * for the given key is cached
+     */
+    public boolean pin(Object key) {
+        writeLock();
+        try {
+            // if we don't have a pinned map we need to create one; else if the
+            // pinned map already contains the key, nothing to do
+            if (pinnedMap.containsKey(key))
+                return pinnedMap.get(key) != null;
+
+            // check other maps for key
+            Object val = remove(cacheMap, key);
+            if (val == null)
+                val = remove(softMap, key);
+
+            // pin key
+            put(pinnedMap, key, val);
+            if (val != null) {
+                _pinnedSize++;
+                return true;
+            }
+            return false;
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    /**
+     * Undo a pinning.
+     */
+    public boolean unpin(Object key) {
+        writeLock();
+        try {
+            Object val = remove(pinnedMap, key);
+            if (val != null) {
+                // put back into unpinned cache
+                put(key, val);
+                _pinnedSize--;
+                return true;
+            }
+            return false;
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    /**
+     * Invoked when a key-value pair is evicted from this data
+     * structure. This is invoked with <code>expired</code> set to
+     * <code>true</code> when an object is dropped because of space
+     * requirements or through garbage collection of soft references.
+     * It is invoked with <code>expired</code> set to <code>false</code>
+     * when an object is explicitly removed via the {@link #remove} or
+     * {@link #clear} methods. This may be invoked more than once for a
+     * given entry.
+     *
+     * @param value may be null if the value was a soft reference that has
+     * been GCd
+     * @since 0.2.5.0
+     */
+    protected void entryRemoved(Object key, Object value, boolean expired) {
+    }
+
+    /**
+     * Invoked when an entry is added to the cache. This may be invoked
+     * more than once for an entry.
+     */
+    protected void entryAdded(Object key, Object value) {
+    }
+
+    public Object get(Object key) {
+        readLock();
+        try {
+            Object val = pinnedMap.get(key);
+            if (val != null)
+                return val;
+
+            val = cacheMap.get(key);
+            if (val == null) {
+                // if we find the key in the soft map, move it back into
+                // the primary map
+                val = softMap.get(key);
+                if (val != null)
+                    put(key, val);
+            }
+            return val;
+        } finally {
+            readUnlock();
+        }
+    }
+
+    public Object put(Object key, Object value) {
+        writeLock();
+        try {
+            // if the key is pinned, just interact directly with the pinned map
+            Object val;
+            if (pinnedMap.containsKey(key)) {
+                val = put(pinnedMap, key, value);
+                if (val == null) {
+                    _pinnedSize++;
+                    entryAdded(key, value);
+                } else {
+                    entryRemoved(key, val, false);
+                    entryAdded(key, value);
+                }
+                return val;
+            }
+
+            // if no hard refs, don't put anything
+            if (cacheMap.getMaxSize() == 0)
+                return null;
+
+            // otherwise, put the value into the map and clear it from the
+            // soft map
+            val = put(cacheMap, key, value);
+            if (val == null) {
+                val = remove(softMap, key);
+                if (val == null)
+                    entryAdded(key, value);
+                else {
+                    entryRemoved(key, val, false);
+                    entryAdded(key, value);
+                }
+            } else {
+                entryRemoved(key, val, false);
+                entryAdded(key, value);
+            }
+            return val;
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    public void putAll(Map map) {
+        Map.Entry entry;
+        for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
+            entry = (Map.Entry) itr.next();
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * If <code>key</code> is pinned into the cache, the pin is
+     * cleared and the object is removed.
+     */
+    public Object remove(Object key) {
+        writeLock();
+        try {
+            // if the key is pinned, just interact directly with the
+            // pinned map
+            Object val;
+            if (pinnedMap.containsKey(key)) {
+                // re-put with null value; we still want key pinned
+                val = put(pinnedMap, key, null);
+                if (val != null) {
+                    _pinnedSize--;
+                    entryRemoved(key, val, false);
+                }
+                return val;
+            }
+
+            val = remove(cacheMap, key);
+            if (val == null)
+                val = softMap.remove(key);
+            if (val != null)
+                entryRemoved(key, val, false);
+
+            return val;
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    /**
+     * Removes pinned objects as well as unpinned ones.
+     */
+    public void clear() {
+        writeLock();
+        try {
+            notifyEntryRemovals(pinnedMap.entrySet());
+            pinnedMap.clear();
+            _pinnedSize = 0;
+
+            notifyEntryRemovals(cacheMap.entrySet());
+            cacheMap.clear();
+
+            notifyEntryRemovals(softMap.entrySet());
+            softMap.clear();
+        } finally {
+            writeUnlock();
+        }
+    }
+
+    private void notifyEntryRemovals(Set set) {
+        Map.Entry entry;
+        for (Iterator itr = set.iterator(); itr.hasNext();) {
+            entry = (Map.Entry) itr.next();
+            if (entry.getValue() != null)
+                entryRemoved(entry.getKey(), entry.getValue(), false);
+        }
+    }
+
+    public int size() {
+        readLock();
+        try {
+            return _pinnedSize + cacheMap.size() + softMap.size();
+        } finally {
+            readUnlock();
+        }
+    }
+
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    public boolean containsKey(Object key) {
+        readLock();
+        try {
+            return pinnedMap.get(key) != null
+                || cacheMap.containsKey(key)
+                || softMap.containsKey(key);
+        } finally {
+            readUnlock();
+        }
+    }
+
+    public boolean containsValue(Object val) {
+        readLock();
+        try {
+            return pinnedMap.containsValue(val)
+                || cacheMap.containsValue(val)
+                || softMap.containsValue(val);
+        } finally {
+            readUnlock();
+        }
+    }
+
+    public Set keySet() {
+        return new KeySet();
+    }
+
+    public Collection values() {
+        return new ValueCollection();
+    }
+
+    public Set entrySet() {
+        return new EntrySet();
+    }
+
+    public String toString() {
+        readLock();
+        try {
+            return "CacheMap:" + cacheMap.toString() + "::"
+                + softMap.toString();
+        } finally {
+            readUnlock();
+        }
+    }
+
+    /**
+     * View of the entry set.
+     */
+    private class EntrySet
+        extends AbstractSet {
+
+        public int size() {
+            return CacheMap.this.size();
+        }
+
+        public boolean add(Object o) {
+            Map.Entry entry = (Map.Entry) o;
+            put(entry.getKey(), entry.getValue());
+            return true;
+        }
+
+        public Iterator iterator() {
+            return new EntryIterator(EntryIterator.ENTRY);
+        }
+    }
+
+    /**
+     * View of the key set.
+     */
+    private class KeySet
+        extends AbstractSet {
+
+        public int size() {
+            return CacheMap.this.size();
+        }
+
+        public Iterator iterator() {
+            return new EntryIterator(EntryIterator.KEY);
+        }
+    }
+
+    /**
+     * View of the value collection.
+     */
+    private class ValueCollection
+        extends AbstractCollection {
+
+        public int size() {
+            return CacheMap.this.size();
+        }
+
+        public Iterator iterator() {
+            return new EntryIterator(EntryIterator.VALUE);
+        }
+    }
+
+    /**
+     * Iterator over all entries.
+     */
+    private class EntryIterator
+        implements Iterator, Predicate {
+
+        public static final int ENTRY = 0;
+        public static final int KEY = 1;
+        public static final int VALUE = 2;
+
+        private final IteratorChain _itr = new IteratorChain();
+        private final int _type;
+
+        public EntryIterator(int type) {
+            _type = type;
+            _itr.addIterator(new FilterIterator(getView(pinnedMap), this));
+            _itr.addIterator(getView(cacheMap));
+            _itr.addIterator(getView(softMap));
+        }
+
+        /**
+         * Return an iterator over the appropriate view of the given map.
+         */
+        private Iterator getView(Map m) {
+            if (m == null)
+                return null;
+
+            switch (_type) {
+                case KEY:
+                    return m.keySet().iterator();
+                case VALUE:
+                    return m.values().iterator();
+                default:
+                    return m.entrySet().iterator();
+            }
+        }
+
+        public boolean hasNext() {
+            return _itr.hasNext();
+        }
+
+        public Object next() {
+            return _itr.next();
+        }
+
+        public void remove() {
+            _itr.remove();
+        }
+
+        public boolean evaluate(Object obj) {
+            switch (_type) {
+                case ENTRY:
+                    return ((Map.Entry) obj).getValue() != null;
+			case VALUE:
+				return obj != null;
+			default:
+				return true;
+			}
+		}
+	}
+}
+

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java?rev=640685&r1=640684&r2=640685&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ImplHelper.java Mon Mar 24 20:37:56 2008
@@ -1,322 +1,322 @@
-/*
- * 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.openjpa.util;
-
-import java.util.ArrayList;
-import java.util.BitSet;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.openjpa.enhance.PersistenceCapable;
-import org.apache.openjpa.enhance.PCRegistry;
-import org.apache.openjpa.enhance.StateManager;
-import org.apache.openjpa.enhance.ManagedInstanceProvider;
-import org.apache.openjpa.enhance.ReflectingPersistenceCapable;
-import org.apache.openjpa.enhance.RuntimeUnenhancedClasssesModes;
-import org.apache.openjpa.kernel.FetchConfiguration;
-import org.apache.openjpa.kernel.LockManager;
-import org.apache.openjpa.kernel.OpenJPAStateManager;
-import org.apache.openjpa.kernel.PCState;
-import org.apache.openjpa.kernel.StoreContext;
-import org.apache.openjpa.kernel.StoreManager;
-import org.apache.openjpa.lib.util.Closeable;
-import org.apache.openjpa.lib.util.ReferenceMap;
-import org.apache.openjpa.lib.util.UUIDGenerator;
-import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
-import org.apache.openjpa.meta.ClassMetaData;
-import org.apache.openjpa.meta.FieldMetaData;
-import org.apache.openjpa.meta.JavaTypes;
-import org.apache.openjpa.meta.SequenceMetaData;
-import org.apache.openjpa.meta.ValueStrategies;
-import org.apache.openjpa.conf.OpenJPAConfiguration;
-
-/**
- * Helper for OpenJPA back-ends.
- *
- * @since 0.3.0
- * @author Abe White
- * @nojavadoc
- */
-public class ImplHelper {
-
-    // Cache for from/to type assignments
-    private static final Map _assignableTypes =
-        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
-
-    // map of all new unenhanced instances active in this classloader
-    public static final Map _unenhancedInstanceMap =
-        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD) {
-
-            protected boolean eq(Object x, Object y) {
-                // the Entries in ConcurrentReferenceHashMap delegate back to
-                // eq() in their equals() impls
-                if (x instanceof Map.Entry)
-                    return super.eq(x, y);
-                else
-                    return x == y;
-            }
-
-            protected int hc(Object o) {
-                // the Entries in ConcurrentReferenceHashMap delegate back to
-                // hc() in their hashCode() impls
-                if (o instanceof Map.Entry)
-                    return super.hc(o);
-                else
-                    return System.identityHashCode(o);
-            }
-        };
-
-    /**
-     * Helper for store manager implementations. This method simply delegates
-     * to the proper singular method for each state manager.
-     *
-     * @see StoreManager#loadAll
-     * @since 0.4.0
-     */
-    public static Collection loadAll(Collection sms, StoreManager store,
-        PCState state, int load, FetchConfiguration fetch, Object context) {
-        Collection failed = null;
-        OpenJPAStateManager sm;
-        LockManager lm;
-        for (Iterator itr = sms.iterator(); itr.hasNext();) {
-            sm = (OpenJPAStateManager) itr.next();
-            if (sm.getManagedInstance() == null) {
-                if (!store.initialize(sm, state, fetch, context))
-                    failed = addFailedId(sm, failed);
-            } else if (load != StoreManager.FORCE_LOAD_NONE
-                || sm.getPCState() == PCState.HOLLOW) {
-                lm = sm.getContext().getLockManager();
-                if (!store.load(sm, sm.getUnloaded(fetch), fetch, 
-                    lm.getLockLevel(sm), context))
-                    failed = addFailedId(sm, failed);
-            } else if (!store.exists(sm, context))
-                failed = addFailedId(sm, failed);
-        }
-        return (failed == null) ? Collections.EMPTY_LIST : failed;
-    }
-
-    /**
-     * Add identity of given instance to collection.
-     */
-    private static Collection addFailedId(OpenJPAStateManager sm,
-        Collection failed) {
-        if (failed == null)
-            failed = new ArrayList();
-        failed.add(sm.getId());
-        return failed;
-    }
-
-    /**
-     * Generate a value for the given metadata, or return null. Generates
-     * values for hte following strategies: {@link ValueStrategies#SEQUENCE},
-     * {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
-     */
-    public static Object generateIdentityValue(StoreContext ctx,
-        ClassMetaData meta, int typeCode) {
-        return generateValue(ctx, meta, null, typeCode);
-    }
-
-    /**
-     * Generate a value for the given metadata, or return null. Generates
-     * values for hte following strategies: {@link ValueStrategies#SEQUENCE},
-     * {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
-     */
-    public static Object generateFieldValue(StoreContext ctx,
-        FieldMetaData fmd) {
-        return generateValue(ctx, fmd.getDefiningMetaData(), fmd, 
-            fmd.getDeclaredTypeCode());
-    }
-
-    /**
-     * Generate a value for the given metadaa.
-     */
-    private static Object generateValue(StoreContext ctx,
-        ClassMetaData meta, FieldMetaData fmd, int typeCode) {
-        int strategy = (fmd == null) ? meta.getIdentityStrategy()
-            : fmd.getValueStrategy();
-        switch (strategy) {
-            case ValueStrategies.SEQUENCE:
-                SequenceMetaData smd = (fmd == null)
-                    ? meta.getIdentitySequenceMetaData()
-                    : fmd.getValueSequenceMetaData();
-                return JavaTypes.convert(smd.getInstance(ctx.getClassLoader()).
-                    next(ctx, meta), typeCode);
-            case ValueStrategies.UUID_STRING:
-                return UUIDGenerator.nextString();
-            case ValueStrategies.UUID_HEX:
-                return UUIDGenerator.nextHex();
-            default:
-                return null;
-        }
-    }
-
-    /**
-     * Returns the fields of the state that require an update.
-     *
-     * @param  sm  the state to check
-     * @return the BitSet of fields that need update, or null if none
-     */
-    public static BitSet getUpdateFields(OpenJPAStateManager sm) {
-        if ((sm.getPCState() == PCState.PDIRTY
-            && (!sm.isFlushed() || sm.isFlushedDirty()))
-            || (sm.getPCState() == PCState.PNEW && sm.isFlushedDirty())) {
-            BitSet dirty = sm.getDirty();
-            if (sm.isFlushed()) {
-                dirty = (BitSet) dirty.clone();
-                dirty.andNot(sm.getFlushed());
-            }
-            if (dirty.length() > 0)
-                return dirty;
-        }
-        return null;
-    }
-
-    /**
-     * Close the given resource. The resource can be an extent iterator,
-     * query result, large result set relation, or any closeable OpenJPA
-     * component.
-     */
-    public static void close(Object o) {
-        try {
-            if (o instanceof Closeable)
-                ((Closeable) o).close();
-        } catch (RuntimeException re) {
-            throw re;
-        } catch (Exception e) {
-            throw new GeneralException(e);
-        }
-    }
-
-    /**
-     * Returns true if the specified class is a type that can be managed by
-     * OpenJPA.
-     *
-     * @param type the class to test
-     * @return true if the class is manageable.
-     *
-     * @since 1.0.0
-     */
-    public static boolean isManagedType(OpenJPAConfiguration conf, Class type) {
-        return (PersistenceCapable.class.isAssignableFrom(type)
-            || (type != null
-                && (conf == null || conf.getRuntimeUnenhancedClassesConstant()
-                    == RuntimeUnenhancedClasssesModes.SUPPORTED)
-                && PCRegistry.isRegistered(type)));
-    }
-
-    /**
-     * Returns true if the specified instance is manageable.
-     *
-     * @param instance the object to check
-     * @return true if the instance is a persistent type, false otherwise
-     */
-    public static boolean isManageable(Object instance) {
-        return instance instanceof PersistenceCapable
-            || instance != null && PCRegistry.isRegistered(instance.getClass());
-    }
-
-    /**
-     * Returns true if the referenced "to" class is assignable to the "from"
-     * class.  This helper method utilizes a cache to help avoid the overhead
-     * of the Class.isAssignableFrom() method.
-     *
-     * @param from target class instance to be checked for assignability
-     * @param to second class instance to be checked for assignability
-     * @return true if the "to" class is assignable to the "from" class
-     */
-    public static boolean isAssignable(Class from, Class to) {
-        if (from == null || to == null)
-            return false;
-
-        Boolean isAssignable = null;
-        Map assignableTo = (Map) _assignableTypes.get(from);
-        if (assignableTo == null) { // "to" cache doesn't exist, so create it...
-            assignableTo = new ConcurrentReferenceHashMap(ReferenceMap.WEAK,
-                    ReferenceMap.HARD);
-            _assignableTypes.put(from, assignableTo);
-        } else { // "to" cache exists...
-            isAssignable = (Boolean) assignableTo.get(to);
-        }
-
-        if (isAssignable == null) {// we don't have a record of this pair...
-            isAssignable = Boolean.valueOf(from.isAssignableFrom(to));
-            assignableTo.put(to, isAssignable);
-        }
-
-        return isAssignable.booleanValue();
-    }
-
-    /**
-     * @return the persistence-capable instance responsible for managing
-     * <code>o</code>, or <code>null</code> if <code>o</code> is not manageable.
-     * @since 1.0.0
-     */
-    public static PersistenceCapable toPersistenceCapable(Object o, Object ctx){
-        if (o instanceof PersistenceCapable)
-            return (PersistenceCapable) o;
-
-        OpenJPAConfiguration conf = null;
-        if (ctx instanceof OpenJPAConfiguration)
-            conf = (OpenJPAConfiguration) ctx;
-        else if (ctx instanceof StateManager
-            && ((StateManager) ctx).getGenericContext() instanceof StoreContext)
-            conf = ((StoreContext) ((StateManager) ctx).getGenericContext())
-                .getConfiguration();
-
-        if (!isManageable(o))
-            return null;
-
-        // if we had a putIfAbsent() method, we wouldn't need to sync here
-        synchronized (o) {
-            PersistenceCapable pc = (PersistenceCapable)
-                _unenhancedInstanceMap.get(o);
-
-            if (pc != null)
-                return pc;
-
-            // if we don't have a conf passed in, then we can't create a new
-            // ReflectingPC; this will only be the case when invoked from a
-            // context outside of OpenJPA.
-            if (conf == null)
-                return null;
-
-            pc = new ReflectingPersistenceCapable(o, conf);
-            _unenhancedInstanceMap.put(o, pc);
-            return pc;
-        }
-    }
-
-    public static void registerPersistenceCapable(
-        ReflectingPersistenceCapable pc) {
-        _unenhancedInstanceMap.put(pc.getManagedInstance(), pc);
-    }
-
-    /**
-     * @return the user-visible representation of <code>o</code>.
-     * @since 1.0.0
-     */
-    public static Object getManagedInstance(Object o) {
-        if (o instanceof ManagedInstanceProvider)
-            return ((ManagedInstanceProvider) o).getManagedInstance();
-        else
-            return o;
-    }
-}
+/*
+ * 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.openjpa.util;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.enhance.PCRegistry;
+import org.apache.openjpa.enhance.StateManager;
+import org.apache.openjpa.enhance.ManagedInstanceProvider;
+import org.apache.openjpa.enhance.ReflectingPersistenceCapable;
+import org.apache.openjpa.enhance.RuntimeUnenhancedClasssesModes;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.LockManager;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.PCState;
+import org.apache.openjpa.kernel.StoreContext;
+import org.apache.openjpa.kernel.StoreManager;
+import org.apache.openjpa.lib.util.Closeable;
+import org.apache.openjpa.lib.util.ReferenceMap;
+import org.apache.openjpa.lib.util.UUIDGenerator;
+import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.meta.SequenceMetaData;
+import org.apache.openjpa.meta.ValueStrategies;
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+
+/**
+ * Helper for OpenJPA back-ends.
+ *
+ * @since 0.3.0
+ * @author Abe White
+ * @nojavadoc
+ */
+public class ImplHelper {
+
+    // Cache for from/to type assignments
+    private static final Map _assignableTypes =
+        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
+
+    // map of all new unenhanced instances active in this classloader
+    public static final Map _unenhancedInstanceMap =
+        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD) {
+
+            protected boolean eq(Object x, Object y) {
+                // the Entries in ConcurrentReferenceHashMap delegate back to
+                // eq() in their equals() impls
+                if (x instanceof Map.Entry)
+                    return super.eq(x, y);
+                else
+                    return x == y;
+            }
+
+            protected int hc(Object o) {
+                // the Entries in ConcurrentReferenceHashMap delegate back to
+                // hc() in their hashCode() impls
+                if (o instanceof Map.Entry)
+                    return super.hc(o);
+                else
+                    return System.identityHashCode(o);
+            }
+        };
+
+    /**
+     * Helper for store manager implementations. This method simply delegates
+     * to the proper singular method for each state manager.
+     *
+     * @see StoreManager#loadAll
+     * @since 0.4.0
+     */
+    public static Collection loadAll(Collection sms, StoreManager store,
+        PCState state, int load, FetchConfiguration fetch, Object context) {
+        Collection failed = null;
+        OpenJPAStateManager sm;
+        LockManager lm;
+        for (Iterator itr = sms.iterator(); itr.hasNext();) {
+            sm = (OpenJPAStateManager) itr.next();
+            if (sm.getManagedInstance() == null) {
+                if (!store.initialize(sm, state, fetch, context))
+                    failed = addFailedId(sm, failed);
+            } else if (load != StoreManager.FORCE_LOAD_NONE
+                || sm.getPCState() == PCState.HOLLOW) {
+                lm = sm.getContext().getLockManager();
+                if (!store.load(sm, sm.getUnloaded(fetch), fetch, 
+                    lm.getLockLevel(sm), context))
+                    failed = addFailedId(sm, failed);
+            } else if (!store.exists(sm, context))
+                failed = addFailedId(sm, failed);
+        }
+        return (failed == null) ? Collections.EMPTY_LIST : failed;
+    }
+
+    /**
+     * Add identity of given instance to collection.
+     */
+    private static Collection addFailedId(OpenJPAStateManager sm,
+        Collection failed) {
+        if (failed == null)
+            failed = new ArrayList();
+        failed.add(sm.getId());
+        return failed;
+    }
+
+    /**
+     * Generate a value for the given metadata, or return null. Generates
+     * values for hte following strategies: {@link ValueStrategies#SEQUENCE},
+     * {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
+     */
+    public static Object generateIdentityValue(StoreContext ctx,
+        ClassMetaData meta, int typeCode) {
+        return generateValue(ctx, meta, null, typeCode);
+    }
+
+    /**
+     * Generate a value for the given metadata, or return null. Generates
+     * values for hte following strategies: {@link ValueStrategies#SEQUENCE},
+     * {@link ValueStrategies#UUID_STRING}, {@link ValueStrategies#UUID_HEX}
+     */
+    public static Object generateFieldValue(StoreContext ctx,
+        FieldMetaData fmd) {
+        return generateValue(ctx, fmd.getDefiningMetaData(), fmd, 
+            fmd.getDeclaredTypeCode());
+    }
+
+    /**
+     * Generate a value for the given metadaa.
+     */
+    private static Object generateValue(StoreContext ctx,
+        ClassMetaData meta, FieldMetaData fmd, int typeCode) {
+        int strategy = (fmd == null) ? meta.getIdentityStrategy()
+            : fmd.getValueStrategy();
+        switch (strategy) {
+            case ValueStrategies.SEQUENCE:
+                SequenceMetaData smd = (fmd == null)
+                    ? meta.getIdentitySequenceMetaData()
+                    : fmd.getValueSequenceMetaData();
+                return JavaTypes.convert(smd.getInstance(ctx.getClassLoader()).
+                    next(ctx, meta), typeCode);
+            case ValueStrategies.UUID_STRING:
+                return UUIDGenerator.nextString();
+            case ValueStrategies.UUID_HEX:
+                return UUIDGenerator.nextHex();
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Returns the fields of the state that require an update.
+     *
+     * @param  sm  the state to check
+     * @return the BitSet of fields that need update, or null if none
+     */
+    public static BitSet getUpdateFields(OpenJPAStateManager sm) {
+        if ((sm.getPCState() == PCState.PDIRTY
+            && (!sm.isFlushed() || sm.isFlushedDirty()))
+            || (sm.getPCState() == PCState.PNEW && sm.isFlushedDirty())) {
+            BitSet dirty = sm.getDirty();
+            if (sm.isFlushed()) {
+                dirty = (BitSet) dirty.clone();
+                dirty.andNot(sm.getFlushed());
+            }
+            if (dirty.length() > 0)
+                return dirty;
+        }
+        return null;
+    }
+
+    /**
+     * Close the given resource. The resource can be an extent iterator,
+     * query result, large result set relation, or any closeable OpenJPA
+     * component.
+     */
+    public static void close(Object o) {
+        try {
+            if (o instanceof Closeable)
+                ((Closeable) o).close();
+        } catch (RuntimeException re) {
+            throw re;
+        } catch (Exception e) {
+            throw new GeneralException(e);
+        }
+    }
+
+    /**
+     * Returns true if the specified class is a type that can be managed by
+     * OpenJPA.
+     *
+     * @param type the class to test
+     * @return true if the class is manageable.
+     *
+     * @since 1.0.0
+     */
+    public static boolean isManagedType(OpenJPAConfiguration conf, Class type) {
+        return (PersistenceCapable.class.isAssignableFrom(type)
+            || (type != null
+                && (conf == null || conf.getRuntimeUnenhancedClassesConstant()
+                    == RuntimeUnenhancedClasssesModes.SUPPORTED)
+                && PCRegistry.isRegistered(type)));
+    }
+
+    /**
+     * Returns true if the specified instance is manageable.
+     *
+     * @param instance the object to check
+     * @return true if the instance is a persistent type, false otherwise
+     */
+    public static boolean isManageable(Object instance) {
+        return instance instanceof PersistenceCapable
+            || instance != null && PCRegistry.isRegistered(instance.getClass());
+    }
+
+    /**
+     * Returns true if the referenced "to" class is assignable to the "from"
+     * class.  This helper method utilizes a cache to help avoid the overhead
+     * of the Class.isAssignableFrom() method.
+     *
+     * @param from target class instance to be checked for assignability
+     * @param to second class instance to be checked for assignability
+     * @return true if the "to" class is assignable to the "from" class
+     */
+    public static boolean isAssignable(Class from, Class to) {
+        if (from == null || to == null)
+            return false;
+
+        Boolean isAssignable = null;
+        Map assignableTo = (Map) _assignableTypes.get(from);
+        if (assignableTo == null) { // "to" cache doesn't exist, so create it...
+            assignableTo = new ConcurrentReferenceHashMap(ReferenceMap.WEAK,
+                    ReferenceMap.HARD);
+            _assignableTypes.put(from, assignableTo);
+        } else { // "to" cache exists...
+            isAssignable = (Boolean) assignableTo.get(to);
+        }
+
+        if (isAssignable == null) {// we don't have a record of this pair...
+            isAssignable = Boolean.valueOf(from.isAssignableFrom(to));
+            assignableTo.put(to, isAssignable);
+        }
+
+        return isAssignable.booleanValue();
+    }
+
+    /**
+     * @return the persistence-capable instance responsible for managing
+     * <code>o</code>, or <code>null</code> if <code>o</code> is not manageable.
+     * @since 1.0.0
+     */
+    public static PersistenceCapable toPersistenceCapable(Object o, Object ctx){
+        if (o instanceof PersistenceCapable)
+            return (PersistenceCapable) o;
+
+        OpenJPAConfiguration conf = null;
+        if (ctx instanceof OpenJPAConfiguration)
+            conf = (OpenJPAConfiguration) ctx;
+        else if (ctx instanceof StateManager
+            && ((StateManager) ctx).getGenericContext() instanceof StoreContext)
+            conf = ((StoreContext) ((StateManager) ctx).getGenericContext())
+                .getConfiguration();
+
+        if (!isManageable(o))
+            return null;
+
+        // if we had a putIfAbsent() method, we wouldn't need to sync here
+        synchronized (o) {
+            PersistenceCapable pc = (PersistenceCapable)
+                _unenhancedInstanceMap.get(o);
+
+            if (pc != null)
+                return pc;
+
+            // if we don't have a conf passed in, then we can't create a new
+            // ReflectingPC; this will only be the case when invoked from a
+            // context outside of OpenJPA.
+            if (conf == null)
+                return null;
+
+            pc = new ReflectingPersistenceCapable(o, conf);
+            _unenhancedInstanceMap.put(o, pc);
+            return pc;
+        }
+    }
+
+    public static void registerPersistenceCapable(
+        ReflectingPersistenceCapable pc) {
+        _unenhancedInstanceMap.put(pc.getManagedInstance(), pc);
+    }
+
+    /**
+     * @return the user-visible representation of <code>o</code>.
+     * @since 1.0.0
+     */
+    public static Object getManagedInstance(Object o) {
+        if (o instanceof ManagedInstanceProvider)
+            return ((ManagedInstanceProvider) o).getManagedInstance();
+        else
+            return o;
+    }
+}

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java?rev=640685&r1=640684&r2=640685&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/OpenJPAId.java Mon Mar 24 20:37:56 2008
@@ -1,149 +1,149 @@
-/*
- * 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.openjpa.util;
-
-import java.io.Serializable;
-
-import org.apache.openjpa.lib.util.ReferenceMap;
-import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
-
-/**
- * Identity class extended by builtin OpenJPA identity objects.
- *
- * @author Steve Kim
- */
-public abstract class OpenJPAId
-    implements Comparable, Serializable {
-
-    // cache the types' generated hashcodes
-    private static ConcurrentReferenceHashMap _typeCache =
-        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
-
-    protected Class type;
-    protected boolean subs = true;
-
-    // type has his based on the least-derived non-object class so that
-    // user-given ids with non-exact types match ids with exact types
-    private transient int _typeHash = 0;
-
-    protected OpenJPAId() {
-    }
-
-    protected OpenJPAId(Class type) {
-        this.type = type;
-    }
-
-    protected OpenJPAId(Class type, boolean subs) {
-        this.type = type;
-        this.subs = subs;
-    }
-
-    /**
-     * Return the persitent class which this id instance represents.
-     */
-    public Class getType() {
-        return type;
-    }
-
-    /**
-     * Whether this oid might be for a subclass of the given type.
-     * Defaults to true.
-     */
-    public boolean hasSubclasses() {
-        return subs;
-    }
-
-    /**
-     * Set the exact type of the described instance once it is known.
-     */
-    public void setManagedInstanceType(Class type) {
-        this.type = type;
-        this.subs = false;
-    }
-
-    /**
-     * Set the exact type of the described instance once it is known.
-     */
-    public void setManagedInstanceType(Class type, boolean subs) {
-        this.type = type;
-        this.subs = subs;
-    }
-
-    /**
-     * Return the identity value as an object.
-     */
-    public abstract Object getIdObject();
-
-    /**
-     * Return the id's hash code.
-     */
-    protected abstract int idHash();
-
-    /**
-     * Compare the id to the id of the given instance.
-     */
-    protected abstract boolean idEquals(OpenJPAId other);
-
-    /**
-     * Generate the hashcode for this Id.  Cache the type's generated hashcode
-     * so that it doesn't have to be generated each time.
-     */
-    public int hashCode() {
-        if (_typeHash == 0) {
-            Integer typeHashInt = (Integer) _typeCache.get(type);
-            if (typeHashInt == null) {
-                Class base = type;
-                Class superclass = base.getSuperclass();
-                while (superclass != null && superclass != Object.class) {
-                    base = base.getSuperclass();
-                    superclass = base.getSuperclass();
-                }
-                _typeHash = base.hashCode();
-                _typeCache.put(type, new Integer(_typeHash));
-            } else {
-                _typeHash = typeHashInt.intValue();
-            }
-        }
-        return _typeHash ^ idHash();
-    }
-
-    public boolean equals(Object o) {
-        if (o == this)
-            return true;
-        if (o == null || getClass() != o.getClass())
-            return false;
-
-        OpenJPAId id = (OpenJPAId) o;
-        return idEquals(id) && (id.type.isAssignableFrom(type)
-            || (subs && type.isAssignableFrom(id.type)));
-    }
-
-    public String toString() {
-        return type.getName() + "-" + getIdObject();
-    }
-
-    public int compareTo(Object other) {
-        if (other == this)
-            return 0;
-        if (other == null)
-            return 1;
-        return ((Comparable) getIdObject()).compareTo(((OpenJPAId) other).
-            getIdObject ());
-	}
-}
+/*
+ * 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.openjpa.util;
+
+import java.io.Serializable;
+
+import org.apache.openjpa.lib.util.ReferenceMap;
+import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap;
+
+/**
+ * Identity class extended by builtin OpenJPA identity objects.
+ *
+ * @author Steve Kim
+ */
+public abstract class OpenJPAId
+    implements Comparable, Serializable {
+
+    // cache the types' generated hashcodes
+    private static ConcurrentReferenceHashMap _typeCache =
+        new ConcurrentReferenceHashMap(ReferenceMap.WEAK, ReferenceMap.HARD);
+
+    protected Class type;
+    protected boolean subs = true;
+
+    // type has his based on the least-derived non-object class so that
+    // user-given ids with non-exact types match ids with exact types
+    private transient int _typeHash = 0;
+
+    protected OpenJPAId() {
+    }
+
+    protected OpenJPAId(Class type) {
+        this.type = type;
+    }
+
+    protected OpenJPAId(Class type, boolean subs) {
+        this.type = type;
+        this.subs = subs;
+    }
+
+    /**
+     * Return the persitent class which this id instance represents.
+     */
+    public Class getType() {
+        return type;
+    }
+
+    /**
+     * Whether this oid might be for a subclass of the given type.
+     * Defaults to true.
+     */
+    public boolean hasSubclasses() {
+        return subs;
+    }
+
+    /**
+     * Set the exact type of the described instance once it is known.
+     */
+    public void setManagedInstanceType(Class type) {
+        this.type = type;
+        this.subs = false;
+    }
+
+    /**
+     * Set the exact type of the described instance once it is known.
+     */
+    public void setManagedInstanceType(Class type, boolean subs) {
+        this.type = type;
+        this.subs = subs;
+    }
+
+    /**
+     * Return the identity value as an object.
+     */
+    public abstract Object getIdObject();
+
+    /**
+     * Return the id's hash code.
+     */
+    protected abstract int idHash();
+
+    /**
+     * Compare the id to the id of the given instance.
+     */
+    protected abstract boolean idEquals(OpenJPAId other);
+
+    /**
+     * Generate the hashcode for this Id.  Cache the type's generated hashcode
+     * so that it doesn't have to be generated each time.
+     */
+    public int hashCode() {
+        if (_typeHash == 0) {
+            Integer typeHashInt = (Integer) _typeCache.get(type);
+            if (typeHashInt == null) {
+                Class base = type;
+                Class superclass = base.getSuperclass();
+                while (superclass != null && superclass != Object.class) {
+                    base = base.getSuperclass();
+                    superclass = base.getSuperclass();
+                }
+                _typeHash = base.hashCode();
+                _typeCache.put(type, new Integer(_typeHash));
+            } else {
+                _typeHash = typeHashInt.intValue();
+            }
+        }
+        return _typeHash ^ idHash();
+    }
+
+    public boolean equals(Object o) {
+        if (o == this)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        OpenJPAId id = (OpenJPAId) o;
+        return idEquals(id) && (id.type.isAssignableFrom(type)
+            || (subs && type.isAssignableFrom(id.type)));
+    }
+
+    public String toString() {
+        return type.getName() + "-" + getIdObject();
+    }
+
+    public int compareTo(Object other) {
+        if (other == this)
+            return 0;
+        if (other == null)
+            return 1;
+        return ((Comparable) getIdObject()).compareTo(((OpenJPAId) other).
+            getIdObject ());
+	}
+}



Mime
View raw message