001: package org.hibernate.engine.loading;
002:
003: import java.sql.ResultSet;
004: import java.util.Map;
005: import java.util.Set;
006: import java.util.Iterator;
007: import java.util.HashMap;
008: import java.io.Serializable;
009:
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012:
013: import org.hibernate.util.IdentityMap;
014: import org.hibernate.engine.PersistenceContext;
015: import org.hibernate.engine.CollectionKey;
016: import org.hibernate.engine.SessionImplementor;
017: import org.hibernate.collection.PersistentCollection;
018: import org.hibernate.persister.collection.CollectionPersister;
019: import org.hibernate.pretty.MessageHelper;
020: import org.hibernate.EntityMode;
021:
022: /**
023: * Maps {@link ResultSet result-sets} to specific contextual data
024: * related to processing that {@link ResultSet result-sets}.
025: * <p/>
026: * Implementation note: internally an {@link IdentityMap} is used to maintain
027: * the mappings; {@link IdentityMap} was chosen because I'd rather not be
028: * dependent upon potentially bad {@link ResultSet#equals} and {ResultSet#hashCode}
029: * implementations.
030: * <p/>
031: * Considering the JDBC-redesign work, would further like this contextual info
032: * not mapped seperately, but available based on the result set being processed.
033: * This would also allow maintaining a single mapping as we could reliably get
034: * notification of the result-set closing...
035: *
036: * @author Steve Ebersole
037: */
038: public class LoadContexts {
039: private static final Log log = LogFactory
040: .getLog(LoadContexts.class);
041:
042: private final PersistenceContext persistenceContext;
043: private Map collectionLoadContexts;
044: private Map entityLoadContexts;
045:
046: private Map xrefLoadingCollectionEntries;
047:
048: /**
049: * Creates and binds this to the given persistence context.
050: *
051: * @param persistenceContext The persistence context to which this
052: * will be bound.
053: */
054: public LoadContexts(PersistenceContext persistenceContext) {
055: this .persistenceContext = persistenceContext;
056: }
057:
058: /**
059: * Retrieves the persistence context to which this is bound.
060: *
061: * @return The persistence context to which this is bound.
062: */
063: public PersistenceContext getPersistenceContext() {
064: return persistenceContext;
065: }
066:
067: /**
068: * Get the {@link CollectionLoadContext} associated with the given
069: * {@link ResultSet}, creating one if needed.
070: *
071: * @param resultSet The result set for which to retrieve the context.
072: * @return The processing context.
073: */
074: public CollectionLoadContext getCollectionLoadContext(
075: ResultSet resultSet) {
076: CollectionLoadContext context = null;
077: if (collectionLoadContexts == null) {
078: collectionLoadContexts = IdentityMap.instantiate(8);
079: } else {
080: context = (CollectionLoadContext) collectionLoadContexts
081: .get(resultSet);
082: }
083: if (context == null) {
084: if (log.isTraceEnabled()) {
085: log
086: .trace("constructing collection load context for result set ["
087: + resultSet + "]");
088: }
089: context = new CollectionLoadContext(this , resultSet);
090: collectionLoadContexts.put(resultSet, context);
091: }
092: return context;
093: }
094:
095: /**
096: * Attempt to locate the loading collection given the owner's key. The lookup here
097: * occurs against all result-set contexts...
098: *
099: * @param persister The collection persister
100: * @param ownerKey The owner key
101: * @return The loading collection, or null if not found.
102: */
103: public PersistentCollection locateLoadingCollection(
104: CollectionPersister persister, Serializable ownerKey) {
105: LoadingCollectionEntry lce = locateLoadingCollectionEntry(new CollectionKey(
106: persister, ownerKey, getEntityMode()));
107: if (lce != null) {
108: if (log.isTraceEnabled()) {
109: log.trace("returning loading collection:"
110: + MessageHelper.collectionInfoString(persister,
111: ownerKey, getSession().getFactory()));
112: }
113: return lce.getCollection();
114: } else {
115: // todo : should really move this log statement to CollectionType, where this is used from...
116: if (log.isTraceEnabled()) {
117: log.trace("creating collection wrapper:"
118: + MessageHelper.collectionInfoString(persister,
119: ownerKey, getSession().getFactory()));
120: }
121: return null;
122: }
123: }
124:
125: /**
126: * Locate the LoadingCollectionEntry within *any* of the tracked
127: * {@link CollectionLoadContext}s.
128: * <p/>
129: * Implementation note: package protected, as this is meant solely for use
130: * by {@link CollectionLoadContext} to be able to locate collections
131: * being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
132: *
133: * @param key The collection key.
134: * @return The located entry; or null.
135: */
136: LoadingCollectionEntry locateLoadingCollectionEntry(
137: CollectionKey key) {
138: if (xrefLoadingCollectionEntries == null) {
139: return null;
140: }
141: if (log.isTraceEnabled()) {
142: log.trace("attempting to locate loading collection entry ["
143: + key + "] in any result-set context");
144: }
145: LoadingCollectionEntry rtn = (LoadingCollectionEntry) xrefLoadingCollectionEntries
146: .get(key);
147: if (log.isTraceEnabled()) {
148: if (rtn == null) {
149: log.trace("collection [" + key
150: + "] located in load context");
151: } else {
152: log.trace("collection [" + key
153: + "] not located in load context");
154: }
155: }
156: return rtn;
157: }
158:
159: /*package*/void registerLoadingCollectionEntry(
160: CollectionKey entryKey, LoadingCollectionEntry entry) {
161: if (xrefLoadingCollectionEntries == null) {
162: xrefLoadingCollectionEntries = new HashMap();
163: }
164: xrefLoadingCollectionEntries.put(entryKey, entry);
165: }
166:
167: /*package*/Map getLoadingCollectionEntryMap() {
168: return xrefLoadingCollectionEntries;
169: }
170:
171: /*package*/void cleanupCollectionEntries(Set entryKeys) {
172: Iterator itr = entryKeys.iterator();
173: while (itr.hasNext()) {
174: final CollectionKey entryKey = (CollectionKey) itr.next();
175: xrefLoadingCollectionEntries.remove(entryKey);
176: }
177: }
178:
179: public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
180: EntityLoadContext context = null;
181: if (entityLoadContexts == null) {
182: entityLoadContexts = IdentityMap.instantiate(8);
183: } else {
184: context = (EntityLoadContext) entityLoadContexts
185: .get(resultSet);
186: }
187: if (context == null) {
188: context = new EntityLoadContext(this , resultSet);
189: entityLoadContexts.put(resultSet, context);
190: }
191: return context;
192: }
193:
194: public void cleanup(ResultSet resultSet) {
195: if (collectionLoadContexts != null) {
196: CollectionLoadContext collectionLoadContext = (CollectionLoadContext) collectionLoadContexts
197: .remove(resultSet);
198: collectionLoadContext.cleanup();
199: }
200: if (entityLoadContexts != null) {
201: EntityLoadContext entityLoadContext = (EntityLoadContext) entityLoadContexts
202: .remove(resultSet);
203: entityLoadContext.cleanup();
204: }
205: }
206:
207: private SessionImplementor getSession() {
208: return getPersistenceContext().getSession();
209: }
210:
211: private EntityMode getEntityMode() {
212: return getSession().getEntityMode();
213: }
214:
215: }
|