Added new Map implementations and Closure classes

git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@130471 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James Strachan 2001-05-06 11:04:25 +00:00
parent 963757362a
commit 485615107d
15 changed files with 2004 additions and 4 deletions

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Iterator;
/** Implements {@link Iterator} over an array of objects
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
* @version $Revision: 1.1 $
*/
public class ArrayIterator implements Iterator {
private Object[] array;
private int index = -1;
public ArrayIterator() {
}
public ArrayIterator(Object[] array) {
this.array = array;
}
// Iterator interface
//-------------------------------------------------------------------------
public boolean hasNext() {
return ++index >= 0 && index < array.length;
}
public Object next() {
return array[ index ];
}
public void remove() {
throw new UnsupportedOperationException( "remove() method is not supported" );
}
// Properties
//-------------------------------------------------------------------------
public Object[] getArray() {
return array;
}
public void setArray( Object[] array ) {
this.array = array;
this.index = -1;
}
}

View File

@ -0,0 +1,423 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/** An implementation of Map for JavaBeans which uses introspection to
* get and put properties in the bean.
*
* If an exception occurs during attempts to get or set a property then the
* property is considered non existent in the Map
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class BeanMap extends AbstractMap {
private Object bean;
private HashMap readMethods = new HashMap();
private HashMap writeMethods = new HashMap();
private HashMap types = new HashMap();
public static final Object[] NULL_ARGUMENTS = {};
public static HashMap defaultTransformers = new HashMap();
static {
defaultTransformers.put(
Boolean.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Boolean.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Character.TYPE,
new Transformer() {
public Object transform( Object input ) {
return new Character( input.toString().charAt( 0 ) );
}
}
);
defaultTransformers.put(
Byte.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Byte.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Short.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Short.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Integer.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Integer.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Long.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Long.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Float.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Float.valueOf( input.toString() );
}
}
);
defaultTransformers.put(
Double.TYPE,
new Transformer() {
public Object transform( Object input ) {
return Double.valueOf( input.toString() );
}
}
);
}
// Constructors
//-------------------------------------------------------------------------
public BeanMap() {
}
public BeanMap(Object bean) {
this.bean = bean;
initialise();
}
// Map interface
//-------------------------------------------------------------------------
public Object clone() {
Class beanClass = bean.getClass();
try {
Object newBean = beanClass.newInstance();
Map newMap = new BeanMap( newBean );
newMap.putAll( this );
return newMap;
}
catch (Exception e) {
throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass );
}
}
public void clear() {
Class beanClass = bean.getClass();
try {
bean = beanClass.newInstance();
}
catch (Exception e) {
throw new UnsupportedOperationException( "Could not create new instance of class: " + beanClass );
}
}
public boolean containsKey(String name) {
Method method = getReadMethod( name );
return method != null;
}
public boolean containsValue(Object value) {
// use default implementation
return super.containsValue( value );
}
public Object get(Object name) {
if ( bean != null ) {
Method method = getReadMethod( name );
if ( method != null ) {
try {
return method.invoke( bean, NULL_ARGUMENTS );
}
catch ( IllegalAccessException e ) {
logWarn( e );
}
catch ( IllegalArgumentException e ) {
logWarn( e );
}
catch ( InvocationTargetException e ) {
logWarn( e );
}
catch ( NullPointerException e ) {
logWarn( e );
}
}
}
return null;
}
public Object put(Object name, Object value) throws IllegalArgumentException, ClassCastException {
if ( bean != null ) {
Object oldValue = get( name );
Method method = getWriteMethod( name );
if ( method == null ) {
throw new IllegalArgumentException( "The bean of type: "+ bean.getClass().getName() + " has no property called: " + name );
}
try {
Object[] arguments = createWriteMethodArguments( method, value );
method.invoke( bean, arguments );
Object newValue = get( name );
firePropertyChange( name, oldValue, newValue );
}
catch ( InvocationTargetException e ) {
logInfo( e );
throw new IllegalArgumentException( e.getMessage() );
}
catch ( IllegalAccessException e ) {
logInfo( e );
throw new IllegalArgumentException( e.getMessage() );
}
return oldValue;
}
return null;
}
public int size() {
return readMethods.size();
}
public Set keySet() {
return readMethods.keySet();
}
public Set entrySet() {
return readMethods.keySet();
}
public Collection values() {
ArrayList answer = new ArrayList( readMethods.size() );
for ( Iterator iter = valueIterator(); iter.hasNext(); ) {
answer.add( iter.next() );
}
return answer;
}
// Helper methods
//-------------------------------------------------------------------------
public Class getType(String name) {
return (Class) types.get( name );
}
public Iterator keyIterator() {
return readMethods.keySet().iterator();
}
public Iterator valueIterator() {
final Iterator iter = keyIterator();
return new Iterator() {
public boolean hasNext() {
return iter.hasNext();
}
public Object next() {
Object key = iter.next();
return get( (String) key );
}
public void remove() {
throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
}
};
}
public Iterator entryIterator() {
final Iterator iter = keyIterator();
return new Iterator() {
public boolean hasNext() {
return iter.hasNext();
}
public Object next() {
Object key = iter.next();
Object value = get( (String) key );
return new MyMapEntry( BeanMap.this, key, value );
}
public void remove() {
throw new UnsupportedOperationException( "remove() not supported for BeanMap" );
}
};
}
// Properties
//-------------------------------------------------------------------------
public Object getBean() {
return bean;
}
public void setBean( Object newBean ) {
bean = newBean;
reinitialise();
}
// Implementation methods
//-------------------------------------------------------------------------
protected Method getReadMethod( Object name ) {
return (Method) readMethods.get( name );
}
protected Method getWriteMethod( Object name ) {
return (Method) writeMethods.get( name );
}
protected void reinitialise() {
readMethods.clear();
writeMethods.clear();
types.clear();
initialise();
}
private void initialise() {
Class beanClass = getBean().getClass();
try {
//BeanInfo beanInfo = Introspector.getBeanInfo( bean, null );
BeanInfo beanInfo = Introspector.getBeanInfo( beanClass );
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
if ( propertyDescriptors != null ) {
for ( int i = 0; i < propertyDescriptors.length; i++ ) {
PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
if ( propertyDescriptor != null ) {
String name = propertyDescriptor.getName();
Method readMethod = propertyDescriptor.getReadMethod();
Method writeMethod = propertyDescriptor.getWriteMethod();
Class aType = propertyDescriptor.getPropertyType();
if ( readMethod != null ) {
readMethods.put( name, readMethod );
}
if ( writeMethods != null ) {
writeMethods.put( name, writeMethod );
}
types.put( name, aType );
}
}
}
}
catch ( IntrospectionException e ) {
logWarn( e );
}
}
protected void firePropertyChange( Object key, Object oldValue, Object newValue ) {
}
// Implementation classes
//-------------------------------------------------------------------------
protected static class MyMapEntry extends DefaultMapEntry {
private BeanMap owner;
protected MyMapEntry( BeanMap owner, Object key, Object value ) {
super( key, value );
this.owner = owner;
}
public Object setValue(Object value) {
Object key = getKey();
Object oldValue = owner.get( key );
owner.put( key, value );
Object newValue = owner.get( key );
super.setValue( newValue );
return oldValue;
}
}
protected Object[] createWriteMethodArguments( Method method, Object value ) throws IllegalAccessException, ClassCastException {
try {
if ( value != null ) {
Class[] types = method.getParameterTypes();
if ( types != null && types.length > 0 ) {
Class paramType = types[0];
if ( ! paramType.isAssignableFrom( value.getClass() ) ) {
value = convertType( paramType, value );
}
}
}
Object[] answer = { value };
return answer;
}
catch ( InvocationTargetException e ) {
logInfo( e );
throw new IllegalArgumentException( e.getMessage() );
}
catch ( InstantiationException e ) {
logInfo( e );
throw new IllegalArgumentException( e.getMessage() );
}
}
protected Object convertType( Class newType, Object value )
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// try call constructor
Class[] types = { value.getClass() };
try {
Constructor constructor = newType.getConstructor( types );
Object[] arguments = { value };
return constructor.newInstance( arguments );
}
catch ( NoSuchMethodException e ) {
// try using the transformers
Transformer transformer = getTypeTransformer( newType );
if ( transformer != null ) {
return transformer.transform( value );
}
return value;
}
}
protected Transformer getTypeTransformer( Class aType ) {
return (Transformer) defaultTransformers.get( aType );
}
protected void logInfo(Exception e) {
// XXXX: should probably use log4j here instead...
System.out.println( "INFO: Exception: " + e );
}
protected void logWarn(Exception e) {
// XXXX: should probably use log4j here instead...
System.out.println( "WARN: Exception: " + e );
e.printStackTrace();
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
/** An interface to represent some Closure, a block of code which is executed
* from inside some block, function or iteration which operates on an input
* object.
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public interface Closure {
/** Performs some operation on the input object
*/
public void execute(Object input);
}

