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