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