Author: psteitz
Date: Sat Sep 23 15:27:06 2006
New Revision: 449319
URL: http://svn.apache.org/viewvc?view=rev&rev=449319
Log:
Removed dependency on Commons Collections by adding collections
2.1 sources for LRUMap and SequencedHashMap with package scope to
datasources package.
JIRA: DBCP-68
Added:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java
(with props)
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java
(with props)
Modified:
jakarta/commons/proper/dbcp/trunk/project.xml
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SharedPoolDataSource.java
jakarta/commons/proper/dbcp/trunk/xdocs/changes.xml
Modified: jakarta/commons/proper/dbcp/trunk/project.xml
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/dbcp/trunk/project.xml?view=diff&rev=449319&r1=449318&r2=449319
==============================================================================
--- jakarta/commons/proper/dbcp/trunk/project.xml (original)
+++ jakarta/commons/proper/dbcp/trunk/project.xml Sat Sep 23 15:27:06 2006
@@ -173,11 +173,6 @@
<dependencies>
<dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- <version>3.1</version>
- </dependency>
- <dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.3</version>
@@ -261,6 +256,7 @@
<include>org/apache/commons/dbcp/TestBasicDataSource.java</include>
<include>org/apache/commons/dbcp/TestAbandonedBasicDataSource.java</include>
<include>org/apache/commons/dbcp/TestPStmtPoolingBasicDataSource.java</include>
+ <include>org/apache/commons/dbcp/TestPoolingDataSource.java</include>
<include>org/apache/commons/dbcp/TestJndi.java</include>
<include>org/apache/commons/dbcp/datasources/TestFactory.java</include>
Added:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java?view=auto&rev=449319
==============================================================================
---
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java
(added)
+++
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java
Sat Sep 23 15:27:06 2006
@@ -0,0 +1,255 @@
+/*
+ * $Header:
/home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/LRUMap.java,v
1.17 2002/10/12 22:15:19 scolebourne Exp $
+ * $Revision: 1.17 $
+ * $Date: 2002/10/12 22:15:19 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.commons.dbcp.datasources;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Iterator;
+
+/**
+ * <p>
+ * This class has been copied from Commons Collections, version 2.1 in order
+ * to eliminate the dependency of dbcp on collections. It has package scope
+ * to prevent its inclusion in the dbcp public API. The class declaration below
+ * should *not* be changed to public.
+ * </p>
+ * <p>
+ * An implementation of a Map which has a maximum size and uses a Least
Recently Used
+ * algorithm to remove items from the Map when the maximum size is reached and
new items are added.
+ * </p>
+ *
+ * <p>
+ * A synchronized version can be obtained with:
+ * <code>Collections.synchronizedMap( theMapToSynchronize )</code>
+ * If it will be accessed by multiple threads, you _must_ synchronize access
+ * to this Map. Even concurrent get(Object) operations produce indeterminate
+ * behaviour.
+ * </p>
+ *
+ * <p>
+ * Unlike the Collections 1.0 version, this version of LRUMap does use a true
+ * LRU algorithm. The keys for all gets and puts are moved to the front of
+ * the list. LRUMap is now a subclass of SequencedHashMap, and the "LRU"
+ * key is now equivalent to LRUMap.getFirst().
+ * </p>
+ *
+ * @since 1.0
+ * @author <a href="mailto:[EMAIL PROTECTED]">James Strachan</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Morgan Delagrange</a>
+ */
+class LRUMap extends SequencedHashMap implements Externalizable {
+
+ private int maximumSize = 0;
+
+ /**
+ * Default constructor, primarily for the purpose of
+ * de-externalization. This constructors sets a default
+ * LRU limit of 100 keys, but this value may be overridden
+ * internally as a result of de-externalization.
+ */
+ public LRUMap() {
+ this( 100 );
+ }
+
+ /**
+ * Create a new LRUMap with a maximum capacity of <i>i</i>.
+ * Once <i>i</i> capacity is achieved, subsequent gets
+ * and puts will push keys out of the map. See .
+ *
+ * @param i Maximum capacity of the LRUMap
+ */
+ public LRUMap(int i) {
+ super( i );
+ maximumSize = i;
+ }
+
+ /**
+ * <p>Get the value for a key from the Map. The key
+ * will be promoted to the Most Recently Used position.
+ * Note that get(Object) operations will modify
+ * the underlying Collection. Calling get(Object)
+ * inside of an iteration over keys, values, etc. is
+ * currently unsupported.</p>
+ *
+ * @param key Key to retrieve
+ * @return Returns the value. Returns null if the key has a
+ * null value <i>or</i> if the key has no value.
+ */
+ public Object get(Object key) {
+ if(!containsKey(key)) return null;
+
+ Object value = remove(key);
+ super.put(key,value);
+ return value;
+ }
+
+ /**
+ * <p>Removes the key and its Object from the Map.</p>
+ *
+ * <p>(Note: this may result in the "Least Recently Used"
+ * object being removed from the Map. In that case,
+ * the removeLRU() method is called. See javadoc for
+ * removeLRU() for more details.)</p>
+ *
+ * @param key Key of the Object to add.
+ * @param value Object to add
+ * @return Former value of the key
+ * @see #removeLRU
+ */
+ public Object put( Object key, Object value ) {
+
+ int mapSize = size();
+ Object retval = null;
+
+ if ( mapSize >= maximumSize ) {
+
+ // don't retire LRU if you are just
+ // updating an existing key
+ if (!containsKey(key)) {
+ // lets retire the least recently used item in the cache
+ removeLRU();
+ }
+ }
+
+ retval = super.put(key,value);
+
+ return retval;
+ }
+
+ /**
+ * This method is used internally by the class for
+ * finding and removing the LRU Object.
+ */
+ protected void removeLRU() {
+ Object key = getFirstKey();
+ // be sure to call super.get(key), or you're likely to
+ // get infinite promotion recursion
+ Object value = super.get(key);
+
+ remove(key);
+
+ processRemovedLRU(key,value);
+ }
+
+ /**
+ * Subclasses of LRUMap may hook into this method to
+ * provide specialized actions whenever an Object is
+ * automatically removed from the cache. By default,
+ * this method does nothing.
+ *
+ * @param key key that was removed
+ * @param value value of that key (can be null)
+ */
+ protected void processRemovedLRU(Object key, Object value) {
+ }
+
+ // Externalizable interface
+
//-------------------------------------------------------------------------
+ public void readExternal( ObjectInput in ) throws IOException,
ClassNotFoundException {
+ maximumSize = in.readInt();
+ int size = in.readInt();
+
+ for( int i = 0; i < size; i++ ) {
+ Object key = in.readObject();
+ Object value = in.readObject();
+ put(key,value);
+ }
+ }
+
+ public void writeExternal( ObjectOutput out ) throws IOException {
+ out.writeInt( maximumSize );
+ out.writeInt( size() );
+ for( Iterator iterator = keySet().iterator(); iterator.hasNext(); ) {
+ Object key = iterator.next();
+ out.writeObject( key );
+ // be sure to call super.get(key), or you're likely to
+ // get infinite promotion recursion
+ Object value = super.get( key );
+ out.writeObject( value );
+ }
+ }
+
+
+ // Properties
+
//-------------------------------------------------------------------------
+ /** Getter for property maximumSize.
+ * @return Value of property maximumSize.
+ */
+ public int getMaximumSize() {
+ return maximumSize;
+ }
+ /** Setter for property maximumSize.
+ * @param maximumSize New value of property maximumSize.
+ */
+ public void setMaximumSize(int maximumSize) {
+ this.maximumSize = maximumSize;
+ while (size() > maximumSize) {
+ removeLRU();
+ }
+ }
+
+
+ // add a serial version uid, so that if we change things in the future
+ // without changing the format, we can still deserialize properly.
+ private static final long serialVersionUID = 2197433140769957051L;
+}
Propchange:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/LRUMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java?view=auto&rev=449319
==============================================================================
---
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java
(added)
+++
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java
Sat Sep 23 15:27:06 2006
@@ -0,0 +1,1041 @@
+/*
+ * $Header:
/home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/SequencedHashMap.java,v
1.14 2002/10/12 22:15:19 scolebourne Exp $
+ * $Revision: 1.14 $
+ * $Date: 2002/10/12 22:15:19 $
+ *
+ * ====================================================================
+ *
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Commons", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.commons.dbcp.datasources;
+
+import java.io.Externalizable;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.IOException;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.NoSuchElementException;
+import java.util.ConcurrentModificationException;
+
+/**
+ * <p>
+ * This class has been copied from Commons Collections, version 2.1 in order
+ * to eliminate the dependency of dbcp on collections. It has package scope
+ * to prevent its inclusion in the dbcp public API. The class declaration below
+ * should *not* be changed to public.
+ * </p>
+ * A map of objects whose mapping entries are sequenced based on the order in
+ * which they were added. This data structure has fast <I>O(1)</I> search
+ * time, deletion time, and insertion time.
+ *
+ * <P>Although this map is sequenced, it cannot implement [EMAIL PROTECTED]
+ * java.util.List} because of incompatible interface definitions. The remove
+ * methods in List and Map have different return values (see: [EMAIL
PROTECTED]
+ * java.util.List#remove(Object)} and [EMAIL PROTECTED]
java.util.Map#remove(Object)}).
+ *
+ * <P>This class is not thread safe. When a thread safe implementation is
+ * required, use [EMAIL PROTECTED] Collections#synchronizedMap(Map)} as it is
documented,
+ * or use explicit synchronization controls.
+ *
+ * @since 2.0
+ * @author <a href="mailto:[EMAIL PROTECTED]">Michael A. Smith</A>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Daniel Rall</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Henning P. Schmiedehausen</a>
+ */
+class SequencedHashMap implements Map, Cloneable, Externalizable {
+
+ /**
+ * [EMAIL PROTECTED] java.util.Map.Entry} that doubles as a node in the
linked list
+ * of sequenced mappings.
+ **/
+ private static class Entry implements Map.Entry {
+ // Note: This class cannot easily be made clonable. While the actual
+ // implementation of a clone would be simple, defining the semantics is
+ // difficult. If a shallow clone is implemented, then entry.next.prev !=
+ // entry, which is unintuitive and probably breaks all sorts of assumptions
+ // in code that uses this implementation. If a deep clone is
+ // implementated, then what happens when the linked list is cyclical (as is
+ // the case with SequencedHashMap)? It's impossible to know in the clone
+ // when to stop cloning, and thus you end up in a recursive loop,
+ // continuously cloning the "next" in the list.
+
+ private final Object key;
+ private Object value;
+
+ // package private to allow the SequencedHashMap to access and manipulate
+ // them.
+ Entry next = null;
+ Entry prev = null;
+
+ public Entry(Object key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+
+ // per Map.Entry.getKey()
+ public Object getKey() {
+ return this.key;
+ }
+
+ // per Map.Entry.getValue()
+ public Object getValue() {
+ return this.value;
+ }
+
+ // per Map.Entry.setValue()
+ public Object setValue(Object value) {
+ Object oldValue = this.value;
+ this.value = value;
+ return oldValue;
+ }
+
+ public int hashCode() {
+ // implemented per api docs for Map.Entry.hashCode()
+ return ((getKey() == null ? 0 : getKey().hashCode()) ^
+ (getValue()==null ? 0 : getValue().hashCode()));
+ }
+
+ public boolean equals(Object obj) {
+ if(obj == null) return false;
+ if(obj == this) return true;
+ if(!(obj instanceof Map.Entry)) return false;
+
+ Map.Entry other = (Map.Entry)obj;
+
+ // implemented per api docs for Map.Entry.equals(Object)
+ return((getKey() == null ?
+ other.getKey() == null :
+ getKey().equals(other.getKey())) &&
+ (getValue() == null ?
+ other.getValue() == null :
+ getValue().equals(other.getValue())));
+ }
+ public String toString() {
+ return "[" + getKey() + "=" + getValue() + "]";
+ }
+ }
+
+ /**
+ * Construct an empty sentinel used to hold the head (sentinel.next) and the
+ * tail (sentinel.prev) of the list. The sentinal has a <code>null</code>
+ * key and value.
+ **/
+ private static final Entry createSentinel() {
+ Entry s = new Entry(null, null);
+ s.prev = s;
+ s.next = s;
+ return s;
+ }
+
+ /**
+ * Sentinel used to hold the head and tail of the list of entries.
+ **/
+ private Entry sentinel;
+
+ /**
+ * Map of keys to entries
+ **/
+ private HashMap entries;
+
+ /**
+ * Holds the number of modifications that have occurred to the map,
+ * excluding modifications made through a collection view's iterator
+ * (e.g. entrySet().iterator().remove()). This is used to create a
+ * fail-fast behavior with the iterators.
+ **/
+ private transient long modCount = 0;
+
+ /**
+ * Construct a new sequenced hash map with default initial size and load
+ * factor.
+ **/
+ public SequencedHashMap() {
+ sentinel = createSentinel();
+ entries = new HashMap();
+ }
+
+ /**
+ * Construct a new sequenced hash map with the specified initial size and
+ * default load factor.
+ *
+ * @param initialSize the initial size for the hash table
+ *
+ * @see HashMap#HashMap(int)
+ **/
+ public SequencedHashMap(int initialSize) {
+ sentinel = createSentinel();
+ entries = new HashMap(initialSize);
+ }
+
+ /**
+ * Construct a new sequenced hash map with the specified initial size and
+ * load factor.
+ *
+ * @param initialSize the initial size for the hash table
+ *
+ * @param loadFactor the load factor for the hash table.
+ *
+ * @see HashMap#HashMap(int,float)
+ **/
+ public SequencedHashMap(int initialSize, float loadFactor) {
+ sentinel = createSentinel();
+ entries = new HashMap(initialSize, loadFactor);
+ }
+
+ /**
+ * Construct a new sequenced hash map and add all the elements in the
+ * specified map. The order in which the mappings in the specified map are
+ * added is defined by [EMAIL PROTECTED] #putAll(Map)}.
+ **/
+ public SequencedHashMap(Map m) {
+ this();
+ putAll(m);
+ }
+
+ /**
+ * Removes an internal entry from the linked list. This does not remove
+ * it from the underlying map.
+ **/
+ private void removeEntry(Entry entry) {
+ entry.next.prev = entry.prev;
+ entry.prev.next = entry.next;
+ }
+
+ /**
+ * Inserts a new internal entry to the tail of the linked list. This does
+ * not add the entry to the underlying map.
+ **/
+ private void insertEntry(Entry entry) {
+ entry.next = sentinel;
+ entry.prev = sentinel.prev;
+ sentinel.prev.next = entry;
+ sentinel.prev = entry;
+ }
+
+ // per Map.size()
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#size()}.
+ */
+ public int size() {
+ // use the underlying Map's size since size is not maintained here.
+ return entries.size();
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#isEmpty()}.
+ */
+ public boolean isEmpty() {
+ // for quick check whether the map is entry, we can check the linked list
+ // and see if there's anything in it.
+ return sentinel.next == sentinel;
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#containsKey(Object)}.
+ */
+ public boolean containsKey(Object key) {
+ // pass on to underlying map implementation
+ return entries.containsKey(key);
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#containsValue(Object)}.
+ */
+ public boolean containsValue(Object value) {
+ // unfortunately, we cannot just pass this call to the underlying map
+ // because we are mapping keys to entries, not keys to values. The
+ // underlying map doesn't have an efficient implementation anyway, so this
+ // isn't a big deal.
+
+ // do null comparison outside loop so we only need to do it once. This
+ // provides a tighter, more efficient loop at the expense of slight
+ // code duplication.
+ if(value == null) {
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ if(pos.getValue() == null) return true;
+ }
+ } else {
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ if(value.equals(pos.getValue())) return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#get(Object)}.
+ */
+ public Object get(Object o) {
+ // find entry for the specified key object
+ Entry entry = (Entry)entries.get(o);
+ if(entry == null) return null;
+
+ return entry.getValue();
+ }
+
+ /**
+ * Return the entry for the "oldest" mapping. That is, return the Map.Entry
+ * for the key-value pair that was first put into the map when compared to
+ * all the other pairings in the map. This behavior is equivalent to using
+ * <code>entrySet().iterator().next()</code>, but this method provides an
+ * optimized implementation.
+ *
+ * @return The first entry in the sequence, or <code>null</code> if the
+ * map is empty.
+ **/
+ public Map.Entry getFirst() {
+ // sentinel.next points to the "first" element of the sequence -- the head
+ // of the list, which is exactly the entry we need to return. We must test
+ // for an empty list though because we don't want to return the sentinel!
+ return (isEmpty()) ? null : sentinel.next;
+ }
+
+ /**
+ * Return the key for the "oldest" mapping. That is, return the key for the
+ * mapping that was first put into the map when compared to all the other
+ * objects in the map. This behavior is equivalent to using
+ * <code>getFirst().getKey()</code>, but this method provides a slightly
+ * optimized implementation.
+ *
+ * @return The first key in the sequence, or <code>null</code> if the
+ * map is empty.
+ **/
+ public Object getFirstKey() {
+ // sentinel.next points to the "first" element of the sequence -- the head
+ // of the list -- and the requisite key is returned from it. An empty list
+ // does not need to be tested. In cases where the list is empty,
+ // sentinel.next will point to the sentinel itself which has a null key,
+ // which is exactly what we would want to return if the list is empty (a
+ // nice convient way to avoid test for an empty list)
+ return sentinel.next.getKey();
+ }
+
+ /**
+ * Return the value for the "oldest" mapping. That is, return the value for
+ * the mapping that was first put into the map when compared to all the
+ * other objects in the map. This behavior is equivalent to using
+ * <code>getFirst().getValue()</code>, but this method provides a slightly
+ * optimized implementation.
+ *
+ * @return The first value in the sequence, or <code>null</code> if the
+ * map is empty.
+ **/
+ public Object getFirstValue() {
+ // sentinel.next points to the "first" element of the sequence -- the head
+ // of the list -- and the requisite value is returned from it. An empty
+ // list does not need to be tested. In cases where the list is empty,
+ // sentinel.next will point to the sentinel itself which has a null value,
+ // which is exactly what we would want to return if the list is empty (a
+ // nice convient way to avoid test for an empty list)
+ return sentinel.next.getValue();
+ }
+
+ /**
+ * Return the entry for the "newest" mapping. That is, return the Map.Entry
+ * for the key-value pair that was first put into the map when compared to
+ * all the other pairings in the map. The behavior is equivalent to:
+ *
+ * <pre>
+ * Object obj = null;
+ * Iterator iter = entrySet().iterator();
+ * while(iter.hasNext()) {
+ * obj = iter.next();
+ * }
+ * return (Map.Entry)obj;
+ * </pre>
+ *
+ * However, the implementation of this method ensures an O(1) lookup of the
+ * last key rather than O(n).
+ *
+ * @return The last entry in the sequence, or <code>null</code> if the map
+ * is empty.
+ **/
+ public Map.Entry getLast() {
+ // sentinel.prev points to the "last" element of the sequence -- the tail
+ // of the list, which is exactly the entry we need to return. We must test
+ // for an empty list though because we don't want to return the sentinel!
+ return (isEmpty()) ? null : sentinel.prev;
+ }
+
+ /**
+ * Return the key for the "newest" mapping. That is, return the key for the
+ * mapping that was last put into the map when compared to all the other
+ * objects in the map. This behavior is equivalent to using
+ * <code>getLast().getKey()</code>, but this method provides a slightly
+ * optimized implementation.
+ *
+ * @return The last key in the sequence, or <code>null</code> if the map is
+ * empty.
+ **/
+ public Object getLastKey() {
+ // sentinel.prev points to the "last" element of the sequence -- the tail
+ // of the list -- and the requisite key is returned from it. An empty list
+ // does not need to be tested. In cases where the list is empty,
+ // sentinel.prev will point to the sentinel itself which has a null key,
+ // which is exactly what we would want to return if the list is empty (a
+ // nice convient way to avoid test for an empty list)
+ return sentinel.prev.getKey();
+ }
+
+ /**
+ * Return the value for the "newest" mapping. That is, return the value for
+ * the mapping that was last put into the map when compared to all the other
+ * objects in the map. This behavior is equivalent to using
+ * <code>getLast().getValue()</code>, but this method provides a slightly
+ * optimized implementation.
+ *
+ * @return The last value in the sequence, or <code>null</code> if the map
+ * is empty.
+ **/
+ public Object getLastValue() {
+ // sentinel.prev points to the "last" element of the sequence -- the tail
+ // of the list -- and the requisite value is returned from it. An empty
+ // list does not need to be tested. In cases where the list is empty,
+ // sentinel.prev will point to the sentinel itself which has a null value,
+ // which is exactly what we would want to return if the list is empty (a
+ // nice convient way to avoid test for an empty list)
+ return sentinel.prev.getValue();
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#put(Object, Object)}.
+ */
+ public Object put(Object key, Object value) {
+ modCount++;
+
+ Object oldValue = null;
+
+ // lookup the entry for the specified key
+ Entry e = (Entry)entries.get(key);
+
+ // check to see if it already exists
+ if(e != null) {
+ // remove from list so the entry gets "moved" to the end of list
+ removeEntry(e);
+
+ // update value in map
+ oldValue = e.setValue(value);
+
+ // Note: We do not update the key here because its unnecessary. We only
+ // do comparisons using equals(Object) and we know the specified key and
+ // that in the map are equal in that sense. This may cause a problem if
+ // someone does not implement their hashCode() and/or equals(Object)
+ // method properly and then use it as a key in this map.
+ } else {
+ // add new entry
+ e = new Entry(key, value);
+ entries.put(key, e);
+ }
+ // assert(entry in map, but not list)
+
+ // add to list
+ insertEntry(e);
+
+ return oldValue;
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#remove(Object)}.
+ */
+ public Object remove(Object key) {
+ Entry e = removeImpl(key);
+ return (e == null) ? null : e.getValue();
+ }
+
+ /**
+ * Fully remove an entry from the map, returning the old entry or null if
+ * there was no such entry with the specified key.
+ **/
+ private Entry removeImpl(Object key) {
+ Entry e = (Entry)entries.remove(key);
+ if(e == null) return null;
+ modCount++;
+ removeEntry(e);
+ return e;
+ }
+
+ /**
+ * Adds all the mappings in the specified map to this map, replacing any
+ * mappings that already exist (as per [EMAIL PROTECTED] Map#putAll(Map)}).
The order
+ * in which the entries are added is determined by the iterator returned
+ * from [EMAIL PROTECTED] Map#entrySet()} for the specified map.
+ *
+ * @param t the mappings that should be added to this map.
+ *
+ * @exception NullPointerException if <code>t</code> is <code>null</code>
+ **/
+ public void putAll(Map t) {
+ Iterator iter = t.entrySet().iterator();
+ while(iter.hasNext()) {
+ Map.Entry entry = (Map.Entry)iter.next();
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#clear()}.
+ */
+ public void clear() {
+ modCount++;
+
+ // remove all from the underlying map
+ entries.clear();
+
+ // and the list
+ sentinel.next = sentinel;
+ sentinel.prev = sentinel;
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#equals(Object)}.
+ */
+ public boolean equals(Object obj) {
+ if(obj == null) return false;
+ if(obj == this) return true;
+
+ if(!(obj instanceof Map)) return false;
+
+ return entrySet().equals(((Map)obj).entrySet());
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#hashCode()}.
+ */
+ public int hashCode() {
+ return entrySet().hashCode();
+ }
+
+ /**
+ * Provides a string representation of the entries within the map. The
+ * format of the returned string may change with different releases, so this
+ * method is suitable for debugging purposes only. If a specific format is
+ * required, use [EMAIL PROTECTED] #entrySet()[EMAIL PROTECTED]
Set#iterator() iterator()} and
+ * iterate over the entries in the map formatting them as appropriate.
+ **/
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append('[');
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ buf.append(pos.getKey());
+ buf.append('=');
+ buf.append(pos.getValue());
+ if(pos.next != sentinel) {
+ buf.append(',');
+ }
+ }
+ buf.append(']');
+
+ return buf.toString();
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#keySet()}.
+ */
+ public Set keySet() {
+ return new AbstractSet() {
+
+ // required impls
+ public Iterator iterator() { return new OrderedIterator(KEY); }
+ public boolean remove(Object o) {
+ Entry e = SequencedHashMap.this.removeImpl(o);
+ return (e != null);
+ }
+
+ // more efficient impls than abstract set
+ public void clear() {
+ SequencedHashMap.this.clear();
+ }
+ public int size() {
+ return SequencedHashMap.this.size();
+ }
+ public boolean isEmpty() {
+ return SequencedHashMap.this.isEmpty();
+ }
+ public boolean contains(Object o) {
+ return SequencedHashMap.this.containsKey(o);
+ }
+
+ };
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#values()}.
+ */
+ public Collection values() {
+ return new AbstractCollection() {
+ // required impl
+ public Iterator iterator() { return new OrderedIterator(VALUE); }
+ public boolean remove(Object value) {
+ // do null comparison outside loop so we only need to do it once. This
+ // provides a tighter, more efficient loop at the expense of slight
+ // code duplication.
+ if(value == null) {
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ if(pos.getValue() == null) {
+ SequencedHashMap.this.removeImpl(pos.getKey());
+ return true;
+ }
+ }
+ } else {
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ if(value.equals(pos.getValue())) {
+ SequencedHashMap.this.removeImpl(pos.getKey());
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // more efficient impls than abstract collection
+ public void clear() {
+ SequencedHashMap.this.clear();
+ }
+ public int size() {
+ return SequencedHashMap.this.size();
+ }
+ public boolean isEmpty() {
+ return SequencedHashMap.this.isEmpty();
+ }
+ public boolean contains(Object o) {
+ return SequencedHashMap.this.containsValue(o);
+ }
+ };
+ }
+
+ /**
+ * Implements [EMAIL PROTECTED] Map#entrySet()}.
+ */
+ public Set entrySet() {
+ return new AbstractSet() {
+ // helper
+ private Entry findEntry(Object o) {
+ if(o == null) return null;
+ if(!(o instanceof Map.Entry)) return null;
+
+ Map.Entry e = (Map.Entry)o;
+ Entry entry = (Entry)entries.get(e.getKey());
+ if(entry != null && entry.equals(e)) return entry;
+ else return null;
+ }
+
+ // required impl
+ public Iterator iterator() {
+ return new OrderedIterator(ENTRY);
+ }
+ public boolean remove(Object o) {
+ Entry e = findEntry(o);
+ if(e == null) return false;
+
+ return SequencedHashMap.this.removeImpl(e.getKey()) != null;
+ }
+
+ // more efficient impls than abstract collection
+ public void clear() {
+ SequencedHashMap.this.clear();
+ }
+ public int size() {
+ return SequencedHashMap.this.size();
+ }
+ public boolean isEmpty() {
+ return SequencedHashMap.this.isEmpty();
+ }
+ public boolean contains(Object o) {
+ return findEntry(o) != null;
+ }
+ };
+ }
+
+ // constants to define what the iterator should return on "next"
+ private static final int KEY = 0;
+ private static final int VALUE = 1;
+ private static final int ENTRY = 2;
+ private static final int REMOVED_MASK = 0x80000000;
+
+ private class OrderedIterator implements Iterator {
+ /**
+ * Holds the type that should be returned from the iterator. The value
+ * should be either [EMAIL PROTECTED] #KEY}, [EMAIL PROTECTED] #VALUE},
or [EMAIL PROTECTED] #ENTRY}. To
+ * save a tiny bit of memory, this field is also used as a marker for when
+ * remove has been called on the current object to prevent a second remove
+ * on the same element. Essientially, if this value is negative (i.e. the
+ * bit specified by [EMAIL PROTECTED] #REMOVED_MASK} is set), the current
position
+ * has been removed. If positive, remove can still be called.
+ **/
+ private int returnType;
+
+ /**
+ * Holds the "current" position in the iterator. When pos.next is the
+ * sentinel, we've reached the end of the list.
+ **/
+ private Entry pos = sentinel;
+
+ /**
+ * Holds the expected modification count. If the actual modification
+ * count of the map differs from this value, then a concurrent
+ * modification has occurred.
+ **/
+ private transient long expectedModCount = modCount;
+
+ /**
+ * Construct an iterator over the sequenced elements in the order in which
+ * they were added. The [EMAIL PROTECTED] #next()} method returns the
type specified
+ * by <code>returnType</code> which must be either [EMAIL PROTECTED]
#KEY}, [EMAIL PROTECTED]
+ * #VALUE}, or [EMAIL PROTECTED] #ENTRY}.
+ **/
+ public OrderedIterator(int returnType) {
+ //// Since this is a private inner class, nothing else should have
+ //// access to the constructor. Since we know the rest of the outer
+ //// class uses the iterator correctly, we can leave of the following
+ //// check:
+ //if(returnType >= 0 && returnType <= 2) {
+ // throw new IllegalArgumentException("Invalid iterator type");
+ //}
+
+ // Set the "removed" bit so that the iterator starts in a state where
+ // "next" must be called before "remove" will succeed.
+ this.returnType = returnType | REMOVED_MASK;
+ }
+
+ /**
+ * Returns whether there is any additional elements in the iterator to be
+ * returned.
+ *
+ * @return <code>true</code> if there are more elements left to be
+ * returned from the iterator; <code>false</code> otherwise.
+ **/
+ public boolean hasNext() {
+ return pos.next != sentinel;
+ }
+
+ /**
+ * Returns the next element from the iterator.
+ *
+ * @return the next element from the iterator.
+ *
+ * @exception NoSuchElementException if there are no more elements in the
+ * iterator.
+ *
+ * @exception ConcurrentModificationException if a modification occurs in
+ * the underlying map.
+ **/
+ public Object next() {
+ if(modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ if(pos.next == sentinel) {
+ throw new NoSuchElementException();
+ }
+
+ // clear the "removed" flag
+ returnType = returnType & ~REMOVED_MASK;
+
+ pos = pos.next;
+ switch(returnType) {
+ case KEY:
+ return pos.getKey();
+ case VALUE:
+ return pos.getValue();
+ case ENTRY:
+ return pos;
+ default:
+ // should never happen
+ throw new Error("bad iterator type: " + returnType);
+ }
+
+ }
+
+ /**
+ * Removes the last element returned from the [EMAIL PROTECTED] #next()}
method from
+ * the sequenced map.
+ *
+ * @exception IllegalStateException if there isn't a "last element" to be
+ * removed. That is, if [EMAIL PROTECTED] #next()} has never been
called, or if
+ * [EMAIL PROTECTED] #remove()} was already called on the element.
+ *
+ * @exception ConcurrentModificationException if a modification occurs in
+ * the underlying map.
+ **/
+ public void remove() {
+ if((returnType & REMOVED_MASK) != 0) {
+ throw new IllegalStateException("remove() must follow next()");
+ }
+ if(modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+
+ SequencedHashMap.this.removeImpl(pos.getKey());
+
+ // update the expected mod count for the remove operation
+ expectedModCount++;
+
+ // set the removed flag
+ returnType = returnType | REMOVED_MASK;
+ }
+ }
+
+ // APIs maintained from previous version of SequencedHashMap for backwards
+ // compatibility
+
+ /**
+ * Creates a shallow copy of this object, preserving the internal structure
+ * by copying only references. The keys and values themselves are not
+ * <code>clone()</code>'d. The cloned object maintains the same sequence.
+ *
+ * @return A clone of this instance.
+ *
+ * @exception CloneNotSupportedException if clone is not supported by a
+ * subclass.
+ */
+ public Object clone () throws CloneNotSupportedException {
+ // yes, calling super.clone() silly since we're just blowing away all
+ // the stuff that super might be doing anyway, but for motivations on
+ // this, see:
+ // http://www.javaworld.com/javaworld/jw-01-1999/jw-01-object.html
+ SequencedHashMap map = (SequencedHashMap)super.clone();
+
+ // create new, empty sentinel
+ map.sentinel = createSentinel();
+
+ // create a new, empty entry map
+ // note: this does not preserve the initial capacity and load factor.
+ map.entries = new HashMap();
+
+ // add all the mappings
+ map.putAll(this);
+
+ // Note: We cannot just clone the hashmap and sentinel because we must
+ // duplicate our internal structures. Cloning those two will not clone all
+ // the other entries they reference, and so the cloned hash map will not be
+ // able to maintain internal consistency because there are two objects with
+ // the same entries. See discussion in the Entry implementation on why we
+ // cannot implement a clone of the Entry (and thus why we need to recreate
+ // everything).
+
+ return map;
+ }
+
+ /**
+ * Returns the Map.Entry at the specified index
+ *
+ * @exception ArrayIndexOutOfBoundsException if the specified index is
+ * <code>< 0</code> or <code>></code> the size of the map.
+ **/
+ private Map.Entry getEntry(int index) {
+ Entry pos = sentinel;
+
+ if(index < 0) {
+ throw new ArrayIndexOutOfBoundsException(index + " < 0");
+ }
+
+ // loop to one before the position
+ int i = -1;
+ while(i < (index-1) && pos.next != sentinel) {
+ i++;
+ pos = pos.next;
+ }
+ // pos.next is the requested position
+
+ // if sentinel is next, past end of list
+ if(pos.next == sentinel) {
+ throw new ArrayIndexOutOfBoundsException(index + " >= " + (i + 1));
+ }
+
+ return pos.next;
+ }
+
+ /**
+ * Returns the key at the specified index.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the <code>index</code> is
+ * <code>< 0</code> or <code>></code> the size of the map.
+ */
+ public Object get (int index)
+ {
+ return getEntry(index).getKey();
+ }
+
+ /**
+ * Returns the value at the specified index.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the <code>index</code> is
+ * <code>< 0</code> or <code>></code> the size of the map.
+ */
+ public Object getValue (int index)
+ {
+ return getEntry(index).getValue();
+ }
+
+ /**
+ * Returns the index of the specified key.
+ */
+ public int indexOf (Object key)
+ {
+ Entry e = (Entry)entries.get(key);
+ int pos = 0;
+ while(e.prev != sentinel) {
+ pos++;
+ e = e.prev;
+ }
+ return pos;
+ }
+
+ /**
+ * Returns a key iterator.
+ */
+ public Iterator iterator ()
+ {
+ return keySet().iterator();
+ }
+
+ /**
+ * Returns the last index of the specified key.
+ */
+ public int lastIndexOf (Object key)
+ {
+ // keys in a map are guarunteed to be unique
+ return indexOf(key);
+ }
+
+ /**
+ * Returns a List view of the keys rather than a set view. The returned
+ * list is unmodifiable. This is required because changes to the values of
+ * the list (using [EMAIL PROTECTED] java.util.ListIterator#set(Object)})
will
+ * effectively remove the value from the list and reinsert that value at
+ * the end of the list, which is an unexpected side effect of changing the
+ * value of a list. This occurs because changing the key, changes when the
+ * mapping is added to the map and thus where it appears in the list.
+ *
+ * <P>An alternative to this method is to use [EMAIL PROTECTED] #keySet()}
+ *
+ * @see #keySet()
+ * @return The ordered list of keys.
+ */
+ public List sequence()
+ {
+ List l = new ArrayList(size());
+ Iterator iter = keySet().iterator();
+ while(iter.hasNext()) {
+ l.add(iter.next());
+ }
+
+ return Collections.unmodifiableList(l);
+ }
+
+ /**
+ * Removes the element at the specified index.
+ *
+ * @param index The index of the object to remove.
+ * @return The previous value coressponding the <code>key</code>, or
+ * <code>null</code> if none existed.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the <code>index</code> is
+ * <code>< 0</code> or <code>></code> the size of the map.
+ */
+ public Object remove (int index)
+ {
+ return remove(get(index));
+ }
+
+ // per Externalizable.readExternal(ObjectInput)
+
+ /**
+ * Deserializes this map from the given stream.
+ *
+ * @param in the stream to deserialize from
+ * @throws IOException if the stream raises it
+ * @throws ClassNotFoundException if the stream raises it
+ */
+ public void readExternal( ObjectInput in )
+ throws IOException, ClassNotFoundException
+ {
+ int size = in.readInt();
+ for(int i = 0; i < size; i++) {
+ Object key = in.readObject();
+ Object value = in.readObject();
+ put(key, value);
+ }
+ }
+
+ /**
+ * Serializes this map to the given stream.
+ *
+ * @param out the stream to serialize to
+ * @throws IOException if the stream raises it
+ */
+ public void writeExternal( ObjectOutput out ) throws IOException {
+ out.writeInt(size());
+ for(Entry pos = sentinel.next; pos != sentinel; pos = pos.next) {
+ out.writeObject(pos.getKey());
+ out.writeObject(pos.getValue());
+ }
+ }
+
+ // add a serial version uid, so that if we change things in the future
+ // without changing the format, we can still deserialize properly.
+ private static final long serialVersionUID = 3380552487888102930L;
+
+}
Propchange:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SequencedHashMap.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SharedPoolDataSource.java
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SharedPoolDataSource.java?view=diff&rev=449319&r1=449318&r2=449319
==============================================================================
---
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SharedPoolDataSource.java
(original)
+++
jakarta/commons/proper/dbcp/trunk/src/java/org/apache/commons/dbcp/datasources/SharedPoolDataSource.java
Sat Sep 23 15:27:06 2006
@@ -27,7 +27,6 @@
import javax.naming.StringRefAddr;
import javax.sql.ConnectionPoolDataSource;
-import org.apache.commons.collections.LRUMap;
import org.apache.commons.pool.KeyedObjectPool;
import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.commons.pool.impl.GenericObjectPool;
Modified: jakarta/commons/proper/dbcp/trunk/xdocs/changes.xml
URL:
http://svn.apache.org/viewvc/jakarta/commons/proper/dbcp/trunk/xdocs/changes.xml?view=diff&rev=449319&r1=449318&r2=449319
==============================================================================
--- jakarta/commons/proper/dbcp/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/dbcp/trunk/xdocs/changes.xml Sat Sep 23 15:27:06 2006
@@ -145,6 +145,11 @@
connection after validation when this property is set to true to
eliminate
Oracle driver exceptions. Default property value is false.
</action>
+ <action dev="psteitz" type="update" issue="DBCP-68">
+ Removed dependency on Commons Collections by adding collections
+ 2.1 sources for LRUMap and SequencedHashMap with package scope to
+ datasources package.
+ </action>
</release>
<release version="1.2.1" date="2004-06-12" description="Maintenance
Release to restore JDK 1.3 compatibility">
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]