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 }