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.loader.entity;
26
27 import java.io.Serializable;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.hibernate.HibernateException;
33 import org.hibernate.LockMode;
34 import org.hibernate.MappingException;
35 import org.hibernate.engine.SessionFactoryImplementor;
36 import org.hibernate.engine.SessionImplementor;
37 import org.hibernate.loader.Loader;
38 import org.hibernate.persister.entity.EntityPersister;
39 import org.hibernate.persister.entity.OuterJoinLoadable;
40 import org.hibernate.type.Type;
41 import org.hibernate.util.ArrayHelper;
42
43 /**
44 * "Batch" loads entities, using multiple primary key values in the
45 * SQL <tt>where</tt> clause.
46 *
47 * @see EntityLoader
48 * @author Gavin King
49 */
50 public class BatchingEntityLoader implements UniqueEntityLoader {
51
52 private final Loader[] loaders;
53 private final int[] batchSizes;
54 private final EntityPersister persister;
55 private final Type idType;
56
57 public BatchingEntityLoader(EntityPersister persister, int[] batchSizes, Loader[] loaders) {
58 this.batchSizes = batchSizes;
59 this.loaders = loaders;
60 this.persister = persister;
61 idType = persister.getIdentifierType();
62 }
63
64 private Object getObjectFromList(List results, Serializable id, SessionImplementor session) {
65 // get the right object from the list ... would it be easier to just call getEntity() ??
66 Iterator iter = results.iterator();
67 while ( iter.hasNext() ) {
68 Object obj = iter.next();
69 final boolean equal = idType.isEqual(
70 id,
71 session.getContextEntityIdentifier(obj),
72 session.getEntityMode(),
73 session.getFactory()
74 );
75 if ( equal ) return obj;
76 }
77 return null;
78 }
79
80 public Object load(Serializable id, Object optionalObject, SessionImplementor session)
81 throws HibernateException {
82
83 Serializable[] batch = session.getPersistenceContext()
84 .getBatchFetchQueue()
85 .getEntityBatch( persister, id, batchSizes[0], session.getEntityMode() );
86
87 for ( int i=0; i<batchSizes.length-1; i++) {
88 final int smallBatchSize = batchSizes[i];
89 if ( batch[smallBatchSize-1]!=null ) {
90 Serializable[] smallBatch = new Serializable[smallBatchSize];
91 System.arraycopy(batch, 0, smallBatch, 0, smallBatchSize);
92 final List results = loaders[i].loadEntityBatch(
93 session,
94 smallBatch,
95 idType,
96 optionalObject,
97 persister.getEntityName(),
98 id,
99 persister
100 );
101 return getObjectFromList(results, id, session); //EARLY EXIT
102 }
103 }
104
105 return ( (UniqueEntityLoader) loaders[batchSizes.length-1] ).load(id, optionalObject, session);
106
107 }
108
109 public static UniqueEntityLoader createBatchingEntityLoader(
110 final OuterJoinLoadable persister,
111 final int maxBatchSize,
112 final LockMode lockMode,
113 final SessionFactoryImplementor factory,
114 final Map enabledFilters)
115 throws MappingException {
116
117 if ( maxBatchSize>1 ) {
118 int[] batchSizesToCreate = ArrayHelper.getBatchSizes(maxBatchSize);
119 Loader[] loadersToCreate = new Loader[ batchSizesToCreate.length ];
120 for ( int i=0; i<batchSizesToCreate.length; i++ ) {
121 loadersToCreate[i] = new EntityLoader(persister, batchSizesToCreate[i], lockMode, factory, enabledFilters);
122 }
123 return new BatchingEntityLoader(persister, batchSizesToCreate, loadersToCreate);
124 }
125 else {
126 return new EntityLoader(persister, lockMode, factory, enabledFilters);
127 }
128 }
129
130 }