package edu.ualberta.med.biobank.common.wrappers; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Helper class to {@link ModelWrapper} to track the original set of collection * {@link Property}-s (if they're about to change) so that it can be easily * determined later what the added and removed elements of the collection were, * if any. Tracks a single given {@link ModelWrapper}. * * @author jferland * * @param <E> */ // TODO: should add a class to check that the elements that we think were added // and removed were actually added and removed (as this could be wrong if the // underlying model object was modified then given to the wrapper). public class ElementTracker<E> { private final Map<Property<? extends Collection<?>, ? super E>, Object> originalElementsMap = new HashMap<Property<? extends Collection<?>, ? super E>, Object>(); private final Map<Property<?, ? super E>, Object> originalValueMap = new HashMap<Property<?, ? super E>, Object>(); private final ModelWrapper<E> wrapper; /** * @param wrapper the {@link ModelWrapper} to track */ public ElementTracker(ModelWrapper<E> wrapper) { this.wrapper = wrapper; } /** * This method only does something the first time it is called for any given * property. * * @param <T> * @param property */ public <T> void trackProperty(Property<T, ? super E> property) { if (!originalValueMap.containsKey(property)) { ModelWrapper<T> originalValue = wrapper.getWrappedProperty( property, null); originalValueMap.put(property, originalValue); } } public <T> ModelWrapper<T> getRemovedValue(Property<T, ? super E> property) { ModelWrapper<T> removedValue = null; ModelWrapper<T> oldValue = getOldValue(property); ModelWrapper<T> newValue = getCurrentValue(property); if (oldValue != null && !oldValue.equals(newValue)) { removedValue = oldValue; } return removedValue; } /** * This method only does something the first time it is called for any given * property. * * @param <T> * @param property */ public <T> void trackCollection(Property<Collection<T>, ? super E> property) { if (!originalElementsMap.containsKey(property)) { Collection<ModelWrapper<T>> originalValues = getCurrentElements(property); originalElementsMap.put(property, originalValues); } } /** * Gets a list of {@link ModelWrapper}-ed elements that were added to the * given collection {@link Property}. * * @param <T> * @param property * @return */ public <T> Collection<ModelWrapper<T>> getAddedElements( Property<Collection<T>, ? super E> property) { Collection<ModelWrapper<T>> addedElements = new ArrayList<ModelWrapper<T>>(); if (originalElementsMap.containsKey(property)) { Collection<ModelWrapper<T>> originalValues = getOriginalElements(property); Collection<ModelWrapper<T>> newValues = getCurrentElements(property); addedElements.addAll(newValues); addedElements.removeAll(originalValues); } else { // the property getter (on the wrapper) was never called if the map // is missing the property; however, there might still be added // elements in the ElementQueue. Collection<ModelWrapper<T>> queued = wrapper.getElementQueue() .getAdded(property); addedElements.addAll(queued); } return addedElements; } /** * Gets a list of {@link ModelWrapper}-ed elements that were removed from * the given collection {@link Property}. * * @param <T> * @param property * @return */ public <T> Collection<ModelWrapper<T>> getRemovedElements( Property<Collection<T>, ? super E> property) { Collection<ModelWrapper<T>> removedElements = new ArrayList<ModelWrapper<T>>(); if (originalElementsMap.containsKey(property)) { Collection<ModelWrapper<T>> originalValues = getOriginalElements(property); Collection<ModelWrapper<T>> newValues = getCurrentElements(property); removedElements.addAll(originalValues); removedElements.removeAll(newValues); } else { // the property getter (on the wrapper) was never called if the map // is missing the property; however, there might still be removed // elements in the ElementQueue. Collection<ModelWrapper<T>> queued = wrapper.getElementQueue() .getRemoved(property); removedElements.addAll(queued); } return removedElements; } /** * Clears the tracked collection {@link Property} list. */ public void clear() { originalElementsMap.clear(); originalValueMap.clear(); } private <T> ModelWrapper<T> getCurrentValue(Property<T, ? super E> property) { @SuppressWarnings("unchecked") ModelWrapper<T> currentValue = (ModelWrapper<T>) wrapper .getWrappedProperty(property, null); return currentValue; } private <T> ModelWrapper<T> getOldValue(Property<T, ? super E> property) { ModelWrapper<T> oldValue = null; if (originalValueMap.containsKey(property)) { @SuppressWarnings("unchecked") ModelWrapper<T> tmp = (ModelWrapper<T>) originalValueMap .get(property); oldValue = tmp; } return oldValue; } private <T> Collection<ModelWrapper<T>> getCurrentElements( Property<Collection<T>, ? super E> property) { Collection<ModelWrapper<T>> current = new ArrayList<ModelWrapper<T>>(); List<ModelWrapper<T>> tmp = wrapper.getWrapperCollection(property, null, false); current.addAll(tmp); return current; } private <T> Collection<ModelWrapper<T>> getOriginalElements( Property<? extends Collection<? extends T>, ? super E> property) { Collection<ModelWrapper<T>> original = new ArrayList<ModelWrapper<T>>(); if (originalElementsMap.containsKey(property)) { @SuppressWarnings("unchecked") Collection<ModelWrapper<T>> tmp = (Collection<ModelWrapper<T>>) originalElementsMap .get(property); original.addAll(tmp); } return original; } }