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 */
022package org.granite.messaging.amf.persistence;
023
024import java.io.IOException;
025import java.io.ObjectInput;
026import java.io.ObjectOutput;
027import java.util.Arrays;
028import java.util.Collection;
029import java.util.Comparator;
030import java.util.Iterator;
031import java.util.Map;
032import java.util.Map.Entry;
033import java.util.NoSuchElementException;
034import java.util.Set;
035
036import org.granite.messaging.persistence.PersistentCollectionSnapshot;
037
038/**
039 * @author Franck WOLFF
040 */
041public 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}