001: package org.apache.commons.events.observable;
002:
003: import java.util.SortedMap;
004: import java.util.Comparator;
005:
006: /**
007: * <p>
008: * Decorates a <code>SortedMap</code> implementation with a <b>bound
009: * property</b> named "collection".
010: * </p>
011: * <p>
012: * Each modifying method call made on this <code>SortedMap</code> is
013: * handled as a change to the "collection" property. This
014: * facility serves to notify subscribers of a change to the collection
015: * but does not allow users the option of vetoing the change. To
016: * gain the ability to veto the change, use a {@link ConstrainedSortedMap}
017: * decorater.
018: * </p>
019: * <p>
020: * Due to the fact that a Map offers several "views" of the
021: * same data, some confusion may arise as to what action caused a
022: * particular event. For instance, entries in the map may be
023: * deleted by <code>Map.values().remove(object)</code>. There is no
024: * known method, short of digging into the implementation of a Map,
025: * to determine <i>which</i> key-value pair was deleted by this operation,
026: * particularly if there is more than one occurence of a specific
027: * value. (Conversely, there is also no means of controlling which
028: * key-value pair is deleted by this method; therefore it's not a
029: * terribly smart thing to do.)
030: * </p>
031: * <p>
032: * This implementation of a bound map makes no attempt to interpret
033: * events generated by these alternate views of the data. It merely
034: * ensures that registered listeners receive <i>all</i> events generated
035: * by <i>any</i> view of the Map's data. It is left to the client
036: * to interpret the events generated by their map's usage.
037: * </p>
038: *
039: * @see BoundMap
040: * @since Commons Events 1.0
041: * @author Bryce Nordgren / USDA Forest Service
042: */
043: public class BoundSortedMap extends BoundMap implements SortedMap {
044:
045: // Constructors
046: //-----------------------------------------------------------------------
047: protected BoundSortedMap(final SortedMap source,
048: final CollectionChangeEventFactory eventFactory) {
049:
050: super (source, eventFactory);
051: }
052:
053: protected BoundSortedMap(final SortedMap source) {
054: super (source);
055: }
056:
057: // Factory methods
058: //-----------------------------------------------------------------------
059: public static BoundSortedMap decorate(final SortedMap source,
060: final CollectionChangeEventFactory eventFactory) {
061:
062: return new BoundSortedMap(source, eventFactory);
063: }
064:
065: public static BoundSortedMap decorate(final SortedMap source) {
066: return new BoundSortedMap(source);
067: }
068:
069: // Utility methods
070: //-----------------------------------------------------------------------
071: /**
072: * Typecast to the SortedMap interface...
073: * @return a SortedMap
074: */
075: private SortedMap getSortedMap() {
076: return (SortedMap) (getMap());
077: }
078:
079: /**
080: * Binds an unbound SortedMap returned by the decorated object.
081: * Ensures that this map and the newly bound map get each other's
082: * events.
083: */
084: private SortedMap bindSortedMap(SortedMap unbound) {
085: // make a copy of the event factory
086: CollectionChangeEventFactory factoryCopy = (CollectionChangeEventFactory) (eventFactory
087: .clone());
088:
089: // bind the subMap view
090: BoundSortedMap boundMap = BoundSortedMap.decorate(unbound,
091: factoryCopy);
092:
093: // send "boundMap's" events to our listeners
094: boundMap.addPropertyChangeListener(createEventRepeater());
095:
096: // send our events to "boundMap's" listeners
097: addPropertyChangeListener(boundMap.createEventRepeater());
098:
099: return boundMap;
100: }
101:
102: // SortedMap API (methods which do not change map contents.)
103: //-----------------------------------------------------------------------
104: public Comparator comparator() {
105: return getSortedMap().comparator();
106: }
107:
108: public Object firstKey() {
109: return getSortedMap().firstKey();
110: }
111:
112: public Object lastKey() {
113: return getSortedMap().lastKey();
114: }
115:
116: // Decorator methods
117: //-----------------------------------------------------------------------
118: public SortedMap subMap(Object fromKey, Object toKey) {
119: SortedMap subMap = getSortedMap().subMap(fromKey, toKey);
120: return bindSortedMap(subMap);
121: }
122:
123: public SortedMap headMap(Object toKey) {
124: SortedMap subMap = getSortedMap().headMap(toKey);
125: return bindSortedMap(subMap);
126: }
127:
128: public SortedMap tailMap(Object fromKey) {
129: SortedMap subMap = getSortedMap().tailMap(fromKey);
130: return bindSortedMap(subMap);
131: }
132: }
|