1 /* 2 Copyright 2010 Ramon Servadei 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 package mirrormap.collections; 17 18 import java.util.Collection; 19 import java.util.Iterator; 20 import java.util.List; 21 import java.util.Map; 22 import java.util.Map.Entry; 23 24 /** 25 * A base class for an iterator that can be returned from the {@link Collection} 26 * objects returned from the methods {@link NotifyingMap#keySet()}, 27 * {@link NotifyingMap#values()} and {@link NotifyingMap#entrySet()}. This 28 * iterator will fire {@link IMapListener#willRemove(Object)} and 29 * {@link IMapListener#didRemove(Object, Object)} events when items from the 30 * underlying {@link Map} of the {@link NotifyingMap} are removed by this 31 * iterator. 32 * 33 * @author Ramon Servadei 34 * @param <IteratorType> 35 * the type the {@link Iterator} returns 36 * @param <K> 37 * the key type of the backing {@link Map} the iterator operates on 38 * @param <V> 39 * the value type of the backing {@link Map} the iterator operates on 40 */ 41 abstract class AbstractNotifyingIterator<IteratorType, K, V> implements 42 Iterator<IteratorType> 43 { 44 /** The {@link NotifyingMap} this entry set iterator operates on */ 45 protected final NotifyingMap<K, V> notifyingMap; 46 47 /** The iterator returned from the {@link #notifyingMap} */ 48 private final Iterator<Entry<K, V>> entryIterator; 49 50 /** Tracks the current iteration item */ 51 private Entry<K, V> current; 52 53 AbstractNotifyingIterator(NotifyingMap<K, V> notifyingMap) 54 { 55 this.notifyingMap = notifyingMap; 56 this.entryIterator = notifyingMap.getBackingEntrySet().iterator(); 57 } 58 59 public boolean hasNext() 60 { 61 return this.entryIterator.hasNext(); 62 } 63 64 public IteratorType next() 65 { 66 final Entry<K, V> next = this.entryIterator.next(); 67 this.current = next; 68 return getValueForNext(this.current); 69 } 70 71 public void remove() 72 { 73 final List<IMapListener<K, V>> listeners = 74 this.notifyingMap.getListeners(); 75 for (IMapListener<K, V> listener : listeners) 76 { 77 listener.willRemove(this.current.getKey()); 78 } 79 this.entryIterator.remove(); 80 for (IMapListener<K, V> listener : listeners) 81 { 82 listener.didRemove(this.current.getKey(), this.current.getValue()); 83 } 84 } 85 86 /** 87 * Called from the {@link #next()} method to return the correct value from 88 * the current map entry. 89 * 90 * @param currentEntry 91 * the current map entry the iterator is pointing to after the 92 * delegate iterator's call to {@link #next()} 93 * @return the correct value from the current map entry 94 */ 95 protected abstract IteratorType getValueForNext(Entry<K, V> currentEntry); 96 }