KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > engine > BatchFetchQueue


1 //$Id: BatchFetchQueue.java,v 1.13 2005/06/19 03:48:48 oneovthafew Exp $
2
package org.hibernate.engine;
3
4 import java.io.Serializable JavaDoc;
5 import java.util.HashMap JavaDoc;
6 import java.util.Iterator JavaDoc;
7 import java.util.Map JavaDoc;
8
9 import org.apache.commons.collections.SequencedHashMap;
10 import org.hibernate.EntityMode;
11 import org.hibernate.collection.PersistentCollection;
12 import org.hibernate.persister.collection.CollectionPersister;
13 import org.hibernate.persister.entity.EntityPersister;
14 import org.hibernate.util.MarkerObject;
15
16 /**
17  * Tracks entity and collection keys that are available for batch
18  * fetching, and the queries which were used to load entities, which
19  * can be re-used as a subquery for loading owned collections.
20  *
21  * @author Gavin King
22  */

23 public class BatchFetchQueue {
24
25     public static final Object JavaDoc MARKER = new MarkerObject("MARKER");
26     
27     // A set of entity keys that we predict we might need to load soon
28
// TODO: this would be better as a SequencedReferenceSet, but no such beast exists!
29
private final Map JavaDoc batchLoadableEntityKeys = new SequencedHashMap(8); //actually, a Set
30

31     // The subqueries that were used to load the entity with the given key
32
private final Map JavaDoc subselectsByEntityKey = new HashMap JavaDoc(8); //new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT);
33

34     // The owning persistence context
35
private final PersistenceContext context;
36     
37     public BatchFetchQueue(PersistenceContext context) {
38         this.context = context;
39     }
40     
41     public void clear() {
42         batchLoadableEntityKeys.clear();
43         subselectsByEntityKey.clear();
44     }
45
46     public SubselectFetch getSubselect(EntityKey key) {
47         return (SubselectFetch) subselectsByEntityKey.get(key);
48     }
49
50     public void addSubselect(EntityKey key, SubselectFetch subquery) {
51         subselectsByEntityKey.put(key, subquery);
52     }
53
54     public void clearSubselects() {
55         subselectsByEntityKey.clear();
56     }
57     
58     /**
59      * After evicting or deleting or loading an entity, we don't
60      * need to batch fetch it anymore, remove it from the queue
61      * if necessary
62      */

63     public void removeBatchLoadableEntityKey(EntityKey key) {
64         if ( key.isBatchLoadable() ) batchLoadableEntityKeys.remove(key);
65     }
66     
67     /**
68      * After evicting or deleting an entity, we don't need to
69      * know the query that was used to load it anymore (don't
70      * call this after loading the entity, since we might still
71      * need to load its collections)
72      */

73     public void removeSubselect(EntityKey key) {
74         subselectsByEntityKey.remove(key);
75     }
76     
77     /**
78      * If an EntityKey represents a batch loadable entity, add
79      * it to the queue.
80      */

81     public void addBatchLoadableEntityKey(EntityKey key) {
82         if ( key.isBatchLoadable() ) batchLoadableEntityKeys.put(key, MARKER);
83     }
84
85     /**
86      * Get a batch of uninitialized collection keys for this role
87      * @param collectionPersister the collection role
88      * @param id a key that must be included
89      * @param batchSize the maximum number of keys to return
90      * @return an array of collection keys, of length batchSize (padded with nulls)
91      */

92     public Serializable JavaDoc[] getCollectionBatch(
93             final CollectionPersister collectionPersister,
94             final Serializable JavaDoc id,
95             final int batchSize,
96             final EntityMode entityMode
97     ) {
98         Serializable JavaDoc[] keys = new Serializable JavaDoc[batchSize];
99         keys[0] = id;
100         int i = 1;
101         //int count = 0;
102
int end = -1;
103         boolean checkForEnd = false;
104         // this only works because collection entries are kept in a sequenced
105
// map by persistence context (maybe we should do like entities and
106
// keep a separate sequences set...)
107
Iterator JavaDoc iter = context.getCollectionEntries().entrySet().iterator(); //TODO: calling entrySet on an IdentityMap is SLOW!!
108
while ( iter.hasNext() ) {
109             Map.Entry JavaDoc me = (Map.Entry JavaDoc) iter.next();
110             
111             CollectionEntry ce = (CollectionEntry) me.getValue();
112             PersistentCollection collection = (PersistentCollection) me.getKey();
113             if ( !collection.wasInitialized() && ce.getLoadedPersister() == collectionPersister ) {
114                 
115                 if ( checkForEnd && i == end ) return keys; //the first key found after the given key
116

117                 //if ( end == -1 && count > batchSize*10 ) return keys; //try out ten batches, max
118

119                 final boolean isEqual = collectionPersister.getKeyType().isEqual(
120                         id,
121                         ce.getLoadedKey(),
122                         entityMode,
123                         collectionPersister.getFactory()
124                     );
125                 
126                 if ( isEqual ) {
127                     end = i;
128                     //checkForEnd = false;
129
}
130                 else {
131                     keys[i++] = ce.getLoadedKey();
132                     //count++;
133
}
134                 
135                 if ( i == batchSize ) {
136                     i = 1; //end of array, start filling again from start
137
if (end!=-1) checkForEnd = true;
138                 }
139             }
140             
141         }
142         return keys; //we ran out of keys to try
143
}
144
145     /**
146      * Get a batch of unloaded identifiers for this class, using a slightly
147      * complex algorithm that tries to grab keys registered immediately after
148      * the given key.
149      *
150      * @param entityName The name of the persistent class
151      * @param id an identifier that must be included
152      * @param batchSize the maximum number of keys to return
153      * @return an array of identifiers, of length batchSize (padded with nulls)
154      */

155     public Serializable JavaDoc[] getEntityBatch(
156             final EntityPersister persister,
157             final Serializable JavaDoc id,
158             final int batchSize,
159             final EntityMode entityMode
160     ) {
161         Serializable JavaDoc[] ids = new Serializable JavaDoc[batchSize];
162         ids[0] = id; //first element of array is reserved for the actual instance we are loading!
163
int i = 1;
164         int end = -1;
165         boolean checkForEnd = false;
166         //int count = 0;
167
Iterator JavaDoc iter = batchLoadableEntityKeys.keySet().iterator();
168         while ( iter.hasNext() ) {
169             
170             EntityKey key = (EntityKey) iter.next();
171             if ( key.getEntityName().equals( persister.getEntityName() ) ) { //TODO: this needn't exclude subclasses...
172

173                 if ( checkForEnd && i == end ) return ids; //the first id found after the given id
174

175                 //if ( end == -1 && count > batchSize*10 ) return ids; //try out ten batches, max
176

177                 if ( persister.getIdentifierType().isEqual( id, key.getIdentifier(), entityMode ) ) {
178                     end = i;
179                     //checkForEnd = false;
180
}
181                 else {
182                     ids[i++] = key.getIdentifier();
183                     //count++;
184
}
185                 
186                 if ( i == batchSize ) {
187                     i = 1; //end of array, start filling again from start
188
if (end!=-1) checkForEnd = true;
189                 }
190                 
191             }
192             
193         }
194         return ids; //we ran out of ids to try
195
}
196
197 }
198
Popular Tags