001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2013 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.client.persistence.collection;
022    
023    import java.io.IOException;
024    import java.io.ObjectInput;
025    import java.io.ObjectOutput;
026    import java.util.Collection;
027    import java.util.Comparator;
028    import java.util.Iterator;
029    import java.util.List;
030    import java.util.ListIterator;
031    import java.util.Map;
032    import java.util.Set;
033    import java.util.SortedMap;
034    import java.util.SortedSet;
035    
036    import org.granite.client.persistence.LazyInitializationException;
037    import org.granite.messaging.persistence.PersistentCollectionSnapshot;
038    
039    /**
040     * @author Franck WOLFF
041     */
042    public abstract class AbstractPersistentCollection<C> implements PersistentCollection {
043    
044            private volatile C collection = null;
045            private volatile boolean dirty = false;
046            
047            protected AbstractPersistentCollection() {
048            }
049            
050            protected void init(C collection, boolean dirty) {
051                    this.collection = collection;
052                    this.dirty = dirty;
053            }
054    
055            protected void checkInitialized() {
056                    if (!wasInitialized())
057                            throw new LazyInitializationException(getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(this)));
058            }
059            
060            protected C getCollection() {
061                    return collection;
062            }
063            
064            protected ClassLoader getClassLoader() {
065                    return Thread.currentThread().getContextClassLoader();
066            }
067    
068            public boolean wasInitialized() {
069                    return collection != null;
070            }
071    
072            public boolean isDirty() {
073                    return dirty;
074            }
075    
076            public void dirty() {
077                    dirty = true;
078            }
079    
080            public void clearDirty() {
081                    dirty = false;
082            }
083            
084            protected abstract PersistentCollectionSnapshot createSnapshot(boolean forReading);
085            protected abstract void updateFromSnapshot(ObjectInput in, PersistentCollectionSnapshot snapshot);
086    
087            public void writeExternal(ObjectOutput out) throws IOException {
088                    PersistentCollectionSnapshot snapshot = createSnapshot(false);
089                    snapshot.writeExternal(out);
090            }
091    
092            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
093                    PersistentCollectionSnapshot snapshot = createSnapshot(true);
094                    snapshot.readExternal(in);
095                    updateFromSnapshot(in, snapshot);
096            }
097            
098            static class IteratorProxy<E> implements Iterator<E> {
099                    
100                    private final AbstractPersistentCollection<?> persistentCollection;
101                    private final Iterator<E> iterator;
102                    
103                    public IteratorProxy(AbstractPersistentCollection<?> persistentCollection, Iterator<E> iterator) {
104                            this.persistentCollection = persistentCollection;
105                            this.iterator = iterator;
106                    }
107    
108                    public boolean hasNext() {
109                            return iterator.hasNext();
110                    }
111    
112                    public E next() {
113                            return iterator.next();
114                    }
115    
116                    public void remove() {
117                            iterator.remove();
118                            persistentCollection.dirty();
119                    }
120    
121                    @Override
122                    public int hashCode() {
123                            return iterator.hashCode();
124                    }
125    
126                    @Override
127                    public boolean equals(Object obj) {
128                            return iterator.equals(obj);
129                    }
130            }
131            
132            static class ListIteratorProxy<E> implements ListIterator<E> {
133                    
134                    private final AbstractPersistentCollection<?> persistentCollection;
135                    private final ListIterator<E> iterator;
136    
137                    private E lastNextOrPrevious = null;
138                    
139                    public ListIteratorProxy(AbstractPersistentCollection<?> persistentCollection, ListIterator<E> iterator) {
140                            this.persistentCollection = persistentCollection;
141                            this.iterator = iterator;
142                    }
143                    
144                    public boolean hasNext() {
145                            return iterator.hasNext();
146                    }
147    
148                    public E next() {
149                            return (lastNextOrPrevious = iterator.next());
150                    }
151    
152                    public boolean hasPrevious() {
153                            return iterator.hasPrevious();
154                    }
155    
156                    public E previous() {
157                            return (lastNextOrPrevious = iterator.previous());
158                    }
159    
160                    public int nextIndex() {
161                            return iterator.nextIndex();
162                    }
163    
164                    public int previousIndex() {
165                            return iterator.previousIndex();
166                    }
167    
168                    public void remove() {
169                            iterator.remove();
170                            lastNextOrPrevious = null;
171                            persistentCollection.dirty();
172                    }
173    
174                    public void set(E e) {
175                            iterator.set(e);
176                            if (e == null ? lastNextOrPrevious != null : !e.equals(lastNextOrPrevious))
177                                    persistentCollection.dirty();
178                    }
179    
180                    public void add(E e) {
181                            iterator.add(e);
182                            lastNextOrPrevious = null;
183                            persistentCollection.dirty();
184                    }
185    
186                    @Override
187                    public int hashCode() {
188                            return iterator.hashCode();
189                    }
190    
191                    @Override
192                    public boolean equals(Object obj) {
193                            return iterator.equals(obj);
194                    }
195            }
196            
197            static class CollectionProxy<E> implements Collection<E> {
198                    
199                    protected final AbstractPersistentCollection<?> persistentCollection;
200                    protected final Collection<E> collection;
201    
202                    public CollectionProxy(AbstractPersistentCollection<?> persistentCollection, Collection<E> collection) {
203                            this.persistentCollection = persistentCollection;
204                            this.collection = collection;
205                    }
206    
207                    public int size() {
208                            return collection.size();
209                    }
210    
211                    public boolean isEmpty() {
212                            return collection.isEmpty();
213                    }
214    
215                    public boolean contains(Object o) {
216                            return collection.contains(o);
217                    }
218    
219                    public Iterator<E> iterator() {
220                            return new IteratorProxy<E>(persistentCollection, collection.iterator());
221                    }
222    
223                    public Object[] toArray() {
224                            return collection.toArray();
225                    }
226    
227                    public <T> T[] toArray(T[] a) {
228                            return collection.toArray(a);
229                    }
230    
231                    public boolean add(E e) {
232                            if (collection.add(e)) {
233                                    persistentCollection.dirty();
234                                    return true;
235                            }
236                            return false;
237                    }
238    
239                    public boolean remove(Object o) {
240                            if (collection.remove(o)) {
241                                    persistentCollection.dirty();
242                                    return true;
243                            }
244                            return false;
245                    }
246    
247                    public boolean containsAll(Collection<?> c) {
248                            return collection.containsAll(c);
249                    }
250    
251                    public boolean addAll(Collection<? extends E> c) {
252                            if (collection.addAll(c)) {
253                                    persistentCollection.dirty();
254                                    return true;
255                            }
256                            return false;
257                    }
258    
259                    public boolean removeAll(Collection<?> c) {
260                            if (collection.removeAll(c)) {
261                                    persistentCollection.dirty();
262                                    return true;
263                            }
264                            return false;
265                    }
266    
267                    public boolean retainAll(Collection<?> c) {
268                            if (collection.retainAll(c)) {
269                                    persistentCollection.dirty();
270                                    return true;
271                            }
272                            return false;
273                    }
274    
275                    public void clear() {
276                            if (!collection.isEmpty()) {
277                                    collection.clear();
278                                    persistentCollection.dirty();
279                            }
280                    }
281    
282                    @Override
283                    public int hashCode() {
284                            return collection.hashCode();
285                    }
286    
287                    @Override
288                    public boolean equals(Object obj) {
289                            return collection.equals(obj);
290                    }
291            }
292            
293            static class SetProxy<E> extends CollectionProxy<E> implements Set<E> {
294    
295                    public SetProxy(AbstractPersistentCollection<?> persistentCollection, Set<E> collection) {
296                            super(persistentCollection, collection);
297                    }
298            }
299            
300            static class ListProxy<E> extends CollectionProxy<E> implements List<E> {
301    
302                    public ListProxy(AbstractPersistentCollection<?> persistentCollection, List<E> collection) {
303                            super(persistentCollection, collection);
304                    }
305    
306                    public boolean addAll(int index, Collection<? extends E> c) {
307                            if (((List<E>)collection).addAll(index, c)) {
308                                    persistentCollection.dirty();
309                                    return true;
310                            }
311                            return false;
312                    }
313    
314                    public E get(int index) {
315                            return ((List<E>)collection).get(index);
316                    }
317    
318                    public E set(int index, E element) {
319                            E previousElement = ((List<E>)collection).set(index, element);
320                            if (previousElement == null ? element != null : !previousElement.equals(element))
321                                    persistentCollection.dirty();
322                            return previousElement;
323                    }
324    
325                    public void add(int index, E element) {
326                            ((List<E>)collection).add(index, element);
327                            persistentCollection.dirty();
328                    }
329    
330                    public E remove(int index) {
331                            E removedElement = ((List<E>)collection).remove(index);
332                            persistentCollection.dirty();
333                            return removedElement;
334                    }
335    
336                    public int indexOf(Object o) {
337                            return ((List<E>)collection).indexOf(o);
338                    }
339    
340                    public int lastIndexOf(Object o) {
341                            return ((List<E>)collection).lastIndexOf(o);
342                    }
343    
344                    public ListIterator<E> listIterator() {
345                            return listIterator(0);
346                    }
347    
348                    public ListIterator<E> listIterator(int index) {
349                            return new ListIteratorProxy<E>(persistentCollection, ((List<E>)collection).listIterator(index));
350                    }
351    
352                    public List<E> subList(int fromIndex, int toIndex) {
353                            return new ListProxy<E>(persistentCollection, ((List<E>)collection).subList(fromIndex, toIndex));
354                    }
355            }
356            
357            static class SortedSetProxy<E> extends SetProxy<E> implements SortedSet<E> {
358    
359                    public SortedSetProxy(AbstractPersistentCollection<?> persistentCollection, SortedSet<E> collection) {
360                            super(persistentCollection, collection);
361                    }
362    
363                    public Comparator<? super E> comparator() {
364                            return ((SortedSet<E>)collection).comparator();
365                    }
366    
367                    public SortedSet<E> subSet(E fromElement, E toElement) {
368                            return new SortedSetProxy<E>(persistentCollection, ((SortedSet<E>)collection).subSet(fromElement, toElement));
369                    }
370    
371                    public SortedSet<E> headSet(E toElement) {
372                            return new SortedSetProxy<E>(persistentCollection, ((SortedSet<E>)collection).headSet(toElement));
373                    }
374    
375                    public SortedSet<E> tailSet(E fromElement) {
376                            return new SortedSetProxy<E>(persistentCollection, ((SortedSet<E>)collection).tailSet(fromElement));
377                    }
378    
379                    public E first() {
380                            return ((SortedSet<E>)collection).first();
381                    }
382    
383                    public E last() {
384                            return ((SortedSet<E>)collection).last();
385                    }
386            }
387            
388            static class SortedMapProxy<K, V> implements SortedMap<K, V> {
389                    
390                    protected final AbstractPersistentCollection<?> persistentCollection;
391                    protected final SortedMap<K, V> sortedMap;
392                    
393                    public SortedMapProxy(AbstractPersistentCollection<?> persistentCollection, SortedMap<K, V> sortedMap) {
394                            this.persistentCollection = persistentCollection;
395                            this.sortedMap = sortedMap;
396                    }
397    
398                    public int size() {
399                            return sortedMap.size();
400                    }
401    
402                    public boolean isEmpty() {
403                            return sortedMap.isEmpty();
404                    }
405    
406                    public boolean containsKey(Object key) {
407                            return sortedMap.containsKey(key);
408                    }
409    
410                    public boolean containsValue(Object value) {
411                            return sortedMap.containsValue(value);
412                    }
413    
414                    public V get(Object key) {
415                            return sortedMap.get(key);
416                    }
417    
418                    public V put(K key, V value) {
419                            boolean containsKey = sortedMap.containsKey(key);
420                            V previousValue = sortedMap.put(key, value);
421                            if (!containsKey || (previousValue == null ? value != null : !previousValue.equals(value)))
422                                    persistentCollection.dirty();
423                            return previousValue;
424                    }
425    
426                    public V remove(Object key) {
427                            boolean containsKey = sortedMap.containsKey(key);
428                            V removedValue = sortedMap.remove(key);
429                            if (containsKey)
430                                    persistentCollection.dirty();
431                            return removedValue;
432                    }
433    
434                    public void putAll(Map<? extends K, ? extends V> m) {
435                            for (Map.Entry<? extends K, ? extends V> entry : m.entrySet())
436                                    put(entry.getKey(), entry.getValue());
437                    }
438    
439                    public void clear() {
440                            if (!sortedMap.isEmpty()) {
441                                    sortedMap.clear();
442                                    persistentCollection.dirty();
443                            }
444                    }
445    
446                    public Comparator<? super K> comparator() {
447                            return sortedMap.comparator();
448                    }
449    
450                    public SortedMap<K, V> subMap(K fromKey, K toKey) {
451                            return new SortedMapProxy<K, V>(persistentCollection, sortedMap.subMap(fromKey, toKey));
452                    }
453    
454                    public SortedMap<K, V> headMap(K toKey) {
455                            return new SortedMapProxy<K, V>(persistentCollection, sortedMap.headMap(toKey));
456                    }
457    
458                    public SortedMap<K, V> tailMap(K fromKey) {
459                            return new SortedMapProxy<K, V>(persistentCollection, sortedMap.tailMap(fromKey));
460                    }
461    
462                    public K firstKey() {
463                            return sortedMap.firstKey();
464                    }
465    
466                    public K lastKey() {
467                            return sortedMap.lastKey();
468                    }
469    
470                    public Set<K> keySet() {
471                            return new SetProxy<K>(persistentCollection, sortedMap.keySet());
472                    }
473    
474                    public Collection<V> values() {
475                            return new CollectionProxy<V>(persistentCollection, sortedMap.values());
476                    }
477    
478                    public Set<Entry<K, V>> entrySet() {
479                            return new SetProxy<Entry<K, V>>(persistentCollection, sortedMap.entrySet());
480                    }
481    
482                    @Override
483                    public int hashCode() {
484                            return sortedMap.hashCode();
485                    }
486    
487                    @Override
488                    public boolean equals(Object obj) {
489                            return sortedMap.equals(obj);
490                    }
491            }
492    }