Package org.hibernate.collection

Source Code of org.hibernate.collection.PersistentBag$SimpleAdd

//$Id: PersistentBag.java 10738 2006-11-06 21:56:38Z steve.ebersole@jboss.com $
package org.hibernate.collection;

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

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

/**
* An unordered, unkeyed collection that can contain the same element
* multiple times. The Java collections API, curiously, has no <tt>Bag</tt>.
* Most developers seem to use <tt>List</tt>s to represent bag semantics,
* so Hibernate follows this practice.
*
* @author Gavin King
*/
public class PersistentBag extends AbstractPersistentCollection implements List {

  protected List bag;

  public PersistentBag(SessionImplementor session) {
    super(session);
  }

  public PersistentBag(SessionImplementor session, Collection coll) {
    super(session);
    if (coll instanceof List) {
      bag = (List) coll;
    }
    else {
      bag = new ArrayList();
      Iterator iter = coll.iterator();
      while ( iter.hasNext() ) {
        bag.add( iter.next() );
      }
    }
    setInitialized();
    setDirectlyAccessible(true);
  }

  public PersistentBag() {} //needed for SOAP libraries, etc

  public boolean isWrapper(Object collection) {
    return bag==collection;
  }
  public boolean empty() {
    return bag.isEmpty();
  }

  public Iterator entries(CollectionPersister persister) {
    return bag.iterator();
  }

  public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
  throws HibernateException, SQLException {
    // note that if we load this collection from a cartesian product
    // the multiplicity would be broken ... so use an idbag instead
    Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
    if (element!=null) bag.add(element);
    return element;
  }

