All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.collection.PersistentMap Maven / Gradle / Ivy

There is a newer version: 3.6.0.Beta2
Show newest version
//$Id: PersistentMap.java 11256 2007-03-07 19:32:58Z [email protected] $
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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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;


/**
 * A persistent wrapper for a java.util.Map. Underlying collection
 * is a HashMap.
 *
 * @see java.util.HashMap
 * @author Gavin King
 */
public class PersistentMap extends AbstractPersistentCollection implements Map {

	protected Map map;

	/**
	 * Empty constructor.
	 * 

* Note: this form is not ever ever ever used by Hibernate; it is, however, * needed for SOAP libraries and other such marshalling code. */ public PersistentMap() { // intentionally empty } /** * Instantiates a lazy map (the underlying map is un-initialized). * * @param session The session to which this map will belong. */ public PersistentMap(SessionImplementor session) { super(session); } /** * Instantiates a non-lazy map (the underlying map is constructed * from the incoming map reference). * * @param session The session to which this map will belong. * @param map The underlying map data. */ public PersistentMap(SessionImplementor session, Map map) { super(session); this.map = map; setInitialized(); setDirectlyAccessible(true); } public Serializable getSnapshot(CollectionPersister persister) throws HibernateException { EntityMode entityMode = getSession().getEntityMode(); HashMap clonedMap = new HashMap( map.size() ); Iterator iter = map.entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry e = (Map.Entry) iter.next(); final Object copy = persister.getElementType() .deepCopy( e.getValue(), entityMode, persister.getFactory() ); clonedMap.put( e.getKey(), copy ); } return clonedMap; } public Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException { Map sn = (Map) snapshot; return getOrphans( sn.values(), map.values(), entityName, getSession() ); } public boolean equalsSnapshot(CollectionPersister persister) throws HibernateException { Type elementType = persister.getElementType(); Map xmap = (Map) getSnapshot(); if ( xmap.size()!=this.map.size() ) return false; Iterator iter = map.entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry entry = (Map.Entry) iter.next(); if ( elementType.isDirty( entry.getValue(), xmap.get( entry.getKey() ), getSession() ) ) return false; } return true; } public boolean isSnapshotEmpty(Serializable snapshot) { return ( (Map) snapshot ).isEmpty(); } public boolean isWrapper(Object collection) { return map==collection; } public void beforeInitialize(CollectionPersister persister, int anticipatedSize) { this.map = ( Map ) persister.getCollectionType().instantiate( anticipatedSize ); } /** * @see java.util.Map#size() */ public int size() { return readSize() ? getCachedSize() : map.size(); } /** * @see java.util.Map#isEmpty() */ public boolean isEmpty() { return readSize() ? getCachedSize()==0 : map.isEmpty(); } /** * @see java.util.Map#containsKey(Object) */ public boolean containsKey(Object key) { Boolean exists = readIndexExistence(key); return exists==null ? map.containsKey(key) : exists.booleanValue(); } /** * @see java.util.Map#containsValue(Object) */ public boolean containsValue(Object value) { Boolean exists = readElementExistence(value); return exists==null ? map.containsValue(value) : exists.booleanValue(); } /** * @see java.util.Map#get(Object) */ public Object get(Object key) { Object result = readElementByIndex(key); return result==UNKNOWN ? map.get(key) : result; } /** * @see java.util.Map#put(Object, Object) */ public Object put(Object key, Object value) { if ( isPutQueueEnabled() ) { Object old = readElementByIndex( key ); if ( old != UNKNOWN ) { queueOperation( new Put( key, value, old ) ); return old; } } initialize( true ); Object old = map.put( key, value ); // would be better to use the element-type to determine // whether the old and the new are equal here; the problem being // we do not necessarily have access to the element type in all // cases if ( value != old ) { dirty(); } return old; } /** * @see java.util.Map#remove(Object) */ public Object remove(Object key) { if ( isPutQueueEnabled() ) { Object old = readElementByIndex( key ); queueOperation( new Remove( key, old ) ); return old; } else { // TODO : safe to interpret "map.remove(key) == null" as non-dirty? initialize( true ); if ( map.containsKey( key ) ) { dirty(); } return map.remove( key ); } } /** * @see java.util.Map#putAll(java.util.Map puts) */ public void putAll(Map puts) { if ( puts.size()>0 ) { initialize( true ); Iterator itr = puts.entrySet().iterator(); while ( itr.hasNext() ) { Map.Entry entry = ( Entry ) itr.next(); put( entry.getKey(), entry.getValue() ); } } } /** * @see java.util.Map#clear() */ public void clear() { if ( isClearQueueEnabled() ) { queueOperation( new Clear() ); } else { initialize( true ); if ( ! map.isEmpty() ) { dirty(); map.clear(); } } } /** * @see java.util.Map#keySet() */ public Set keySet() { read(); return new SetProxy( map.keySet() ); } /** * @see java.util.Map#values() */ public Collection values() { read(); return new SetProxy( map.values() ); } /** * @see java.util.Map#entrySet() */ public Set entrySet() { read(); return new EntrySetProxy( map.entrySet() ); } public boolean empty() { return map.isEmpty(); } public String toString() { read(); return map.toString(); } public Object readFrom(ResultSet rs, CollectionPersister persister, CollectionAliases descriptor, Object owner) throws HibernateException, SQLException { Object element = persister.readElement( rs, owner, descriptor.getSuffixedElementAliases(), getSession() ); Object index = persister.readIndex( rs, descriptor.getSuffixedIndexAliases(), getSession() ); if ( element!=null ) map.put(index, element); return element; } public Iterator entries(CollectionPersister persister) { return map.entrySet().iterator(); } /** a wrapper for Map.Entry sets */ class EntrySetProxy implements Set { private final Set set; EntrySetProxy(Set set) { this.set=set; } public boolean add(Object entry) { //write(); -- doesn't return set.add(entry); } public boolean addAll(Collection entries) { //write(); -- doesn't return set.addAll(entries); } public void clear() { write(); set.clear(); } public boolean contains(Object entry) { return set.contains(entry); } public boolean containsAll(Collection entries) { return set.containsAll(entries); } public boolean isEmpty() { return set.isEmpty(); } public Iterator iterator() { return new EntryIteratorProxy( set.iterator() ); } public boolean remove(Object entry) { write(); return set.remove(entry); } public boolean removeAll(Collection entries) { write(); return set.removeAll(entries); } public boolean retainAll(Collection entries) { write(); return set.retainAll(entries); } public int size() { return set.size(); } // amazingly, these two will work because AbstractCollection // uses iterator() to fill the array public Object[] toArray() { return set.toArray(); } public Object[] toArray(Object[] array) { return set.toArray(array); } } final class EntryIteratorProxy implements Iterator { private final Iterator iter; EntryIteratorProxy(Iterator iter) { this.iter=iter; } public boolean hasNext() { return iter.hasNext(); } public Object next() { return new MapEntryProxy( (Map.Entry) iter.next() ); } public void remove() { write(); iter.remove(); } } final class MapEntryProxy implements Map.Entry { private final Map.Entry me; MapEntryProxy( Map.Entry me ) { this.me = me; } public Object getKey() { return me.getKey(); } public Object getValue() { return me.getValue(); } public boolean equals(Object o) { return me.equals(o); } public int hashCode() { return me.hashCode(); } // finally, what it's all about... public Object setValue(Object value) { write(); return me.setValue(value); } } 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+=2 ) { map.put( persister.getIndexType().assemble( array[i], getSession(), owner ), persister.getElementType().assemble( array[i+1], getSession(), owner ) ); } } public Serializable disassemble(CollectionPersister persister) throws HibernateException { Serializable[] result = new Serializable[ map.size() * 2 ]; Iterator iter = map.entrySet().iterator(); int i=0; while ( iter.hasNext() ) { Map.Entry e = (Map.Entry) iter.next(); result[i++] = persister.getIndexType().disassemble( e.getKey(), getSession(), null ); result[i++] = persister.getElementType().disassemble( e.getValue(), getSession(), null ); } return result; } public Iterator getDeletes(CollectionPersister persister, boolean indexIsFormula) throws HibernateException { List deletes = new ArrayList(); Iterator iter = ( (Map) getSnapshot() ).entrySet().iterator(); while ( iter.hasNext() ) { Map.Entry e = (Map.Entry) iter.next(); Object key = e.getKey(); if ( e.getValue()!=null && map.get(key)==null ) { deletes.add( indexIsFormula ? e.getValue() : key ); } } return deletes.iterator(); } public boolean needsInserting(Object entry, int i, Type elemType) throws HibernateException { final Map sn = (Map) getSnapshot(); Map.Entry e = (Map.Entry) entry; return e.getValue()!=null && sn.get( e.getKey() )==null; } public boolean needsUpdating(Object entry, int i, Type elemType) throws HibernateException { final Map sn = (Map) getSnapshot(); Map.Entry e = (Map.Entry) entry; Object snValue = sn.get( e.getKey() ); return e.getValue()!=null && snValue!=null && elemType.isDirty( snValue, e.getValue(), getSession() ); } public Object getIndex(Object entry, int i, CollectionPersister persister) { return ( (Map.Entry) entry ).getKey(); } public Object getElement(Object entry) { return ( (Map.Entry) entry ).getValue(); } public Object getSnapshotElement(Object entry, int i) { final Map sn = (Map) getSnapshot(); return sn.get( ( (Map.Entry) entry ).getKey() ); } public boolean equals(Object other) { read(); return map.equals(other); } public int hashCode() { read(); return map.hashCode(); } public boolean entryExists(Object entry, int i) { return ( (Map.Entry) entry ).getValue()!=null; } final class Clear implements DelayedOperation { public void operate() { map.clear(); } public Object getAddedInstance() { return null; } public Object getOrphan() { throw new UnsupportedOperationException("queued clear cannot be used with orphan delete"); } } final class Put implements DelayedOperation { private Object index; private Object value; private Object old; public Put(Object index, Object value, Object old) { this.index = index; this.value = value; this.old = old; } public void operate() { map.put(index, value); } public Object getAddedInstance() { return value; } public Object getOrphan() { return old; } } final class Remove implements DelayedOperation { private Object index; private Object old; public Remove(Object index, Object old) { this.index = index; this.old = old; } public void operate() { map.remove(index); } public Object getAddedInstance() { return null; } public Object getOrphan() { return old; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy