/* * Copyright (c) 2011-2014 Jeppetto and Jonathan Thompson * * 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 org.iternine.jeppetto.dao.mongodb.enhance; import org.iternine.jeppetto.dao.JeppettoException; import org.bson.BSON; import org.bson.Transformer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * A DirtyableDBObjectSet uses two underlying collection objects to manage the semantics of this class. The * first is a Set object which is used to ensure Set semantics are followed, the second is an underlying List, * provided by the base class, to ensure ordering and provide the lookup by index methods that DBObject * implementations require. */ @SuppressWarnings({ "unchecked" }) public class DirtyableDBObjectSet extends DirtyableDBObjectList implements Set { //------------------------------------------------------------- // Variables - Private //------------------------------------------------------------- private Set delegate; private static Logger logger = LoggerFactory.getLogger(DirtyableDBObjectSet.class); //------------------------------------------------------------- // Constructors //------------------------------------------------------------- public DirtyableDBObjectSet() { super(); this.delegate = new HashSet(); } /** * * @param delegate Set instance this object should delegate responsibility to * @param modifiableDelegate true if access is possible to the delegate by non-Jeppetto code */ // TODO: Determine who calls and if we should have a DirtyableDBObjectSet(List delegate, boolean modi...) // TODO: Do we need to convert items in the delegate() to DirtyableDBObjects? public DirtyableDBObjectSet(Set delegate, boolean modifiableDelegate) { super(new ArrayList(delegate), modifiableDelegate); this.delegate = delegate; } //------------------------------------------------------------- // Implementation - Set //------------------------------------------------------------- @Override public int size() { return super.size(); } @Override public boolean isEmpty() { return super.isEmpty(); } @Override public boolean contains(Object element) { return delegate.contains(element); } @Override public Iterator iterator() { final Iterator iterator = super.iterator(); return new Iterator() { @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Object next() { return iterator.next(); } @Override public void remove() { // TODO: Verify this will return the same 'next()' Object next = iterator.next(); delegate.remove(next); iterator.remove(); // TODO: Mark super as dirty? } }; } @Override public Object[] toArray() { return super.toArray(); } @Override public Object[] toArray(Object[] objects) { return super.toArray(objects); } @Override public boolean add(Object element) { if (delegate.add(element)) { super.add(element); return true; } return false; } @Override public boolean remove(Object element) { if (delegate.remove(element)) { super.remove(element); // TODO: verify remove? return true; } return false; } @Override public boolean containsAll(Collection collection) { return delegate.containsAll(collection); } @Override public boolean addAll(Collection elements) { boolean changed = false; for (Object element : elements) { changed |= add(element); } return changed; } @Override public boolean retainAll(Collection elements) { throw new JeppettoException("Not implemented"); } @Override public boolean removeAll(Collection elements) { boolean changed = false; for (Object element : elements) { changed |= remove(element); } return changed; } @Override public void clear() { super.clear(); delegate.clear(); } //------------------------------------------------------------- // Implementation - DirtyableDBObject //------------------------------------------------------------- @Override public Object getDelegate() { return delegate; } //------------------------------------------------------------- // Implementation - DBObject //------------------------------------------------------------- @Override public Object removeField(String s) { Object o = super.removeField(s); if (o != null) { delegate.remove(o); } return o; } //------------------------------------------------------------- // Methods - Public //------------------------------------------------------------- public Transformer getDecodingTransformer() { return new DecodingTransformer(); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof Set)) { return false; } Set thatSet = o instanceof DirtyableDBObjectSet ? ((DirtyableDBObjectSet) o).delegate : (Set) o; return delegate.equals(thatSet); } @Override public int hashCode() { return delegate.hashCode(); } //------------------------------------------------------------- // Inner Class - DecodingTransformer //------------------------------------------------------------- class DecodingTransformer implements Transformer { //------------------------------------------------------------- // Implementation - Transformer //------------------------------------------------------------- @Override public Object transform(Object o) { if (o != DirtyableDBObjectSet.this) { return o; } Iterator iterator = iterator(); while (iterator.hasNext()) { Object next = iterator.next(); if (!delegate.add(next)) { logger.error("Dropping object because it is already a member of the set. Did you change the" + " equals() method and/or collection type? Object = " + next); DirtyableDBObjectSet.super.remove(next); } } BSON.removeDecodingHook(DirtyableDBObjectSet.class, this); return DirtyableDBObjectSet.this; } } }