1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.millscript.commons.util.map;
22
23 import org.millscript.commons.alert.alerts.Fault;
24 import org.millscript.commons.alert.alerts.IllegalArgumentAlert;
25 import org.millscript.commons.util.IList;
26 import org.millscript.commons.util.MapIterator;
27 import org.millscript.commons.util.Maplet;
28 import org.millscript.commons.util.iterator.AbstractMapIterator;
29 import org.millscript.commons.util.list.IArrayList;
30 import org.millscript.commons.util.list.IJavaUtilList;
31 import org.millscript.commons.util.maplet.IMaplet;
32
33 import java.io.Serializable;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Method;
36 import java.util.Collections;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.Map;
40 import java.util.NoSuchElementException;
41 import java.util.Map.Entry;
42
43 /**
44 * This class provides an immutable <code>Map</code> implementation which is
45 * backed by a java.util.Map instance.
46 */
47 public class IJavaUtilMap< K, V > extends AbstractIMap< K, V > implements Cloneable, Serializable {
48
49
50
51
52
53 /**
54 * This is the ID from the release 0.1.0 for future compatibility.
55 */
56 private static final long serialVersionUID = -8344051250886359924L;
57
58 /**
59 * This class implements a map iterator which iterates over the mappings in
60 * a {@link Map}.
61 */
62 public static class JavaUtilMapIterator< K, V > extends AbstractMapIterator< K, V > {
63
64 /**
65 * The current Map.Entry for the current iterator position.
66 */
67 private Entry< K, V > currentMapEntry;
68
69 /**
70 * The java.util.Iterator we are fetching values from.
71 */
72 private final Iterator< Entry< K, V > > it;
73
74 /**
75 * Constructs a new array iterator to iterate over the mappings in a
76 * {@link Map}.
77 *
78 * @param map the {@link Map} whose mappings to iterate over
79 */
80 public JavaUtilMapIterator( final Map< K, V > map ) {
81 this.it = map.entrySet().iterator();
82 }
83
84 /**
85 * @see org.millscript.commons.util.iterator.AbstractMapIterator#advance()
86 */
87 @Override
88 protected void advance() {
89 try {
90 this.currentMapEntry = this.it.next();
91 } catch ( NoSuchElementException ex ) {
92
93
94 this.currentMapEntry = null;
95 }
96 }
97
98 /**
99 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getKey()
100 */
101 @Override
102 protected K getKey() {
103 return this.currentMapEntry.getKey();
104 }
105
106 /**
107 * @see org.millscript.commons.util.iterator.AbstractMapIterator#getValue()
108 */
109 @Override
110 protected V getValue() {
111 return this.currentMapEntry.getValue();
112 }
113
114 /**
115 * @see org.millscript.commons.util.MapIterator#hasNext()
116 */
117 public boolean hasNext() {
118 return this.it.hasNext();
119 }
120
121 /**
122 * @see org.millscript.commons.util.iterator.AbstractMapIterator#outOfBounds()
123 */
124 @Override
125 protected boolean outOfBounds() {
126 return this.currentMapEntry == null;
127 }
128
129 }
130
131 /**
132 * The backing store java.util.Map.
133 */
134 private final Map< K, V > store;
135
136 /**
137 * Constructs a new empty immutable java util map.
138 */
139 @SuppressWarnings( "unchecked" )
140 public IJavaUtilMap() {
141 this.store = Collections.EMPTY_MAP;
142 }
143
144 /**
145 * Constructs a new immutable java util map with a copy of the specified
146 * backing array containing alternate name-value objects.
147 *
148 * @param objects the backing array of alternate name-value objects to
149 * copy
150 */
151 @SuppressWarnings( "unchecked" )
152 public IJavaUtilMap( final Map< K, V > map ) {
153 if ( map instanceof Cloneable ) {
154 try {
155 Class c = map.getClass();
156 Method m = c.getMethod( "clone" );
157 this.store = (Map< K, V >) m.invoke( map );
158 } catch ( NoSuchMethodException ex ) {
159 throw new IllegalArgumentAlert(
160 "Trying to make an immutable map from a non-cloneable java.util.Map instance"
161 ).culprit( "list type", map.getClass() ).culprit( "list", map ).mishap();
162 } catch ( IllegalAccessException ex ) {
163 throw new IllegalArgumentAlert(
164 "Trying to make an immutable map from a non-cloneable java.util.Map instance"
165 ).culprit( "list type", map.getClass() ).culprit( "list", map ).mishap();
166 } catch ( InvocationTargetException ex ) {
167 throw new IllegalArgumentAlert(
168 "Trying to make an immutable map from a non-cloneable java.util.Map instance"
169 ).culprit( "list type", map.getClass() ).culprit( "list", map ).mishap();
170 }
171 } else {
172 this.store = new HashMap< K, V >( map.size() );
173 try {
174 for ( Iterator< Entry< K, V > > it = map.entrySet().iterator(); it.hasNext(); ) {
175 final Entry< K, V > entry = it.next();
176 this.store.put( entry.getKey(), entry.getValue() );
177 }
178 } catch ( Exception ex ) {
179 throw new Fault(
180 "Failed to take a copy of the specified list slice"
181 ).setParentThrowable( ex ).mishap();
182 }
183 }
184 }
185
186 /**
187 * @see java.lang.Object#clone()
188 */
189 @Override
190 public Object clone() throws CloneNotSupportedException {
191
192 return super.clone();
193 }
194
195 /**
196 * @see org.millscript.commons.util.IMap#contains(java.lang.Object, java.lang.Object)
197 */
198 public boolean contains( final K key, final V value ) {
199 if ( this.store.containsKey( key ) ) {
200
201
202 return value == null ? this.store.get( key ) == null
203 : value.equals( this.store.get( key ) );
204 }
205 return false;
206 }
207
208 /**
209 * @see org.millscript.commons.util.IMap#containsKey(java.lang.Object)
210 */
211 public boolean containsKey( final K key ) {
212 return this.store.containsKey( key );
213 }
214
215 /**
216 * @see org.millscript.commons.util.IMap#containsValue(java.lang.Object)
217 */
218 public boolean containsValue( final V value ) {
219 return this.store.containsValue( value );
220 }
221
222 /**
223 * @see org.millscript.commons.util.IMap#get(java.lang.Object)
224 */
225 public V get( final K key ) {
226
227
228 return this.store.containsKey( key ) ? this.store.get( key )
229 : this.getDefault().get( this, key );
230 }
231
232 /**
233 * @see org.millscript.commons.util.IMap#iterator()
234 */
235 public MapIterator< K, V > iterator() {
236 return new JavaUtilMapIterator< K, V >( this.store );
237 }
238
239 /**
240 * @see org.millscript.commons.util.IMap#iterator(boolean)
241 */
242 @SuppressWarnings( "unchecked" )
243 public MapIterator< K, V > iterator( final boolean share ) {
244 if ( share ) {
245 return new JavaUtilMapIterator< K, V >( this.store );
246 } else {
247
248
249
250 final Maplet< K, V >[] maplets = new Maplet[ this.size() ];
251 final Iterator< Entry< K, V > > it = this.store.entrySet().iterator();
252 for ( int i = 0; it.hasNext(); i++ ) {
253 Entry< K, V > entry = it.next();
254 maplets[ i ] = new IMaplet< K, V >(
255 entry.getKey(),
256 entry.getValue()
257 );
258 }
259 return new IMapletArrayMap.MapletArrayMapIterator< K, V >( maplets, true );
260 }
261 }
262
263 /**
264 * @see org.millscript.commons.util.map.AbstractIMap#sharedKeyList()
265 */
266 @Override
267 protected IList< K > sharedKeyList() {
268
269 return new IJavaUtilList< K >( this.store.keySet() );
270 }
271
272 /**
273 * @see org.millscript.commons.util.map.AbstractIMap#sharedMapletList()
274 */
275 @Override
276 @SuppressWarnings( "unchecked" )
277 protected IList< Maplet< K, V > > sharedMapletList() {
278
279 final Iterator< Entry< K, V > > it = this.store.entrySet().iterator();
280 final Maplet< K, V >[] maplets = new Maplet[ this.size() ];
281 for ( int i = 0; it.hasNext(); i++ ) {
282 Entry< K, V > entry = it.next();
283 maplets[ i ] = new IMaplet< K, V >( entry );
284 }
285 return new IArrayList< Maplet< K, V > >( maplets, true );
286 }
287
288 /**
289 * @see org.millscript.commons.util.map.AbstractIMap#sharedValueList()
290 */
291 @Override
292 protected IList< V > sharedValueList() {
293
294 return new IJavaUtilList< V >( this.store.values() );
295 }
296
297 /**
298 * @see org.millscript.commons.util.IMap#size()
299 */
300 public int size() {
301 return this.store.size();
302 }
303
304 }