/*
Copyright (C) 2006 EBI
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the itmplied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.biomart.common.utils;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* This class wraps an existing map, and causes {@link PropertyChangeEvent}
* events to be fired whenever it changes.
* <p>
* Adding objects to the map will result in events where the before value is
* null and the after value is the key being added.
* <p>
* Removing them will result in events where the before value is they key being
* removed and the after value is null.
* <p>
* Multiple add/remove events will have both before and after values of null.
* <p>
* All events will have a property of {@link BeanMap#propertyName}.
*
* @author Richard Holland <holland@ebi.ac.uk>
* @version $Revision: 1.4 $, $Date: 2007-10-31 10:32:56 $, modified by
* $Author: rh4 $
* @since 0.7
*/
public class BeanMap extends WeakPropertyChangeSupport implements Map {
private static final long serialVersionUID = 1L;
private final Map delegate;
/**
* The property key used in events generated by this map.
*/
public static final String propertyName = "MapEntry";
/**
* Construct a new instance that wraps the delegate map and produces
* {@link PropertyChangeEvent} events whenever the delegate map changes.
*
* @param delegate
* the delegate map.
*/
public BeanMap(final Map delegate) {
super(delegate);
this.delegate = delegate;
}
/**
* Construct a new instance that wraps the delegate map and produces
* {@link PropertyChangeEvent} events whenever the delegate map changes.
* <p>
* As the delegate is a {@link BeanMap} instance, it doesn't wrap the map
* directly, instead it finds out the delegate's delegate and wraps that
* instead. It will also notify all listeners that are already listening to
* the delegate.
*
* @param delegate
* the delegate map.
*/
public BeanMap(final BeanMap delegate) {
this(delegate.delegate);
final PropertyChangeListener[] listeners = delegate
.getPropertyChangeListeners();
for (int i = 0; i < listeners.length; i++)
this.addPropertyChangeListener(listeners[i]);
}
public void clear() {
this.delegate.clear();
this.firePropertyChange(BeanMap.propertyName, null, null);
}
public boolean containsKey(final Object key) {
return this.delegate.containsKey(key);
}
public boolean containsValue(final Object value) {
return this.delegate.containsValue(value);
}
private final PropertyChangeListener entrySetListener = new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
final Map.Entry oldValue = (Map.Entry) evt.getOldValue();
final Map.Entry newValue = (Map.Entry) evt.getNewValue();
BeanMap.this.firePropertyChange(BeanMap.propertyName,
oldValue == null ? null : oldValue.getKey(),
newValue == null ? null : newValue.getKey());
}
};
public Set entrySet() {
// Wrap the entry set in a BeanCollection.
final BeanSet beanSet = new BeanSet(this.delegate.entrySet());
// Add a PropertyChangeListener to the BeanSet
// which fires events as if they came from us.
beanSet.addPropertyChangeListener(this.entrySetListener);
// Return the wrapped entry set.
return beanSet;
}
public Object get(final Object key) {
return this.delegate.get(key);
}
public boolean isEmpty() {
return this.delegate.isEmpty();
}
private final PropertyChangeListener keySetListener = new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
BeanMap.this.firePropertyChange(BeanMap.propertyName, evt
.getOldValue(), evt.getNewValue());
}
};
public Set keySet() {
// Wrap the entry set in a BeanCollection.
final BeanSet beanSet = new BeanSet(this.delegate.keySet());
// Add a PropertyChangeListener to the BeanSet
// which fires events as if they came from us.
beanSet.addPropertyChangeListener(this.keySetListener);
// Return the wrapped entry set.
return beanSet;
}
public Object put(final Object arg0, final Object arg1) {
final boolean already = this.delegate.containsKey(arg0);
final Object result = this.delegate.put(arg0, arg1);
this.firePropertyChange(BeanMap.propertyName, already ? arg0 : null,
arg0);
return result;
}
public void putAll(final Map arg0) {
this.delegate.putAll(arg0);
this.firePropertyChange(BeanMap.propertyName, null, null);
}
public Object remove(final Object key) {
final Object result = this.delegate.remove(key);
this.firePropertyChange(BeanMap.propertyName, key, null);
return result;
}
public int size() {
return this.delegate.size();
}
public Collection values() {
return this.delegate.values();
}
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
public boolean equals(final Object obj) {
if (obj == this)
return true;
else if (obj instanceof BeanMap)
return this.delegate.equals(((BeanMap) obj).delegate);
else if (obj instanceof Map)
return this.delegate.equals(obj);
else
return false;
}
public int hashCode() {
return this.delegate.hashCode();
}
public String toString() {
return this.delegate.toString();
}
}