/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: CollectionsUtil.java,v 1.4 2006/11/23 20:38:22 mlipp Exp $
*
* $Log: CollectionsUtil.java,v $
* Revision 1.4 2006/11/23 20:38:22 mlipp
* Minor optimization.
*
* Revision 1.3 2006/09/29 12:32:08 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.2 2005/09/28 15:09:44 drmlipp
* Added tracked list.
*
* Revision 1.1.1.3 2004/08/18 15:17:34 drmlipp
* Update to 1.2
*
* Revision 1.5 2004/02/25 12:05:38 lipp
* Added debugging helper for Map.
*
* Revision 1.4 2003/09/22 12:32:57 lipp
* Implemented deadline creation for block activities.
*
* Revision 1.3 2003/06/27 08:51:47 lipp
* Fixed copyright/license information.
*
* Revision 1.2 2002/11/05 10:16:49 schlue
* Tracked map added.
*
* Revision 1.1 2002/10/17 14:45:33 lipp
* Initial version.
*
*/
package de.danet.an.util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
/**
* This class provides some helper methods for the use of the Java
* collection framework (this includes both collections and maps).
*
* @author <a href="mailto:lipp@danet.de"></a>
* @version $Revision: 1.4 $
*/
public class CollectionsUtil {
private static class TrackedMap implements Map, Serializable {
/** Backing Map. */
private Map m;
/** Modified entries. */
private Set modifiedEntries = new HashSet ();
/**
* Sole constructor for creating a new tracked map.
* @return new tracked map.
*/
public TrackedMap(Map map) {
m = map;
}
/**
* Return the set of modified entries.
* @return the modified entries
*/
Set modifiedEntries () {
if (modifiedEntries.size() == 0) {
return Collections.EMPTY_SET;
}
Set res = modifiedEntries;
modifiedEntries = new HashSet ();
return res;
}
// Implementation of the methods from java.util.Map;
/**
* Returns the number of key-value mappings in this map. If
* the map contains more than Integer.MAX_VALUE elements,
* returns Integer.MAX_VALUE.
* This method call is delegated to the backing map.
* @return the number of key-value mappings in this map.
*/
public int size() {
return m.size();
}
/**
* Checks if map is empty.
* This method call is delegated to the backing map.
* @return true if this map contains no key-value mappings.
*/
public boolean isEmpty() {
return m.isEmpty();
}
/**
* Check if map contains the given key.
* This method call is delegated to the backing map.
* @param key key whose presence in this map is to be tested.
* @return true if this map contains a mapping for the specified key.
*/
public boolean containsKey(Object key) {
return m.containsKey(key);
}
/**
* Check if given value is part of the map.
* This method call is delegated to the backing map.
* @param value value whose presence in this map is to be tested.
* @return true if this map maps one or more keys to the
* specified value.
*/
public boolean containsValue(Object value) {
return m.containsValue(value);
}
/**
* Returns the value to which this map maps the specified
* key. Returns null if the map contains no mapping for this
* key. A return value of null does not necessarily indicate
* that the map contains no mapping for the key; it's also
* possible that the map explicitly maps the key to null. The
* containsKey operation may be used to distinguish these two
* cases.
* This method call is delegated to the backing map.
* @param key key whose associated value is to be returned.
* @return the value to which this map maps the specified key,
* or null if the map contains no mapping for this key.
* @throws ClassCastException if the key is of an
* inappropriate type for this map.
* @throws NullPointerException key is null and this map does
* not not permit null keys.
*/
public Object get(Object key)
throws ClassCastException, NullPointerException{
return m.get(key);
}
/**
* Associates the specified value with the specified key in
* this map (optional operation). If the map previously
* contained a mapping for this key, the old value is
* replaced.
* This method call is delegated to the backing map.
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or
* null if there was no mapping for key. A null return can
* also indicate that the map previously associated null with
* the specified key, if the implementation supports null
* values.
* @throws UnsupportedOperationException if the put operation
* is not supported by this map.
* @throws ClassCastException if the class of the specified
* key or value prevents it from being stored in this map.
* @throws IllegalArgumentException if some aspect of this key
* or value prevents it from being stored in this map.
* @throws NullPointerException this map does not permit null
* keys or values, and the specified key or value is null.
*/
public Object put(Object key, Object value)
throws UnsupportedOperationException, ClassCastException,
IllegalArgumentException, NullPointerException {
Object oldValue = m.put(key, value);
modifiedEntries.add (key);
return oldValue;
}
/**
* Removes the mapping for this key from this map if present.
* This method call is delegated to the backing map.
* @param key key whose mapping is to be removed from the map.
* @return previous value associated with specified key, or
* null if there was no mapping for key. A null return can
* also indicate that the map previously associated null with
* the specified key, if the implementation supports null
* values.
* @throws UnsupportedOperationException if the remove
* method is not supported by this map.
*/
public Object remove(Object key) throws UnsupportedOperationException {
Object oldValue = m.remove(key);
modifiedEntries.add(key);
return oldValue;
}
/**
* Copies all of the mappings from the specified map to this
* map. These mappings will replace any mappings that this map
* had for any of the keys currently in the specified map.
* This method call is delegated to the backing map.
* @param t Mappings to be stored in this map.
* @throws UnsupportedOperationException if the put operation
* is not supported by this map.
* @throws ClassCastException if the class of the specified
* key or value prevents it from being stored in this map.
* @throws IllegalArgumentException if some aspect of this key
* or value prevents it from being stored in this map.
* @throws NullPointerException this map does not permit null
* keys or values, and the specified key or value is null.
*/
public void putAll(Map t)
throws UnsupportedOperationException, ClassCastException,
IllegalArgumentException, NullPointerException {
m.putAll(t);
modifiedEntries.addAll (t.keySet());
}
/**
* Removes all mappings from this map.
* This method call is delegated to the backing map.
* @throws UnsupportedOperationException clear is not
* supported by this map.
*/
public void clear() throws UnsupportedOperationException {
modifiedEntries.addAll (keySet());
m.clear();
}
/**
* Returns a set view of the keys contained in this map. The
* set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is
* modified while an iteration over the set is in progress,
* the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
* mapping from the map, via the Iterator.remove, Set.remove,
* removeAll retainAll, and clear operations. It does not
* support the add or addAll operations.
* This method call is delegated to the backing map.
* @return set view of the keys contained in this map.
*/
public Set keySet() {
return m.keySet();
}
/**
* Returns a collection view of the values contained in this
* map. The collection is backed by the map, so changes to the
* map are reflected in the collection, and vice-versa. If the
* map is modified while an iteration over the collection is
* in progress, the results of the iteration are
* undefined. The collection supports element removal, which
* removes the corresponding mapping from the map, via the
* Iterator.remove, Collection.remove, removeAll, retainAll
* and clear operations. It does not support the add or addAll
* operations.
* This method call is delegated to the backing map.
* @return a collection view of the values contained in this map.
*/
public Collection values() {
return m.values();
}
/**
* Returns a set view of the mappings contained in this
* map. Each element in the returned set is a Map.Entry. The
* set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa. If the map is
* modified while an iteration over the set is in progress,
* the results of the iteration are undefined. The set
* supports element removal, which removes the corresponding
* mapping from the map, via the Iterator.remove, Set.remove,
* removeAll, retainAll and clear operations. It does not
* support the add or addAll operations.
* This method call is delegated to the backing map.
* @return a set view of the mappings contained in this map.
*/
public Set entrySet() {
return m.entrySet();
}
/**
* Compares the specified object with this map for
* equality. Returns true if the given object is also a map
* and the two Maps represent the same mappings. More
* formally, two maps t1 and t2 represent the same mappings if
* t1.entrySet().equals(t2.entrySet()). This ensures that the
* equals method works properly across different
* implementations of the Map interface. This method call is
* delegated to the backing map.
* @param o object to be compared for equality with this map.
* @return true if the specified object is equal to this map.
*/
public boolean equals(Object o) {
return m.equals(o);
}
/**
* Returns the hash code value for this map. The hash code of
* a map is defined to be the sum of the hashCodes of each
* entry in the map's entrySet view. This ensures that
* t1.equals(t2) implies that t1.hashCode()==t2.hashCode() for
* any two maps t1 and t2, as required by the general contract
* of Object.hashCode.
* This method call is delegated to the backing map.
* @return the hash code value for this map.
*/
public int hashCode() {
return m.hashCode();
}
}
/**
* Factory method for creating a new tracked map out of an "ordinary" Map.
* @param map the backing map for modification tracking.
* @return a tracked map as a Map.
*/
public static Map trackedMap (Map map) {
return new TrackedMap (map);
}
/**
* Check if the given map is a tracked map.
* @param map the map to be tested
* @return true if map is tracked, otherwise false.
*/
public static boolean isTracked (Map map) {
return (map instanceof TrackedMap);
}
/**
* Check if the given map has been modified. The method resets the
* internal modified flag as it is assumed that after calling this
* method some synchronization will be done and tracking starts
* anew.<P>
*
* The method throws an <code>IllegalArgumentException</code> if
* the argument is not a result of {@link #trackedMap
* <code>trackedMap</code>}, i.e. if <code>isTracked(map) ==
* false</code>.
* @param map the backing map for modification tracking.
* @return true if map has been modified, otherwise false.
*/
public static boolean hasBeenModified (Map map) {
if (map instanceof TrackedMap) {
return ((TrackedMap)map).modifiedEntries().size() > 0;
}
throw new IllegalArgumentException ("Not a tracked map.");
}
/**
* Returns the modified entries in the given map. The method
* resets the internal modified flag as it is assumed that after
* calling this method some synchronization will be done and
* tracking starts anew.<P>
*
* The method throws an <code>IllegalArgumentException</code> if
* the argument is not a result of {@link #trackedMap
* <code>trackedMap</code>}, i.e. if <code>isTracked(map) ==
* false</code>.
* @param map the backing map for modification tracking.
* @return true if map has been modified, otherwise false.
*/
public static Set modifiedEntries (Map map) {
if (map instanceof TrackedMap) {
return ((TrackedMap)map).modifiedEntries();
}
throw new IllegalArgumentException ("Not a tracked map.");
}
/**
* Generate a string representation of a map for debugging
* purposes.
* @param map the map
* @return string representation
*/
public static String toString (Map map) {
List keys = new ArrayList (map.keySet ());
try {
Collections.sort (keys);
} catch (Throwable e) {
}
StringBuffer res = new StringBuffer ("Map[");
boolean first = true;
for (Iterator i = keys.iterator (); i.hasNext (); ) {
String key = (String)i.next();
if (!first) {
res.append (",");
} else {
first = false;
}
res.append (key + "=" + map.get(key));
}
res.append ("]");
return res.toString ();
}
public static class TrackedList implements List {
/** Backing List. */
private List l;
/** Modified entries. */
private boolean modified = false;
/**
* Create a new tracked list with the given list as backing list.
* @param list the list to track.
*/
public TrackedList (List list) {
l = list;
}
/**
* Check if list has been modified and reset modified flag.
* @return <code>true</code> if list has been modified.
*/
public boolean isModified () {
boolean m = modified;
modified = false;
return m;
}
/* (non-Javadoc)
* @see java.util.List#add(int, java.lang.Object)
*/
public void add(int index, Object element) {
l.add(index, element);
modified = true;
}
/* (non-Javadoc)
* @see java.util.List#add(java.lang.Object)
*/
public boolean add(Object o) {
modified = true;
return l.add(o);
}
/* (non-Javadoc)
* @see java.util.List#addAll(java.util.Collection)
*/
public boolean addAll(Collection c) {
modified = true;
return l.addAll(c);
}
/* (non-Javadoc)
* @see java.util.List#addAll(int, java.util.Collection)
*/
public boolean addAll(int index, Collection c) {
modified = true;
return l.addAll(index, c);
}
/* (non-Javadoc)
* @see java.util.List#clear()
*/
public void clear() {
modified = true;
l.clear();
}
/* (non-Javadoc)
* @see java.util.List#contains(java.lang.Object)
*/
public boolean contains(Object o) {
return l.contains(o);
}
/* (non-Javadoc)
* @see java.util.List#containsAll(java.util.Collection)
*/
public boolean containsAll(Collection c) {
return l.containsAll(c);
}
/* (non-Javadoc)
* @see java.util.List#equals(java.lang.Object)
*/
public boolean equals(Object o) {
return l.equals(o);
}
/* (non-Javadoc)
* @see java.util.List#get(int)
*/
public Object get(int index) {
return l.get(index);
}
/* (non-Javadoc)
* @see java.util.List#hashCode()
*/
public int hashCode() {
return l.hashCode();
}
/* (non-Javadoc)
* @see java.util.List#indexOf(java.lang.Object)
*/
public int indexOf(Object o) {
return l.indexOf(o);
}
/* (non-Javadoc)
* @see java.util.List#isEmpty()
*/
public boolean isEmpty() {
return l.isEmpty();
}
/* (non-Javadoc)
* @see java.util.List#iterator()
*/
public Iterator iterator() {
return l.iterator();
}
/* (non-Javadoc)
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
public int lastIndexOf(Object o) {
return l.lastIndexOf(o);
}
/* (non-Javadoc)
* @see java.util.List#listIterator()
*/
public ListIterator listIterator() {
return l.listIterator();
}
/* (non-Javadoc)
* @see java.util.List#listIterator(int)
*/
public ListIterator listIterator(int index) {
return l.listIterator(index);
}
/* (non-Javadoc)
* @see java.util.List#remove(int)
*/
public Object remove(int index) {
modified = true;
return l.remove(index);
}
/* (non-Javadoc)
* @see java.util.List#remove(java.lang.Object)
*/
public boolean remove(Object o) {
modified = true;
return l.remove(o);
}
/* (non-Javadoc)
* @see java.util.List#removeAll(java.util.Collection)
*/
public boolean removeAll(Collection c) {
modified = true;
return l.removeAll(c);
}
/* (non-Javadoc)
* @see java.util.List#retainAll(java.util.Collection)
*/
public boolean retainAll(Collection c) {
modified = true;
return l.retainAll(c);
}
/* (non-Javadoc)
* @see java.util.List#set(int, java.lang.Object)
*/
public Object set(int index, Object element) {
modified = true;
return l.set(index, element);
}
/* (non-Javadoc)
* @see java.util.List#size()
*/
public int size() {
return l.size();
}
/* (non-Javadoc)
* @see java.util.List#subList(int, int)
*/
public List subList(int fromIndex, int toIndex) {
return l.subList(fromIndex, toIndex);
}
/* (non-Javadoc)
* @see java.util.List#toArray()
*/
public Object[] toArray() {
return l.toArray();
}
/* (non-Javadoc)
* @see java.util.List#toArray(java.lang.Object[])
*/
public Object[] toArray(Object[] a) {
return l.toArray(a);
}
public String toString() {
return l.toString();
}
}
/**
* Factory method for creating a new tracked list out of an "ordinary" List.
* @param list the backing list for modification tracking.
* @return a tracked list as a List.
*/
public static List trackedList (List list) {
return new TrackedList (list);
}
/**
* Check if the given list is a tracked list.
* @param list the list to be tested
* @return true if list is tracked, otherwise false.
*/
public static boolean isTracked (List list) {
return (list instanceof TrackedList);
}
/**
* Check if the given list has been modified. The method resets the
* internal modified flag as it is assumed that after calling this
* method some synchronization will be done and tracking starts
* anew.<P>
*
* The method throws an <code>IllegalArgumentException</code> if
* the argument is not a result of {@link #trackedList
* <code>trackedList</code>}, i.e. if <code>isTracked(list) ==
* false</code>.
* @param list the list to be checked.
* @return true if list has been modified, otherwise false.
*/
public static boolean hasBeenModified (List list) {
if (list instanceof TrackedList) {
return ((TrackedList)list).isModified ();
}
throw new IllegalArgumentException ("Not a tracked list.");
}
}
|