org.hibernate.collection.internal.PersistentSet.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.collection.internal.PersistentSet.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.collection.internal;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.type.Type;

/**
 * A persistent wrapper for a <tt>java.util.Set</tt>. The underlying
 * collection is a <tt>HashSet</tt>.
 *
 * @see java.util.HashSet
 * @author Gavin King
 */
public class PersistentSet extends AbstractPersistentCollection implements java.util.Set {
    protected Set set;
    protected transient List tempList;

    /**
     * Empty constructor.
     * <p/>
     * Note: this form is not ever ever ever used by Hibernate; it is, however,
     * needed for SOAP libraries and other such marshalling code.
     */
    public PersistentSet() {
        // intentionally empty
    }

    /**
     * Constructor matching super.  Instantiates a lazy set (the underlying
     * set is un-initialized).
     *
     * @param session The session to which this set will belong.
     */
    public PersistentSet(SharedSessionContractImplementor session) {
        super(session);
    }

    /**
     *  Instantiates a lazy set (the underlying set is un-initialized).
     *
     * @param session The session to which this set will belong.
     * @deprecated {@link #PersistentSet(SharedSessionContractImplementor)} should be used instead.
     */
    @Deprecated
    public PersistentSet(SessionImplementor session) {
        this((SharedSessionContractImplementor) session);
    }

    /**
     * Instantiates a non-lazy set (the underlying set is constructed
     * from the incoming set reference).
     *
     * @param session The session to which this set will belong.
     * @param set The underlying set data.
     */
    public PersistentSet(SharedSessionContractImplementor session, java.util.Set set) {
        super(session);
        // Sets can be just a view of a part of another collection.
        // do we need to copy it to be sure it won't be changing
        // underneath us?
        // ie. this.set.addAll(set);
        this.set = set;
        setInitialized();
        setDirectlyAccessible(true);
    }

    /**
     * Instantiates a non-lazy set (the underlying set is constructed
     * from the incoming set reference).
     *
     * @param session The session to which this set will belong.
     * @param set The underlying set data.
     * @deprecated {@link #PersistentSet(SharedSessionContractImplementor, java.util.Set)} should be used instead.
     */
    @Deprecated
    public PersistentSet(SessionImplementor session, java.util.Set set) {
        this((SharedSessionContractImplementor) session, set);
    }

