Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » collection » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.collection;
   26   
   27   import java.io.Serializable;
   28   import java.sql.ResultSet;
   29   import java.sql.SQLException;
   30   import java.util.ArrayList;
   31   import java.util.Collection;
   32   import java.util.Iterator;
   33   import java.util.List;
   34   import java.util.ListIterator;
   35   
   36   import org.hibernate.EntityMode;
   37   import org.hibernate.HibernateException;
   38   import org.hibernate.engine.SessionImplementor;
   39   import org.hibernate.loader.CollectionAliases;
   40   import org.hibernate.persister.collection.CollectionPersister;
   41   import org.hibernate.type.Type;
   42   
   43   /**
   44    * An unordered, unkeyed collection that can contain the same element
   45    * multiple times. The Java collections API, curiously, has no <tt>Bag</tt>.
   46    * Most developers seem to use <tt>List</tt>s to represent bag semantics,
   47    * so Hibernate follows this practice.
   48    *
   49    * @author Gavin King
   50    */
   51   public class PersistentBag extends AbstractPersistentCollection implements List {
   52   
   53   	protected List bag;
   54   
   55   	public PersistentBag(SessionImplementor session) {
   56   		super(session);
   57   	}
   58   
   59   	public PersistentBag(SessionImplementor session, Collection coll) {
   60   		super(session);
   61   		if (coll instanceof List) {
   62   			bag = (List) coll;
   63   		}
   64   		else {
   65   			bag = new ArrayList();
   66   			Iterator iter = coll.iterator();
   67   			while ( iter.hasNext() ) {
   68   				bag.add( iter.next() );
   69   			}
   70   		}
   71   		setInitialized();
   72   		setDirectlyAccessible(true);
   73   	}
   74   
   75   	public PersistentBag() {} //needed for SOAP libraries, etc
   76   
   77   	public boolean isWrapper(Object collection) {
   78   		return bag==collection;
   79   	}
   80   	public boolean empty() {
   81   		return bag.isEmpty();
   82   	}
   83   
   84   	public Iterator entries(CollectionPersister persister) {
   85   		return bag.iterator();
   86   	}
   87   
   88   	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
   89   	throws HibernateException, SQLException {
   90   		// note that if we load this collection from a cartesian product
   91   		// the multiplicity would be broken ... so use an idbag instead
   92   		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ) ;
   93   		if (element!=null) bag.add(element);
   94   		return element;
   95   	}
   96   
   97   	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
   98   		this.bag = ( List ) persister.getCollectionType().instantiate( anticipatedSize );
   99   	}
  100   
  101   	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
  102   		Type elementType = persister.getElementType();
  103   		EntityMode entityMode = getSession().getEntityMode();
  104   		List sn = (List) getSnapshot();
  105   		if ( sn.size()!=bag.size() ) return false;
  106   		Iterator iter = bag.iterator();
  107   		while ( iter.hasNext() ) {
  108   			Object elt = iter.next();
  109   			final boolean unequal = countOccurrences(elt, bag, elementType, entityMode) !=
  110   				countOccurrences(elt, sn, elementType, entityMode);
  111   			if ( unequal ) return false;
  112   		}
  113   		return true;
  114   	}
  115   
  116   	public boolean isSnapshotEmpty(Serializable snapshot) {
  117   		return ( (Collection) snapshot ).isEmpty();
  118   	}
  119   
  120   	private int countOccurrences(Object element, List list, Type elementType, EntityMode entityMode)
  121   	throws HibernateException {
  122   		Iterator iter = list.iterator();
  123   		int result=0;
  124   		while ( iter.hasNext() ) {
  125   			if ( elementType.isSame( element, iter.next(), entityMode ) ) result++;
  126   		}
  127   		return result;
  128   	}
  129   
  130   	public Serializable getSnapshot(CollectionPersister persister)
  131   	throws HibernateException {
  132   		EntityMode entityMode = getSession().getEntityMode();
  133   		ArrayList clonedList = new ArrayList( bag.size() );
  134   		Iterator iter = bag.iterator();
  135   		while ( iter.hasNext() ) {
  136   			clonedList.add( persister.getElementType().deepCopy( iter.next(), entityMode, persister.getFactory() ) );
  137   		}
  138   		return clonedList;
  139   	}
  140   
  141   	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
  142   	    List sn = (List) snapshot;
  143   	    return getOrphans( sn, bag, entityName, getSession() );
  144   	}
  145   
  146   
  147   	public Serializable disassemble(CollectionPersister persister)
  148   	throws HibernateException {
  149   
  150   		int length = bag.size();
  151   		Serializable[] result = new Serializable[length];
  152   		for ( int i=0; i<length; i++ ) {
  153   			result[i] = persister.getElementType().disassemble( bag.get(i), getSession(), null );
  154   		}
  155   		return result;
  156   	}
  157   
  158   	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
  159   	throws HibernateException {
  160   		Serializable[] array = (Serializable[]) disassembled;
  161   		int size = array.length;
  162   		beforeInitialize( persister, size );
  163   		for ( int i = 0; i < size; i++ ) {
  164   			Object element = persister.getElementType().assemble( array[i], getSession(), owner );
  165   			if ( element!=null ) {
  166   				bag.add( element );
  167   			}
  168   		}
  169   	}
  170   
  171   	public boolean needsRecreate(CollectionPersister persister) {
  172   		return !persister.isOneToMany();
  173   	}
  174   
  175   
  176   	// For a one-to-many, a <bag> is not really a bag;
  177   	// it is *really* a set, since it can't contain the
  178   	// same element twice. It could be considered a bug
  179   	// in the mapping dtd that <bag> allows <one-to-many>.
  180   
  181   	// Anyway, here we implement <set> semantics for a
  182   	// <one-to-many> <bag>!
  183   
  184   	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException {
  185   		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
  186   		Type elementType = persister.getElementType();
  187   		EntityMode entityMode = getSession().getEntityMode();
  188   		ArrayList deletes = new ArrayList();
  189   		List sn = (List) getSnapshot();
  190   		Iterator olditer = sn.iterator();
  191   		int i=0;
  192   		while ( olditer.hasNext() ) {
  193   			Object old = olditer.next();
  194   			Iterator newiter = bag.iterator();
  195   			boolean found = false;
  196   			if ( bag.size()>i && elementType.isSame( old, bag.get(i++), entityMode ) ) {
  197   			//a shortcut if its location didn't change!
  198   				found = true;
  199   			}
  200   			else {
  201   				//search for it
  202   				//note that this code is incorrect for other than one-to-many
  203   				while ( newiter.hasNext() ) {
  204   					if ( elementType.isSame( old, newiter.next(), entityMode ) ) {
  205   						found = true;
  206   						break;
  207   					}
  208   				}
  209   			}
  210   			if (!found) deletes.add(old);
  211   		}
  212   		return deletes.iterator();
  213   	}
  214   
  215   	public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException {
  216   		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
  217   		List sn = (List) getSnapshot();
  218   		final EntityMode entityMode = getSession().getEntityMode();
  219   		if ( sn.size()>i && elemType.isSame( sn.get(i), entry, entityMode ) ) {
  220   		//a shortcut if its location didn't change!
  221   			return false;
  222   		}
  223   		else {
  224   			//search for it
  225   			//note that this code is incorrect for other than one-to-many
  226   			Iterator olditer = sn.iterator();
  227   			while ( olditer.hasNext() ) {
  228   				Object old = olditer.next();
  229   				if ( elemType.isSame( old, entry, entityMode ) ) return false;
  230   			}
  231   			return true;
  232   		}
  233   	}
  234   
  235   	public boolean isRowUpdatePossible() {
  236   		return false;
  237   	}
  238   
  239   	public boolean needsUpdating(Object entry, int i, Type elemType) {
  240   		//if ( !persister.isOneToMany() ) throw new AssertionFailure("Not implemented for Bags");
  241   		return false;
  242   	}
  243   
  244   	/**
  245   	 * @see java.util.Collection#size()
  246   	 */
  247   	public int size() {
  248   		return readSize() ? getCachedSize() : bag.size();
  249   	}
  250   
  251   	/**
  252   	 * @see java.util.Collection#isEmpty()
  253   	 */
  254   	public boolean isEmpty() {
  255   		return readSize() ? getCachedSize()==0 : bag.isEmpty();
  256   	}
  257   
  258   	/**
  259   	 * @see java.util.Collection#contains(Object)
  260   	 */
  261   	public boolean contains(Object object) {
  262   		Boolean exists = readElementExistence(object);
  263   		return exists==null ?
  264   				bag.contains(object) :
  265   				exists.booleanValue();
  266   	}
  267   
  268   	/**
  269   	 * @see java.util.Collection#iterator()
  270   	 */
  271   	public Iterator iterator() {
  272   		read();
  273   		return new IteratorProxy( bag.iterator() );
  274   	}
  275   
  276   	/**
  277   	 * @see java.util.Collection#toArray()
  278   	 */
  279   	public Object[] toArray() {
  280   		read();
  281   		return bag.toArray();
  282   	}
  283   
  284   	/**
  285   	 * @see java.util.Collection#toArray(Object[])
  286   	 */
  287   	public Object[] toArray(Object[] a) {
  288   		read();
  289   		return bag.toArray(a);
  290   	}
  291   
  292   	/**
  293   	 * @see java.util.Collection#add(Object)
  294   	 */
  295   	public boolean add(Object object) {
  296   		if ( !isOperationQueueEnabled() ) {
  297   			write();
  298   			return bag.add(object);
  299   		}
  300   		else {
  301   			queueOperation( new SimpleAdd(object) );
  302   			return true;
  303   		}
  304   	}
  305   
  306   	/**
  307   	 * @see java.util.Collection#remove(Object)
  308   	 */
  309   	public boolean remove(Object o) {
  310   		initialize( true );
  311   		if ( bag.remove( o ) ) {
  312   			dirty();
  313   			return true;
  314   		}
  315   		else {
  316   			return false;
  317   		}
  318   	}
  319   
  320   	/**
  321   	 * @see java.util.Collection#containsAll(Collection)
  322   	 */
  323   	public boolean containsAll(Collection c) {
  324   		read();
  325   		return bag.containsAll(c);
  326   	}
  327   
  328   	/**
  329   	 * @see java.util.Collection#addAll(Collection)
  330   	 */
  331   	public boolean addAll(Collection values) {
  332   		if ( values.size()==0 ) return false;
  333   		if ( !isOperationQueueEnabled() ) {
  334   			write();
  335   			return bag.addAll(values);
  336   		}
  337   		else {
  338   			Iterator iter = values.iterator();
  339   			while ( iter.hasNext() ) {
  340   				queueOperation( new SimpleAdd( iter.next() ) );
  341   			}
  342   			return values.size()>0;
  343   		}
  344   	}
  345   
  346   	/**
  347   	 * @see java.util.Collection#removeAll(Collection)
  348   	 */
  349   	public boolean removeAll(Collection c) {
  350   		if ( c.size()>0 ) {
  351   			initialize( true );
  352   			if ( bag.removeAll( c ) ) {
  353   				dirty();
  354   				return true;
  355   			}
  356   			else {
  357   				return false;
  358   			}
  359   		}
  360   		else {
  361   			return false;
  362   		}
  363   	}
  364   
  365   	/**
  366   	 * @see java.util.Collection#retainAll(Collection)
  367   	 */
  368   	public boolean retainAll(Collection c) {
  369   		initialize( true );
  370   		if ( bag.retainAll( c ) ) {
  371   			dirty();
  372   			return true;
  373   		}
  374   		else {
  375   			return false;
  376   		}
  377   	}
  378   
  379   	/**
  380   	 * @see java.util.Collection#clear()
  381   	 */
  382   	public void clear() {
  383   		if ( isClearQueueEnabled() ) {
  384   			queueOperation( new Clear() );
  385   		}
  386   		else {
  387   			initialize( true );
  388   			if ( ! bag.isEmpty() ) {
  389   				bag.clear();
  390   				dirty();
  391   			}
  392   		}
  393   	}
  394   
  395   	public Object getIndex(Object entry, int i, CollectionPersister persister) {
  396   		throw new UnsupportedOperationException("Bags don't have indexes");
  397   	}
  398   
  399   	public Object getElement(Object entry) {
  400   		return entry;
  401   	}
  402   
  403   	public Object getSnapshotElement(Object entry, int i) {
  404   		List sn = (List) getSnapshot();
  405   		return sn.get(i);
  406   	}
  407   
  408   	public int occurrences(Object o) {
  409   		read();
  410   		Iterator iter = bag.iterator();
  411   		int result=0;
  412   		while ( iter.hasNext() ) {
  413   			if ( o.equals( iter.next() ) ) result++;
  414   		}
  415   		return result;
  416   	}
  417   
  418   	// List OPERATIONS:
  419   
  420   	/**
  421   	 * @see java.util.List#add(int, Object)
  422   	 */
  423   	public void add(int i, Object o) {
  424   		write();
  425   		bag.add(i, o);
  426   	}
  427   
  428   	/**
  429   	 * @see java.util.List#addAll(int, Collection)
  430   	 */
  431   	public boolean addAll(int i, Collection c) {
  432   		if ( c.size()>0 ) {
  433   			write();
  434   			return bag.addAll(i, c);
  435   		}
  436   		else {
  437   			return false;
  438   		}
  439   	}
  440   
  441   	/**
  442   	 * @see java.util.List#get(int)
  443   	 */
  444   	public Object get(int i) {
  445   		read();
  446   		return bag.get(i);
  447   	}
  448   
  449   	/**
  450   	 * @see java.util.List#indexOf(Object)
  451   	 */
  452   	public int indexOf(Object o) {
  453   		read();
  454   		return bag.indexOf(o);
  455   	}
  456   
  457   	/**
  458   	 * @see java.util.List#lastIndexOf(Object)
  459   	 */
  460   	public int lastIndexOf(Object o) {
  461   		read();
  462   		return bag.lastIndexOf(o);
  463   	}
  464   
  465   	/**
  466   	 * @see java.util.List#listIterator()
  467   	 */
  468   	public ListIterator listIterator() {
  469   		read();
  470   		return new ListIteratorProxy( bag.listIterator() );
  471   	}
  472   
  473   	/**
  474   	 * @see java.util.List#listIterator(int)
  475   	 */
  476   	public ListIterator listIterator(int i) {
  477   		read();
  478   		return new ListIteratorProxy( bag.listIterator(i) );
  479   	}
  480   
  481   	/**
  482   	 * @see java.util.List#remove(int)
  483   	 */
  484   	public Object remove(int i) {
  485   		write();
  486   		return bag.remove(i);
  487   	}
  488   
  489   	/**
  490   	 * @see java.util.List#set(int, Object)
  491   	 */
  492   	public Object set(int i, Object o) {
  493   		write();
  494   		return bag.set(i, o);
  495   	}
  496   
  497   	/**
  498   	 * @see java.util.List#subList(int, int)
  499   	 */
  500   	public List subList(int start, int end) {
  501   		read();
  502   		return new ListProxy( bag.subList(start, end) );
  503   	}
  504   
  505   	public String toString() {
  506   		read();
  507   		return bag.toString();
  508   	}
  509   
  510   	/*public boolean equals(Object other) {
  511   		read();
  512   		return bag.equals(other);
  513   	}
  514   
  515   	public int hashCode(Object other) {
  516   		read();
  517   		return bag.hashCode();
  518   	}*/
  519   
  520   	public boolean entryExists(Object entry, int i) {
  521   		return entry!=null;
  522   	}
  523   
  524   	/**
  525   	 * Bag does not respect the collection API and do an
  526   	 * JVM instance comparison to do the equals.
  527   	 * The semantic is broken not to have to initialize a
  528   	 * collection for a simple equals() operation.
  529   	 * @see java.lang.Object#equals(java.lang.Object)
  530   	 */
  531   	public boolean equals(Object obj) {
  532   		return super.equals(obj);
  533   	}
  534   
  535   	/**
  536   	 * @see java.lang.Object#hashCode()
  537   	 */
  538   	public int hashCode() {
  539   		return super.hashCode();
  540   	}
  541   
  542   	final class Clear implements DelayedOperation {
  543   		public void operate() {
  544   			bag.clear();
  545   		}
  546   		public Object getAddedInstance() {
  547   			return null;
  548   		}
  549   		public Object getOrphan() {
  550   			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
  551   		}
  552   	}
  553   
  554   	final class SimpleAdd implements DelayedOperation {
  555   		private Object value;
  556   
  557   		public SimpleAdd(Object value) {
  558   			this.value = value;
  559   		}
  560   		public void operate() {
  561   			bag.add(value);
  562   		}
  563   		public Object getAddedInstance() {
  564   			return value;
  565   		}
  566   		public Object getOrphan() {
  567   			return null;
  568   		}
  569   	}
  570   
  571   }

Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » collection » [javadoc | source]