001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004     *
005     *   This file is part of the Granite Data Services Platform.
006     *
007     *   Granite Data Services is free software; you can redistribute it and/or
008     *   modify it under the terms of the GNU Lesser General Public
009     *   License as published by the Free Software Foundation; either
010     *   version 2.1 of the License, or (at your option) any later version.
011     *
012     *   Granite Data Services is distributed in the hope that it will be useful,
013     *   but WITHOUT ANY WARRANTY; without even the implied warranty of
014     *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015     *   General Public License for more details.
016     *
017     *   You should have received a copy of the GNU Lesser General Public
018     *   License along with this library; if not, write to the Free Software
019     *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020     *   USA, or see <http://www.gnu.org/licenses/>.
021     */
022    package org.granite.messaging.amf.persistence;
023    
024    import java.io.IOException;
025    import java.io.ObjectInput;
026    import java.io.ObjectOutput;
027    import java.util.Arrays;
028    import java.util.Collection;
029    import java.util.Comparator;
030    import java.util.Iterator;
031    import java.util.Map;
032    import java.util.Map.Entry;
033    import java.util.NoSuchElementException;
034    import java.util.Set;
035    
036    import org.granite.messaging.persistence.PersistentCollectionSnapshot;
037    
038    /**
039     * @author Franck WOLFF
040     */
041    public class AMFPersistentCollectionSnapshot implements PersistentCollectionSnapshot {
042            
043            private static final long serialVersionUID = 1L;
044            
045            protected boolean initialized = false;
046            protected String detachedState = null;
047            protected boolean dirty = false;
048            protected Object[] elements = null;
049            
050            public AMFPersistentCollectionSnapshot(String detachedState) {
051                    this.detachedState = detachedState;
052            }
053            
054            public AMFPersistentCollectionSnapshot(boolean sorted, String detachedState) {
055                    this.detachedState = detachedState;
056            }
057    
058            public AMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Collection<?> collection) {
059                    this.initialized = initialized;
060                    this.detachedState = detachedState;
061                    if (initialized) {
062                            this.dirty = dirty;
063                            this.elements = collection.toArray();
064                    }
065            }
066    
067            public AMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Map<?, ?> collection) {
068                    this.initialized = initialized;
069                    this.detachedState = detachedState;
070                    if (initialized) {
071                            this.dirty = dirty;
072                            
073                            Object[] entries = collection.entrySet().toArray();
074                            this.elements = new Object[entries.length];
075                            
076                            int elementIndex = 0;
077                            for (int entryIndex = 0; entryIndex < entries.length; entryIndex++) {
078                                    Map.Entry<?, ?> entry = (Map.Entry<?, ?>)entries[entryIndex];
079                                    this.elements[elementIndex++] = new Object[] { entry.getKey(), entry.getValue() };
080                            }
081                    }
082            }
083            
084            public boolean isInitialized() {
085                    return initialized;
086            }
087            
088            public String getDetachedState() {
089                    return detachedState;
090            }
091    
092            public boolean isDirty() {
093                    return dirty;
094            }
095            
096            public boolean isSorted() {
097                    return false;
098            }
099            
100            public <T> Comparator<T> newComparator(ObjectInput in) {
101                    return null;
102            }
103            
104            @SuppressWarnings("unchecked")
105            public <T> Collection<T> getElementsAsCollection() {
106                    return (Collection<T>)Arrays.asList(elements);
107            }
108            
109            public <K, V> Map<K, V> getElementsAsMap() {
110                    return new SnapshotMap<K, V>(elements);
111            }
112            
113            public void writeExternal(ObjectOutput out) throws IOException {
114                    out.writeObject(initialized);
115                    out.writeObject(detachedState);
116                    if (initialized) {
117                            out.writeObject(dirty);
118                            out.writeObject(elements);
119                    }
120            }
121    
122            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
123                    readInitializationData(in);
124                    if (initialized)
125                            readCoreData(in);
126            }
127            
128            public void readInitializationData(ObjectInput in) throws IOException, ClassNotFoundException {
129                    initialized = ((Boolean)in.readObject()).booleanValue();
130                    detachedState = (String)in.readObject();
131            }
132            
133            public void readCoreData(ObjectInput in) throws IOException, ClassNotFoundException {
134                    this.dirty = ((Boolean)in.readObject()).booleanValue();
135                    this.elements = (Object[])in.readObject();
136            }
137            
138            static class SnapshotMap<K, V> implements Map<K, V> {
139                    
140                    private final Object[] elements;
141                    
142                    public SnapshotMap(Object[] elements) {
143                            this.elements = elements;
144                    }
145                    
146                    public int size() {
147                            return elements.length;
148                    }
149    
150                    public boolean isEmpty() {
151                            return elements.length == 0;
152                    }
153    
154                    public Set<Entry<K, V>> entrySet() {
155                            return new Set<Entry<K, V>>() {
156    
157                                    public int size() {
158                                            return elements.length;
159                                    }
160    
161                                    public boolean isEmpty() {
162                                            return elements.length == 0;
163                                    }
164    
165                                    public Iterator<Entry<K, V>> iterator() {
166                                            
167                                            return new Iterator<Entry<K, V>>() {
168    
169                                                    private int cursor = 0;
170                                                    
171                                                    public boolean hasNext() {
172                                                            return cursor < elements.length;
173                                                    }
174    
175                                                    @SuppressWarnings("unchecked")
176                                                    public Entry<K, V> next() {
177                                                            if (cursor >= elements.length)
178                                                                    throw new NoSuchElementException();
179                                                            
180                                                            Object[] element = (Object[])elements[cursor++];
181                                                            K key = (K)element[0];
182                                                            V value = (V)element[1];
183                                                            return new SnapshotMapEntry<K, V>(key, value);
184                                                    }
185    
186                                                    public void remove() {
187                                                            throw new UnsupportedOperationException();
188                                                    }
189                                            };
190                                    }
191    
192                                    public boolean contains(Object o) {
193                                            throw new UnsupportedOperationException();
194                                    }
195    
196                                    public Object[] toArray() {
197                                            throw new UnsupportedOperationException();
198                                    }
199    
200                                    public <T> T[] toArray(T[] a) {
201                                            throw new UnsupportedOperationException();
202                                    }
203    
204                                    public boolean add(Entry<K, V> e) {
205                                            throw new UnsupportedOperationException();
206                                    }
207    
208                                    public boolean remove(Object o) {
209                                            throw new UnsupportedOperationException();
210                                    }
211    
212                                    public boolean containsAll(Collection<?> c) {
213                                            throw new UnsupportedOperationException();
214                                    }
215    
216                                    public boolean addAll(Collection<? extends Entry<K, V>> c) {
217                                            throw new UnsupportedOperationException();
218                                    }
219    
220                                    public boolean retainAll(Collection<?> c) {
221                                            throw new UnsupportedOperationException();
222                                    }
223    
224                                    public boolean removeAll(Collection<?> c) {
225                                            throw new UnsupportedOperationException();
226                                    }
227    
228                                    public void clear() {
229                                            throw new UnsupportedOperationException();
230                                    }
231    
232                                    @Override
233                                    public int hashCode() {
234                                            throw new UnsupportedOperationException();
235                                    }
236    
237                                    @Override
238                                    public boolean equals(Object obj) {
239                                            throw new UnsupportedOperationException();
240                                    }
241                            };
242                    }
243    
244                    public boolean containsKey(Object key) {
245                            throw new UnsupportedOperationException();
246                    }
247    
248                    public boolean containsValue(Object value) {
249                            throw new UnsupportedOperationException();
250                    }
251    
252                    public V get(Object key) {
253                            throw new UnsupportedOperationException();
254                    }
255    
256                    public V put(K key, V value) {
257                            throw new UnsupportedOperationException();
258                    }
259    
260                    public V remove(Object key) {
261                            throw new UnsupportedOperationException();
262                    }
263    
264                    public void putAll(Map<? extends K, ? extends V> m) {
265                            throw new UnsupportedOperationException();
266                    }
267    
268                    public void clear() {
269                            throw new UnsupportedOperationException();
270                    }
271    
272                    public Set<K> keySet() {
273                            throw new UnsupportedOperationException();
274                    }
275    
276                    public Collection<V> values() {
277                            throw new UnsupportedOperationException();
278                    }
279    
280                    @Override
281                    public int hashCode() {
282                            throw new UnsupportedOperationException();
283                    }
284    
285                    @Override
286                    public boolean equals(Object obj) {
287                            throw new UnsupportedOperationException();
288                    }
289            }
290            
291            static class SnapshotMapEntry<K, V> implements Entry<K, V> {
292    
293                    private final K key;
294                    private final V value;
295                    
296                    public SnapshotMapEntry(K key, V value) {
297                            this.key = key;
298                            this.value = value;
299                    }
300    
301                    public K getKey() {
302                            return key;
303                    }
304    
305                    public V getValue() {
306                            return value;
307                    }
308    
309                    public V setValue(V value) {
310                            throw new UnsupportedOperationException();
311                    }
312    
313                    @Override
314                    public int hashCode() {
315                            return (key == null   ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
316                    }
317    
318                    @Override
319                    public boolean equals(Object obj) {
320                            if (!(obj instanceof Entry))
321                                    return false;
322                            Entry<?, ?> e = (Entry<?, ?>)obj;
323                            return (
324                                    (key == null ? e.getKey() == null : key.equals(e.getKey()))  &&
325                                    (value == null ? e.getValue() == null : value.equals(e.getValue()))
326                            );
327                    }
328            }
329    }