  public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
    this.bag = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
  }

  public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
    Type elementType = persister.getElementType();
    EntityMode entityMode = getSession().getEntityMode();
    List sn = (List) getSnapshot();
    if ( sn.size()!=bag.size() ) return false;
    Iterator iter = bag.iterator();
    while ( iter.hasNext() ) {
      Object elt = iter.next();
      final boolean unequal = countOccurrences(elt, bag, elementType, entityMode) !=
        countOccurrences(elt, sn, elementType, entityMode);
      if ( unequal ) return false;
    }
    return true;
  }

  public boolean isSnapshotEmpty(Serializable snapshot) {
    return ( (Collection) snapshot ).isEmpty();
  }

  private int countOccurrences(Object element, List list, Type elementType, EntityMode entityMode)
  throws HibernateException {
    Iterator iter = list.iterator();
    int result=0;
    while ( iter.hasNext() ) {
      if ( elementType.isSame( element, iter.next(), entityMode ) ) result++;
    }
    return result;
  }

  public Serializable getSnapshot(CollectionPersister persister)
  throws HibernateException {
    EntityMode entityMode = getSession().getEntityMode();
    ArrayList clonedList = new ArrayList( bag.size() );
    Iterator iter = bag.iterator();
    while ( iter.hasNext() ) {
      clonedList.add( persister.getElementType().deepCopy( iter.next(), entityMode, persister.getFactory() ) );
    }
    return clonedList;
  }

  public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
      List sn = (List) snapshot;
      return getOrphans( sn, bag, entityName, getSession() );
  }


  public Serializable disassemble(CollectionPersister persister)
  throws HibernateException {

    int length = bag.size();
    Serializable[] result = new Serializable[length];
    for ( int i=0; i<length; i++ ) {
      result[i] = persister.getElementType().disassemble( bag.get(i), getSession(), null );
    }
    return result;
  }

  public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
  throws HibernateException {
    Serializable[] array = (Serializable[]) disassembled;
    int size = array.length;
    beforeInitialize( persister, size );
    for ( int i = 0; i < size; i++ ) {
      Object element = persister.getElementType().assemble( array[i], getSession(), owner );
      if ( element!=null ) {
        bag.add( element );
      }
    }
  }

  public boolean needsRecreate(CollectionPersister persister) {
    return !persister.isOneToMany();
  }


  // For a one-to-many, a <bag> is not really a bag;
  // it is *really* a set, since it can't contain the
  // same element twice. It could be considered a bug
  // in the mapping dtd that <bag> allows <one-to-many>.

  // Anyway, here we implement <set> semantics for a
  // <one-to-many> <bag>!

  public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
    //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
    Type elementType = persister.getElementType();
    EntityMode entityMode = getSession().getEntityMode();
    ArrayList deletes = new ArrayList();
    List sn = (List) getSnapshot();
    Iterator olditer = sn.iterator();
    int i=0;
    while ( olditer.hasNext() ) {
      Object old = olditer.next();
      Iterator newiter = bag.iterator();
      boolean found = false;
      if ( bag.size()>i && elementType.isSame( old, bag.get(i++), entityMode ) ) {
      //a shortcut if its location didn't change!
        found = true;
      }
      else {
        //search for it
        //note that this code is incorrect for other than one-to-many
        while ( newiter.hasNext() ) {
          if ( elementType.isSame( old, newiter.next(), entityMode ) ) {
            found = true;
            break;
          }
        }
      }
      if (!found) deletes.add(old);
    }
    return deletes.iterator();
  }

  public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
    //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
    List sn = (List) getSnapshot();
    final EntityMode entityMode = getSession().getEntityMode();
    if ( sn.size()>i && elemType.isSame( sn.get(i), entry, entityMode ) ) {
    //a shortcut if its location didn't change!
      return false;
    }
    else {
      //search for it
      //note that this code is incorrect for other than one-to-many
      Iterator olditer = sn.iterator();
      while ( olditer.hasNext() ) {
        Object old = olditer.next();
        if ( elemType.isSame( old, entry, entityMode ) ) return false;
      }
      return true;
    }
  }

  public boolean isRowUpdatePossible() {
    return false;
  }

  public boolean needsUpdating(Object entry, int i, Type elemType) {
    //if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
    return false;
  }

  /**
   * @see java.util.Collection#size()
   */
  public int size() {
    return readSize() ? getCachedSize() : bag.size();
  }

  /**
   * @see java.util.Collection#isEmpty()
   */
  public boolean isEmpty() {
    return readSize() ? getCachedSize()==0 : bag.isEmpty();
  }

  /**
   * @see java.util.Collection#contains(Object)
   */
  public boolean contains(Object object) {
    Boolean exists = readElementExistence(object);
    return exists==null ?
        bag.contains(object) :
        exists.booleanValue();
  }

  /**
   * @see java.util.Collection#iterator()
   */
  public Iterator iterator() {
    read();
    return new IteratorProxy( bag.iterator() );
  }

  /**
   * @see java.util.Collection#toArray()
   */
  public Object[] toArray() {
    read();
    return bag.toArray();
  }

  /**
   * @see java.util.Collection#toArray(Object[])
   */
  public Object[] toArray(Object[] a) {
    read();
    return bag.toArray(a);
  }

  /**
   * @see java.util.Collection#add(Object)
   */
  public boolean add(Object object) {
    if ( !isOperationQueueEnabled() ) {
      write();
      return bag.add(object);
    }
    else {
      queueOperation( new SimpleAdd(object) );
      return true;
    }
  }

  /**
   * @see java.util.Collection#remove(Object)
   */
  public boolean remove(Object o) {
    initialize( true );
    if ( bag.remove( o ) ) {
      dirty();
      return true;
    }
    else {
      return false;
    }
  }

  /**
   * @see java.util.Collection#containsAll(Collection)
   */
  public boolean containsAll(Collection c) {
    read();
    return bag.containsAll(c);
  }

  /**
   * @see java.util.Collection#addAll(Collection)
   */
  public boolean addAll(Collection values) {
    if ( values.size()==0 ) return false;
    if ( !isOperationQueueEnabled() ) {
      write();
      return bag.addAll(values);
    }
    else {
      Iterator iter = values.iterator();
      while ( iter.hasNext() ) {
        queueOperation( new SimpleAdd( iter.next() ) );
      }
      return values.size()>0;
    }
  }

  /**
   * @see java.util.Collection#removeAll(Collection)
   */
  public boolean removeAll(Collection c) {
    if ( c.size()>0 ) {
      initialize( true );
      if ( bag.removeAll( c ) ) {
        dirty();
        return true;
      }
      else {
        return false;
      }
    }
    else {
      return false;
    }
  }

  /**
   * @see java.util.Collection#retainAll(Collection)
   */
  public boolean retainAll(Collection c) {
    initialize( true );
    if ( bag.retainAll( c ) ) {
      dirty();
      return true;
    }
    else {
      return false;
    }
  }

  /**
   * @see java.util.Collection#clear()
   */
  public void clear() {
    if ( isClearQueueEnabled() ) {
      queueOperation( new Clear() );
    }
    else {
      initialize( true );
      if ( ! bag.isEmpty() ) {
        bag.clear();
        dirty();
      }
    }
  }

  public Object getIndex(Object entry, int i, CollectionPersister persister) {
    throw new UnsupportedOperationException("Bags don't have indexes");
  }

  public Object getElement(Object entry) {
    return entry;
  }

  public Object getSnapshotElement(Object entry, int i) {
    List sn = (List) getSnapshot();
    return sn.get(i);
  }

  public int occurrences(Object o) {
    read();
    Iterator iter = bag.iterator();
    int result=0;
    while ( iter.hasNext() ) {
      if ( o.equals( iter.next() ) ) result++;
    }
    return result;
  }

  // List OPERATIONS:

  /**
   * @see java.util.List#add(int, Object)
   */
  public void add(int i, Object o) {
    write();
    bag.add(i, o);
  }

  /**
   * @see java.util.List#addAll(int, Collection)
   */
  public boolean addAll(int i, Collection c) {
    if ( c.size()>0 ) {
      write();
      return bag.addAll(i, c);
    }
    else {
      return false;
    }
  }

  /**
   * @see java.util.List#get(int)
   */
  public Object get(int i) {
    read();
    return bag.get(i);
  }

  /**
   * @see java.util.List#indexOf(Object)
   */
  public int indexOf(Object o) {
    read();
    return bag.indexOf(o);
  }

  /**
   * @see java.util.List#lastIndexOf(Object)
   */
  public int lastIndexOf(Object o) {
    read();
    return bag.lastIndexOf(o);
  }

  /**
   * @see java.util.List#listIterator()
   */
  public ListIterator listIterator() {
    read();
    return new ListIteratorProxy( bag.listIterator() );
  }

  /**
   * @see java.util.List#listIterator(int)
   */
  public ListIterator listIterator(int i) {
    read();
    return new ListIteratorProxy( bag.listIterator(i) );
  }

  /**
   * @see java.util.List#remove(int)
   */
  public Object remove(int i) {
    write();
    return bag.remove(i);
  }

  /**
   * @see java.util.List#set(int, Object)
   */
  public Object set(int i, Object o) {
    write();
    return bag.set(i, o);
  }

  /**
   * @see java.util.List#subList(int, int)
   */
  public List subList(int start, int end) {
    read();
    return new ListProxy( bag.subList(start, end) );
  }

  public String toString() {
    read();
    return bag.toString();
  }

  /*public boolean equals(Object other) {
    read();
    return bag.equals(other);
  }

  public int hashCode(Object other) {
    read();
    return bag.hashCode();
  }*/

  public boolean entryExists(Object entry, int i) {
    return entry!=null;
  }

  /**
   * Bag does not respect the collection API and do an
   * JVM instance comparison to do the equals.
   * The semantic is broken not to have to initialize a
   * collection for a simple equals() operation.
   * @see java.lang.Object#equals(java.lang.Object)
   */
  public boolean equals(Object obj) {
    return super.equals(obj);
  }

  /**
   * @see java.lang.Object#hashCode()
   */
  public int hashCode() {
    return super.hashCode();
  }

  final class Clear implements DelayedOperation {
    public void operate() {
      bag.clear();
    }
    public Object getAddedInstance() {
      return null;
    }
    public Object getOrphan() {
      throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
    }
  }

  final class SimpleAdd implements DelayedOperation {
    private Object value;

    public SimpleAdd(Object value) {
      this.value = value;
    }
    public void operate() {
      bag.add(value);
    }
    public Object getAddedInstance() {
      return value;
    }
    public Object getOrphan() {
      return null;
    }
  }

}
TOP

Related Classes of org.hibernate.collection.PersistentBag$SimpleAdd

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.