Source code: jtemporal/PublishedSortedMap.java
1 /*
2 Copyright (C) 2002 Thomas A Beck (http://thomas.beck.name)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
18 package jtemporal;
19
20 import java.util.SortedMap;
21 import java.util.Comparator;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.Collection;
25 import java.util.AbstractSet;
26 import java.util.Iterator;
27 import java.util.NoSuchElementException;
28 import java.util.AbstractMap;
29
30 /**
31 * Decorates a SortedMap allowing a single third object to subscribe to updates.
32 * That's more efficient in terms of performance than using events and listeners.
33 * If you need events and multiple listener, you need to create an intermediate
34 * map subscriber class, which creates and dispatches the events. <BR>
35 * This class is optimized for the jtemporal use, that's
36 * why the class is not public (also some methods not used by JTemporal are not
37 * implemented). However with minimal changes, this class can become generic.
38 * @author Thomas Beck
39 * @version $Id$
40 */
41
42 class PublishedSortedMap implements SortedMap {
43
44 private final SortedMap map;
45 private final MapSubscriber subscriber;
46
47 // compulsory constructor
48 public PublishedSortedMap(SortedMap decoratedMap, MapSubscriber sub) {
49 this.map = decoratedMap;
50 this.subscriber = sub;
51 }
52
53 //accessors
54 public SortedMap getDecoratedMap() {
55 return this.map;
56 }
57 public MapSubscriber getSubscriber() {
58 return this.subscriber;
59 }
60
61 // notifications
62 private void firePut(Object key, Object value) {
63 this.subscriber.put(this, key, value);
64 }
65
66 private void fireRemoved(Object key) {
67 this.subscriber.removed(this, key);
68 }
69
70
71 // read-only methods
72
73 public Comparator comparator() {
74 return this.map.comparator();
75 }
76 public Object firstKey() {
77 return this.map.firstKey();
78 }
79 public Object lastKey() {
80 return this.map.lastKey();
81 }
82 public int size() {
83 return this.map.size();
84 }
85 public boolean isEmpty() {
86 return this.map.isEmpty();
87 }
88 public boolean containsKey(Object key) {
89 return this.map.containsKey(key);
90 }
91 public boolean containsValue(Object value) {
92 return this.map.containsValue(value);
93 }
94 public Object get(Object key) {
95 return this.map.get(key);
96 }
97 public boolean equals(Object o) {
98 return this.map.equals(o);
99 }
100 public int hashCode() {
101 return this.map.hashCode();
102 }
103
104
105 // submaps
106
107 public SortedMap subMap(Object fromKey, Object toKey) {
108 SortedMap subMap = this.map.subMap(fromKey, toKey);
109 return new PublishedSortedMap(subMap, this.subscriber);
110 }
111 public SortedMap headMap(Object toKey) {
112 SortedMap subMap = this.map.headMap(toKey);
113 return new PublishedSortedMap(subMap, this.subscriber);
114 }
115 public SortedMap tailMap(Object fromKey) {
116 SortedMap subMap = this.map.tailMap(fromKey);
117 return new PublishedSortedMap(subMap, this.subscriber);
118 }
119
120
121 // changes
122
123 public Object put(Object key, Object value) {
124 Object replaced = this.map.put(key, value);
125 this.firePut(key, value);
126 return replaced;
127 }
128 public Object remove(Object key) {
129 Object removed = this.map.remove(key);
130 this.fireRemoved(key);
131 return removed;
132 }
133
134 /**
135 * Internaly, instead caling clear(); this method iterates and removes all the
136 * elements one by one. That allows a subscriber to receive the detail of the
137 * deletions.
138 */
139 public void clear() {
140 Iterator i = this.keySet().iterator();
141 while (i.hasNext()) {
142 i.next();
143 i.remove();
144 }
145 //consistency check
146 if (this.map.size() != 0) {
147 // should never happen
148 throw new IllegalStateException("The published SortedMap is inconsistent");
149 }
150 }
151 public void putAll(Map t) {
152 Iterator i = t.entrySet().iterator();
153 while (i.hasNext()) {
154 Map.Entry e = (Map.Entry) i.next();
155 put(e.getKey(), e.getValue());
156 }
157 }
158 public Set keySet() {
159 Set decSet = this.map.keySet();
160 return new PublishedSortedMap.KeySet(decSet);
161 }
162 public Collection values() {
163 // not used by JTemporal
164 // must be implemented if used outside JTemporal
165 throw new UnsupportedOperationException();
166 //return this.map.values();
167 }
168 public Set entrySet() {
169 // not used by JTemporal
170 // must be implemented if used outside JTemporal
171 throw new UnsupportedOperationException();
172 //return this.map.entrySet();
173 }
174
175
176 private class KeySet extends AbstractSet
177 {
178 final Set decSet;
179
180 public KeySet(Set decoratedSet) {
181 this.decSet = decoratedSet;
182 }
183
184 public int size() {
185 return this.decSet.size();
186 }
187 public boolean isEmpty() {
188 return this.decSet.isEmpty();
189 }
190 public boolean contains(Object o) {
191 return this.decSet.contains(o);
192 }
193
194 public boolean remove(Object o) {
195 boolean b = this.decSet.remove(o);
196 PublishedSortedMap.this.fireRemoved(o);
197 return b;
198 }
199
200 public Iterator iterator() {
201 Iterator decIterator = this.decSet.iterator();
202 return new SetIterator(decIterator);
203 } // iterator()
204
205 private class SetIterator implements Iterator
206 {
207 private final Iterator decIterator;
208 private Object lastRead = null;
209
210 SetIterator(Iterator decoratedIterator) {
211 this.decIterator = decoratedIterator;
212 }
213
214 public boolean hasNext() {
215 return decIterator.hasNext();
216 }
217
218 public Object next() {
219 return lastRead = decIterator.next();
220 }
221
222 public void remove() {
223 decIterator.remove();
224 PublishedSortedMap.this.fireRemoved(lastRead);
225 }
226
227 } // SetIterator
228
229
230 } // class KeySet */
231
232 } // class PublishedSortedMap