Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » 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.util.ArrayList;
   29   import java.util.Collection;
   30   import java.util.HashSet;
   31   import java.util.Iterator;
   32   import java.util.List;
   33   import java.util.ListIterator;
   34   
   35   import org.hibernate.AssertionFailure;
   36   import org.hibernate.HibernateException;
   37   import org.hibernate.LazyInitializationException;
   38   import org.hibernate.engine.CollectionEntry;
   39   import org.hibernate.engine.ForeignKeys;
   40   import org.hibernate.engine.SessionImplementor;
   41   import org.hibernate.engine.TypedValue;
   42   import org.hibernate.persister.collection.CollectionPersister;
   43   import org.hibernate.pretty.MessageHelper;
   44   import org.hibernate.type.Type;
   45   import org.hibernate.util.CollectionHelper;
   46   import org.hibernate.util.EmptyIterator;
   47   import org.hibernate.util.MarkerObject;
   48   
   49   /**
   50    * Base class implementing {@link PersistentCollection}
   51    *
   52    * @author Gavin King
   53    */
   54   public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
   55   
   56   	private transient SessionImplementor session;
   57   	private boolean initialized;
   58   	private transient List operationQueue;
   59   	private transient boolean directlyAccessible;
   60   	private transient boolean initializing;
   61   	private Object owner;
   62   	private int cachedSize = -1;
   63   	
   64   	private String role;
   65   	private Serializable key;
   66   	// collections detect changes made via their public interface and mark
   67   	// themselves as dirty as a performance optimization
   68   	private boolean dirty;
   69   	private Serializable storedSnapshot;
   70   
   71   	public final String getRole() {
   72   		return role;
   73   	}
   74   	
   75   	public final Serializable getKey() {
   76   		return key;
   77   	}
   78   	
   79   	public final boolean isUnreferenced() {
   80   		return role==null;
   81   	}
   82   	
   83   	public final boolean isDirty() {
   84   		return dirty;
   85   	}
   86   	
   87   	public final void clearDirty() {
   88   		dirty = false;
   89   	}
   90   	
   91   	public final void dirty() {
   92   		dirty = true;
   93   	}
   94   	
   95   	public final Serializable getStoredSnapshot() {
   96   		return storedSnapshot;
   97   	}
   98   	
   99   	//Careful: these methods do not initialize the collection.
  100   	/**
  101   	 * Is the initialized collection empty?
  102   	 */
  103   	public abstract boolean empty();
  104   	/**
  105   	 * Called by any read-only method of the collection interface
  106   	 */
  107   	protected final void read() {
  108   		initialize(false);
  109   	}
  110   	/**
  111   	 * Called by the <tt>size()</tt> method
  112   	 */
  113   	protected boolean readSize() {
  114   		if (!initialized) {
  115   			if ( cachedSize!=-1 && !hasQueuedOperations() ) {
  116   				return true;
  117   			}
  118   			else {
  119   				throwLazyInitializationExceptionIfNotConnected();
  120   				CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
  121   				CollectionPersister persister = entry.getLoadedPersister();
  122   				if ( persister.isExtraLazy() ) {
  123   					if ( hasQueuedOperations() ) {
  124   						session.flush();
  125   					}
  126   					cachedSize = persister.getSize( entry.getLoadedKey(), session );
  127   					return true;
  128   				}
  129   			}
  130   		}
  131   		read();
  132   		return false;
  133   	}
  134   	
  135   	protected Boolean readIndexExistence(Object index) {
  136   		if (!initialized) {
  137   			throwLazyInitializationExceptionIfNotConnected();
  138   			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
  139   			CollectionPersister persister = entry.getLoadedPersister();
  140   			if ( persister.isExtraLazy() ) {
  141   				if ( hasQueuedOperations() ) {
  142   					session.flush();
  143   				}
  144   				return new Boolean( persister.indexExists( entry.getLoadedKey(), index, session ) );
  145   			}
  146   		}
  147   		read();
  148   		return null;
  149   		
  150   	}
  151   	
  152   	protected Boolean readElementExistence(Object element) {
  153   		if (!initialized) {
  154   			throwLazyInitializationExceptionIfNotConnected();
  155   			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
  156   			CollectionPersister persister = entry.getLoadedPersister();
  157   			if ( persister.isExtraLazy() ) {
  158   				if ( hasQueuedOperations() ) {
  159   					session.flush();
  160   				}
  161   				return new Boolean( persister.elementExists( entry.getLoadedKey(), element, session ) );
  162   			}
  163   		}
  164   		read();
  165   		return null;
  166   		
  167   	}
  168   	
  169   	protected static final Object UNKNOWN = new MarkerObject("UNKNOWN");
  170   	
  171   	protected Object readElementByIndex(Object index) {
  172   		if (!initialized) {
  173   			throwLazyInitializationExceptionIfNotConnected();
  174   			CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
  175   			CollectionPersister persister = entry.getLoadedPersister();
  176   			if ( persister.isExtraLazy() ) {
  177   				if ( hasQueuedOperations() ) {
  178   					session.flush();
  179   				}
  180   				return persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
  181   			}
  182   		}
  183   		read();
  184   		return UNKNOWN;
  185   		
  186   	}
  187   	
  188   	protected int getCachedSize() {
  189   		return cachedSize;
  190   	}
  191   	
  192   	/**
  193   	 * Is the collection currently connected to an open session?
  194   	 */
  195   	private final boolean isConnectedToSession() {
  196   		return session!=null && 
  197   				session.isOpen() &&
  198   				session.getPersistenceContext().containsCollection(this);
  199   	}
  200   
  201   	/**
  202   	 * Called by any writer method of the collection interface
  203   	 */
  204   	protected final void write() {
  205   		initialize(true);
  206   		dirty();
  207   	}
  208   	/**
  209   	 * Is this collection in a state that would allow us to
  210   	 * "queue" operations?
  211   	 */
  212   	protected boolean isOperationQueueEnabled() {
  213   		return !initialized &&
  214   				isConnectedToSession() &&
  215   				isInverseCollection();
  216   	}
  217   	/**
  218   	 * Is this collection in a state that would allow us to
  219   	 * "queue" puts? This is a special case, because of orphan
  220   	 * delete.
  221   	 */
  222   	protected boolean isPutQueueEnabled() {
  223   		return !initialized &&
  224   				isConnectedToSession() &&
  225   				isInverseOneToManyOrNoOrphanDelete();
  226   	}
  227   	/**
  228   	 * Is this collection in a state that would allow us to
  229   	 * "queue" clear? This is a special case, because of orphan
  230   	 * delete.
  231   	 */
  232   	protected boolean isClearQueueEnabled() {
  233   		return !initialized &&
  234   				isConnectedToSession() &&
  235   				isInverseCollectionNoOrphanDelete();
  236   	}
  237   
  238   	/**
  239   	 * Is this the "inverse" end of a bidirectional association?
  240   	 */
  241   	private boolean isInverseCollection() {
  242   		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
  243   		return ce != null && ce.getLoadedPersister().isInverse();
  244   	}
  245   
  246   	/**
  247   	 * Is this the "inverse" end of a bidirectional association with
  248   	 * no orphan delete enabled?
  249   	 */
  250   	private boolean isInverseCollectionNoOrphanDelete() {
  251   		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
  252   		return ce != null && 
  253   				ce.getLoadedPersister().isInverse() &&
  254   				!ce.getLoadedPersister().hasOrphanDelete();
  255   	}
  256   
  257   	/**
  258   	 * Is this the "inverse" end of a bidirectional one-to-many, or 
  259   	 * of a collection with no orphan delete?
  260   	 */
  261   	private boolean isInverseOneToManyOrNoOrphanDelete() {
  262   		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
  263   		return ce != null && ce.getLoadedPersister().isInverse() && (
  264   				ce.getLoadedPersister().isOneToMany() || 
  265   				!ce.getLoadedPersister().hasOrphanDelete() 
  266   			);
  267   	}
  268   
  269   	/**
  270   	 * Queue an addition
  271   	 */
  272   	protected final void queueOperation(Object element) {
  273   		if (operationQueue==null) operationQueue = new ArrayList(10);
  274   		operationQueue.add(element);
  275   		dirty = true; //needed so that we remove this collection from the second-level cache
  276   	}
  277   
  278   	/**
  279   	 * After reading all existing elements from the database,
  280   	 * add the queued elements to the underlying collection.
  281   	 */
  282   	protected final void performQueuedOperations() {
  283   		for ( int i=0; i<operationQueue.size(); i++ ) {
  284   			( (DelayedOperation) operationQueue.get(i) ).operate();
  285   		}
  286   	}
  287   
  288   	/**
  289   	 * After flushing, re-init snapshot state.
  290   	 */
  291   	public void setSnapshot(Serializable key, String role, Serializable snapshot) {
  292   		this.key = key;
  293   		this.role = role;
  294   		this.storedSnapshot = snapshot;
  295   	}
  296   
  297   	/**
  298   	 * After flushing, clear any "queued" additions, since the
  299   	 * database state is now synchronized with the memory state.
  300   	 */
  301   	public void postAction() {
  302   		operationQueue=null;
  303   		cachedSize = -1;
  304   		clearDirty();
  305   	}
  306   	
  307   	/**
  308   	 * Not called by Hibernate, but used by non-JDK serialization,
  309   	 * eg. SOAP libraries.
  310   	 */
  311   	public AbstractPersistentCollection() {}
  312   
  313   	protected AbstractPersistentCollection(SessionImplementor session) {
  314   		this.session = session;
  315   	}
  316   
  317   	/**
  318   	 * return the user-visible collection (or array) instance
  319   	 */
  320   	public Object getValue() {
  321   		return this;
  322   	}
  323   
  324   	/**
  325   	 * Called just before reading any rows from the JDBC result set
  326   	 */
  327   	public void beginRead() {
  328   		// override on some subclasses
  329   		initializing = true;
  330   	}
  331   
  332   	/**
  333   	 * Called after reading all rows from the JDBC result set
  334   	 */
  335   	public boolean endRead() {
  336   		//override on some subclasses
  337   		return afterInitialize();
  338   	}
  339   	
  340   	public boolean afterInitialize() {
  341   		setInitialized();
  342   		//do this bit after setting initialized to true or it will recurse
  343   		if (operationQueue!=null) {
  344   			performQueuedOperations();
  345   			operationQueue=null;
  346   			cachedSize = -1;
  347   			return false;
  348   		}
  349   		else {
  350   			return true;
  351   		}
  352   	}
  353   
  354   	/**
  355   	 * Initialize the collection, if possible, wrapping any exceptions
  356   	 * in a runtime exception
  357   	 * @param writing currently obsolete
  358   	 * @throws LazyInitializationException if we cannot initialize
  359   	 */
  360   	protected final void initialize(boolean writing) {
  361   		if (!initialized) {
  362   			if (initializing) {
  363   				throw new LazyInitializationException("illegal access to loading collection");
  364   			}
  365   			throwLazyInitializationExceptionIfNotConnected();
  366   			session.initializeCollection(this, writing);
  367   		}
  368   	}
  369   	
  370   	private void throwLazyInitializationExceptionIfNotConnected() {
  371   		if ( !isConnectedToSession() )  {
  372   			throwLazyInitializationException("no session or session was closed");
  373   		}
  374   		if ( !session.isConnected() ) {
  375               throwLazyInitializationException("session is disconnected");
  376   		}		
  377   	}
  378   	
  379   	private void throwLazyInitializationException(String message) {
  380   		throw new LazyInitializationException(
  381   				"failed to lazily initialize a collection" + 
  382   				( role==null ?  "" : " of role: " + role ) + 
  383   				", " + message
  384   			);
  385   	}
  386   
  387   	protected final void setInitialized() {
  388   		this.initializing = false;
  389   		this.initialized = true;
  390   	}
  391   
  392   	protected final void setDirectlyAccessible(boolean directlyAccessible) {
  393   		this.directlyAccessible = directlyAccessible;
  394   	}
  395   
  396   	/**
  397   	 * Could the application possibly have a direct reference to
  398   	 * the underlying collection implementation?
  399   	 */
  400   	public boolean isDirectlyAccessible() {
  401   		return directlyAccessible;
  402   	}
  403   
  404   	/**
  405   	 * Disassociate this collection from the given session.
  406   	 * @return true if this was currently associated with the given session
  407   	 */
  408   	public final boolean unsetSession(SessionImplementor currentSession) {
  409   		if (currentSession==this.session) {
  410   			this.session=null;
  411   			return true;
  412   		}
  413   		else {
  414   			return false;
  415   		}
  416   	}
  417   
  418   	/**
  419   	 * Associate the collection with the given session.
  420   	 * @return false if the collection was already associated with the session
  421   	 * @throws HibernateException if the collection was already associated
  422   	 * with another open session
  423   	 */
  424   	public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
  425   		if (session==this.session) {
  426   			return false;
  427   		}
  428   		else {
  429   			if ( isConnectedToSession() ) {
  430   				CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
  431   				if (ce==null) {
  432   					throw new HibernateException(
  433   							"Illegal attempt to associate a collection with two open sessions"
  434   						);
  435   				}
  436   				else {
  437   					throw new HibernateException(
  438   							"Illegal attempt to associate a collection with two open sessions: " +
  439   							MessageHelper.collectionInfoString( 
  440   									ce.getLoadedPersister(), 
  441   									ce.getLoadedKey(), 
  442   									session.getFactory() 
  443   								)
  444   						);
  445   				}
  446   			}
  447   			else {
  448   				this.session = session;
  449   				return true;
  450   			}
  451   		}
  452   	}
  453   
  454   	/**
  455   	 * Do we need to completely recreate this collection when it changes?
  456   	 */
  457   	public boolean needsRecreate(CollectionPersister persister) {
  458   		return false;
  459   	}
  460   	
  461   	/**
  462   	 * To be called internally by the session, forcing
  463   	 * immediate initialization.
  464   	 */
  465   	public final void forceInitialization() throws HibernateException {
  466   		if (!initialized) {
  467   			if (initializing) {
  468   				throw new AssertionFailure("force initialize loading collection");
  469   			}
  470   			if (session==null) {
  471   				throw new HibernateException("collection is not associated with any session");
  472   			}
  473   			if ( !session.isConnected() ) {
  474   				throw new HibernateException("disconnected session");
  475   			}
  476   			session.initializeCollection(this, false);
  477   		}
  478   	}
  479   
  480   
  481   	/**
  482   	 * Get the current snapshot from the session
  483   	 */
  484   	protected final Serializable getSnapshot() {
  485   		return session.getPersistenceContext().getSnapshot(this);
  486   	}
  487   
  488   	/**
  489   	 * Is this instance initialized?
  490   	 */
  491   	public final boolean wasInitialized() {
  492   		return initialized;
  493   	}
  494   	
  495   	public boolean isRowUpdatePossible() {
  496   		return true;
  497   	}
  498   
  499   	/**
  500   	 * Does this instance have any "queued" additions?
  501   	 */
  502   	public final boolean hasQueuedOperations() {
  503   		return operationQueue!=null;
  504   	}
  505   	/**
  506   	 * Iterate the "queued" additions
  507   	 */
  508   	public final Iterator queuedAdditionIterator() {
  509   		if ( hasQueuedOperations() ) {
  510   			return new Iterator() {
  511   				int i = 0;
  512   				public Object next() {
  513   					return ( (DelayedOperation) operationQueue.get(i++) ).getAddedInstance();
  514   				}
  515   				public boolean hasNext() {
  516   					return i<operationQueue.size();
  517   				}
  518   				public void remove() {
  519   					throw new UnsupportedOperationException();
  520   				}
  521   			};
  522   		}
  523   		else {
  524   			return EmptyIterator.INSTANCE;
  525   		}
  526   	}
  527   	/**
  528   	 * Iterate the "queued" additions
  529   	 */
  530   	public final Collection getQueuedOrphans(String entityName) {
  531   		if ( hasQueuedOperations() ) {
  532   			Collection additions = new ArrayList( operationQueue.size() );
  533   			Collection removals = new ArrayList( operationQueue.size() );
  534   			for ( int i = 0; i < operationQueue.size(); i++ ) {
  535   				DelayedOperation op = (DelayedOperation) operationQueue.get(i);
  536   				additions.add( op.getAddedInstance() );
  537   				removals.add( op.getOrphan() );
  538   			}
  539   			return getOrphans(removals, additions, entityName, session);
  540   		}
  541   		else {
  542   			return CollectionHelper.EMPTY_COLLECTION;
  543   		}
  544   	}
  545   
  546   	/**
  547   	 * Called before inserting rows, to ensure that any surrogate keys
  548   	 * are fully generated
  549   	 */
  550   	public void preInsert(CollectionPersister persister) throws HibernateException {}
  551   	/**
  552   	 * Called after inserting a row, to fetch the natively generated id
  553   	 */
  554   	public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {}
  555   	/**
  556   	 * get all "orphaned" elements
  557   	 */
  558   	public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
  559   
  560   	/**
  561   	 * Get the current session
  562   	 */
  563   	public final SessionImplementor getSession() {
  564   		return session;
  565   	}
  566   
  567   	final class IteratorProxy implements Iterator {
  568   		private final Iterator iter;
  569   		IteratorProxy(Iterator iter) {
  570   			this.iter=iter;
  571   		}
  572   		public boolean hasNext() {
  573   			return iter.hasNext();
  574   		}
  575   
  576   		public Object next() {
  577   			return iter.next();
  578   		}
  579   
  580   		public void remove() {
  581   			write();
  582   			iter.remove();
  583   		}
  584   
  585   	}
  586   
  587   	final class ListIteratorProxy implements ListIterator {
  588   		private final ListIterator iter;
  589   		ListIteratorProxy(ListIterator iter) {
  590   			this.iter = iter;
  591   		}
  592   		public void add(Object o) {
  593   			write();
  594   			iter.add(o);
  595   		}
  596   
  597   		public boolean hasNext() {
  598   			return iter.hasNext();
  599   		}
  600   
  601   		public boolean hasPrevious() {
  602   			return iter.hasPrevious();
  603   		}
  604   
  605   		public Object next() {
  606   			return iter.next();
  607   		}
  608   
  609   		public int nextIndex() {
  610   			return iter.nextIndex();
  611   		}
  612   
  613   		public Object previous() {
  614   			return iter.previous();
  615   		}
  616   
  617   		public int previousIndex() {
  618   			return iter.previousIndex();
  619   		}
  620   
  621   		public void remove() {
  622   			write();
  623   			iter.remove();
  624   		}
  625   
  626   		public void set(Object o) {
  627   			write();
  628   			iter.set(o);
  629   		}
  630   
  631   	}
  632   
  633   	class SetProxy implements java.util.Set {
  634   
  635   		final Collection set;
  636   
  637   		SetProxy(Collection set) {
  638   			this.set=set;
  639   		}
  640   		public boolean add(Object o) {
  641   			write();
  642   			return set.add(o);
  643   		}
  644   
  645   		public boolean addAll(Collection c) {
  646   			write();
  647   			return set.addAll(c);
  648   		}
  649   
  650   		public void clear() {
  651   			write();
  652   			set.clear();
  653   		}
  654   
  655   		public boolean contains(Object o) {
  656   			return set.contains(o);
  657   		}
  658   
  659   		public boolean containsAll(Collection c) {
  660   			return set.containsAll(c);
  661   		}
  662   
  663   		public boolean isEmpty() {
  664   			return set.isEmpty();
  665   		}
  666   
  667   		public Iterator iterator() {
  668   			return new IteratorProxy( set.iterator() );
  669   		}
  670   
  671   		public boolean remove(Object o) {
  672   			write();
  673   			return set.remove(o);
  674   		}
  675   
  676   		public boolean removeAll(Collection c) {
  677   			write();
  678   			return set.removeAll(c);
  679   		}
  680   
  681   		public boolean retainAll(Collection c) {
  682   			write();
  683   			return set.retainAll(c);
  684   		}
  685   
  686   		public int size() {
  687   			return set.size();
  688   		}
  689   
  690   		public Object[] toArray() {
  691   			return set.toArray();
  692   		}
  693   
  694   		public Object[] toArray(Object[] array) {
  695   			return set.toArray(array);
  696   		}
  697   
  698   	}
  699   
  700   	final class ListProxy implements java.util.List {
  701   
  702   		private final java.util.List list;
  703   
  704   		ListProxy(java.util.List list) {
  705   			this.list = list;
  706   		}
  707   
  708   		public void add(int index, Object value) {
  709   			write();
  710   			list.add(index, value);
  711   		}
  712   
  713   		/**
  714   		 * @see java.util.Collection#add(Object)
  715   		 */
  716   		public boolean add(Object o) {
  717   			write();
  718   			return list.add(o);
  719   		}
  720   
  721   		/**
  722   		 * @see java.util.Collection#addAll(Collection)
  723   		 */
  724   		public boolean addAll(Collection c) {
  725   			write();
  726   			return list.addAll(c);
  727   		}
  728   
  729   		/**
  730   		 * @see java.util.List#addAll(int, Collection)
  731   		 */
  732   		public boolean addAll(int i, Collection c) {
  733   			write();
  734   			return list.addAll(i, c);
  735   		}
  736   
  737   		/**
  738   		 * @see java.util.Collection#clear()
  739   		 */
  740   		public void clear() {
  741   			write();
  742   			list.clear();
  743   		}
  744   
  745   		/**
  746   		 * @see java.util.Collection#contains(Object)
  747   		 */
  748   		public boolean contains(Object o) {
  749   			return list.contains(o);
  750   		}
  751   
  752   		/**
  753   		 * @see java.util.Collection#containsAll(Collection)
  754   		 */
  755   		public boolean containsAll(Collection c) {
  756   			return list.containsAll(c);
  757   		}
  758   
  759   		/**
  760   		 * @see java.util.List#get(int)
  761   		 */
  762   		public Object get(int i) {
  763   			return list.get(i);
  764   		}
  765   
  766   		/**
  767   		 * @see java.util.List#indexOf(Object)
  768   		 */
  769   		public int indexOf(Object o) {
  770   			return list.indexOf(o);
  771   		}
  772   
  773   		/**
  774   		 * @see java.util.Collection#isEmpty()
  775   		 */
  776   		public boolean isEmpty() {
  777   			return list.isEmpty();
  778   		}
  779   
  780   		/**
  781   		 * @see java.util.Collection#iterator()
  782   		 */
  783   		public Iterator iterator() {
  784   			return new IteratorProxy( list.iterator() );
  785   		}
  786   
  787   		/**
  788   		 * @see java.util.List#lastIndexOf(Object)
  789   		 */
  790   		public int lastIndexOf(Object o) {
  791   			return list.lastIndexOf(o);
  792   		}
  793   
  794   		/**
  795   		 * @see java.util.List#listIterator()
  796   		 */
  797   		public ListIterator listIterator() {
  798   			return new ListIteratorProxy( list.listIterator() );
  799   		}
  800   
  801   		/**
  802   		 * @see java.util.List#listIterator(int)
  803   		 */
  804   		public ListIterator listIterator(int i) {
  805   			return new ListIteratorProxy( list.listIterator(i) );
  806   		}
  807   
  808   		/**
  809   		 * @see java.util.List#remove(int)
  810   		 */
  811   		public Object remove(int i) {
  812   			write();
  813   			return list.remove(i);
  814   		}
  815   
  816   		/**
  817   		 * @see java.util.Collection#remove(Object)
  818   		 */
  819   		public boolean remove(Object o) {
  820   			write();
  821   			return list.remove(o);
  822   		}
  823   
  824   		/**
  825   		 * @see java.util.Collection#removeAll(Collection)
  826   		 */
  827   		public boolean removeAll(Collection c) {
  828   			write();
  829   			return list.removeAll(c);
  830   		}
  831   
  832   		/**
  833   		 * @see java.util.Collection#retainAll(Collection)
  834   		 */
  835   		public boolean retainAll(Collection c) {
  836   			write();
  837   			return list.retainAll(c);
  838   		}
  839   
  840   		/**
  841   		 * @see java.util.List#set(int, Object)
  842   		 */
  843   		public Object set(int i, Object o) {
  844   			write();
  845   			return list.set(i, o);
  846   		}
  847   
  848   		/**
  849   		 * @see java.util.Collection#size()
  850   		 */
  851   		public int size() {
  852   			return list.size();
  853   		}
  854   
  855   		/**
  856   		 * @see java.util.List#subList(int, int)
  857   		 */
  858   		public List subList(int i, int j) {
  859   			return list.subList(i, j);
  860   		}
  861   
  862   		/**
  863   		 * @see java.util.Collection#toArray()
  864   		 */
  865   		public Object[] toArray() {
  866   			return list.toArray();
  867   		}
  868   
  869   		/**
  870   		 * @see java.util.Collection#toArray(Object[])
  871   		 */
  872   		public Object[] toArray(Object[] array) {
  873   			return list.toArray(array);
  874   		}
  875   
  876   	}
  877   
  878   
  879   	protected interface DelayedOperation {
  880   		public void operate();
  881   		public Object getAddedInstance();
  882   		public Object getOrphan();
  883   	}
  884   	
  885   	/**
  886   	 * Given a collection of entity instances that used to
  887   	 * belong to the collection, and a collection of instances
  888   	 * that currently belong, return a collection of orphans
  889   	 */
  890   	protected static Collection getOrphans(
  891   			Collection oldElements, 
  892   			Collection currentElements, 
  893   			String entityName, 
  894   			SessionImplementor session)
  895   	throws HibernateException {
  896   
  897   		// short-circuit(s)
  898   		if ( currentElements.size()==0 ) return oldElements; // no new elements, the old list contains only Orphans
  899   		if ( oldElements.size()==0) return oldElements; // no old elements, so no Orphans neither
  900   		
  901   		Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
  902   
  903   		// create the collection holding the Orphans
  904   		Collection res = new ArrayList();
  905   
  906   		// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
  907   		java.util.Set currentIds = new HashSet();
  908   		for ( Iterator it=currentElements.iterator(); it.hasNext(); ) {
  909   			Object current = it.next();
  910   			if ( current!=null && ForeignKeys.isNotTransient(entityName, current, null, session) ) {
  911   				Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, current, session);
  912   				currentIds.add( new TypedValue( idType, currentId, session.getEntityMode() ) );
  913   			}
  914   		}
  915   
  916   		// iterate over the *old* list
  917   		for ( Iterator it=oldElements.iterator(); it.hasNext(); ) {
  918   			Object old = it.next();
  919   			Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, old, session);
  920   			if ( !currentIds.contains( new TypedValue( idType, oldId, session.getEntityMode() ) ) ) {
  921   				res.add(old);
  922   			}
  923   		}
  924   
  925   		return res;
  926   	}
  927   
  928   	static void identityRemove(
  929   			Collection list, 
  930   			Object object, 
  931   			String entityName, 
  932   			SessionImplementor session)
  933   	throws HibernateException {
  934   
  935   		if ( object!=null && ForeignKeys.isNotTransient(entityName, object, null, session) ) {
  936   			
  937   			Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
  938   
  939   			Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, session);
  940   			Iterator iter = list.iterator();
  941   			while ( iter.hasNext() ) {
  942   				Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, iter.next(), session);
  943   				if ( idType.isEqual( idOfCurrent, idOfOld, session.getEntityMode(), session.getFactory() ) ) {
  944   					iter.remove();
  945   					break;
  946   				}
  947   			}
  948   
  949   		}
  950   	}
  951   	
  952   	public Object getIdentifier(Object entry, int i) {
  953   		throw new UnsupportedOperationException();
  954   	}
  955   	
  956   	public Object getOwner() {
  957   		return owner;
  958   	}
  959   	
  960   	public void setOwner(Object owner) {
  961   		this.owner = owner;
  962   	}
  963   	
  964   }
  965   

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » collection » [javadoc | source]