View File

@ -1,7 +1,7 @@
/*
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/CollectionUtils.java,v 1.2 2001/05/04 16:32:17 rwaldhoff Exp $
* $Revision: 1.2 $
* $Date: 2001/05/04 16:32:17 $
* $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/CollectionUtils.java,v 1.3 2001/05/06 11:04:25 jstrachan Exp $
* $Revision: 1.3 $
* $Date: 2001/05/06 11:04:25 $
*
* ====================================================================
*
@ -63,6 +63,7 @@ package org.apache.commons.collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@ -75,7 +76,7 @@ import java.util.Set;
*
* @author Rodney Waldhoff
*
* @version $Id: CollectionUtils.java,v 1.2 2001/05/04 16:32:17 rwaldhoff Exp $
* @version $Id: CollectionUtils.java,v 1.3 2001/05/06 11:04:25 jstrachan Exp $
*/
public class CollectionUtils {
/**
@ -283,6 +284,132 @@ public class CollectionUtils {
return count;
}
/** Finds the first element in the given collection which matches the given predicate
*
* @return the first element of the collection which matches the predicate or null if none could be found
*/
public static Object find( Collection collection, Predicate predicate ) {
if ( collection != null && predicate != null ) {
for ( Iterator iter = collection.iterator(); iter.hasNext(); ) {
Object item = iter.next();
if ( predicate.evaluate( item ) ) {
return item;
}
}
}
return null;
}
/** Executes the given closure on each element in the colleciton
*/
public static void forAllDo( Collection collection, Closure closure) {
if ( collection != null ) {
for ( Iterator iter = collection.iterator(); iter.hasNext(); ) {
Object element = iter.next();
closure.execute( element );
}
}
}
/** Selects all elements from inputCollection which match the given predicate
* into an output collection
*/
public static Collection select( Collection inputCollection, Predicate predicate ) {
ArrayList answer = new ArrayList( inputCollection.size() );
select( inputCollection, predicate, answer );
return answer;
}
/** Selects all elements from inputCollection which match the given predicate
* and adds them to outputCollection
*
* @return the outputCollection
*/
public static Collection select( Collection inputCollection, Predicate predicate, Collection outputCollection ) {
if ( inputCollection != null && predicate != null ) {
for ( Iterator iter = inputCollection.iterator(); iter.hasNext(); ) {
Object item = iter.next();
if ( predicate.evaluate( item ) ) {
outputCollection.add( item );
}
}
}
return outputCollection;
}
/** Transforms all elements from inputCollection with the given transformer
* and adds them to the outputCollection
*/
public static Collection collect( Collection inputCollection, Transformer transformer ) {
ArrayList answer = new ArrayList( inputCollection.size() );
collect( inputCollection, transformer, answer );
return answer;
}
/** Transforms all elements from the inputIterator with the given transformer
* and adds them to the outputCollection
*/
public static Collection collect( Iterator inputIterator, Transformer transformer ) {
ArrayList answer = new ArrayList();
collect( inputIterator, transformer, answer );
return answer;
}
/** Transforms all elements from inputCollection with the given transformer
* and adds them to the outputCollection
*
* @return the outputCollection
*/
public static Collection collect( Collection inputCollection, final Transformer transformer, final Collection outputCollection ) {
if ( inputCollection != null ) {
return collect( inputCollection.iterator(), transformer, outputCollection );
}
return outputCollection;
}
/** Transforms all elements from the inputIterator with the given transformer
* and adds them to the outputCollection
*
* @return the outputCollection
*/
public static Collection collect( Iterator inputIterator, final Transformer transformer, final Collection outputCollection ) {
if ( inputIterator != null && transformer != null ) {
while ( inputIterator.hasNext() ) {
Object item = inputIterator.next();
Object value = transformer.transform( item );
outputCollection.add( value );
}
}
return outputCollection;
}
/** Adds all elements in the iteration to the given collection
*/
public static void addAll( Collection collection, Iterator iterator ) {
while ( iterator.hasNext() ) {
collection.add( iterator.next() );
}
}
/** Adds all elements in the enumeration to the given collection
*/
public static void addAll( Collection collection, Enumeration enumeration ) {
while ( enumeration.hasMoreElements() ) {
collection.add( enumeration.nextElement() );
}
}
/** Adds all elements in the array to the given collection
*/
public static void addAll( Collection collection, Object[] elements ) {
for ( int i = 0, size = elements.length; i < size; i++ ) {
collection.add( elements[i] );
}
}
private static final int getFreq(final Object obj, final Map freqMap) {
try {
return ((Integer)(freqMap.get(obj))).intValue();

View File

@ -0,0 +1,97 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.*;
/** A default implementation of {@link Map.Entry Map.Entry}
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class DefaultMapEntry implements Map.Entry {
private Object key;
private Object value;
protected static final int HASH_CODE_SEED = 123456789;
public DefaultMapEntry() {
}
public DefaultMapEntry(Object key, Object value) {
this.key = key;
this.value = value;
}
public boolean equals(Object o) {
if ( ! (o instanceof DefaultMapEntry ) )
return false;
DefaultMapEntry that = (DefaultMapEntry) o;
if ( ( this.key == null && that.key == null )
|| ( this.key != null && this.key.equals( that.key ) ) )
{
if ( ( this.value == null && that.value == null )
|| ( this.value != null && this.value.equals( that.value ) ) )
{
return true;
}
}
return false;
}
public boolean equals( DefaultMapEntry that ) {
if ( ( key == null && that.key == null ) || ( key != null && key.equals( that.key ) ) ) {
return ( value == null && value == null ) || ( value != null && value.equals( that.value ) );
}
return false;
}
public int hashCode() {
int answer = HASH_CODE_SEED;
if ( key != null ) {
answer ^= key.hashCode();
}
if ( value != null ) {
answer ^= value.hashCode();
}
return answer;
}
// Map.Entry interface
//-------------------------------------------------------------------------
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
// Properties
//-------------------------------------------------------------------------
public void setKey(Object key) {
this.key = key;
}
/** Note that this method only sets the local reference inside this object and
* does not modify the original Map.
*
* @return the old value of the value
* @param value the new value
*/
public Object setValue(Object value) {
Object answer = this.value;
this.value = value;
return answer;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Enumeration;
import java.util.Iterator;
/** Adapter to make {@link Enumeration Enumeration} instances appear to be {@link Iterator Iterator} instances
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class EnumerationIterator implements Iterator {
private Enumeration enumeration;
public EnumerationIterator() {
}
public EnumerationIterator( Enumeration enumeration ) {
this.enumeration = enumeration;
}
// Iterator interface
//-------------------------------------------------------------------------
public boolean hasNext() {
return enumeration.hasMoreElements();
}
public Object next() {
return enumeration.nextElement();
}
public void remove() {
throw new UnsupportedOperationException( "remove() method is not supported" );
}
// Properties
//-------------------------------------------------------------------------
public Enumeration getEnumeration() {
return enumeration;
}
public void setEnumeration( Enumeration enumeration ) {
this.enumeration = enumeration;
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Enumeration;
import java.util.Iterator;
/** A Proxy {@link Iterator Iterator} which takes a {@link Predicate Predicate} instance to filter
* out objects from an underlying {@link Iterator Iterator} instance.
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class FilterIterator extends ProxyIterator {
/** Holds value of property predicate. */
private Predicate predicate;
private Object nextObject;
//-------------------------------------------------------------------------
public FilterIterator() {
}
public FilterIterator( Iterator iterator ) {
super( iterator );
}
public FilterIterator( Iterator iterator, Predicate predicate ) {
super( iterator );
this.predicate = predicate;
}
// Iterator interface
//-------------------------------------------------------------------------
public boolean hasNext() {
Iterator iterator = getIterator();
Predicate predicate = getPredicate();
while ( iterator.hasNext() ) {
Object object = iterator.next();
if ( predicate.evaluate( object ) ) {
nextObject = object;
return true;
}
}
return false;
}
public Object next() {
return nextObject;
}
// Properties
//-------------------------------------------------------------------------
/** Getter for property predicate.
* @return Value of property predicate.
*/
public Predicate getPredicate() {
return predicate;
}
/** Setter for property predicate.
* @param predicate New value of property predicate.
*/
public void setPredicate(Predicate predicate) {
this.predicate = predicate;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Enumeration;
import java.util.Iterator;
/** Adapter to make an {@link Iterator Iterator} instance appear to be an {@link Enumeration Enumeration} instances
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class IteratorEnumeration implements Enumeration {
private Iterator iterator;
public IteratorEnumeration() {
}
public IteratorEnumeration( Iterator iterator ) {
this.iterator = iterator;
}
// Iterator interface
//-------------------------------------------------------------------------
public boolean hasMoreElements() {
return iterator.hasNext();
}
public Object nextElement() {
return iterator.next();
}
// Properties
//-------------------------------------------------------------------------
public Iterator getIterator() {
return iterator;
}
public void setIterator( Iterator iterator ) {
this.iterator = iterator;
}
}

View File

@ -0,0 +1,300 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.io.*;
import java.util.*;
/** <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>
* This implementation uses a simple bubbling
* algorithm, whereby every random access get() method call bubbles the item
* up the list, further away from the 'drop zone'.
* </p>
*
* <p>
* A synchronized version can be obtained with:
* <code>Collections.synchronizedMap( theMapToSynchronize )</code>
* </p>
*
* <p>
* <b>WARNING</b> the values() and entrySet() methods require optimisation
* like the standard {@link HashMap} implementations so that iteration
* over this Map is efficient.
* </p>
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class LRUMap extends HashMap implements Externalizable {
/** Holds value of property maximumSize. */
private int maximumSize;
/** Used to hold the bubble list - bubbles keys up the list as they are accessed */
private ArrayList bubbleList;
//static final long serialVersionUID = 0x9e1e06764b24cb05L;
public LRUMap() {
this( 100 );
}
public LRUMap(int i) {
super( i );
maximumSize = i;
bubbleList = new ArrayList( i );
}
/** Removes the least recently used object from the Map.
* @return the key of the removed item
*/
public Object removeLRU() {
int lastItem = size();
Object key = bubbleList.remove( lastItem );
ValuePositionPair pair = removePair( key );
return key;
}
// Map interface
//-------------------------------------------------------------------------
public Object get( Object key ) {
ValuePositionPair pair = getPair( key );
if ( pair == null ) {
return null;
}
int position = pair.position;
if ( position > 0 ) {
// lets bubble up this entry up the list
// avoiding expesive list removal / insertion
int position2 = position - 1;
Object key2 = bubbleList.get( position2 );
ValuePositionPair pair2 = getPair( key2 );
if ( pair2 != null ) {
pair2.position = position;
pair.position = position2;
bubbleList.set( position, key2 );
bubbleList.set( position2, key );
}
}
return pair.value;
}
public Object put( Object key, Object value ) {
int i = size();
ValuePositionPair pair = new ValuePositionPair( value );
if ( i >= maximumSize ) {
// lets retire the least recently used item in the cache
int lastIndex = maximumSize - 1;
pair.position = lastIndex;
Object oldKey = bubbleList.set( lastIndex, key );
super.remove( oldKey );
}
else {
pair.position = i;
bubbleList.add( i, key );
}
pair = (ValuePositionPair) putPair( key, pair );
return ( pair != null ) ? pair.value : null;
}
public Object remove( Object key ) {
ValuePositionPair pair = removePair( key );
return ( pair != null ) ? pair.value : null;
}
public boolean containsKey( Object key ) {
return super.containsKey( key );
}
public boolean containsValue( Object value ) {
for ( Iterator iter = pairIterator(); iter.hasNext(); ) {
ValuePositionPair pair = (ValuePositionPair) iter.next();
Object otherValue = pair.value;
if ( value == otherValue ) {
return true;
}
if ( value != null && value.equals( otherValue ) ) {
return true;
}
}
return false;
}
public Set keySet() {
return super.keySet();
}
public Set entrySet() {
HashSet answer = new HashSet();
for ( Iterator iter = super.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry otherEntry = (Map.Entry) iter.next();
Object key = otherEntry.getKey();
ValuePositionPair pair = (ValuePositionPair) otherEntry.getValue();
Object value = pair.value;
Entry newEntry = new Entry( key, value );
answer.add( newEntry );
}
return answer;
}
public Collection values() {
ArrayList answer = new ArrayList();
for ( Iterator iter = super.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry otherEntry = (Map.Entry) iter.next();
Entry newEntry = new Entry( otherEntry.getKey(), otherEntry.getValue() );
answer.add( newEntry );
}
return answer;
}
// Externalizable interface
//-------------------------------------------------------------------------
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
maximumSize = in.readInt();
int size = in.readInt();
// create a populated list
bubbleList = new ArrayList( maximumSize );
for( int i = 0; i < size; i++ ) {
bubbleList.add( "" );
}
for( int i = 0; i < size; i++ ) {
Object key = in.readObject();
Object value = in.readObject();
ValuePositionPair pair = (ValuePositionPair) value;
int position = pair.position;
bubbleList.set( position, pair );
putPair( key, pair );
}
}
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 );
Object value = getPair( 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;
}
// Implementation methods
//-------------------------------------------------------------------------
protected ValuePositionPair getPair( Object key ) {
return (ValuePositionPair) super.get( key );
}
protected ValuePositionPair putPair( Object key, ValuePositionPair pair ) {
return (ValuePositionPair) super.put( key, pair );
}
protected ValuePositionPair removePair( Object key ) {
return (ValuePositionPair) super.remove( key );
}
protected Iterator pairIterator() {
return super.values().iterator();
}
// Implementation classes
//-------------------------------------------------------------------------
protected static class ValuePositionPair implements Serializable {
public Object value;
public int position;
public ValuePositionPair() {
}
public ValuePositionPair( Object value ) {
this.value = value;
}
public String toString() {
return "[ " + position + ": " + value + " ]";
}
}
/**
* A map entry, which is backed by this RefHashMap
*/
class Entry implements Map.Entry {
/**
* Constructor
*/
public Entry( Object key, Object value ) {
this.key = key;
this.value = value;
}
// Map.Entry interface
// -----------------------------------------------------------
/**
* Retrieves the key of this mapping
*/
public Object getKey() {
return key;
}
/**
* Retrieves the value of this mapping
*/
public Object getValue() {
return value;
}
/**
* Sets the value of this mapping
*/
public Object setValue( Object value ) {
this.value = value;
put( key, value );
return value;
}
/**
* Return the hash code of this mapping.
* This algorithm was taken from the JavaDoc for Map.Entry
*/
public int hashCode() {
return ( getKey() == null ? 0 : getKey().hashCode() ) ^
( getValue() == null ? 0 : getValue().hashCode() );
}
/** The domain of this mapping */
private Object key;
/** The range of this mapping */
private Object value;
}
}

View File

@ -0,0 +1,347 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.io.*;
import java.text.*;
import java.util.*;
/** A helper class for using {@link Map Map} instances.
*
* It contains various typesafe methods
* as well as other useful features like deep copying
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class MapUtils {
private static int debugIndent = 0;
// Type safe getters
//-------------------------------------------------------------------------
public static Object getObject( Map map, Object key ) {
if ( map != null ) {
return map.get( key );
}
return null;
}
public static String getString( Map map, Object key ) {
if ( map != null ) {
Object answer = map.get( key );
if ( answer != null ) {
return answer.toString();
}
}
return null;
}
public static Boolean getBoolean( Map map, Object key ) {
if ( map != null ) {
Object answer = map.get( key );
if ( answer != null ) {
if ( answer instanceof Boolean ) {
return (Boolean) answer;
}
else
if ( answer instanceof String ) {
return new Boolean( (String) answer );
}
else
if ( answer instanceof Number ) {
Number n = (Number) answer;
return ( n.intValue() != 0 ) ? Boolean.TRUE : Boolean.FALSE;
}
}
}
return null;
}
public static Number getNumber( Map map, Object key ) {
if ( map != null ) {
Object answer = map.get( key );
if ( answer != null ) {
if ( answer instanceof Number ) {
return (Number) answer;
}
else
if ( answer instanceof String ) {
try {
String text = (String) answer;
return NumberFormat.getInstance().parse( text );
}
catch (ParseException e) {
logInfo( e );
}
}
}
}
return null;
}
public static Byte getByte( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Byte ) {
return (Byte) answer;
}
return new Byte( answer.byteValue() );
}
public static Short getShort( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Short ) {
return (Short) answer;
}
return new Short( answer.shortValue() );
}
public static Integer getInteger( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Integer ) {
return (Integer) answer;
}
return new Integer( answer.intValue() );
}
public static Long getLong( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Long ) {
return (Long) answer;
}
return new Long( answer.longValue() );
}
public static Float getFloat( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Float ) {
return (Float) answer;
}
return new Float( answer.floatValue() );
}
public static Double getDouble( Map map, Object key ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
return null;
}
else
if ( answer instanceof Double ) {
return (Double) answer;
}
return new Double( answer.doubleValue() );
}
public static Map getMap( Map map, Object key ) {
if ( map != null ) {
Object answer = map.get( key );
if ( answer != null && answer instanceof Map ) {
return (Map) answer;
}
}
return null;
}
// Type safe getters with default values
//-------------------------------------------------------------------------
public static Object getObject( Map map, Object key, Object defaultValue ) {
if ( map != null ) {
Object answer = map.get( key );
if ( answer != null ) {
return answer;
}
}
return defaultValue;
}
public static String getString( Map map, Object key, String defaultValue ) {
String answer = getString( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Boolean getBoolean( Map map, Object key, Boolean defaultValue ) {
Boolean answer = getBoolean( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Number getNumber( Map map, Object key, Number defaultValue ) {
Number answer = getNumber( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Byte getByte( Map map, Object key, Byte defaultValue ) {
Byte answer = getByte( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Short getShort( Map map, Object key, Short defaultValue ) {
Short answer = getShort( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Integer getInteger( Map map, Object key, Integer defaultValue ) {
Integer answer = getInteger( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Long getLong( Map map, Object key, Long defaultValue ) {
Long answer = getLong( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Float getFloat( Map map, Object key, Float defaultValue ) {
Float answer = getFloat( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Double getDouble( Map map, Object key, Double defaultValue ) {
Double answer = getDouble( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
public static Map getMap( Map map, Object key, Map defaultValue ) {
Map answer = getMap( map, key );
if ( answer == null ) {
answer = defaultValue;
}
return answer;
}
// Conversion methods
//-------------------------------------------------------------------------
public static Properties toProperties(Map input) {
Properties answer = new Properties();
if ( input != null ) {
for ( Iterator iter = input.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object value = entry.getValue();
answer.put(key, value);
}
}
return answer;
}
// Printing methods
//-------------------------------------------------------------------------
public static synchronized void verbosePrint( PrintStream out, Object key, Map map ) {
debugPrintIndent( out );
out.println( key + " = " );
debugPrintIndent( out );
out.println( "{" );
++debugIndent;
for ( Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry) iter.next();
String childKey = (String) entry.getKey();
Object childValue = entry.getValue();
if ( childValue instanceof Map ) {
verbosePrint( out, childKey, (Map) childValue );
}
else {
debugPrintIndent( out );
out.println( childKey + " = " + childValue);
}
}
--debugIndent;
debugPrintIndent( out );
out.println( "}" );
}
public static synchronized void debugPrint( PrintStream out, Object key, Map map ) {
debugPrintIndent( out );
out.println( key + " = " );
debugPrintIndent( out );
out.println( "{" );
++debugIndent;
for ( Iterator iter = map.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry) iter.next();
String childKey = (String) entry.getKey();
Object childValue = entry.getValue();
if ( childValue instanceof Map ) {
verbosePrint( out, childKey, (Map) childValue );
}
else {
debugPrintIndent( out );
String typeName = ( childValue != null )
? childValue.getClass().getName()
: null;
out.println( childKey + " = " + childValue + " class: " + typeName );
}
}
--debugIndent;
debugPrintIndent( out );
out.println( "}" );
}
// Implementation methods
//-------------------------------------------------------------------------
protected static void debugPrintIndent( PrintStream out ) {
for ( int i = 0; i < debugIndent; i++ ) {
out.print( " " );
}
}
protected static void logInfo(Exception e) {
// XXXX: should probably use log4j here instead...
System.out.println( "INFO: Exception: " + e );
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
/** Performs some predicate which returns true or false based on the input object.
* Predicate instances can be used to implement queries or to do filtering.
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public interface Predicate {
/** @return true if the input object matches this predicate, else returns false
*/
public boolean evaluate(Object input);
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Enumeration;
import java.util.Iterator;
/** A Proxy {@link Iterator Iterator} which delegates its methods to a proxy instance.
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class ProxyIterator implements Iterator {
/** Holds value of property iterator. */
private Iterator iterator;
public ProxyIterator() {
}
public ProxyIterator( Iterator iterator ) {
this.iterator = iterator;
}
// Iterator interface
//-------------------------------------------------------------------------
public boolean hasNext() {
return getIterator().hasNext();
}
public Object next() {
return getIterator().next();
}
public void remove() {
getIterator().remove();
}
// Properties
//-------------------------------------------------------------------------
/** Getter for property iterator.
* @return Value of property iterator.
*/
public Iterator getIterator() {
return iterator;
}
/** Setter for property iterator.
* @param iterator New value of property iterator.
*/
public void setIterator(Iterator iterator) {
this.iterator = iterator;
}
}

View File

@ -0,0 +1,291 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.lang.ref.*;
import java.lang.reflect.*;
import java.util.*;
/** <p>
* HashMap with SoftReference links to values which allows the values of the Map
* to be garbage collected by the JVM if it becomes low on memory.
* Derive from this class and
* override the factory method <code>createReference()</code> method to make
* a Map wrapped in other types of Reference.
* </p>
*
* <p>
* A synchronized version can be obtained with:
* <code>Collections.synchronizedMap( theMapToSynchronize )</code>
* </p>
*
* <p>
* <b>WARNING</b> the values() and entrySet() methods require optimisation
* like the standard {@link HashMap} implementations so that iteration
* over this Map is efficient.
* </p>
*
* @author James.Dodd
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class SoftRefHashMap implements Map {
/** The wrapped HashMap */
private Map hashMap = new HashMap();
public SoftRefHashMap() {
}
/**
* Removes References that have had their referents garbage collected
*/
public void purge() {
Map map = getMap();
Set keys = map.keySet();
if ( keys == null ) {
return;
}
for ( Iterator i = keys.iterator(); i.hasNext(); ) {
Object key = (Object) i.next();
Reference ref = (Reference) map.get( key );
if ( ref.get() == null ) {
map.remove( key );
}
}
}
// Map implementation
// -------------------------------------------------------
/**
* Retrieves the referent of the Referenced value
* @param key The key with which to retrieve the value
*/
public Object get( final Object key ) {
Reference ref = (Reference) getMap().get( key );
if ( ref == null ) {
return null;
}
return ref.get();
}
/**
* Adds a key-value mapping, wrapping the value in a Reference
*/
public Object put( final Object key, final Object value ) {
Object answer = getMap().put( key, createReference( value ) );
if ( answer != null ) {
return ((Reference) answer).get();
}
return null;
}
/**
* Returns a collection of the Referenced values
*/
public Collection values() {
Set wrappedValues = (Set) getMap().values();
Set values = new TreeSet();
if ( wrappedValues == null ) {
return values;
}
for ( Iterator i = wrappedValues.iterator(); i.hasNext(); ) {
Reference ref = (Reference) i.next();
if ( ref != null ) {
values.add( ref.get() );
}
}
return values;
}
/**
* Answers whether the argument is in the domain of the mappings
*/
public boolean containsKey( Object key ) {
return getMap().containsKey( key );
}
/**
* Answers whether the argument is a Referenced value
*/
public boolean containsValue( Object value ) {
Collection values = (Collection) getMap().values();
if ( values == null ) {
return false;
}
for ( Iterator i = values.iterator(); i.hasNext(); ) {
Reference ref = (Reference) i.next();
if ( ref == null ) {
continue;
}
Object target = ref.get();
if ( target == value ) {
return true;
}
}
return false;
}
/**
* Put all of the mappings in the argument into this wrapped map
*/
public void putAll( final java.util.Map map ) {
if ( map == null || map.size() == 0 ) {
return;
}
for ( Iterator i = map.keySet().iterator(); i.hasNext(); ) {
Object key = (Object) i.next();
put( key, map.get( key ) );
}
}
/**
* Returns a set view of the mappings in the wrapped map
*/
public Set entrySet() {
Set entries = new HashSet();
if ( size() == 0 ) {
return entries;
}
for ( Iterator i = keySet().iterator(); i.hasNext(); ) {
Object key = i.next();
Object value = get( key );
Entry entry = new Entry( key, value );
entries.add( entry );
}
return entries;
}
/**
* Removes a mapping from this map
*/
public Object remove( final Object key ) {
Reference ref = (Reference) getMap().remove( key );
if ( ref != null ) {
return ref.get();
}
return null;
}
/**
* Clears all mappings
*/
public void clear() {
getMap().clear();
}
/**
* Calculates the hash code for this map
*/
public int hashCode() {
return getMap().hashCode();
}
/**
* Returns the domain of the mappings
*/
public Set keySet() {
return getMap().keySet();
}
/**
* Answers whether there are any mappings
*/
public boolean isEmpty() {
return getMap().isEmpty();
}
/**
* Answers whether this map and the argument are 'the same'
*/
public boolean equals( final Object object ) {
return getMap().equals( object );
}
/**
* Returns the number of mappings in this map
*/
public int size() {
return getMap().size();
}
// Inner Classes
// ---------------------------------------------------------------------
/**
* A map entry, which is backed by this RefHashMap
*/
class Entry implements Map.Entry {
/**
* Constructor
*/
public Entry( Object key, Object value ) {
this.key = key;
this.value = value;
}
// Map.Entry interface
// -----------------------------------------------------------
/**
* Retrieves the key of this mapping
*/
public Object getKey() {
return key;
}
/**
* Retrieves the value of this mapping
*/
public Object getValue() {
return value;
}
/**
* Sets the value of this mapping
*/
public Object setValue( Object value ) {
this.value = value;
put( key, value );
return value;
}
/**
* Return the hash code of this mapping.
* This algorithm was taken from the JavaDoc for Map.Entry
*/
public int hashCode() {
return ( getKey() == null ? 0 : getKey().hashCode() ) ^
( getValue() == null ? 0 : getValue().hashCode() );
}
/** The domain of this mapping */
private Object key;
/** The range of this mapping */
private Object value;
}
/**
* Returns a reference to the argument.
* Override this method to make wrapped maps for other Reference types
*/
protected Reference createReference( Object referent ) {
return new SoftReference( referent );
}
/**
* Retrieves the wrapped HashMap
* @return The wrapped HashMap
*/
protected Map getMap() {
return hashMap;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
import java.util.Enumeration;
import java.util.Iterator;
/** A Proxy {@link Iterator Iterator} which uses a {@link Transformer Transformer} instance to
* transform the contents of the {@link Iterator Iterator} into some other form
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public class TransformIterator extends ProxyIterator {
/** Holds value of property transformer. */
private Transformer transformer;
public TransformIterator() {
}
public TransformIterator( Iterator iterator ) {
super( iterator );
}
public TransformIterator( Iterator iterator, Transformer transformer ) {
super( iterator );
this.transformer = transformer;
}
// Iterator interface
//-------------------------------------------------------------------------
public Object next() {
return transform( super.next() );
}
// Properties
//-------------------------------------------------------------------------
/** Getter for property transformer.
* @return Value of property transformer.
*/
public Transformer getTransformer() {
return transformer;
}
/** Setter for property transformer.
* @param transformer New value of property transformer.
*/
public void setTransformer(Transformer transformer) {
this.transformer = transformer;
}
// Implementation methods
//-------------------------------------------------------------------------
protected Object transform( Object source ) {
Transformer transformer = getTransformer();
if ( transformer != null ) {
return transformer.transform( source );
}
return source;
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.commons.collections;
/** An object capable of transforming an input object into some output object.
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
*/
public interface Transformer {
/** Transforms the input object (leaving it unchanged) into some output object.
* @return the transformation of the input object to the output object
*/
public Object transform(Object input);
}