001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.util.collections;
018
019import java.io.Serializable;
020import java.util.AbstractList;
021import java.util.AbstractSet;
022import java.util.Collection;
023import java.util.Iterator;
024import java.util.Map;
025import java.util.NoSuchElementException;
026import java.util.Set;
027
028/**
029 * An implementation of the java.util.Map interface which can only hold a single object. This is
030 * particularly useful to control memory usage in Wicket because many containers hold only a single
031 * component.
032 *
033 * @author Jonathan Locke
034 * @param <K>
035 *            Key type
036 * @param <V>
037 *            Value type
038 *
039 * @deprecated Please use {@link Map#of(Object, Object)} instead
040 */
041@Deprecated(forRemoval = true, since = "9.0.0")
042public final class MicroMap<K, V> implements Map<K, V>, Serializable
043{
044        private static final long serialVersionUID = 1L;
045
046        /** The maximum number of entries this map supports. */
047        public static final int MAX_ENTRIES = 1;
048
049        /** The one and only key in this tiny map */
050        private K key;
051
052        /** The value for the only key in this tiny map */
053        private V value;
054
055        /**
056         * Constructor
057         */
058        public MicroMap()
059        {
060        }
061
062        /**
063         * Constructs map with a single key and value pair.
064         *
065         * @param key
066         *            The key
067         * @param value
068         *            The value
069         */
070        public MicroMap(final K key, final V value)
071        {
072                put(key, value);
073        }
074
075        /**
076         * @return True if this MicroMap is full
077         */
078        public boolean isFull()
079        {
080                return size() == MAX_ENTRIES;
081        }
082
083        /**
084         * @see java.util.Map#size()
085         */
086        @Override
087        public int size()
088        {
089                return (key != null) ? 1 : 0;
090        }
091
092        /**
093         * @see java.util.Map#isEmpty()
094         */
095        @Override
096        public boolean isEmpty()
097        {
098                return size() == 0;
099        }
100
101        /**
102         * @see java.util.Map#containsKey(java.lang.Object)
103         */
104        @Override
105        public boolean containsKey(final Object key)
106        {
107                return key.equals(this.key);
108        }
109
110        /**
111         * @see java.util.Map#containsValue(java.lang.Object)
112         */
113        @Override
114        public boolean containsValue(final Object value)
115        {
116                return value.equals(this.value);
117        }
118
119        /**
120         * @see java.util.Map#get(java.lang.Object)
121         */
122        @Override
123        public V get(final Object key)
124        {
125                if (key.equals(this.key))
126                {
127                        return value;
128                }
129
130                return null;
131        }
132
133        /**
134         * @see java.util.Map#put(java.lang.Object, java.lang.Object)
135         */
136        @Override
137        public V put(final K key, final V value)
138        {
139                // Replace?
140                if (key.equals(this.key))
141                {
142                        final V oldValue = this.value;
143
144                        this.value = value;
145
146                        return oldValue;
147                }
148                else
149                {
150                        // Is there room for a new entry?
151                        if (size() < MAX_ENTRIES)
152                        {
153                                // Store
154                                this.key = key;
155                                this.value = value;
156
157                                return null;
158                        }
159                        else
160                        {
161                                throw new IllegalStateException("Map full");
162                        }
163                }
164        }
165
166        /**
167         * @see java.util.Map#remove(java.lang.Object)
168         */
169        @Override
170        public V remove(final Object key)
171        {
172                if (key.equals(this.key))
173                {
174                        final V oldValue = value;
175
176                        this.key = null;
177                        value = null;
178
179                        return oldValue;
180                }
181
182                return null;
183        }
184
185        /**
186         * @see java.util.Map#putAll(java.util.Map)
187         */
188        @Override
189        public void putAll(final Map<? extends K, ? extends V> map)
190        {
191                if (map.size() <= MAX_ENTRIES)
192                {
193                        final Entry<? extends K, ? extends V> e = map.entrySet().iterator().next();
194
195                        put(e.getKey(), e.getValue());
196                }
197                else
198                {
199                        throw new IllegalStateException("Map full.  Cannot add " + map.size() + " entries");
200                }
201        }
202
203        /**
204         * @see java.util.Map#clear()
205         */
206        @Override
207        public void clear()
208        {
209                key = null;
210                value = null;
211        }
212
213        /**
214         * @see java.util.Map#keySet()
215         */
216        @Override
217        public Set<K> keySet()
218        {
219                return new AbstractSet<K>()
220                {
221                        @Override
222                        public Iterator<K> iterator()
223                        {
224                                return new Iterator<K>()
225                                {
226                                        @Override
227                                        public boolean hasNext()
228                                        {
229                                                return index < MicroMap.this.size();
230                                        }
231
232                                        @Override
233                                        public K next()
234                                        {
235                                                if (!hasNext())
236                                                {
237                                                        throw new NoSuchElementException();
238                                                }
239                                                index++;
240
241                                                return key;
242                                        }
243
244                                        @Override
245                                        public void remove()
246                                        {
247                                                MicroMap.this.clear();
248                                        }
249
250                                        int index;
251                                };
252                        }
253
254                        @Override
255                        public int size()
256                        {
257                                return MicroMap.this.size();
258                        }
259                };
260        }
261
262        /**
263         * @see java.util.Map#values()
264         */
265        @Override
266        public Collection<V> values()
267        {
268                return new AbstractList<V>()
269                {
270                        @Override
271                        public V get(final int index)
272                        {
273                                if (index > size() - 1)
274                                {
275                                        throw new IndexOutOfBoundsException();
276                                }
277                                return value;
278                        }
279
280                        @Override
281                        public int size()
282                        {
283                                return MicroMap.this.size();
284                        }
285                };
286        }
287
288        /**
289         * @see java.util.Map#entrySet()
290         */
291        @Override
292        public Set<Entry<K, V>> entrySet()
293        {
294                return new AbstractSet<Entry<K, V>>()
295                {
296                        @Override
297                        public Iterator<Entry<K, V>> iterator()
298                        {
299                                return new Iterator<Entry<K, V>>()
300                                {
301                                        @Override
302                                        public boolean hasNext()
303                                        {
304                                                return index < MicroMap.this.size();
305                                        }
306
307                                        @Override
308                                        public Entry<K, V> next()
309                                        {
310                                                if (!hasNext())
311                                                {
312                                                        throw new NoSuchElementException();
313                                                }
314                                                index++;
315
316                                                return new Map.Entry<K, V>()
317                                                {
318                                                        @Override
319                                                        public K getKey()
320                                                        {
321                                                                return key;
322                                                        }
323
324                                                        @Override
325                                                        public V getValue()
326                                                        {
327                                                                return value;
328                                                        }
329
330                                                        @Override
331                                                        public V setValue(final V value)
332                                                        {
333                                                                final V oldValue = MicroMap.this.value;
334
335                                                                MicroMap.this.value = value;
336
337                                                                return oldValue;
338                                                        }
339                                                };
340                                        }
341
342                                        @Override
343                                        public void remove()
344                                        {
345                                                clear();
346                                        }
347
348                                        int index = 0;
349                                };
350                        }
351
352                        @Override
353                        public int size()
354                        {
355                                return MicroMap.this.size();
356                        }
357                };
358        }
359}