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.messaging.amf.persistence;
022    
023    import java.io.IOException;
024    import java.io.ObjectInput;
025    import java.io.ObjectOutput;
026    import java.util.Arrays;
027    import java.util.Collection;
028    import java.util.Comparator;
029    import java.util.Iterator;
030    import java.util.Map;
031    import java.util.Map.Entry;
032    import java.util.NoSuchElementException;
033    import java.util.Set;
034    
035    import org.granite.messaging.persistence.PersistentCollectionSnapshot;
036    
037    /**
038     * @author Franck WOLFF
039     */
040    public class AMFPersistentCollectionSnapshot implements PersistentCollectionSnapshot {
041            
042            protected boolean initialized = false;
043            protected String detachedState = null;
044            protected boolean dirty = false;
045            protected Object[] elements = null;
046            
047            public AMFPersistentCollectionSnapshot(String detachedState) {
048                    this.detachedState = detachedState;
049            }
050            
051            public AMFPersistentCollectionSnapshot(boolean sorted, String detachedState) {
052                    this.detachedState = detachedState;
053            }
054    
055            public AMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Collection<?> collection) {
056                    this.initialized = initialized;
057                    this.detachedState = detachedState;
058                    if (initialized) {
059                            this.dirty = dirty;
060                            this.elements = collection.toArray();
061                    }
062            }
063    
064            public AMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Map<?, ?> collection) {
065                    this.initialized = initialized;
066                    this.detachedState = detachedState;
067                    if (initialized) {
068                            this.dirty = dirty;
069                            
070                            Object[] entries = collection.entrySet().toArray();
071                            this.elements = new Object[entries.length];
072                            
073                            int elementIndex = 0;
074                            for (int entryIndex = 0; entryIndex < entries.length; entryIndex++) {
075                                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>)entries[entryIndex];
076                                    this.elements[elementIndex++] = new Object[] { entry.getKey(), entry.getValue() };
077                            }
078                    }
079            }
080            
081            public boolean isInitialized() {
082                    return initialized;
083            }
084            
085            public String getDetachedState() {
086                    return detachedState;
087            }
088    
089            public boolean isDirty() {
090                    return dirty;
091            }
092            
093            public boolean isSorted() {
094                    return false;
095            }
096            
097            public <T> Comparator<T> newComparator(ObjectInput in) {
098                    return null;
099            }
100            
101            @SuppressWarnings("unchecked")
102            public <T> Collection<T> getElementsAsCollection() {
103                    return (Collection<T>)Arrays.asList(elements);
104            }
105            
106            public <K, V> Map<K, V> getElementsAsMap() {
107                    return new SnapshotMap<K, V>(elements);
108            }
109            
110            public void writeExternal(ObjectOutput out) throws IOException {
111                    out.writeObject(initialized);
112                    out.writeObject(detachedState);
113                    if (initialized) {
114                            out.writeObject(dirty);
115                            out.writeObject(elements);
116                    }
117            }
118    
119            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
120                    readInitializationData(in);
121                    if (initialized)
122                            readCoreData(in);
123            }
124            
125            public void readInitializationData(ObjectInput in) throws IOException, ClassNotFoundException {
126                    initialized = ((Boolean)in.readObject()).booleanValue();
127                    detachedState = (String)in.readObject();
128            }
129            
130            public void readCoreData(ObjectInput in) throws IOException, ClassNotFoundException {
131                    this.dirty = ((Boolean)in.readObject()).booleanValue();
132                    this.elements = (Object[])in.readObject();
133            }
134            
135            static class SnapshotMap<K, V> implements Map<K, V> {
136                    
137                    private final Object[] elements;
138                    
139                    public SnapshotMap(Object[] elements) {
140                            this.elements = elements;
141                    }
142                    
143                    public int size() {
144                            return elements.length;
145                    }
146    
147                    public boolean isEmpty() {
148                            return elements.length == 0;
149                    }
150    
151                    public Set<Entry<K, V>> entrySet() {
152                            return new Set<Entry<K, V>>() {
153    
154                                    public int size() {
155                                            return elements.length;
156                                    }
157    
158                                    public boolean isEmpty() {
159                                            return elements.length == 0;
160                                    }
161    
162                                    public Iterator<Entry<K, V>> iterator() {
163                                            
164                                            return new Iterator<Entry<K, V>>() {
165    
166                                                    private int cursor = 0;
167                                                    
168                                                    public boolean hasNext() {
169                                                            return cursor < elements.length;
170                                                    }
171    
172                                                    @SuppressWarnings("unchecked")
173                                                    public Entry<K, V> next() {
174                                                            if (cursor >= elements.length)
175                                                                    throw new NoSuchElementException();
176                                                            
177                                                            Object[] element = (Object[])elements[cursor++];
178                                                            K key = (K)element[0];
179                                                            V value = (V)element[1];
180                                                            return new SnapshotMapEntry<K, V>(key, value);
181                                                    }
182    
183                                                    public void remove() {
184                                                            throw new UnsupportedOperationException();
185                                                    }
186                                            };
187                                    }
188    
189                                    public boolean contains(Object o) {
190                                            throw new UnsupportedOperationException();
191                                    }
192    
193                                    public Object[] toArray() {
194                                            throw new UnsupportedOperationException();
195                                    }
196    
197                                    public <T> T[] toArray(T[] a) {
198                                            throw new UnsupportedOperationException();
199                                    }
200    
201                                    public boolean add(Entry<K, V> e) {
202                                            throw new UnsupportedOperationException();
203                                    }
204    
205                                    public boolean remove(Object o) {
206                                            throw new UnsupportedOperationException();
207                                    }
208    
209                                    public boolean containsAll(Collection<?> c) {
210                                            throw new UnsupportedOperationException();
211                                    }
212    
213                                    public boolean addAll(Collection<? extends Entry<K, V>> c) {
214                                            throw new UnsupportedOperationException();
215                                    }
216    
217                                    public boolean retainAll(Collection<?> c) {
218                                            throw new UnsupportedOperationException();
219                                    }
220    
221                                    public boolean removeAll(Collection<?> c) {
222                                            throw new UnsupportedOperationException();
223                                    }
224    
225                                    public void clear() {
226                                            throw new UnsupportedOperationException();
227                                    }
228    
229                                    @Override
230                                    public int hashCode() {
231                                            throw new UnsupportedOperationException();
232                                    }
233    
234                                    @Override
235                                    public boolean equals(Object obj) {
236                                            throw new UnsupportedOperationException();
237                                    }
238                            };
239                    }
240    
241                    public boolean containsKey(Object key) {
242                            throw new UnsupportedOperationException();
243                    }
244    
245                    public boolean containsValue(Object value) {
246                            throw new UnsupportedOperationException();
247                    }
248    
249                    public V get(Object key) {
250                            throw new UnsupportedOperationException();
251                    }
252    
253                    public V put(K key, V value) {
254                            throw new UnsupportedOperationException();
255                    }
256    
257                    public V remove(Object key) {
258                            throw new UnsupportedOperationException();
259                    }
260    
261                    public void putAll(Map<? extends K, ? extends V> m) {
262                            throw new UnsupportedOperationException();
263                    }
264    
265                    public void clear() {
266                            throw new UnsupportedOperationException();
267                    }
268    
269                    public Set<K> keySet() {
270                            throw new UnsupportedOperationException();
271                    }
272    
273                    public Collection<V> values() {
274                            throw new UnsupportedOperationException();
275                    }
276    
277                    @Override
278                    public int hashCode() {
279                            throw new UnsupportedOperationException();
280                    }
281    
282                    @Override
283                    public boolean equals(Object obj) {
284                            throw new UnsupportedOperationException();
285                    }
286            }
287            
288            static class SnapshotMapEntry<K, V> implements Entry<K, V> {
289    
290                    private final K key;
291                    private final V value;
292                    
293                    public SnapshotMapEntry(K key, V value) {
294                            this.key = key;
295                            this.value = value;
296                    }
297    
298                    public K getKey() {
299                            return key;
300                    }
301    
302                    public V getValue() {
303                            return value;
304                    }
305    
306                    public V setValue(V value) {
307                            throw new UnsupportedOperationException();
308                    }
309    
310                    @Override
311                    public int hashCode() {
312                            return (key == null   ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
313                    }
314    
315                    @Override
316                    public boolean equals(Object obj) {
317                            if (!(obj instanceof Entry))
318                                    return false;
319                            Entry<?, ?> e = (Entry<?, ?>)obj;
320                            return (
321                                    (key == null ? e.getKey() == null : key.equals(e.getKey()))  &&
322                                    (value == null ? e.getValue() == null : value.equals(e.getValue()))
323                            );
324                    }
325            }
326    }