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