001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.reef.tang.util; 020 021import java.util.*; 022import java.util.Map.Entry; 023 024public abstract class AbstractMonotonicMultiMap<K, V> implements Collection<Entry<K, V>> { 025 protected Map<K, Set<V>> map; 026 private int size = 0; 027 028 public AbstractMonotonicMultiMap(final Map<K, Set<V>> map) { 029 this.map = map; 030 } 031 032 public void put(final K key, final V v) { 033 Set<V> vals = map.get(key); 034 if (vals == null) { 035 vals = new MonotonicHashSet<V>(); 036 map.put(key, vals); 037 } 038 vals.add(v); 039 size++; 040 } 041 042 public Set<K> keySet() { 043 return map.keySet(); 044 } 045 046 public Set<V> getValuesForKey(final K key) { 047 final Set<V> ret = map.get(key); 048 if (ret == null) { 049 return new MonotonicHashSet<V>(); 050 } else { 051 return ret; 052 } 053 } 054 055 public boolean contains(final K key, final V v) { 056 final Set<V> vals = map.get(key); 057 if (vals != null) { 058 return vals.contains(v); 059 } 060 return false; 061 } 062 063 @Override 064 public boolean add(final Entry<K, V> e) { 065 put(e.getKey(), e.getValue()); 066 return true; 067 } 068 069 @Override 070 public boolean addAll(final Collection<? extends Entry<K, V>> c) { 071 boolean ret = false; 072 for (final Entry<K, V> e : c) { 073 add(e); 074 ret = true; 075 } 076 return ret; 077 } 078 079 @Override 080 public void clear() { 081 throw new UnsupportedOperationException("MonotonicMultiMap cannot be cleared!"); 082 } 083 084 @SuppressWarnings("unchecked") 085 @Override 086 public boolean contains(final Object o) { 087 final Entry<?, ?> e = (Entry<?, ?>) o; 088 return contains((K) e.getKey(), (V) e.getValue()); 089 } 090 091 @Override 092 public boolean containsAll(final Collection<?> c) { 093 for (final Object o : c) { 094 if (!contains(o)) { 095 return false; 096 } 097 } 098 return true; 099 } 100 101 @Override 102 public boolean isEmpty() { 103 return size == 0; 104 } 105 106 @Override 107 public Iterator<Entry<K, V>> iterator() { 108 final Iterator<Entry<K, Set<V>>> it = map.entrySet().iterator(); 109 return new Iterator<Entry<K, V>>() { 110 private Iterator<V> cur; 111 private K curKey; 112 113 @Override 114 public boolean hasNext() { 115 return it.hasNext() || cur != null && cur.hasNext(); 116 } 117 118 @Override 119 public Entry<K, V> next() { 120 if (cur == null && it.hasNext()) { 121 final Entry<K, Set<V>> e = it.next(); 122 curKey = e.getKey(); 123 cur = e.getValue().iterator(); 124 } 125 final K k = curKey; 126 final V v = cur.next(); 127 if (!cur.hasNext()) { 128 cur = null; 129 } 130 131 return new Entry<K, V>() { 132 133 @Override 134 public K getKey() { 135 return k; 136 } 137 138 @Override 139 public V getValue() { 140 return v; 141 } 142 143 @Override 144 public V setValue(final V value) { 145 throw new UnsupportedOperationException(); 146 } 147 148 }; 149 } 150 151 @Override 152 public void remove() { 153 throw new UnsupportedOperationException(); 154 } 155 156 }; 157 } 158 159 public Set<V> values() { 160 final Set<V> s = new HashSet<>(); 161 for (final Entry<K, V> e : this) { 162 s.add(e.getValue()); 163 } 164 return s; 165 } 166 167 @Override 168 public boolean remove(final Object o) { 169 throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method remove!"); 170 } 171 172 @Override 173 public boolean removeAll(final Collection<?> c) { 174 throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method removeAll!"); 175 } 176 177 @Override 178 public boolean retainAll(final Collection<?> c) { 179 throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method retainAll!"); 180 } 181 182 @Override 183 public int size() { 184 return size; 185 } 186 187 @Override 188 public Entry<K, V>[] toArray() { 189 throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)"); 190 } 191 192 @Override 193 public <T> T[] toArray(final T[] a) { 194 throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)"); 195 } 196 197 public boolean containsKey(final K k) { 198 if (map.containsKey(k)) { 199 return !getValuesForKey(k).isEmpty(); 200 } else { 201 return false; 202 } 203 } 204}