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.sql.ResultSet;
   29   import java.sql.SQLException;
   30   import java.util.ArrayList;
   31   import java.util.Collection;
   32   import java.util.HashMap;
   33   import java.util.Iterator;
   34   import java.util.List;
   35   import java.util.Map;
   36   import java.util.Set;
   37   
   38   import org.hibernate.EntityMode;
   39   import org.hibernate.HibernateException;
   40   import org.hibernate.engine.SessionImplementor;
   41   import org.hibernate.loader.CollectionAliases;
   42   import org.hibernate.persister.collection.CollectionPersister;
   43   import org.hibernate.type.Type;
   44   
   45   
   46   /**
   47    * A persistent wrapper for a <tt>java.util.Map</tt>. Underlying collection
   48    * is a <tt>HashMap</tt>.
   49    *
   50    * @see java.util.HashMap
   51    * @author Gavin King
   52    */
   53   public class PersistentMap extends AbstractPersistentCollection implements Map {
   54   
   55   	protected Map map;
   56   
   57   	/**
   58   	 * Empty constructor.
   59   	 * <p/>
   60   	 * Note: this form is not ever ever ever used by Hibernate; it is, however,
   61   	 * needed for SOAP libraries and other such marshalling code.
   62   	 */
   63   	public PersistentMap() {
   64   		// intentionally empty
   65   	}
   66   
   67   	/**
   68   	 * Instantiates a lazy map (the underlying map is un-initialized).
   69   	 *
   70   	 * @param session The session to which this map will belong.
   71   	 */
   72   	public PersistentMap(SessionImplementor session) {
   73   		super(session);
   74   	}
   75   
   76   	/**
   77   	 * Instantiates a non-lazy map (the underlying map is constructed
   78   	 * from the incoming map reference).
   79   	 *
   80   	 * @param session The session to which this map will belong.
   81   	 * @param map The underlying map data.
   82   	 */
   83   	public PersistentMap(SessionImplementor session, Map map) {
   84   		super(session);
   85   		this.map = map;
   86   		setInitialized();
   87   		setDirectlyAccessible(true);
   88   	}
   89   
   90   	public Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
   91   		EntityMode entityMode = getSession().getEntityMode();
   92   		HashMap clonedMap = new HashMap( map.size() );
   93   		Iterator iter = map.entrySet().iterator();
   94   		while ( iter.hasNext() ) {
   95   			Map.Entry e = (Map.Entry) iter.next();
   96   			final Object copy = persister.getElementType()
   97   				.deepCopy( e.getValue(), entityMode, persister.getFactory() );
   98   			clonedMap.put( e.getKey(), copy );
   99   		}
  100   		return clonedMap;
  101   	}
  102   
  103   	public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException {
  104   		Map sn = (Map) snapshot;
  105   		return getOrphans( sn.values(), map.values(), entityName, getSession() );
  106   	}
  107   
  108   	public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException {
  109   		Type elementType = persister.getElementType();
  110   		Map xmap = (Map) getSnapshot();
  111   		if ( xmap.size()!=this.map.size() ) return false;
  112   		Iterator iter = map.entrySet().iterator();
  113   		while ( iter.hasNext() ) {
  114   			Map.Entry entry = (Map.Entry) iter.next();
  115   			if ( elementType.isDirty( entry.getValue(), xmap.get( entry.getKey() ), getSession() ) ) return false;
  116   		}
  117   		return true;
  118   	}
  119   
  120   	public boolean isSnapshotEmpty(Serializable snapshot) {
  121   		return ( (Map) snapshot ).isEmpty();
  122   	}
  123   
  124   	public boolean isWrapper(Object collection) {
  125   		return map==collection;
  126   	}
  127   
  128   	public void beforeInitialize(CollectionPersister persister, int anticipatedSize) {
  129   		this.map = ( Map ) persister.getCollectionType().instantiate( anticipatedSize );
  130   	}
  131   
  132   
  133   	/**
  134   	 * @see java.util.Map#size()
  135   	 */
  136   	public int size() {
  137   		return readSize() ? getCachedSize() : map.size();
  138   	}
  139   
  140   	/**
  141   	 * @see java.util.Map#isEmpty()
  142   	 */
  143   	public boolean isEmpty() {
  144   		return readSize() ? getCachedSize()==0 : map.isEmpty();
  145   	}
  146   
  147   	/**
  148   	 * @see java.util.Map#containsKey(Object)
  149   	 */
  150   	public boolean containsKey(Object key) {
  151   		Boolean exists = readIndexExistence(key);
  152   		return exists==null ? map.containsKey(key) : exists.booleanValue();
  153   	}
  154   
  155   	/**
  156   	 * @see java.util.Map#containsValue(Object)
  157   	 */
  158   	public boolean containsValue(Object value) {
  159   		Boolean exists = readElementExistence(value);
  160   		return exists==null ? 
  161   				map.containsValue(value) : 
  162   				exists.booleanValue();
  163   	}
  164   
  165   	/**
  166   	 * @see java.util.Map#get(Object)
  167   	 */
  168   	public Object get(Object key) {
  169   		Object result = readElementByIndex(key);
  170   		return result==UNKNOWN ? map.get(key) : result;
  171   	}
  172   
  173   	/**
  174   	 * @see java.util.Map#put(Object, Object)
  175   	 */
  176   	public Object put(Object key, Object value) {
  177   		if ( isPutQueueEnabled() ) {
  178   			Object old = readElementByIndex( key );
  179   			if ( old != UNKNOWN ) {
  180   				queueOperation( new Put( key, value, old ) );
  181   				return old;
  182   			}
  183   		}
  184   		initialize( true );
  185   		Object old = map.put( key, value );
  186   		// would be better to use the element-type to determine
  187   		// whether the old and the new are equal here; the problem being
  188   		// we do not necessarily have access to the element type in all
  189   		// cases
  190   		if ( value != old ) {
  191   			dirty();
  192   		}
  193   		return old;
  194   	}
  195   
  196   	/**
  197   	 * @see java.util.Map#remove(Object)
  198   	 */
  199   	public Object remove(Object key) {
  200   		if ( isPutQueueEnabled() ) {
  201   			Object old = readElementByIndex( key );
  202   			queueOperation( new Remove( key, old ) );
  203   			return old;
  204   		}
  205   		else {
  206   			// TODO : safe to interpret "map.remove(key) == null" as non-dirty?
  207   			initialize( true );
  208   			if ( map.containsKey( key ) ) {
  209   				dirty();
  210   			}
  211   			return map.remove( key );
  212   		}
  213   	}
  214   
  215   	/**
  216   	 * @see java.util.Map#putAll(java.util.Map puts)
  217   	 */
  218   	public void putAll(Map puts) {
  219   		if ( puts.size()>0 ) {
  220   			initialize( true );
  221   			Iterator itr = puts.entrySet().iterator();
  222   			while ( itr.hasNext() ) {
  223   				Map.Entry entry = ( Entry ) itr.next();
  224   				put( entry.getKey(), entry.getValue() );
  225   			}
  226   		}
  227   	}
  228   
  229   	/**
  230   	 * @see java.util.Map#clear()
  231   	 */
  232   	public void clear() {
  233   		if ( isClearQueueEnabled() ) {
  234   			queueOperation( new Clear() );
  235   		}
  236   		else {
  237   			initialize( true );
  238   			if ( ! map.isEmpty() ) {
  239   				dirty();
  240   				map.clear();
  241   			}
  242   		}
  243   	}
  244   
  245   	/**
  246   	 * @see java.util.Map#keySet()
  247   	 */
  248   	public Set keySet() {
  249   		read();
  250   		return new SetProxy( map.keySet() );
  251   	}
  252   
  253   	/**
  254   	 * @see java.util.Map#values()
  255   	 */
  256   	public Collection values() {
  257   		read();
  258   		return new SetProxy( map.values() );
  259   	}
  260   
  261   	/**
  262   	 * @see java.util.Map#entrySet()
  263   	 */
  264   	public Set entrySet() {
  265   		read();
  266   		return new EntrySetProxy( map.entrySet() );
  267   	}
  268   
  269   	public boolean empty() {
  270   		return map.isEmpty();
  271   	}
  272   
  273   	public String toString() {
  274   		read();
  275   		return map.toString();
  276   	}
  277   
  278   	public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner)
  279   	throws HibernateException, SQLException {
  280   		Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() );
  281   		Object index = persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() );
  282   		if ( element!=null ) map.put(index, element);
  283   		return element;
  284   	}
  285   
  286   	public Iterator entries(CollectionPersister persister) {
  287   		return map.entrySet().iterator();
  288   	}
  289   
  290   	/** a wrapper for Map.Entry sets */
  291   	class EntrySetProxy implements Set {
  292   		private final Set set;
  293   		EntrySetProxy(Set set) {
  294   			this.set=set;
  295   		}
  296   		public boolean add(Object entry) {
  297   			//write(); -- doesn't
  298   			return set.add(entry);
  299   		}
  300   		public boolean addAll(Collection entries) {
  301   			//write(); -- doesn't
  302   			return set.addAll(entries);
  303   		}
  304   		public void clear() {
  305   			write();
  306   			set.clear();
  307   		}
  308   		public boolean contains(Object entry) {
  309   			return set.contains(entry);
  310   		}
  311   		public boolean containsAll(Collection entries) {
  312   			return set.containsAll(entries);
  313   		}
  314   		public boolean isEmpty() {
  315   			return set.isEmpty();
  316   		}
  317   		public Iterator iterator() {
  318   			return new EntryIteratorProxy( set.iterator() );
  319   		}
  320   		public boolean remove(Object entry) {
  321   			write();
  322   			return set.remove(entry);
  323   		}
  324   		public boolean removeAll(Collection entries) {
  325   			write();
  326   			return set.removeAll(entries);
  327   		}
  328   		public boolean retainAll(Collection entries) {
  329   			write();
  330   			return set.retainAll(entries);
  331   		}
  332   		public int size() {
  333   			return set.size();
  334   		}
  335   		// amazingly, these two will work because AbstractCollection
  336   		// uses iterator() to fill the array
  337   		public Object[] toArray() {
  338   			return set.toArray();
  339   		}
  340   		public Object[] toArray(Object[] array) {
  341   			return set.toArray(array);
  342   		}
  343   	}
  344   	final class EntryIteratorProxy implements Iterator {
  345   		private final Iterator iter;
  346   		EntryIteratorProxy(Iterator iter) {
  347   			this.iter=iter;
  348   		}
  349   		public boolean hasNext() {
  350   			return iter.hasNext();
  351   		}
  352   		public Object next() {
  353   			return new MapEntryProxy( (Map.Entry) iter.next() );
  354   		}
  355   		public void remove() {
  356   			write();
  357   			iter.remove();
  358   		}
  359   	}
  360   
  361   	final class MapEntryProxy implements Map.Entry {
  362   		private final Map.Entry me;
  363   		MapEntryProxy( Map.Entry me ) {
  364   			this.me = me;
  365   		}
  366   		public Object getKey() { return me.getKey(); }
  367   		public Object getValue() { return me.getValue(); }
  368   		public boolean equals(Object o) { return me.equals(o); }
  369   		public int hashCode() { return me.hashCode(); }
  370   		// finally, what it's all about...
  371   		public Object setValue(Object value) {
  372   			write();
  373   			return me.setValue(value);
  374   		}
  375   	}
  376   
  377   	public void initializeFromCache(CollectionPersister persister, Serializable disassembled, Object owner)
  378   	throws HibernateException {
  379   		Serializable[] array = ( Serializable[] ) disassembled;
  380   		int size = array.length;
  381   		beforeInitialize( persister, size );
  382   		for ( int i = 0; i < size; i+=2 ) {
  383   			map.put(
  384   					persister.getIndexType().assemble( array[i], getSession(), owner ),
  385   					persister.getElementType().assemble( array[i+1], getSession(), owner )
  386   				);
  387   		}
  388   	}
  389   
  390   	public Serializable disassemble(CollectionPersister persister) throws HibernateException {
  391   
  392   		Serializable[] result = new Serializable[ map.size() * 2 ];
  393   		Iterator iter = map.entrySet().iterator();
  394   		int i=0;
  395   		while ( iter.hasNext() ) {
  396   			Map.Entry e = (Map.Entry) iter.next();
  397   			result[i++] = persister.getIndexType().disassemble( e.getKey(), getSession(), null );
  398   			result[i++] = persister.getElementType().disassemble( e.getValue(), getSession(), null );
  399   		}
  400   		return result;
  401   
  402   	}
  403   
  404   	public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) 
  405   	throws HibernateException {
  406   		List deletes = new ArrayList();
  407   		Iterator iter = ( (Map) getSnapshot() ).entrySet().iterator();
  408   		while ( iter.hasNext() ) {
  409   			Map.Entry e = (Map.Entry) iter.next();
  410   			Object key = e.getKey();
  411   			if ( e.getValue()!=null && map.get(key)==null ) {
  412   				deletes.add( indexIsFormula ? e.getValue() : key );
  413   			}
  414   		}
  415   		return deletes.iterator();
  416   	}
  417   
  418   	public boolean needsInserting(Object entry, int i, Type elemType) 
  419   	throws HibernateException {
  420   		final Map sn = (Map) getSnapshot();
  421   		Map.Entry e = (Map.Entry) entry;
  422   		return e.getValue()!=null && sn.get( e.getKey() )==null;
  423   	}
  424   
  425   	public boolean needsUpdating(Object entry, int i, Type elemType) 
  426   	throws HibernateException {
  427   		final Map sn = (Map) getSnapshot();
  428   		Map.Entry e = (Map.Entry) entry;
  429   		Object snValue = sn.get( e.getKey() );
  430   		return e.getValue()!=null &&
  431   			snValue!=null &&
  432   			elemType.isDirty( snValue, e.getValue(), getSession() );
  433   	}
  434   
  435   
  436   	public Object getIndex(Object entry, int i, CollectionPersister persister) {
  437   		return ( (Map.Entry) entry ).getKey();
  438   	}
  439   
  440   	public Object getElement(Object entry) {
  441   		return ( (Map.Entry) entry ).getValue();
  442   	}
  443   
  444   	public Object getSnapshotElement(Object entry, int i) {
  445   		final Map sn = (Map) getSnapshot();
  446   		return sn.get( ( (Map.Entry) entry ).getKey() );
  447   	}
  448   
  449   	public boolean equals(Object other) {
  450   		read();
  451   		return map.equals(other);
  452   	}
  453   
  454   	public int hashCode() {
  455   		read();
  456   		return map.hashCode();
  457   	}
  458   
  459   	public boolean entryExists(Object entry, int i) {
  460   		return ( (Map.Entry) entry ).getValue()!=null;
  461   	}
  462   
  463   	final class Clear implements DelayedOperation {
  464   		public void operate() {
  465   			map.clear();
  466   		}
  467   		public Object getAddedInstance() {
  468   			return null;
  469   		}
  470   		public Object getOrphan() {
  471   			throw new UnsupportedOperationException("queued clear cannot be used with orphan delete");
  472   		}
  473   	}
  474   
  475   	final class Put implements DelayedOperation {
  476   		private Object index;
  477   		private Object value;
  478   		private Object old;
  479   		
  480   		public Put(Object index, Object value, Object old) {
  481   			this.index = index;
  482   			this.value = value;
  483   			this.old = old;
  484   		}
  485   		public void operate() {
  486   			map.put(index, value);
  487   		}
  488   		public Object getAddedInstance() {
  489   			return value;
  490   		}
  491   		public Object getOrphan() {
  492   			return old;
  493   		}
  494   	}
  495   
  496   	final class Remove implements DelayedOperation {
  497   		private Object index;
  498   		private Object old;
  499   		
  500   		public Remove(Object index, Object old) {
  501   			this.index = index;
  502   			this.old = old;
  503   		}
  504   		public void operate() {
  505   			map.remove(index);
  506   		}
  507   		public Object getAddedInstance() {
  508   			return null;
  509   		}
  510   		public Object getOrphan() {
  511   			return old;
  512   		}
  513   	}
  514   }

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