001package jmri.jmrit.logixng.util; 002 003import java.util.Collection; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009import java.util.Set; 010 011/** 012 * A map that may contain multiple items with same key 013 */ 014public class DuplicateKeyMap<K, V> implements Map<K, V> { 015 016 Map<K, List<V>> _internalMap = new HashMap<>(); 017 018 @Override 019 public int size() { 020 int c = 0; 021 for (List<V> l : _internalMap.values()) { 022 c += l.size(); 023 } 024 return c; 025 } 026 027 @Override 028 public boolean isEmpty() { 029 return size() == 0; 030 } 031 032 @Override 033 public boolean containsKey(Object key) { 034 return _internalMap.containsKey(key); 035 } 036 037 @Override 038 public boolean containsValue(Object value) { 039 for (List<V> l : _internalMap.values()) { 040 if (l.contains(value)) { 041 return true; 042 } 043 } 044 return false; 045 } 046 047 @Override 048 public V get(Object key) { 049 throw new UnsupportedOperationException("Not supported"); 050 } 051 052 /** 053 * Get all items in the map that has the key 'key' 054 * @param key the key whose associated values is to be returned 055 * @return an unmodifiable list of all the items 056 */ 057 public List<V> getAll(K key) { 058 List<V> list = _internalMap.get(key); 059 if (list == null) list = new ArrayList<>(); 060 return Collections.unmodifiableList(list); 061 } 062 063 /** 064 * {@inheritDoc} 065 * @return always null 066 */ 067 @Override 068 public V put(K key, V value) { 069 List<V> l = _internalMap.get(key); 070 if (l == null) { 071 l = new ArrayList<>(); 072 _internalMap.put(key, l); 073 } 074 if (! l.contains(value)) { 075 l.add(value); 076 } 077 return null; 078 } 079 080 @Override 081 public void putAll(Map<? extends K,? extends V> m) { 082 throw new UnsupportedOperationException("Not supported"); 083 } 084 085 @Override 086 public V remove(Object key) { 087 throw new UnsupportedOperationException("Not supported"); 088 } 089 090 /** {@inheritDoc} */ 091 @Override 092 public boolean remove(Object key, Object value) { 093 // NetBeans complains about suspicious call to Map.get(), but 094 // JMRI Static analysis doesn't allow casting to (K)key 095 List<V> l = _internalMap.get(key); 096 if (l != null) { 097 if (l.remove(value)) { 098 if (l.isEmpty()) _internalMap.remove(key); 099 return true; 100 } 101 } 102 return false; 103 } 104 105 /** 106 * Remove a value. 107 * @param key the key 108 * @param value the value 109 */ 110 public void removeValue(K key, V value) { 111 List<V> l = _internalMap.get(key); 112 if (l != null) { 113 l.remove(value); 114 } 115 } 116 117 @Override 118 public void clear() { 119 // Empty the lists since others may have indirect references to the list 120 // after calling the method getAll() 121 for (List<V> l : _internalMap.values()) { 122 l.clear(); 123 } 124 _internalMap.clear(); 125 } 126 127 @Override 128 public Set<K> keySet() { 129 return Collections.unmodifiableSet(_internalMap.keySet()); 130 } 131 132 @Override 133 public Collection<V> values() { 134 List<V> list = new ArrayList<>(); 135 for (List<V> l : _internalMap.values()) { 136 list.addAll(l); 137 } 138 return Collections.unmodifiableList(list); 139 } 140 141 @Override 142 public Set<Map.Entry<K,V>> entrySet() { 143 throw new UnsupportedOperationException("Not supported"); 144 } 145 146}