001 package org.apache.ojb.broker.accesslayer;
002
003 /* Copyright 2003-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import java.util.ArrayList;
019 import java.util.Collection;
020 import java.util.Iterator;
021
022 import org.apache.ojb.broker.Identity;
023 import org.apache.ojb.broker.PersistenceBrokerFactory;
024 import org.apache.ojb.broker.core.PersistenceBrokerConfiguration;
025 import org.apache.ojb.broker.core.PersistenceBrokerImpl;
026 import org.apache.ojb.broker.metadata.ClassDescriptor;
027 import org.apache.ojb.broker.metadata.DescriptorRepository;
028 import org.apache.ojb.broker.metadata.FieldDescriptor;
029 import org.apache.ojb.broker.query.Criteria;
030 import org.apache.ojb.broker.query.Query;
031 import org.apache.ojb.broker.query.QueryByCriteria;
032 import org.apache.ojb.broker.query.QueryFactory;
033 import org.apache.ojb.broker.util.configuration.ConfigurationException;
034 import org.apache.ojb.broker.util.logging.Logger;
035 import org.apache.ojb.broker.util.logging.LoggerFactory;
036
037 /**
038 * Abstract Prefetcher.
039 * @author <a href="mailto:olegnitz@apache.org">Oleg Nitz</a>
040 * @version $Id: BasePrefetcher.java,v 1.1 2007-08-24 22:17:30 ewestfal Exp $
041 */
042 public abstract class BasePrefetcher implements RelationshipPrefetcher
043 {
044 /** The numer of columns to query for. */
045 protected static final int IN_LIMIT = getPrefetchInLimit();
046
047 private Logger logger;
048 private PersistenceBrokerImpl broker;
049 /** Class descriptor for the item type. */
050 protected ClassDescriptor itemClassDesc;
051 /** Maximum number of pk's in one query. */
052 protected final int pkLimit;
053
054 /**
055 * Returns the number of column to query for, from the configuration.
056 *
057 * @return The prefetch limit
058 */
059 private static int getPrefetchInLimit()
060 {
061 try
062 {
063 PersistenceBrokerConfiguration config = (PersistenceBrokerConfiguration) PersistenceBrokerFactory.getConfigurator().getConfigurationFor(null);
064
065 return config.getSqlInLimit();
066 }
067 catch (ConfigurationException e)
068 {
069 return 200;
070 }
071 }
072
073 /**
074 * Constructor for BasePrefetcher.
075 */
076 public BasePrefetcher(PersistenceBrokerImpl aBroker, Class anItemClass)
077 {
078 super();
079 broker = aBroker;
080 itemClassDesc = aBroker.getDescriptorRepository().getDescriptorFor(anItemClass);
081 logger = LoggerFactory.getLogger(this.getClass());
082 pkLimit = getPrefetchInLimit() / getItemClassDescriptor().getPkFields().length;
083 }
084
085 /**
086 * The limit of objects loaded by one SQL query
087 */
088 public int getLimit()
089 {
090 return pkLimit;
091 }
092
093 /**
094 * associate the batched Children with their owner object <br>
095 */
096 protected abstract void associateBatched(Collection owners, Collection children);
097
098 /**
099 * @see org.apache.ojb.broker.accesslayer.RelationshipPrefetcher#prefetchRelationship(Collection)
100 */
101 public void prefetchRelationship(Collection owners)
102 {
103 Query queries[];
104 Collection children = new ArrayList();
105
106 queries = buildPrefetchQueries(owners, children);
107
108 for (int i = 0; i < queries.length; i++)
109 {
110 Iterator iter = getBroker().getIteratorByQuery(queries[i]);
111 while (iter.hasNext())
112 {
113 children.add(iter.next());
114 }
115 }
116
117 // BRJ: performRetrieval of childrens references BEFORE associating with owners
118 // TODO: this is a quick fix !
119 getBroker().getReferenceBroker().performRetrievalTasks();
120
121 associateBatched(owners, children);
122 }
123
124
125 protected QueryByCriteria buildPrefetchQuery(Collection ids, FieldDescriptor[] fields)
126 {
127 return buildPrefetchQuery(getItemClassDescriptor().getClassOfObject(), ids, fields);
128 }
129
130
131 /**
132 *
133 * @param ids collection of identities
134 * @param fields
135 * @return
136 */
137 protected Criteria buildPrefetchCriteria(Collection ids, FieldDescriptor[] fields)
138 {
139 if (fields.length == 1)
140 {
141 return buildPrefetchCriteriaSingleKey(ids, fields[0]);
142 }
143 else
144 {
145 return buildPrefetchCriteriaMultipleKeys(ids, fields);
146 }
147
148 }
149
150 /**
151 *
152 * @param clazz
153 * @param ids collection of identities
154 * @param fields
155 * @return
156 */
157 protected QueryByCriteria buildPrefetchQuery(Class clazz, Collection ids, FieldDescriptor[] fields)
158 {
159 return QueryFactory.newQuery(clazz, buildPrefetchCriteria(ids, fields));
160 }
161
162 /**
163 * Build the Criteria using IN(...) for single keys
164 * @param ids collection of identities
165 * @param field
166 * @return Criteria
167 */
168 private Criteria buildPrefetchCriteriaSingleKey(Collection ids, FieldDescriptor field)
169 {
170 Criteria crit = new Criteria();
171 ArrayList values = new ArrayList(ids.size());
172 Iterator iter = ids.iterator();
173 Identity id;
174
175 while (iter.hasNext())
176 {
177 id = (Identity) iter.next();
178 values.add(id.getPrimaryKeyValues()[0]);
179 }
180
181 switch (values.size())
182 {
183 case 0:
184 break;
185 case 1:
186 crit.addEqualTo(field.getAttributeName(), values.get(0));
187 break;
188 default:
189 // create IN (...) for the single key field
190 crit.addIn(field.getAttributeName(), values);
191 break;
192 }
193
194 return crit;
195 }
196
197 /**
198 * Build the Criteria using multiple ORs
199 * @param ids collection of identities
200 * @param fields
201 * @return Criteria
202 */
203 private Criteria buildPrefetchCriteriaMultipleKeys(Collection ids, FieldDescriptor fields[])
204 {
205 Criteria crit = new Criteria();
206 Iterator iter = ids.iterator();
207 Object[] val;
208 Identity id;
209
210 while (iter.hasNext())
211 {
212 Criteria c = new Criteria();
213 id = (Identity) iter.next();
214 val = id.getPrimaryKeyValues();
215 for (int i = 0; i < val.length; i++)
216 {
217 if (val[i] == null)
218 {
219 c.addIsNull(fields[i].getAttributeName());
220 }
221 else
222 {
223 c.addEqualTo(fields[i].getAttributeName(), val[i]);
224 }
225 }
226 crit.addOrCriteria(c);
227 }
228
229 return crit;
230 }
231
232 /**
233 * Return the DescriptorRepository
234 */
235 protected DescriptorRepository getDescriptorRepository()
236 {
237 return getBroker().getDescriptorRepository();
238 }
239
240 /**
241 * Returns the ClassDescriptor of the item Class
242 * @return ClassDescriptor
243 */
244 public ClassDescriptor getItemClassDescriptor()
245 {
246 return itemClassDesc;
247 }
248
249 protected abstract Query[] buildPrefetchQueries(Collection owners, Collection children);
250
251 /**
252 * Returns the broker.
253 * @return PersistenceBrokerImpl
254 */
255 protected PersistenceBrokerImpl getBroker()
256 {
257 return broker;
258 }
259
260 /**
261 * Returns the logger.
262 * @return Logger
263 */
264 protected Logger getLogger()
265 {
266 return logger;
267 }
268 }