/** * GRANITE DATA SERVICES * Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S. * * This file is part of the Granite Data Services Platform. * * Granite Data Services is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * Granite Data Services is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA, or see <http://www.gnu.org/licenses/>. */ package org.granite.messaging.jmf.persistence; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedMap; import java.util.SortedSet; import org.granite.messaging.jmf.ExtendedObjectInput; import org.granite.messaging.persistence.PersistentCollectionSnapshot; /** * @author Franck WOLFF */ public class JMFPersistentCollectionSnapshot implements PersistentCollectionSnapshot { private static final long serialVersionUID = 1L; protected boolean initialized = false; protected boolean dirty = false; protected Object[] elements = null; protected boolean sorted = false; protected String comparatorClassName = null; public JMFPersistentCollectionSnapshot(String detachedState) { } public JMFPersistentCollectionSnapshot(boolean sorted, String detachedState) { this.sorted = sorted; } public JMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Collection<?> collection) { this.initialized = initialized; if (initialized) { this.dirty = dirty; this.elements = collection.toArray(); if (collection instanceof SortedSet) { this.sorted = true; Comparator<?> comparator = ((SortedSet<?>)collection).comparator(); if (comparator != null) this.comparatorClassName = comparator.getClass().getName(); } } } public JMFPersistentCollectionSnapshot(boolean initialized, String detachedState, boolean dirty, Map<?, ?> collection) { this.initialized = initialized; if (initialized) { this.dirty = dirty; Object[] entries = collection.entrySet().toArray(); this.elements = new Object[entries.length * 2]; int elementIndex = 0; for (int entryIndex = 0; entryIndex < entries.length; entryIndex++) { Map.Entry<?, ?> entry = (Map.Entry<?, ?>)entries[entryIndex]; this.elements[elementIndex++] = entry.getKey(); this.elements[elementIndex++] = entry.getValue(); } if (collection instanceof SortedMap) { this.sorted = true; Comparator<?> comparator = ((SortedMap<?, ?>)collection).comparator(); if (comparator != null) this.comparatorClassName = comparator.getClass().getName(); } } } public boolean isInitialized() { return initialized; } public String getDetachedState() { return null; } public boolean isDirty() { return dirty; } public boolean isSorted() { return sorted; } public String getComparatorClassName() { return comparatorClassName; } public <T> Comparator<T> newComparator(ObjectInput in) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { if (comparatorClassName == null) return null; return ((ExtendedObjectInput)in).getReflection().newInstance(comparatorClassName); } @SuppressWarnings("unchecked") public <T> Collection<T> getElementsAsCollection() { return (Collection<T>)Arrays.asList(elements); } public <K, V> Map<K, V> getElementsAsMap() { return new SnapshotMap<K, V>(elements); } public void writeExternal(ObjectOutput out) throws IOException { out.writeBoolean(initialized); if (initialized) { if (sorted) out.writeUTF(comparatorClassName); out.writeBoolean(dirty); out.writeObject(elements); } } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { readInitializationData(in); if (initialized) readCoreData(in); } public void readInitializationData(ObjectInput in) throws IOException { initialized = in.readBoolean(); if (initialized && sorted) comparatorClassName = in.readUTF(); } public void readCoreData(ObjectInput in) throws IOException, ClassNotFoundException { this.dirty = in.readBoolean(); this.elements = (Object[])in.readObject(); } static class SnapshotMap<K, V> implements Map<K, V> { private final Object[] elements; public SnapshotMap(Object[] elements) { if ((elements.length % 2) != 0) throw new IllegalArgumentException("Elements must have an even length: " + elements.length); this.elements = elements; } public int size() { return elements.length / 2; } public boolean isEmpty() { return elements.length == 0; } public Set<Entry<K, V>> entrySet() { return new Set<Entry<K, V>>() { public int size() { return elements.length / 2; } public boolean isEmpty() { return elements.length == 0; } public Iterator<Entry<K, V>> iterator() { return new Iterator<Entry<K, V>>() { private int cursor = 0; public boolean hasNext() { return cursor < elements.length; } @SuppressWarnings("unchecked") public Entry<K, V> next() { if (cursor >= elements.length) throw new NoSuchElementException(); K key = (K)elements[cursor++]; V value = (V)elements[cursor++]; return new SnapshotMapEntry<K, V>(key, value); } public void remove() { throw new UnsupportedOperationException(); } }; } public boolean contains(Object o) { throw new UnsupportedOperationException(); } public Object[] toArray() { throw new UnsupportedOperationException(); } public <T> T[] toArray(T[] a) { throw new UnsupportedOperationException(); } public boolean add(Entry<K, V> e) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public boolean containsAll(Collection<?> c) { throw new UnsupportedOperationException(); } public boolean addAll(Collection<? extends Entry<K, V>> c) { throw new UnsupportedOperationException(); } public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } @Override public int hashCode() { throw new UnsupportedOperationException(); } @Override public boolean equals(Object obj) { throw new UnsupportedOperationException(); } }; } public boolean containsKey(Object key) { throw new UnsupportedOperationException(); } public boolean containsValue(Object value) { throw new UnsupportedOperationException(); } public V get(Object key) { throw new UnsupportedOperationException(); } public V put(K key, V value) { throw new UnsupportedOperationException(); } public V remove(Object key) { throw new UnsupportedOperationException(); } public void putAll(Map<? extends K, ? extends V> m) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } public Set<K> keySet() { throw new UnsupportedOperationException(); } public Collection<V> values() { throw new UnsupportedOperationException(); } @Override public int hashCode() { throw new UnsupportedOperationException(); } @Override public boolean equals(Object obj) { throw new UnsupportedOperationException(); } } static class SnapshotMapEntry<K, V> implements Entry<K, V> { private final K key; private final V value; public SnapshotMapEntry(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { throw new UnsupportedOperationException(); } @Override public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } @Override public boolean equals(Object obj) { if (!(obj instanceof Entry)) return false; Entry<?, ?> e = (Entry<?, ?>)obj; return ( (key == null ? e.getKey() == null : key.equals(e.getKey())) && (value == null ? e.getValue() == null : value.equals(e.getValue())) ); } } }