001/*
002 * HA-JDBC: High-Availability JDBC
003 * Copyright (C) 2012  Paul Ferraro
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Lesser General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Lesser General Public License for more details.
014 *
015 * You should have received a copy of the GNU Lesser General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package net.sf.hajdbc.util.ref;
019
020import java.lang.ref.Reference;
021import java.util.Collection;
022import java.util.Iterator;
023import java.util.Map;
024import java.util.Set;
025
026/**
027 * A map that stores its values using a reference.
028 * @author Paul Ferraro
029 */
030public class ReferenceMap<K, V> implements Map<K, V>
031{
032        private final Map<K, Reference<V>> map;
033        final ReferenceFactory referenceFactory;
034        
035        public ReferenceMap(Map<K, Reference<V>> map, ReferenceFactory referenceFactory)
036        {
037                this.map = map;
038                this.referenceFactory = referenceFactory;
039        }
040
041        @Override
042        public void clear()
043        {
044                this.map.clear();
045        }
046
047        @Override
048        public boolean containsKey(Object key)
049        {
050                return this.map.containsKey(key);
051        }
052
053        @Override
054        public boolean containsValue(Object object)
055        {
056                for (Reference<V> reference: this.map.values())
057                {
058                        V value = reference.get();
059                        
060                        if ((value != null) && value.equals(object))
061                        {
062                                return true;
063                        }
064                }
065                return false;
066        }
067
068        @Override
069        public Set<Map.Entry<K, V>> entrySet()
070        {
071                final Set<Map.Entry<K, Reference<V>>> entrySet = this.map.entrySet();
072                
073                return new Set<Map.Entry<K, V>>()
074                {
075                        @Override
076                        public boolean add(Map.Entry<K, V> entry)
077                        {
078                                throw new UnsupportedOperationException();
079                        }
080
081                        @Override
082                        public boolean addAll(Collection<? extends Map.Entry<K, V>> entries)
083                        {
084                                throw new UnsupportedOperationException();
085                        }
086
087                        @Override
088                        public void clear()
089                        {
090                                entrySet.clear();
091                        }
092
093                        @Override
094                        public boolean contains(Object object)
095                        {
096                                return false;
097                        }
098
099                        @Override
100                        public boolean containsAll(Collection<?> collection)
101                        {
102                                return false;
103                        }
104
105                        @Override
106                        public boolean isEmpty()
107                        {
108                                return entrySet.isEmpty();
109                        }
110
111                        @Override
112                        public Iterator<Map.Entry<K, V>> iterator()
113                        {
114                                final Iterator<Map.Entry<K, Reference<V>>> entries = entrySet.iterator();
115                                
116                                return new Iterator<Map.Entry<K, V>>()
117                                {
118                                        @Override
119                                        public boolean hasNext()
120                                        {
121                                                return entries.hasNext();
122                                        }
123
124                                        @Override
125                                        public java.util.Map.Entry<K, V> next()
126                                        {
127                                                final Map.Entry<K, Reference<V>> entry = entries.next();
128                                                
129                                                return new Map.Entry<K, V>()
130                                                {
131                                                        @Override
132                                                        public K getKey()
133                                                        {
134                                                                return entry.getKey();
135                                                        }
136
137                                                        @Override
138                                                        public V getValue()
139                                                        {
140                                                                return entry.getValue().get();
141                                                        }
142
143                                                        @Override
144                                                        public V setValue(V value)
145                                                        {
146                                                                Reference<V> reference = entry.setValue(ReferenceMap.this.referenceFactory.createReference(value));
147                                                                
148                                                                return (reference != null) ? reference.get() : null;
149                                                        }
150                                                };
151                                        }
152
153                                        @Override
154                                        public void remove()
155                                        {
156                                                entries.remove();
157                                        }
158                                };
159                        }
160
161                        @Override
162                        public boolean remove(Object object)
163                        {
164                                return false;
165                        }
166
167                        @Override
168                        public boolean removeAll(Collection<?> collection)
169                        {
170                                return false;
171                        }
172
173                        @Override
174                        public boolean retainAll(Collection<?> collection)
175                        {
176                                return false;
177                        }
178
179                        @Override
180                        public int size()
181                        {
182                                return entrySet.size();
183                        }
184
185                        @Override
186                        public Object[] toArray()
187                        {
188                                return null;
189                        }
190
191                        @Override
192                        public <T> T[] toArray(T[] arg0)
193                        {
194                                return null;
195                        }
196                };
197        }
198
199        @Override
200        public V get(Object key)
201        {
202                Reference<V> reference = this.map.get(key);
203                
204                return (reference != null) ? reference.get() : null;
205        }
206
207        @Override
208        public boolean isEmpty()
209        {
210                return this.map.isEmpty();
211        }
212
213        @Override
214        public Set<K> keySet()
215        {
216                return this.map.keySet();
217        }
218
219        @Override
220        public V put(K key, V value)
221        {
222                Reference<V> reference = this.map.put(key, this.referenceFactory.createReference(value));
223                
224                return (reference != null) ? reference.get() : null;
225        }
226
227        @Override
228        public void putAll(Map<? extends K, ? extends V> map)
229        {
230                for (Map.Entry<? extends K, ? extends V> entry: map.entrySet())
231                {
232                        this.put(entry.getKey(), entry.getValue());
233                }
234        }
235
236        @Override
237        public V remove(Object key)
238        {
239                Reference<V> reference = this.map.remove(key);
240                
241                return (reference != null) ? reference.get() : null;
242        }
243
244        @Override
245        public int size()
246        {
247                return this.map.size();
248        }
249
250        @Override
251        public Collection<V> values()
252        {
253                final Collection<Reference<V>> references = this.map.values();
254                
255                return new Collection<V>()
256                {
257                        @Override
258                        public boolean add(V arg0)
259                        {
260                                throw new UnsupportedOperationException();
261                        }
262
263                        @Override
264                        public boolean addAll(Collection<? extends V> arg0)
265                        {
266                                throw new UnsupportedOperationException();
267                        }
268
269                        @Override
270                        public void clear()
271                        {
272                                references.clear();
273                        }
274
275                        @Override
276                        public boolean contains(Object object)
277                        {
278                                for (Reference<V> reference: references)
279                                {
280                                        V value = reference.get();
281                                        
282                                        if ((value != null) && value.equals(object))
283                                        {
284                                                return true;
285                                        }
286                                }
287                                
288                                return false;
289                        }
290
291                        @Override
292                        public boolean containsAll(Collection<?> objects)
293                        {
294                                return false;
295                        }
296
297                        @Override
298                        public boolean isEmpty()
299                        {
300                                return references.isEmpty();
301                        }
302
303                        @Override
304                        public Iterator<V> iterator()
305                        {
306                                final Iterator<Reference<V>> refs = references.iterator();
307                                
308                                return new Iterator<V>()
309                                {
310                                        @Override
311                                        public boolean hasNext()
312                                        {
313                                                return refs.hasNext();
314                                        }
315
316                                        @Override
317                                        public V next()
318                                        {
319                                                Reference<V> reference = refs.next();
320                                                
321                                                return (reference != null) ? reference.get() : null;
322                                        }
323
324                                        @Override
325                                        public void remove()
326                                        {
327                                                refs.remove();
328                                        }
329                                };
330                        }
331
332                        @Override
333                        public boolean remove(Object value)
334                        {
335                                return false;
336                        }
337
338                        @Override
339                        public boolean removeAll(Collection<?> values)
340                        {
341                                return false;
342                        }
343
344                        @Override
345                        public boolean retainAll(Collection<?> values)
346                        {
347                                return false;
348                        }
349
350                        @Override
351                        public int size()
352                        {
353                                return references.size();
354                        }
355
356                        @Override
357                        public Object[] toArray()
358                        {
359                                return null;
360                        }
361
362                        @Override
363                        public <T> T[] toArray(T[] arg0)
364                        {
365                                return null;
366                        }
367                };
368        }
369}