/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * !# */ package net.ontopia.persistence.proxy; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.HashSet; import java.util.Set; import net.ontopia.utils.OntopiaRuntimeException; /** * INTERNAL: A set implementation that track the changes performed on * it. It keeps track of the objects that have been added and the ones * that has been removed. */ public class TrackableSet<E> extends HashSet<E> implements TrackableCollectionIF<E> { protected TransactionIF txn; protected Set<E> added; protected Set<E> removed; public void dump() { System.out.println("(TS: " + this + ")"); System.out.println(" (+: " + added + ")"); System.out.println(" (-: " + removed + ")"); } public TrackableSet(TransactionIF txn, Collection<E> coll) { // init with coll size super((coll == null ? 0 : coll.size())); init(txn, coll); } private synchronized void init(TransactionIF txn, Collection<E> coll) { // add to collection if not null and not empty if (coll != null && !coll.isEmpty()) { Iterator<E> iter = coll.iterator(); while (iter.hasNext()) { super.add(iter.next()); } } this.txn = txn; } public void resetTracking() { // Clears the lists of added and removed objects. // FIXME: Figure out if clearing collection or resetting to null is faster added = null; removed = null; // if (added != null) added.clear(); // if (removed != null) removed.clear(); } public void selfAdded() { if (!isEmpty()) { if (added == null) added = new HashSet<E>(this); else added.addAll(this); } } public Collection<E> getAdded() { return added; } public Collection<E> getRemoved() { return removed; } public boolean addWithTracking(E _o) { // Make sure persistent values are represented by their identity E o; if (_o instanceof PersistentIF) { o = (E) ((PersistentIF)_o)._p_getIdentity(); if (o == null) throw new OntopiaRuntimeException("Attempting to add PersistentIF without identity to TrackableSet"); } else o = _o; boolean result = super.add(o); // Do not track if object wasn't really added. if (result) { // Register added object and remove object from removed objects if (removed == null || !removed.remove(o)) { // Initialize added set if (added == null) added = new HashSet<E>(4); added.add(o); } } return result; } public boolean removeWithTracking(E _o) { // Make sure persistent values are represented by their identity E o; if (_o instanceof PersistentIF) { o = (E) ((PersistentIF)_o)._p_getIdentity(); if (o == null) throw new OntopiaRuntimeException("Attempting to add PersistentIF without identity to TrackableSet"); } else o = _o; boolean result = super.remove(o); // Do not track if object wasn't really removed. if (result) { // Register removed object and remove object from added objects if (added == null || !added.remove(o)) { // Initialize removed set if (removed == null) removed = new HashSet(4); removed.add(o); } } return result; } public void clearWithTracking() { Iterator<E> iter = new ArrayList<E>(this).iterator(); while (iter.hasNext()) { removeWithTracking(iter.next()); } } // -- immutable collection public void clear() { throw new UnsupportedOperationException(); } public boolean add(E o) { throw new UnsupportedOperationException(); } public boolean addAll(Collection<? extends E> c) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException(); } public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException(); } // -- iterator public Iterator<E> iterator() { return new PersistentIterator<E>(txn, true, super.iterator()); } // -- other public boolean contains(Object o) { return super.contains((o instanceof PersistentIF ? ((PersistentIF)o)._p_getIdentity() : o)); } public boolean containsAll(Collection<?> c) { Iterator e = c.iterator(); while (e.hasNext()) if(!contains(e.next())) return false; return true; } public Object[] toArray() { Object[] result = new Object[size()]; Iterator it = iterator(); int i = 0; for (; it.hasNext(); i++) { result[i] = it.next(); } if (i+1 < result.length) { Object[] r = new Object[i+1]; System.arraycopy(result, 0, r, 0, i+1); return r; } else { return result; } } @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); int i = 0; Iterator<E> it = iterator(); for (; it.hasNext(); i++) { a[i] = (T) it.next(); } if (a.length > i+1) a[i+1] = null; return a; } }