    @Override
    @SuppressWarnings({ "unchecked" })
    public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
        final HashMap clonedSet = new HashMap(set.size());
        for (Object aSet : set) {
            final Object copied = persister.getElementType().deepCopy(aSet, persister.getFactory());
            clonedSet.put(copied, copied);
        }
        return clonedSet;
    }

    @Override
    public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
        final java.util.Map sn = (java.util.Map) snapshot;
        return getOrphans(sn.keySet(), set, entityName, getSession());
    }

    @Override
    public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
        final Type elementType = persister.getElementType();
        final java.util.Map sn = (java.util.Map) getSnapshot();
        if (sn.size() != set.size()) {
            return false;
        } else {
            for (Object test : set) {
                final Object oldValue = sn.get(test);
                if (oldValue == null || elementType.isDirty(oldValue, test, getSession())) {
                    return false;
                }
            }
            return true;
        }
    }

    @Override
    public boolean isSnapshotEmpty(Serializable snapshot) {
        return ((java.util.Map) snapshot).isEmpty();
    }

    @Override
    public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
        this.set = (Set) persister.getCollectionType().instantiate(anticipatedSize);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
            throws HibernateException {
        final Serializable[] array = (Serializable[]) disassembled;
        final int size = array.length;
        beforeInitialize(persister, size);
        for (Serializable arrayElement : array) {
            final Object assembledArrayElement = persister.getElementType().assemble(arrayElement, getSession(),
                    owner);
            if (assembledArrayElement != null) {
                set.add(assembledArrayElement);
            }
        }
    }

    @Override
    public boolean empty() {
        return set.isEmpty();
    }

    @Override
    @SuppressWarnings("unchecked")
    public int size() {
        return readSize() ? getCachedSize() : set.size();
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean isEmpty() {
        return readSize() ? getCachedSize() == 0 : set.isEmpty();
    }

    @Override
    public boolean contains(Object object) {
        final Boolean exists = readElementExistence(object);
        return exists == null ? set.contains(object) : exists;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Iterator iterator() {
        read();
        return new IteratorProxy(set.iterator());
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object[] toArray() {
        read();
        return set.toArray();
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object[] toArray(Object[] array) {
        read();
        return set.toArray(array);
    }

    @Override
    public boolean add(Object value) {
        final Boolean exists = isOperationQueueEnabled() ? readElementExistence(value) : null;
        if (exists == null) {
            initialize(true);
            if (set.add(value)) {
                dirty();
                return true;
            } else {
                return false;
            }
        } else if (exists) {
            return false;
        } else {
            queueOperation(new SimpleAdd(value));
            return true;
        }
    }

    @Override
    public boolean remove(Object value) {
        final Boolean exists = isPutQueueEnabled() ? readElementExistence(value) : null;
        if (exists == null) {
            initialize(true);
            if (set.remove(value)) {
                elementRemoved = true;
                dirty();
                return true;
            } else {
                return false;
            }
        } else if (exists) {
            elementRemoved = true;
            queueOperation(new SimpleRemove(value));
            return true;
        } else {
            return false;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean containsAll(Collection coll) {
        read();
        return set.containsAll(coll);
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean addAll(Collection coll) {
        if (coll.size() > 0) {
            initialize(true);
            if (set.addAll(coll)) {
                dirty();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean retainAll(Collection coll) {
        initialize(true);
        if (set.retainAll(coll)) {
            dirty();
            return true;
        } else {
            return false;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean removeAll(Collection coll) {
        if (coll.size() > 0) {
            initialize(true);
            if (set.removeAll(coll)) {
                elementRemoved = true;
                dirty();
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void clear() {
        if (isClearQueueEnabled()) {
            queueOperation(new Clear());
        } else {
            initialize(true);
            if (!set.isEmpty()) {
                set.clear();
                dirty();
            }
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public String toString() {
        read();
        return set.toString();
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
            throws HibernateException, SQLException {
        final Object element = persister.readElement(rs, owner, descriptor.getSuffixedElementAliases(),
                getSession());
        if (element != null) {
            tempList.add(element);
        }
        return element;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void beginRead() {
        super.beginRead();
        tempList = new ArrayList();
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean endRead() {
        set.addAll(tempList);
        tempList = null;
        // ensure that operationQueue is considered
        return super.endRead();
    }

    @Override
    @SuppressWarnings("unchecked")
    public Iterator entries(CollectionPersister persister) {
        return set.iterator();
    }

    @Override
    @SuppressWarnings("unchecked")
    public Serializable disassemble(CollectionPersister persister) throws HibernateException {
        final Serializable[] result = new Serializable[set.size()];
        final Iterator itr = set.iterator();
        int i = 0;
        while (itr.hasNext()) {
            result[i++] = persister.getElementType().disassemble(itr.next(), getSession(), null);
        }
        return result;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
        final Type elementType = persister.getElementType();
        final java.util.Map sn = (java.util.Map) getSnapshot();
        final ArrayList deletes = new ArrayList(sn.size());

        Iterator itr = sn.keySet().iterator();
        while (itr.hasNext()) {
            final Object test = itr.next();
            if (!set.contains(test)) {
                // the element has been removed from the set
                deletes.add(test);
            }
        }

        itr = set.iterator();
        while (itr.hasNext()) {
            final Object test = itr.next();
            final Object oldValue = sn.get(test);
            if (oldValue != null && elementType.isDirty(test, oldValue, getSession())) {
                // the element has changed
                deletes.add(oldValue);
            }
        }

        return deletes.iterator();
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
        final Object oldValue = ((java.util.Map) getSnapshot()).get(entry);
        // note that it might be better to iterate the snapshot but this is safe,
        // assuming the user implements equals() properly, as required by the Set
        // contract!
        return (oldValue == null && entry != null) || elemType.isDirty(oldValue, entry, getSession());
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean needsUpdating(Object entry, int i, Type elemType) {
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean isRowUpdatePossible() {
        return false;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object getIndex(Object entry, int i, CollectionPersister persister) {
        throw new UnsupportedOperationException("Sets don't have indexes");
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object getElement(Object entry) {
        return entry;
    }

    @Override
    @SuppressWarnings("unchecked")
    public Object getSnapshotElement(Object entry, int i) {
        throw new UnsupportedOperationException("Sets don't support updating by element");
    }

    @Override
    @SuppressWarnings({ "unchecked", "EqualsWhichDoesntCheckParameterClass" })
    public boolean equals(Object other) {
        read();
        return set.equals(other);
    }

    @Override
    @SuppressWarnings("unchecked")
    public int hashCode() {
        read();
        return set.hashCode();
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean entryExists(Object key, int i) {
        return key != null;
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean isWrapper(Object collection) {
        return set == collection;
    }

    final class Clear implements DelayedOperation {
        @Override
        public void operate() {
            set.clear();
        }

        @Override
        public Object getAddedInstance() {
            return null;
        }

        @Override
        public Object getOrphan() {
            throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
        }
    }

    final class SimpleAdd extends AbstractValueDelayedOperation {

        public SimpleAdd(Object addedValue) {
            super(addedValue, null);
        }

        @Override
        @SuppressWarnings("unchecked")
        public void operate() {
            set.add(getAddedInstance());
        }
    }

    final class SimpleRemove extends AbstractValueDelayedOperation {

        public SimpleRemove(Object orphan) {
            super(null, orphan);
        }

        @Override
        @SuppressWarnings("unchecked")
        public void operate() {
            set.remove(getOrphan());
        }
    }
}