0001: // $Id: StatefulPersistenceContext.java 11489 2007-05-09 01:42:44Z steve.ebersole@jboss.com $
0002: package org.hibernate.engine;
0003:
0004: import java.io.IOException;
0005: import java.io.InvalidObjectException;
0006: import java.io.ObjectInputStream;
0007: import java.io.ObjectOutputStream;
0008: import java.io.Serializable;
0009: import java.util.ArrayList;
0010: import java.util.HashMap;
0011: import java.util.HashSet;
0012: import java.util.Iterator;
0013: import java.util.List;
0014: import java.util.Map;
0015:
0016: import org.apache.commons.collections.ReferenceMap;
0017: import org.apache.commons.logging.Log;
0018: import org.apache.commons.logging.LogFactory;
0019: import org.hibernate.AssertionFailure;
0020: import org.hibernate.Hibernate;
0021: import org.hibernate.HibernateException;
0022: import org.hibernate.LockMode;
0023: import org.hibernate.MappingException;
0024: import org.hibernate.NonUniqueObjectException;
0025: import org.hibernate.PersistentObjectException;
0026: import org.hibernate.TransientObjectException;
0027: import org.hibernate.engine.loading.LoadContexts;
0028: import org.hibernate.pretty.MessageHelper;
0029: import org.hibernate.collection.PersistentCollection;
0030: import org.hibernate.persister.collection.CollectionPersister;
0031: import org.hibernate.persister.entity.EntityPersister;
0032: import org.hibernate.proxy.HibernateProxy;
0033: import org.hibernate.proxy.LazyInitializer;
0034: import org.hibernate.tuple.ElementWrapper;
0035: import org.hibernate.util.IdentityMap;
0036: import org.hibernate.util.MarkerObject;
0037:
0038: /**
0039: * A <tt>PersistenceContext</tt> represents the state of persistent "stuff" which
0040: * Hibernate is tracking. This includes persistent entities, collections,
0041: * as well as proxies generated.
0042: * </p>
0043: * There is meant to be a one-to-one correspondence between a SessionImpl and
0044: * a PersistentContext. The SessionImpl uses the PersistentContext to track
0045: * the current state of its context. Event-listeners then use the
0046: * PersistentContext to drive their processing.
0047: *
0048: * @author Steve Ebersole
0049: */
0050: public class StatefulPersistenceContext implements PersistenceContext {
0051:
0052: public static final Object NO_ROW = new MarkerObject("NO_ROW");
0053:
0054: private static final Log log = LogFactory
0055: .getLog(StatefulPersistenceContext.class);
0056: private static final Log PROXY_WARN_LOG = LogFactory
0057: .getLog(StatefulPersistenceContext.class.getName()
0058: + ".ProxyWarnLog");
0059: private static final int INIT_COLL_SIZE = 8;
0060:
0061: private SessionImplementor session;
0062:
0063: // Loaded entity instances, by EntityKey
0064: private Map entitiesByKey;
0065:
0066: // Loaded entity instances, by EntityUniqueKey
0067: private Map entitiesByUniqueKey;
0068:
0069: // Identity map of EntityEntry instances, by the entity instance
0070: private Map entityEntries;
0071:
0072: // Entity proxies, by EntityKey
0073: private Map proxiesByKey;
0074:
0075: // Snapshots of current database state for entities
0076: // that have *not* been loaded
0077: private Map entitySnapshotsByKey;
0078:
0079: // Identity map of array holder ArrayHolder instances, by the array instance
0080: private Map arrayHolders;
0081:
0082: // Identity map of CollectionEntry instances, by the collection wrapper
0083: private Map collectionEntries;
0084:
0085: // Collection wrappers, by the CollectionKey
0086: private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection
0087:
0088: // Set of EntityKeys of deleted objects
0089: private HashSet nullifiableEntityKeys;
0090:
0091: // properties that we have tried to load, and not found in the database
0092: private HashSet nullAssociations;
0093:
0094: // A list of collection wrappers that were instantiating during result set
0095: // processing, that we will need to initialize at the end of the query
0096: private List nonlazyCollections;
0097:
0098: // A container for collections we load up when the owning entity is not
0099: // yet loaded ... for now, this is purely transient!
0100: private Map unownedCollections;
0101:
0102: private int cascading = 0;
0103: private int loadCounter = 0;
0104: private boolean flushing = false;
0105:
0106: private boolean hasNonReadOnlyEntities = false;
0107:
0108: private LoadContexts loadContexts;
0109: private BatchFetchQueue batchFetchQueue;
0110:
0111: /**
0112: * Constructs a PersistentContext, bound to the given session.
0113: *
0114: * @param session The session "owning" this context.
0115: */
0116: public StatefulPersistenceContext(SessionImplementor session) {
0117: this .session = session;
0118:
0119: entitiesByKey = new HashMap(INIT_COLL_SIZE);
0120: entitiesByUniqueKey = new HashMap(INIT_COLL_SIZE);
0121: proxiesByKey = new ReferenceMap(ReferenceMap.HARD,
0122: ReferenceMap.WEAK);
0123: entitySnapshotsByKey = new HashMap(INIT_COLL_SIZE);
0124:
0125: entityEntries = IdentityMap
0126: .instantiateSequenced(INIT_COLL_SIZE);
0127: collectionEntries = IdentityMap
0128: .instantiateSequenced(INIT_COLL_SIZE);
0129: collectionsByKey = new HashMap(INIT_COLL_SIZE);
0130: arrayHolders = IdentityMap.instantiate(INIT_COLL_SIZE);
0131:
0132: nullifiableEntityKeys = new HashSet();
0133:
0134: initTransientState();
0135: }
0136:
0137: private void initTransientState() {
0138: nullAssociations = new HashSet(INIT_COLL_SIZE);
0139: nonlazyCollections = new ArrayList(INIT_COLL_SIZE);
0140: }
0141:
0142: public boolean isStateless() {
0143: return false;
0144: }
0145:
0146: public SessionImplementor getSession() {
0147: return session;
0148: }
0149:
0150: public LoadContexts getLoadContexts() {
0151: if (loadContexts == null) {
0152: loadContexts = new LoadContexts(this );
0153: }
0154: return loadContexts;
0155: }
0156:
0157: public void addUnownedCollection(CollectionKey key,
0158: PersistentCollection collection) {
0159: if (unownedCollections == null) {
0160: unownedCollections = new HashMap(8);
0161: }
0162: unownedCollections.put(key, collection);
0163: }
0164:
0165: public PersistentCollection useUnownedCollection(CollectionKey key) {
0166: if (unownedCollections == null) {
0167: return null;
0168: } else {
0169: return (PersistentCollection) unownedCollections
0170: .remove(key);
0171: }
0172: }
0173:
0174: /**
0175: * Get the <tt>BatchFetchQueue</tt>, instantiating one if
0176: * necessary.
0177: */
0178: public BatchFetchQueue getBatchFetchQueue() {
0179: if (batchFetchQueue == null) {
0180: batchFetchQueue = new BatchFetchQueue(this );
0181: }
0182: return batchFetchQueue;
0183: }
0184:
0185: public void clear() {
0186: Iterator itr = proxiesByKey.values().iterator();
0187: while (itr.hasNext()) {
0188: final LazyInitializer li = ((HibernateProxy) itr.next())
0189: .getHibernateLazyInitializer();
0190: li.setSession(null);
0191: }
0192: Map.Entry[] collectionEntryArray = IdentityMap
0193: .concurrentEntries(collectionEntries);
0194: for (int i = 0; i < collectionEntryArray.length; i++) {
0195: ((PersistentCollection) collectionEntryArray[i].getKey())
0196: .unsetSession(getSession());
0197: }
0198: arrayHolders.clear();
0199: entitiesByKey.clear();
0200: entitiesByUniqueKey.clear();
0201: entityEntries.clear();
0202: entitySnapshotsByKey.clear();
0203: collectionsByKey.clear();
0204: collectionEntries.clear();
0205: if (unownedCollections != null) {
0206: unownedCollections.clear();
0207: }
0208: proxiesByKey.clear();
0209: nullifiableEntityKeys.clear();
0210: if (batchFetchQueue != null) {
0211: batchFetchQueue.clear();
0212: }
0213: hasNonReadOnlyEntities = false;
0214: }
0215:
0216: public boolean hasNonReadOnlyEntities() {
0217: return hasNonReadOnlyEntities;
0218: }
0219:
0220: public void setEntryStatus(EntityEntry entry, Status status) {
0221: entry.setStatus(status);
0222: setHasNonReadOnlyEnties(status);
0223: }
0224:
0225: private void setHasNonReadOnlyEnties(Status status) {
0226: if (status == Status.DELETED || status == Status.MANAGED
0227: || status == Status.SAVING) {
0228: hasNonReadOnlyEntities = true;
0229: }
0230: }
0231:
0232: public void afterTransactionCompletion() {
0233: // Downgrade locks
0234: Iterator iter = entityEntries.values().iterator();
0235: while (iter.hasNext()) {
0236: ((EntityEntry) iter.next()).setLockMode(LockMode.NONE);
0237: }
0238: }
0239:
0240: /**
0241: * Get the current state of the entity as known to the underlying
0242: * database, or null if there is no corresponding row
0243: */
0244: public Object[] getDatabaseSnapshot(Serializable id,
0245: EntityPersister persister) throws HibernateException {
0246: EntityKey key = new EntityKey(id, persister, session
0247: .getEntityMode());
0248: Object cached = entitySnapshotsByKey.get(key);
0249: if (cached != null) {
0250: return cached == NO_ROW ? null : (Object[]) cached;
0251: } else {
0252: Object[] snapshot = persister.getDatabaseSnapshot(id,
0253: session);
0254: entitySnapshotsByKey.put(key, snapshot == null ? NO_ROW
0255: : snapshot);
0256: return snapshot;
0257: }
0258: }
0259:
0260: public Object[] getNaturalIdSnapshot(Serializable id,
0261: EntityPersister persister) throws HibernateException {
0262: if (!persister.hasNaturalIdentifier()) {
0263: return null;
0264: }
0265:
0266: // if the natural-id is marked as non-mutable, it is not retrieved during a
0267: // normal database-snapshot operation...
0268: int[] props = persister.getNaturalIdentifierProperties();
0269: boolean[] updateable = persister.getPropertyUpdateability();
0270: boolean allNatualIdPropsAreUpdateable = true;
0271: for (int i = 0; i < props.length; i++) {
0272: if (!updateable[props[i]]) {
0273: allNatualIdPropsAreUpdateable = false;
0274: break;
0275: }
0276: }
0277:
0278: if (allNatualIdPropsAreUpdateable) {
0279: // do this when all the properties are updateable since there is
0280: // a certain likelihood that the information will already be
0281: // snapshot-cached.
0282: Object[] entitySnapshot = getDatabaseSnapshot(id, persister);
0283: if (entitySnapshot == NO_ROW) {
0284: return null;
0285: }
0286: Object[] naturalIdSnapshot = new Object[props.length];
0287: for (int i = 0; i < props.length; i++) {
0288: naturalIdSnapshot[i] = entitySnapshot[props[i]];
0289: }
0290: return naturalIdSnapshot;
0291: } else {
0292: return persister.getNaturalIdentifierSnapshot(id, session);
0293: }
0294: }
0295:
0296: /**
0297: * Retrieve the cached database snapshot for the requested entity key.
0298: * <p/>
0299: * This differs from {@link #getDatabaseSnapshot} is two important respects:<ol>
0300: * <li>no snapshot is obtained from the database if not already cached</li>
0301: * <li>an entry of {@link #NO_ROW} here is interpretet as an exception</li>
0302: * </ol>
0303: * @param key The entity key for which to retrieve the cached snapshot
0304: * @return The cached snapshot
0305: * @throws IllegalStateException if the cached snapshot was == {@link #NO_ROW}.
0306: */
0307: public Object[] getCachedDatabaseSnapshot(EntityKey key) {
0308: Object snapshot = entitySnapshotsByKey.get(key);
0309: if (snapshot == NO_ROW) {
0310: throw new IllegalStateException(
0311: "persistence context reported no row snapshot for "
0312: + MessageHelper.infoString(key
0313: .getEntityName(), key
0314: .getIdentifier()));
0315: }
0316: return (Object[]) snapshot;
0317: }
0318:
0319: /*public void removeDatabaseSnapshot(EntityKey key) {
0320: entitySnapshotsByKey.remove(key);
0321: }*/
0322:
0323: public void addEntity(EntityKey key, Object entity) {
0324: entitiesByKey.put(key, entity);
0325: getBatchFetchQueue().removeBatchLoadableEntityKey(key);
0326: }
0327:
0328: /**
0329: * Get the entity instance associated with the given
0330: * <tt>EntityKey</tt>
0331: */
0332: public Object getEntity(EntityKey key) {
0333: return entitiesByKey.get(key);
0334: }
0335:
0336: public boolean containsEntity(EntityKey key) {
0337: return entitiesByKey.containsKey(key);
0338: }
0339:
0340: /**
0341: * Remove an entity from the session cache, also clear
0342: * up other state associated with the entity, all except
0343: * for the <tt>EntityEntry</tt>
0344: */
0345: public Object removeEntity(EntityKey key) {
0346: Object entity = entitiesByKey.remove(key);
0347: Iterator iter = entitiesByUniqueKey.values().iterator();
0348: while (iter.hasNext()) {
0349: if (iter.next() == entity)
0350: iter.remove();
0351: }
0352: entitySnapshotsByKey.remove(key);
0353: nullifiableEntityKeys.remove(key);
0354: getBatchFetchQueue().removeBatchLoadableEntityKey(key);
0355: getBatchFetchQueue().removeSubselect(key);
0356: return entity;
0357: }
0358:
0359: /**
0360: * Get an entity cached by unique key
0361: */
0362: public Object getEntity(EntityUniqueKey euk) {
0363: return entitiesByUniqueKey.get(euk);
0364: }
0365:
0366: /**
0367: * Add an entity to the cache by unique key
0368: */
0369: public void addEntity(EntityUniqueKey euk, Object entity) {
0370: entitiesByUniqueKey.put(euk, entity);
0371: }
0372:
0373: /**
0374: * Retreive the EntityEntry representation of the given entity.
0375: *
0376: * @param entity The entity for which to locate the EntityEntry.
0377: * @return The EntityEntry for the given entity.
0378: */
0379: public EntityEntry getEntry(Object entity) {
0380: return (EntityEntry) entityEntries.get(entity);
0381: }
0382:
0383: /**
0384: * Remove an entity entry from the session cache
0385: */
0386: public EntityEntry removeEntry(Object entity) {
0387: return (EntityEntry) entityEntries.remove(entity);
0388: }
0389:
0390: /**
0391: * Is there an EntityEntry for this instance?
0392: */
0393: public boolean isEntryFor(Object entity) {
0394: return entityEntries.containsKey(entity);
0395: }
0396:
0397: /**
0398: * Get the collection entry for a persistent collection
0399: */
0400: public CollectionEntry getCollectionEntry(PersistentCollection coll) {
0401: return (CollectionEntry) collectionEntries.get(coll);
0402: }
0403:
0404: /**
0405: * Adds an entity to the internal caches.
0406: */
0407: public EntityEntry addEntity(final Object entity,
0408: final Status status, final Object[] loadedState,
0409: final EntityKey entityKey, final Object version,
0410: final LockMode lockMode, final boolean existsInDatabase,
0411: final EntityPersister persister,
0412: final boolean disableVersionIncrement,
0413: boolean lazyPropertiesAreUnfetched) {
0414:
0415: addEntity(entityKey, entity);
0416:
0417: return addEntry(entity, status, loadedState, null, entityKey
0418: .getIdentifier(), version, lockMode, existsInDatabase,
0419: persister, disableVersionIncrement,
0420: lazyPropertiesAreUnfetched);
0421: }
0422:
0423: /**
0424: * Generates an appropriate EntityEntry instance and adds it
0425: * to the event source's internal caches.
0426: */
0427: public EntityEntry addEntry(final Object entity,
0428: final Status status, final Object[] loadedState,
0429: final Object rowId, final Serializable id,
0430: final Object version, final LockMode lockMode,
0431: final boolean existsInDatabase,
0432: final EntityPersister persister,
0433: final boolean disableVersionIncrement,
0434: boolean lazyPropertiesAreUnfetched) {
0435:
0436: EntityEntry e = new EntityEntry(status, loadedState, rowId, id,
0437: version, lockMode, existsInDatabase, persister, session
0438: .getEntityMode(), disableVersionIncrement,
0439: lazyPropertiesAreUnfetched);
0440: entityEntries.put(entity, e);
0441:
0442: setHasNonReadOnlyEnties(status);
0443: return e;
0444: }
0445:
0446: public boolean containsCollection(PersistentCollection collection) {
0447: return collectionEntries.containsKey(collection);
0448: }
0449:
0450: public boolean containsProxy(Object entity) {
0451: return proxiesByKey.containsValue(entity);
0452: }
0453:
0454: /**
0455: * Takes the given object and, if it represents a proxy, reassociates it with this event source.
0456: *
0457: * @param value The possible proxy to be reassociated.
0458: * @return Whether the passed value represented an actual proxy which got initialized.
0459: * @throws MappingException
0460: */
0461: public boolean reassociateIfUninitializedProxy(Object value)
0462: throws MappingException {
0463: if (value instanceof ElementWrapper) {
0464: value = ((ElementWrapper) value).getElement();
0465: }
0466:
0467: if (!Hibernate.isInitialized(value)) {
0468: HibernateProxy proxy = (HibernateProxy) value;
0469: LazyInitializer li = proxy.getHibernateLazyInitializer();
0470: reassociateProxy(li, proxy);
0471: return true;
0472: } else {
0473: return false;
0474: }
0475: }
0476:
0477: /**
0478: * If a deleted entity instance is re-saved, and it has a proxy, we need to
0479: * reset the identifier of the proxy
0480: */
0481: public void reassociateProxy(Object value, Serializable id)
0482: throws MappingException {
0483: if (value instanceof ElementWrapper) {
0484: value = ((ElementWrapper) value).getElement();
0485: }
0486:
0487: if (value instanceof HibernateProxy) {
0488: if (log.isDebugEnabled())
0489: log.debug("setting proxy identifier: " + id);
0490: HibernateProxy proxy = (HibernateProxy) value;
0491: LazyInitializer li = proxy.getHibernateLazyInitializer();
0492: li.setIdentifier(id);
0493: reassociateProxy(li, proxy);
0494: }
0495: }
0496:
0497: /**
0498: * Associate a proxy that was instantiated by another session with this session
0499: *
0500: * @param li The proxy initializer.
0501: * @param proxy The proxy to reassociate.
0502: */
0503: private void reassociateProxy(LazyInitializer li,
0504: HibernateProxy proxy) {
0505: if (li.getSession() != this .getSession()) {
0506: EntityPersister persister = session.getFactory()
0507: .getEntityPersister(li.getEntityName());
0508: EntityKey key = new EntityKey(li.getIdentifier(),
0509: persister, session.getEntityMode());
0510: // any earlier proxy takes precedence
0511: if (!proxiesByKey.containsKey(key)) {
0512: proxiesByKey.put(key, proxy);
0513: }
0514: proxy.getHibernateLazyInitializer().setSession(session);
0515: }
0516: }
0517:
0518: /**
0519: * Get the entity instance underlying the given proxy, throwing
0520: * an exception if the proxy is uninitialized. If the given object
0521: * is not a proxy, simply return the argument.
0522: */
0523: public Object unproxy(Object maybeProxy) throws HibernateException {
0524: if (maybeProxy instanceof ElementWrapper) {
0525: maybeProxy = ((ElementWrapper) maybeProxy).getElement();
0526: }
0527:
0528: if (maybeProxy instanceof HibernateProxy) {
0529: HibernateProxy proxy = (HibernateProxy) maybeProxy;
0530: LazyInitializer li = proxy.getHibernateLazyInitializer();
0531: if (li.isUninitialized()) {
0532: throw new PersistentObjectException(
0533: "object was an uninitialized proxy for "
0534: + li.getEntityName());
0535: }
0536: return li.getImplementation(); //unwrap the object
0537: } else {
0538: return maybeProxy;
0539: }
0540: }
0541:
0542: /**
0543: * Possibly unproxy the given reference and reassociate it with the current session.
0544: *
0545: * @param maybeProxy The reference to be unproxied if it currently represents a proxy.
0546: * @return The unproxied instance.
0547: * @throws HibernateException
0548: */
0549: public Object unproxyAndReassociate(Object maybeProxy)
0550: throws HibernateException {
0551: if (maybeProxy instanceof ElementWrapper) {
0552: maybeProxy = ((ElementWrapper) maybeProxy).getElement();
0553: }
0554:
0555: if (maybeProxy instanceof HibernateProxy) {
0556: HibernateProxy proxy = (HibernateProxy) maybeProxy;
0557: LazyInitializer li = proxy.getHibernateLazyInitializer();
0558: reassociateProxy(li, proxy);
0559: return li.getImplementation(); //initialize + unwrap the object
0560: } else {
0561: return maybeProxy;
0562: }
0563: }
0564:
0565: /**
0566: * Attempts to check whether the given key represents an entity already loaded within the
0567: * current session.
0568: * @param object The entity reference against which to perform the uniqueness check.
0569: * @throws HibernateException
0570: */
0571: public void checkUniqueness(EntityKey key, Object object)
0572: throws HibernateException {
0573: Object entity = getEntity(key);
0574: if (entity == object) {
0575: throw new AssertionFailure(
0576: "object already associated, but no entry was found");
0577: }
0578: if (entity != null) {
0579: throw new NonUniqueObjectException(key.getIdentifier(), key
0580: .getEntityName());
0581: }
0582: }
0583:
0584: /**
0585: * If the existing proxy is insufficiently "narrow" (derived), instantiate a new proxy
0586: * and overwrite the registration of the old one. This breaks == and occurs only for
0587: * "class" proxies rather than "interface" proxies. Also init the proxy to point to
0588: * the given target implementation if necessary.
0589: *
0590: * @param proxy The proxy instance to be narrowed.
0591: * @param persister The persister for the proxied entity.
0592: * @param key The internal cache key for the proxied entity.
0593: * @param object (optional) the actual proxied entity instance.
0594: * @return An appropriately narrowed instance.
0595: * @throws HibernateException
0596: */
0597: public Object narrowProxy(Object proxy, EntityPersister persister,
0598: EntityKey key, Object object) throws HibernateException {
0599:
0600: boolean alreadyNarrow = persister.getConcreteProxyClass(
0601: session.getEntityMode()).isAssignableFrom(
0602: proxy.getClass());
0603:
0604: if (!alreadyNarrow) {
0605: if (PROXY_WARN_LOG.isWarnEnabled()) {
0606: PROXY_WARN_LOG.warn("Narrowing proxy to "
0607: + persister.getConcreteProxyClass(session
0608: .getEntityMode())
0609: + " - this operation breaks ==");
0610: }
0611:
0612: if (object != null) {
0613: proxiesByKey.remove(key);
0614: return object; //return the proxied object
0615: } else {
0616: proxy = persister.createProxy(key.getIdentifier(),
0617: session);
0618: proxiesByKey.put(key, proxy); //overwrite old proxy
0619: return proxy;
0620: }
0621:
0622: } else {
0623:
0624: if (object != null) {
0625: LazyInitializer li = ((HibernateProxy) proxy)
0626: .getHibernateLazyInitializer();
0627: li.setImplementation(object);
0628: }
0629:
0630: return proxy;
0631:
0632: }
0633:
0634: }
0635:
0636: /**
0637: * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
0638: * third argument (the entity associated with the key) if no proxy exists. Init
0639: * the proxy to the target implementation, if necessary.
0640: */
0641: public Object proxyFor(EntityPersister persister, EntityKey key,
0642: Object impl) throws HibernateException {
0643: if (!persister.hasProxy())
0644: return impl;
0645: Object proxy = proxiesByKey.get(key);
0646: if (proxy != null) {
0647: return narrowProxy(proxy, persister, key, impl);
0648: } else {
0649: return impl;
0650: }
0651: }
0652:
0653: /**
0654: * Return the existing proxy associated with the given <tt>EntityKey</tt>, or the
0655: * argument (the entity associated with the key) if no proxy exists.
0656: * (slower than the form above)
0657: */
0658: public Object proxyFor(Object impl) throws HibernateException {
0659: EntityEntry e = getEntry(impl);
0660: EntityPersister p = e.getPersister();
0661: return proxyFor(p, new EntityKey(e.getId(), p, session
0662: .getEntityMode()), impl);
0663: }
0664:
0665: /**
0666: * Get the entity that owns this persistent collection
0667: */
0668: public Object getCollectionOwner(Serializable key,
0669: CollectionPersister collectionPersister)
0670: throws MappingException {
0671: return getEntity(new EntityKey(key, collectionPersister
0672: .getOwnerEntityPersister(), session.getEntityMode()));
0673: }
0674:
0675: /**
0676: * add a collection we just loaded up (still needs initializing)
0677: */
0678: public void addUninitializedCollection(
0679: CollectionPersister persister,
0680: PersistentCollection collection, Serializable id) {
0681: CollectionEntry ce = new CollectionEntry(collection, persister,
0682: id, flushing);
0683: addCollection(collection, ce, id);
0684: }
0685:
0686: /**
0687: * add a detached uninitialized collection
0688: */
0689: public void addUninitializedDetachedCollection(
0690: CollectionPersister persister,
0691: PersistentCollection collection) {
0692: CollectionEntry ce = new CollectionEntry(persister, collection
0693: .getKey());
0694: addCollection(collection, ce, collection.getKey());
0695: }
0696:
0697: /**
0698: * Add a new collection (ie. a newly created one, just instantiated by the
0699: * application, with no database state or snapshot)
0700: * @param collection The collection to be associated with the persistence context
0701: */
0702: public void addNewCollection(CollectionPersister persister,
0703: PersistentCollection collection) throws HibernateException {
0704: addCollection(collection, persister);
0705: }
0706:
0707: /**
0708: * Add an collection to the cache, with a given collection entry.
0709: *
0710: * @param coll The collection for which we are adding an entry.
0711: * @param entry The entry representing the collection.
0712: * @param key The key of the collection's entry.
0713: */
0714: private void addCollection(PersistentCollection coll,
0715: CollectionEntry entry, Serializable key) {
0716: collectionEntries.put(coll, entry);
0717: CollectionKey collectionKey = new CollectionKey(entry
0718: .getLoadedPersister(), key, session.getEntityMode());
0719: PersistentCollection old = (PersistentCollection) collectionsByKey
0720: .put(collectionKey, coll);
0721: if (old != null) {
0722: if (old == coll) {
0723: throw new AssertionFailure(
0724: "bug adding collection twice");
0725: }
0726: // or should it actually throw an exception?
0727: old.unsetSession(session);
0728: collectionEntries.remove(old);
0729: // watch out for a case where old is still referenced
0730: // somewhere in the object graph! (which is a user error)
0731: }
0732: }
0733:
0734: /**
0735: * Add a collection to the cache, creating a new collection entry for it
0736: *
0737: * @param collection The collection for which we are adding an entry.
0738: * @param persister The collection persister
0739: */
0740: private void addCollection(PersistentCollection collection,
0741: CollectionPersister persister) {
0742: CollectionEntry ce = new CollectionEntry(persister, collection);
0743: collectionEntries.put(collection, ce);
0744: }
0745:
0746: /**
0747: * add an (initialized) collection that was created by another session and passed
0748: * into update() (ie. one with a snapshot and existing state on the database)
0749: */
0750: public void addInitializedDetachedCollection(
0751: CollectionPersister collectionPersister,
0752: PersistentCollection collection) throws HibernateException {
0753: if (collection.isUnreferenced()) {
0754: //treat it just like a new collection
0755: addCollection(collection, collectionPersister);
0756: } else {
0757: CollectionEntry ce = new CollectionEntry(collection,
0758: session.getFactory());
0759: addCollection(collection, ce, collection.getKey());
0760: }
0761: }
0762:
0763: /**
0764: * add a collection we just pulled out of the cache (does not need initializing)
0765: */
0766: public CollectionEntry addInitializedCollection(
0767: CollectionPersister persister,
0768: PersistentCollection collection, Serializable id)
0769: throws HibernateException {
0770: CollectionEntry ce = new CollectionEntry(collection, persister,
0771: id, flushing);
0772: ce.postInitialize(collection);
0773: addCollection(collection, ce, id);
0774: return ce;
0775: }
0776:
0777: /**
0778: * Get the collection instance associated with the <tt>CollectionKey</tt>
0779: */
0780: public PersistentCollection getCollection(
0781: CollectionKey collectionKey) {
0782: return (PersistentCollection) collectionsByKey
0783: .get(collectionKey);
0784: }
0785:
0786: /**
0787: * Register a collection for non-lazy loading at the end of the
0788: * two-phase load
0789: */
0790: public void addNonLazyCollection(PersistentCollection collection) {
0791: nonlazyCollections.add(collection);
0792: }
0793:
0794: /**
0795: * Force initialization of all non-lazy collections encountered during
0796: * the current two-phase load (actually, this is a no-op, unless this
0797: * is the "outermost" load)
0798: */
0799: public void initializeNonLazyCollections()
0800: throws HibernateException {
0801: if (loadCounter == 0) {
0802: log.debug("initializing non-lazy collections");
0803: //do this work only at the very highest level of the load
0804: loadCounter++; //don't let this method be called recursively
0805: try {
0806: int size;
0807: while ((size = nonlazyCollections.size()) > 0) {
0808: //note that each iteration of the loop may add new elements
0809: ((PersistentCollection) nonlazyCollections
0810: .remove(size - 1)).forceInitialization();
0811: }
0812: } finally {
0813: loadCounter--;
0814: clearNullProperties();
0815: }
0816: }
0817: }
0818:
0819: /**
0820: * Get the <tt>PersistentCollection</tt> object for an array
0821: */
0822: public PersistentCollection getCollectionHolder(Object array) {
0823: return (PersistentCollection) arrayHolders.get(array);
0824: }
0825:
0826: /**
0827: * Register a <tt>PersistentCollection</tt> object for an array.
0828: * Associates a holder with an array - MUST be called after loading
0829: * array, since the array instance is not created until endLoad().
0830: */
0831: public void addCollectionHolder(PersistentCollection holder) {
0832: //TODO:refactor + make this method private
0833: arrayHolders.put(holder.getValue(), holder);
0834: }
0835:
0836: public PersistentCollection removeCollectionHolder(Object array) {
0837: return (PersistentCollection) arrayHolders.remove(array);
0838: }
0839:
0840: /**
0841: * Get the snapshot of the pre-flush collection state
0842: */
0843: public Serializable getSnapshot(PersistentCollection coll) {
0844: return getCollectionEntry(coll).getSnapshot();
0845: }
0846:
0847: /**
0848: * Get the collection entry for a collection passed to filter,
0849: * which might be a collection wrapper, an array, or an unwrapped
0850: * collection. Return null if there is no entry.
0851: */
0852: public CollectionEntry getCollectionEntryOrNull(Object collection) {
0853: PersistentCollection coll;
0854: if (collection instanceof PersistentCollection) {
0855: coll = (PersistentCollection) collection;
0856: //if (collection==null) throw new TransientObjectException("Collection was not yet persistent");
0857: } else {
0858: coll = getCollectionHolder(collection);
0859: if (coll == null) {
0860: //it might be an unwrapped collection reference!
0861: //try to find a wrapper (slowish)
0862: Iterator wrappers = IdentityMap
0863: .keyIterator(collectionEntries);
0864: while (wrappers.hasNext()) {
0865: PersistentCollection pc = (PersistentCollection) wrappers
0866: .next();
0867: if (pc.isWrapper(collection)) {
0868: coll = pc;
0869: break;
0870: }
0871: }
0872: }
0873: }
0874:
0875: return (coll == null) ? null : getCollectionEntry(coll);
0876: }
0877:
0878: /**
0879: * Get an existing proxy by key
0880: */
0881: public Object getProxy(EntityKey key) {
0882: return proxiesByKey.get(key);
0883: }
0884:
0885: /**
0886: * Add a proxy to the session cache
0887: */
0888: public void addProxy(EntityKey key, Object proxy) {
0889: proxiesByKey.put(key, proxy);
0890: }
0891:
0892: /**
0893: * Remove a proxy from the session cache.
0894: * <p/>
0895: * Additionally, ensure that any load optimization references
0896: * such as batch or subselect loading get cleaned up as well.
0897: *
0898: * @param key The key of the entity proxy to be removed
0899: * @return The proxy reference.
0900: */
0901: public Object removeProxy(EntityKey key) {
0902: if (batchFetchQueue != null) {
0903: batchFetchQueue.removeBatchLoadableEntityKey(key);
0904: batchFetchQueue.removeSubselect(key);
0905: }
0906: return proxiesByKey.remove(key);
0907: }
0908:
0909: /**
0910: * Record the fact that an entity does not exist in the database
0911: *
0912: * @param key the primary key of the entity
0913: */
0914: /*public void addNonExistantEntityKey(EntityKey key) {
0915: nonExistantEntityKeys.add(key);
0916: }*/
0917:
0918: /**
0919: * Record the fact that an entity does not exist in the database
0920: *
0921: * @param key a unique key of the entity
0922: */
0923: /*public void addNonExistantEntityUniqueKey(EntityUniqueKey key) {
0924: nonExistentEntityUniqueKeys.add(key);
0925: }*/
0926:
0927: /*public void removeNonExist(EntityKey key) {
0928: nonExistantEntityKeys.remove(key);
0929: }*/
0930:
0931: /**
0932: * Retrieve the set of EntityKeys representing nullifiable references
0933: */
0934: public HashSet getNullifiableEntityKeys() {
0935: return nullifiableEntityKeys;
0936: }
0937:
0938: public Map getEntitiesByKey() {
0939: return entitiesByKey;
0940: }
0941:
0942: public Map getEntityEntries() {
0943: return entityEntries;
0944: }
0945:
0946: public Map getCollectionEntries() {
0947: return collectionEntries;
0948: }
0949:
0950: public Map getCollectionsByKey() {
0951: return collectionsByKey;
0952: }
0953:
0954: /**
0955: * Do we already know that the entity does not exist in the
0956: * database?
0957: */
0958: /*public boolean isNonExistant(EntityKey key) {
0959: return nonExistantEntityKeys.contains(key);
0960: }*/
0961:
0962: /**
0963: * Do we already know that the entity does not exist in the
0964: * database?
0965: */
0966: /*public boolean isNonExistant(EntityUniqueKey key) {
0967: return nonExistentEntityUniqueKeys.contains(key);
0968: }*/
0969:
0970: public int getCascadeLevel() {
0971: return cascading;
0972: }
0973:
0974: public int incrementCascadeLevel() {
0975: return ++cascading;
0976: }
0977:
0978: public int decrementCascadeLevel() {
0979: return --cascading;
0980: }
0981:
0982: public boolean isFlushing() {
0983: return flushing;
0984: }
0985:
0986: public void setFlushing(boolean flushing) {
0987: this .flushing = flushing;
0988: }
0989:
0990: /**
0991: * Call this before begining a two-phase load
0992: */
0993: public void beforeLoad() {
0994: loadCounter++;
0995: }
0996:
0997: /**
0998: * Call this after finishing a two-phase load
0999: */
1000: public void afterLoad() {
1001: loadCounter--;
1002: }
1003:
1004: /**
1005: * Returns a string representation of the object.
1006: *
1007: * @return a string representation of the object.
1008: */
1009: public String toString() {
1010: return new StringBuffer().append(
1011: "PersistenceContext[entityKeys=").append(
1012: entitiesByKey.keySet()).append(",collectionKeys=")
1013: .append(collectionsByKey.keySet()).append("]")
1014: .toString();
1015: }
1016:
1017: /**
1018: * Search the persistence context for an owner for the child object,
1019: * given a collection role. If <tt>mergeMap</tt> is non-null, also
1020: * check the detached graph being merged for a parent.
1021: */
1022: public Serializable getOwnerId(String entity, String property,
1023: Object childEntity, Map mergeMap) {
1024:
1025: EntityPersister persister = session.getFactory()
1026: .getEntityPersister(entity);
1027: final CollectionPersister collectionPersister = session
1028: .getFactory().getCollectionPersister(
1029: entity + '.' + property);
1030:
1031: Iterator entities = entityEntries.entrySet().iterator();
1032: while (entities.hasNext()) {
1033: Map.Entry me = (Map.Entry) entities.next();
1034: EntityEntry ee = (EntityEntry) me.getValue();
1035: if (persister.isSubclassEntityName(ee.getEntityName())) {
1036: Object instance = me.getKey();
1037:
1038: //check if the managed object is the parent
1039: boolean found = isFoundInParent(property, childEntity,
1040: persister, collectionPersister, instance);
1041:
1042: if (!found && mergeMap != null) {
1043: //check if the detached object being merged is the parent
1044: Object unmergedInstance = mergeMap.get(instance);
1045: Object unmergedChild = mergeMap.get(childEntity);
1046: if (unmergedInstance != null
1047: && unmergedChild != null) {
1048: found = isFoundInParent(property,
1049: unmergedChild, persister,
1050: collectionPersister, unmergedInstance);
1051: }
1052: }
1053:
1054: if (found) {
1055: return ee.getId();
1056: }
1057:
1058: }
1059: }
1060: return null;
1061: }
1062:
1063: private boolean isFoundInParent(String property,
1064: Object childEntity, EntityPersister persister,
1065: CollectionPersister collectionPersister,
1066: Object potentialParent) {
1067: Object collection = persister.getPropertyValue(potentialParent,
1068: property, session.getEntityMode());
1069: return collection != null
1070: && Hibernate.isInitialized(collection)
1071: && collectionPersister.getCollectionType().contains(
1072: collection, childEntity, session);
1073: }
1074:
1075: /**
1076: * Search the persistence context for an index of the child object,
1077: * given a collection role
1078: */
1079: public Object getIndexInOwner(String entity, String property,
1080: Object childEntity, Map mergeMap) {
1081:
1082: EntityPersister persister = session.getFactory()
1083: .getEntityPersister(entity);
1084: CollectionPersister cp = session.getFactory()
1085: .getCollectionPersister(entity + '.' + property);
1086: Iterator entities = entityEntries.entrySet().iterator();
1087: while (entities.hasNext()) {
1088: Map.Entry me = (Map.Entry) entities.next();
1089: EntityEntry ee = (EntityEntry) me.getValue();
1090: if (persister.isSubclassEntityName(ee.getEntityName())) {
1091: Object instance = me.getKey();
1092:
1093: Object index = getIndexInParent(property, childEntity,
1094: persister, cp, instance);
1095:
1096: if (index == null && mergeMap != null) {
1097: Object unmergedInstance = mergeMap.get(instance);
1098: Object unmergedChild = mergeMap.get(childEntity);
1099: if (unmergedInstance != null
1100: && unmergedChild != null) {
1101: index = getIndexInParent(property,
1102: unmergedChild, persister, cp,
1103: unmergedInstance);
1104: }
1105: }
1106:
1107: if (index != null)
1108: return index;
1109: }
1110: }
1111: return null;
1112: }
1113:
1114: private Object getIndexInParent(String property,
1115: Object childEntity, EntityPersister persister,
1116: CollectionPersister collectionPersister,
1117: Object potentialParent) {
1118: Object collection = persister.getPropertyValue(potentialParent,
1119: property, session.getEntityMode());
1120: if (collection != null && Hibernate.isInitialized(collection)) {
1121: return collectionPersister.getCollectionType().indexOf(
1122: collection, childEntity);
1123: } else {
1124: return null;
1125: }
1126: }
1127:
1128: /**
1129: * Record the fact that the association belonging to the keyed
1130: * entity is null.
1131: */
1132: public void addNullProperty(EntityKey ownerKey, String propertyName) {
1133: nullAssociations
1134: .add(new AssociationKey(ownerKey, propertyName));
1135: }
1136:
1137: /**
1138: * Is the association property belonging to the keyed entity null?
1139: */
1140: public boolean isPropertyNull(EntityKey ownerKey,
1141: String propertyName) {
1142: return nullAssociations.contains(new AssociationKey(ownerKey,
1143: propertyName));
1144: }
1145:
1146: private void clearNullProperties() {
1147: nullAssociations.clear();
1148: }
1149:
1150: public void setReadOnly(Object entity, boolean readOnly) {
1151: EntityEntry entry = getEntry(entity);
1152: if (entry == null) {
1153: throw new TransientObjectException(
1154: "Instance was not associated with the session");
1155: }
1156: entry.setReadOnly(readOnly, entity);
1157: hasNonReadOnlyEntities = hasNonReadOnlyEntities || !readOnly;
1158: }
1159:
1160: public void replaceDelayedEntityIdentityInsertKeys(
1161: EntityKey oldKey, Serializable generatedId) {
1162: Object entity = entitiesByKey.remove(oldKey);
1163: EntityEntry oldEntry = (EntityEntry) entityEntries
1164: .remove(entity);
1165:
1166: EntityKey newKey = new EntityKey(generatedId, oldEntry
1167: .getPersister(), getSession().getEntityMode());
1168: addEntity(newKey, entity);
1169: addEntry(entity, oldEntry.getStatus(), oldEntry
1170: .getLoadedState(), oldEntry.getRowId(), generatedId,
1171: oldEntry.getVersion(), oldEntry.getLockMode(), oldEntry
1172: .isExistsInDatabase(), oldEntry.getPersister(),
1173: oldEntry.isBeingReplicated(), oldEntry
1174: .isLoadedWithLazyPropertiesUnfetched());
1175: }
1176:
1177: /**
1178: * Used by the owning session to explicitly control serialization of the
1179: * persistence context.
1180: *
1181: * @param oos The stream to which the persistence context should get written
1182: * @throws IOException serialization errors.
1183: */
1184: public void serialize(ObjectOutputStream oos) throws IOException {
1185: log.trace("serializing persistent-context");
1186:
1187: oos.writeBoolean(hasNonReadOnlyEntities);
1188:
1189: oos.writeInt(entitiesByKey.size());
1190: log.trace("starting serialization of [" + entitiesByKey.size()
1191: + "] entitiesByKey entries");
1192: Iterator itr = entitiesByKey.entrySet().iterator();
1193: while (itr.hasNext()) {
1194: Map.Entry entry = (Map.Entry) itr.next();
1195: ((EntityKey) entry.getKey()).serialize(oos);
1196: oos.writeObject(entry.getValue());
1197: }
1198:
1199: oos.writeInt(entitiesByUniqueKey.size());
1200: log.trace("starting serialization of ["
1201: + entitiesByUniqueKey.size()
1202: + "] entitiesByUniqueKey entries");
1203: itr = entitiesByUniqueKey.entrySet().iterator();
1204: while (itr.hasNext()) {
1205: Map.Entry entry = (Map.Entry) itr.next();
1206: ((EntityUniqueKey) entry.getKey()).serialize(oos);
1207: oos.writeObject(entry.getValue());
1208: }
1209:
1210: oos.writeInt(proxiesByKey.size());
1211: log.trace("starting serialization of [" + proxiesByKey.size()
1212: + "] proxiesByKey entries");
1213: itr = proxiesByKey.entrySet().iterator();
1214: while (itr.hasNext()) {
1215: Map.Entry entry = (Map.Entry) itr.next();
1216: ((EntityKey) entry.getKey()).serialize(oos);
1217: oos.writeObject(entry.getValue());
1218: }
1219:
1220: oos.writeInt(entitySnapshotsByKey.size());
1221: log.trace("starting serialization of ["
1222: + entitySnapshotsByKey.size()
1223: + "] entitySnapshotsByKey entries");
1224: itr = entitySnapshotsByKey.entrySet().iterator();
1225: while (itr.hasNext()) {
1226: Map.Entry entry = (Map.Entry) itr.next();
1227: ((EntityKey) entry.getKey()).serialize(oos);
1228: oos.writeObject(entry.getValue());
1229: }
1230:
1231: oos.writeInt(entityEntries.size());
1232: log.trace("starting serialization of [" + entityEntries.size()
1233: + "] entityEntries entries");
1234: itr = entityEntries.entrySet().iterator();
1235: while (itr.hasNext()) {
1236: Map.Entry entry = (Map.Entry) itr.next();
1237: oos.writeObject(entry.getKey());
1238: ((EntityEntry) entry.getValue()).serialize(oos);
1239: }
1240:
1241: oos.writeInt(collectionsByKey.size());
1242: log.trace("starting serialization of ["
1243: + collectionsByKey.size()
1244: + "] collectionsByKey entries");
1245: itr = collectionsByKey.entrySet().iterator();
1246: while (itr.hasNext()) {
1247: Map.Entry entry = (Map.Entry) itr.next();
1248: ((CollectionKey) entry.getKey()).serialize(oos);
1249: oos.writeObject(entry.getValue());
1250: }
1251:
1252: oos.writeInt(collectionEntries.size());
1253: log.trace("starting serialization of ["
1254: + collectionEntries.size()
1255: + "] collectionEntries entries");
1256: itr = collectionEntries.entrySet().iterator();
1257: while (itr.hasNext()) {
1258: Map.Entry entry = (Map.Entry) itr.next();
1259: oos.writeObject(entry.getKey());
1260: ((CollectionEntry) entry.getValue()).serialize(oos);
1261: }
1262:
1263: oos.writeInt(arrayHolders.size());
1264: log.trace("starting serialization of [" + arrayHolders.size()
1265: + "] arrayHolders entries");
1266: itr = arrayHolders.entrySet().iterator();
1267: while (itr.hasNext()) {
1268: Map.Entry entry = (Map.Entry) itr.next();
1269: oos.writeObject(entry.getKey());
1270: oos.writeObject(entry.getValue());
1271: }
1272:
1273: oos.writeInt(nullifiableEntityKeys.size());
1274: log.trace("starting serialization of ["
1275: + nullifiableEntityKeys.size()
1276: + "] nullifiableEntityKeys entries");
1277: itr = nullifiableEntityKeys.iterator();
1278: while (itr.hasNext()) {
1279: EntityKey entry = (EntityKey) itr.next();
1280: entry.serialize(oos);
1281: }
1282: }
1283:
1284: public static StatefulPersistenceContext deserialize(
1285: ObjectInputStream ois, SessionImplementor session)
1286: throws IOException, ClassNotFoundException {
1287: log.trace("deserializing persistent-context");
1288: StatefulPersistenceContext rtn = new StatefulPersistenceContext(
1289: session);
1290:
1291: // during deserialization, we need to reconnect all proxies and
1292: // collections to this session, as well as the EntityEntry and
1293: // CollectionEntry instances; these associations are transient
1294: // because serialization is used for different things.
1295:
1296: try {
1297: // todo : we can actually just determine this from the incoming EntityEntry-s
1298: rtn.hasNonReadOnlyEntities = ois.readBoolean();
1299:
1300: int count = ois.readInt();
1301: log.trace("staring deserialization of [" + count
1302: + "] entitiesByKey entries");
1303: rtn.entitiesByKey = new HashMap(
1304: count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count);
1305: for (int i = 0; i < count; i++) {
1306: rtn.entitiesByKey.put(EntityKey.deserialize(ois,
1307: session), ois.readObject());
1308: }
1309:
1310: count = ois.readInt();
1311: log.trace("staring deserialization of [" + count
1312: + "] entitiesByUniqueKey entries");
1313: rtn.entitiesByUniqueKey = new HashMap(
1314: count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count);
1315: for (int i = 0; i < count; i++) {
1316: rtn.entitiesByUniqueKey.put(EntityUniqueKey
1317: .deserialize(ois, session), ois.readObject());
1318: }
1319:
1320: count = ois.readInt();
1321: log.trace("staring deserialization of [" + count
1322: + "] proxiesByKey entries");
1323: rtn.proxiesByKey = new ReferenceMap(ReferenceMap.HARD,
1324: ReferenceMap.WEAK,
1325: count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count,
1326: .75f);
1327: for (int i = 0; i < count; i++) {
1328: EntityKey ek = EntityKey.deserialize(ois, session);
1329: Object proxy = ois.readObject();
1330: if (proxy instanceof HibernateProxy) {
1331: ((HibernateProxy) proxy)
1332: .getHibernateLazyInitializer().setSession(
1333: session);
1334: rtn.proxiesByKey.put(ek, proxy);
1335: } else {
1336: log.trace("encountered prunded proxy");
1337: }
1338: // otherwise, the proxy was pruned during the serialization process
1339: }
1340:
1341: count = ois.readInt();
1342: log.trace("staring deserialization of [" + count
1343: + "] entitySnapshotsByKey entries");
1344: rtn.entitySnapshotsByKey = new HashMap(
1345: count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count);
1346: for (int i = 0; i < count; i++) {
1347: rtn.entitySnapshotsByKey.put(EntityKey.deserialize(ois,
1348: session), ois.readObject());
1349: }
1350:
1351: count = ois.readInt();
1352: log.trace("staring deserialization of [" + count
1353: + "] entityEntries entries");
1354: rtn.entityEntries = IdentityMap
1355: .instantiateSequenced(count < INIT_COLL_SIZE ? INIT_COLL_SIZE
1356: : count);
1357: for (int i = 0; i < count; i++) {
1358: Object entity = ois.readObject();
1359: EntityEntry entry = EntityEntry.deserialize(ois,
1360: session);
1361: rtn.entityEntries.put(entity, entry);
1362: }
1363:
1364: count = ois.readInt();
1365: log.trace("staring deserialization of [" + count
1366: + "] collectionsByKey entries");
1367: rtn.collectionsByKey = new HashMap(
1368: count < INIT_COLL_SIZE ? INIT_COLL_SIZE : count);
1369: for (int i = 0; i < count; i++) {
1370: rtn.collectionsByKey.put(CollectionKey.deserialize(ois,
1371: session), ois.readObject());
1372: }
1373:
1374: count = ois.readInt();
1375: log.trace("staring deserialization of [" + count
1376: + "] collectionEntries entries");
1377: rtn.collectionEntries = IdentityMap
1378: .instantiateSequenced(count < INIT_COLL_SIZE ? INIT_COLL_SIZE
1379: : count);
1380: for (int i = 0; i < count; i++) {
1381: final PersistentCollection pc = (PersistentCollection) ois
1382: .readObject();
1383: final CollectionEntry ce = CollectionEntry.deserialize(
1384: ois, session);
1385: pc.setCurrentSession(session);
1386: rtn.collectionEntries.put(pc, ce);
1387: }
1388:
1389: count = ois.readInt();
1390: log.trace("staring deserialization of [" + count
1391: + "] arrayHolders entries");
1392: rtn.arrayHolders = IdentityMap
1393: .instantiate(count < INIT_COLL_SIZE ? INIT_COLL_SIZE
1394: : count);
1395: for (int i = 0; i < count; i++) {
1396: rtn.arrayHolders
1397: .put(ois.readObject(), ois.readObject());
1398: }
1399:
1400: count = ois.readInt();
1401: log.trace("staring deserialization of [" + count
1402: + "] nullifiableEntityKeys entries");
1403: rtn.nullifiableEntityKeys = new HashSet();
1404: for (int i = 0; i < count; i++) {
1405: rtn.nullifiableEntityKeys.add(EntityKey.deserialize(
1406: ois, session));
1407: }
1408:
1409: } catch (HibernateException he) {
1410: throw new InvalidObjectException(he.getMessage());
1411: }
1412:
1413: return rtn;
1414: }
1415: }
|