1 package org.apache.ojb.broker.accesslayer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import java.lang.reflect.Array;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.apache.ojb.broker.Identity;
27 import org.apache.ojb.broker.ManageableCollection;
28 import org.apache.ojb.broker.PersistenceBroker;
29 import org.apache.ojb.broker.accesslayer.conversions.FieldConversion;
30 import org.apache.ojb.broker.core.PersistenceBrokerImpl;
31 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
32 import org.apache.ojb.broker.metadata.ClassDescriptor;
33 import org.apache.ojb.broker.metadata.CollectionDescriptor;
34 import org.apache.ojb.broker.metadata.FieldDescriptor;
35 import org.apache.ojb.broker.metadata.FieldHelper;
36 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
37 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
38 import org.apache.ojb.broker.query.Criteria;
39 import org.apache.ojb.broker.query.Query;
40 import org.apache.ojb.broker.query.QueryByMtoNCriteria;
41 import org.apache.ojb.broker.query.ReportQueryByMtoNCriteria;
42
43
44
45
46
47
48
49 public class MtoNCollectionPrefetcher extends CollectionPrefetcher
50 {
51
52
53
54
55
56 public MtoNCollectionPrefetcher(PersistenceBrokerImpl aBroker, ObjectReferenceDescriptor anOrd)
57 {
58 super(aBroker, anOrd);
59 }
60
61
62
63
64 public void prefetchRelationship(Collection owners)
65 {
66 Query[] queries;
67 Query[] mnQueries;
68 Collection children = new ArrayList();
69 Collection mnImplementors = new ArrayList();
70
71 queries = buildPrefetchQueries(owners, children);
72 mnQueries = buildMtoNImplementorQueries(owners, children);
73
74 for (int i = 0; i < queries.length; i++)
75 {
76 Iterator iter = getBroker().getIteratorByQuery(queries[i]);
77 while (iter.hasNext())
78 {
79 Object aChild = iter.next();
80
81
82 if (!children.contains(aChild))
83 {
84 children.add(aChild);
85 }
86 }
87
88 Iterator mnIter = getBroker().getReportQueryIteratorByQuery(mnQueries[i]);
89 while (mnIter.hasNext())
90 {
91 mnImplementors.add(mnIter.next());
92 }
93 }
94
95 associateBatched(owners, children, mnImplementors);
96 }
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111 protected Query buildPrefetchQuery(Collection ids)
112 {
113 CollectionDescriptor cds = getCollectionDescriptor();
114 String[] indFkCols = getFksToThisClass();
115 String[] indItemFkCols = getFksToItemClass();
116 FieldDescriptor[] itemPkFields = getItemClassDescriptor().getPkFields();
117
118 Criteria crit = buildPrefetchCriteria(ids, indFkCols, indItemFkCols, itemPkFields);
119
120
121
122
123
124
125
126
127
128
129 return new QueryByMtoNCriteria(cds.getItemClass(), cds.getIndirectionTable(), crit, false);
130 }
131
132
133
134
135
136 protected Query buildMtoNImplementorQuery(Collection ids)
137 {
138 String[] indFkCols = getFksToThisClass();
139 String[] indItemFkCols = getFksToItemClass();
140 FieldDescriptor[] pkFields = getOwnerClassDescriptor().getPkFields();
141 FieldDescriptor[] itemPkFields = getItemClassDescriptor().getPkFields();
142 String[] cols = new String[indFkCols.length + indItemFkCols.length];
143 int[] jdbcTypes = new int[indFkCols.length + indItemFkCols.length];
144
145
146 System.arraycopy(indFkCols, 0, cols, 0, indFkCols.length);
147 System.arraycopy(indItemFkCols, 0, cols, indFkCols.length, indItemFkCols.length);
148
149 Criteria crit = buildPrefetchCriteria(ids, indFkCols, indItemFkCols, itemPkFields);
150
151
152 for (int i = 0; i < pkFields.length; i++)
153 {
154 jdbcTypes[i] = pkFields[i].getJdbcType().getType();
155 }
156 for (int i = 0; i < itemPkFields.length; i++)
157 {
158 jdbcTypes[pkFields.length + i] = itemPkFields[i].getJdbcType().getType();
159 }
160
161 ReportQueryByMtoNCriteria q = new ReportQueryByMtoNCriteria(getItemClassDescriptor().getClassOfObject(), cols,
162 crit, false);
163 q.setIndirectionTable(getCollectionDescriptor().getIndirectionTable());
164 q.setJdbcTypes(jdbcTypes);
165
166 CollectionDescriptor cds = getCollectionDescriptor();
167
168 if (!cds.getOrderBy().isEmpty())
169 {
170 Iterator iter = cds.getOrderBy().iterator();
171 while (iter.hasNext())
172 {
173 q.addOrderBy((FieldHelper) iter.next());
174 }
175 }
176
177 return q;
178 }
179
180
181
182
183 private String[] getFksToThisClass()
184 {
185 String indTable = getCollectionDescriptor().getIndirectionTable();
186 String[] fks = getCollectionDescriptor().getFksToThisClass();
187 String[] result = new String[fks.length];
188
189 for (int i = 0; i < result.length; i++)
190 {
191 result[i] = indTable + "." + fks[i];
192 }
193
194 return result;
195 }
196
197
198
199
200 private String[] getFksToItemClass()
201 {
202 String indTable = getCollectionDescriptor().getIndirectionTable();
203 String[] fks = getCollectionDescriptor().getFksToItemClass();
204 String[] result = new String[fks.length];
205
206 for (int i = 0; i < result.length; i++)
207 {
208 result[i] = indTable + "." + fks[i];
209 }
210
211 return result;
212 }
213
214
215
216
217
218
219 protected Query[] buildMtoNImplementorQueries(Collection owners, Collection children)
220 {
221 ClassDescriptor cld = getOwnerClassDescriptor();
222 PersistenceBroker pb = getBroker();
223
224
225 Collection queries = new ArrayList(owners.size());
226 Collection idsSubset = new HashSet(owners.size());
227
228 Object owner;
229 Identity id;
230
231 Iterator iter = owners.iterator();
232 while (iter.hasNext())
233 {
234 owner = iter.next();
235 id = pb.serviceIdentity().buildIdentity(cld, owner);
236 idsSubset.add(id);
237 if (idsSubset.size() == pkLimit)
238 {
239 queries.add(buildMtoNImplementorQuery(idsSubset));
240 idsSubset.clear();
241 }
242 }
243
244 if (idsSubset.size() > 0)
245 {
246 queries.add(buildMtoNImplementorQuery(idsSubset));
247 }
248
249 return (Query[]) queries.toArray(new Query[queries.size()]);
250 }
251
252
253
254
255
256
257
258
259
260 private Criteria buildPrefetchCriteria(Collection ids, String[] fkCols, String[] itemFkCols,
261 FieldDescriptor[] itemPkFields)
262 {
263 if (fkCols.length == 1 && itemFkCols.length == 1)
264 {
265 return buildPrefetchCriteriaSingleKey(ids, fkCols[0], itemFkCols[0], itemPkFields[0]);
266 }
267 else
268 {
269 return buildPrefetchCriteriaMultipleKeys(ids, fkCols, itemFkCols, itemPkFields);
270 }
271
272 }
273
274
275
276
277
278
279
280
281
282
283 private Criteria buildPrefetchCriteriaSingleKey(Collection ids, String fkCol, String itemFkCol,
284 FieldDescriptor itemPkField)
285 {
286 Criteria crit = new Criteria();
287 ArrayList values = new ArrayList(ids.size());
288 Iterator iter = ids.iterator();
289 Identity id;
290
291 while (iter.hasNext())
292 {
293 id = (Identity) iter.next();
294 values.add(id.getPrimaryKeyValues()[0]);
295 }
296
297 switch (values.size())
298 {
299 case 0 :
300 break;
301 case 1 :
302 crit.addEqualTo(fkCol, values.get(0));
303 break;
304 default :
305
306 crit.addIn(fkCol, values);
307 break;
308 }
309
310 crit.addEqualToField(itemPkField.getAttributeName(), itemFkCol);
311
312 return crit;
313 }
314
315
316
317
318
319
320
321
322
323
324 private Criteria buildPrefetchCriteriaMultipleKeys(Collection ids, String[] fkCols, String[] itemFkCols,
325 FieldDescriptor[] itemPkFields)
326 {
327 Criteria crit = new Criteria();
328 Criteria critValue = new Criteria();
329 Iterator iter = ids.iterator();
330
331 for (int i = 0; i < itemPkFields.length; i++)
332 {
333 crit.addEqualToField(itemPkFields[i].getAttributeName(), itemFkCols[i]);
334 }
335
336 while (iter.hasNext())
337 {
338 Criteria c = new Criteria();
339 Identity id = (Identity) iter.next();
340 Object[] val = id.getPrimaryKeyValues();
341
342 for (int i = 0; i < val.length; i++)
343 {
344
345 if (val[i] == null)
346 {
347 c.addIsNull(fkCols[i]);
348 }
349 else
350 {
351 c.addEqualTo(fkCols[i], val[i]);
352 }
353
354 }
355
356 critValue.addOrCriteria(c);
357 }
358
359 crit.addAndCriteria(critValue);
360 return crit;
361 }
362
363
364
365
366
367
368 private FieldConversion[] getPkFieldConversion(ClassDescriptor cld)
369 {
370 FieldDescriptor[] pks = cld.getPkFields();
371 FieldConversion[] fc = new FieldConversion[pks.length];
372
373 for (int i= 0; i < pks.length; i++)
374 {
375 fc[i] = pks[i].getFieldConversion();
376 }
377
378 return fc;
379 }
380
381
382
383
384
385
386 private Object[] convert(FieldConversion[] fcs, Object[] values)
387 {
388 Object[] convertedValues = new Object[values.length];
389
390 for (int i= 0; i < values.length; i++)
391 {
392 convertedValues[i] = fcs[i].sqlToJava(values[i]);
393 }
394
395 return convertedValues;
396 }
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411 protected void associateBatched(Collection owners, Collection children, Collection mToNImplementors)
412 {
413 CollectionDescriptor cds = getCollectionDescriptor();
414 PersistentField field = cds.getPersistentField();
415 PersistenceBroker pb = getBroker();
416 Class ownerTopLevelClass = pb.getTopLevelClass(getOwnerClassDescriptor().getClassOfObject());
417 Class childTopLevelClass = pb.getTopLevelClass(getItemClassDescriptor().getClassOfObject());
418 Class collectionClass = cds.getCollectionClass();
419 HashMap childMap = new HashMap();
420 HashMap ownerIdsToLists = new HashMap();
421 FieldConversion[] ownerFc = getPkFieldConversion(getOwnerClassDescriptor());
422 FieldConversion[] childFc = getPkFieldConversion(getItemClassDescriptor());
423
424
425 for (Iterator it = owners.iterator(); it.hasNext();)
426 {
427 Object owner = it.next();
428 Identity oid = pb.serviceIdentity().buildIdentity(owner);
429 ownerIdsToLists.put(oid, new ArrayList());
430 }
431
432
433 for (Iterator it = children.iterator(); it.hasNext();)
434 {
435 Object child = it.next();
436 Identity oid = pb.serviceIdentity().buildIdentity(child);
437 childMap.put(oid, child);
438 }
439
440 int ownerPkLen = getOwnerClassDescriptor().getPkFields().length;
441 int childPkLen = getItemClassDescriptor().getPkFields().length;
442 Object[] ownerPk = new Object[ownerPkLen];
443 Object[] childPk = new Object[childPkLen];
444
445
446 for (Iterator it = mToNImplementors.iterator(); it.hasNext();)
447 {
448 Object[] mToN = (Object[]) it.next();
449 System.arraycopy(mToN, 0, ownerPk, 0, ownerPkLen);
450 System.arraycopy(mToN, ownerPkLen, childPk, 0, childPkLen);
451
452
453 ownerPk = convert(ownerFc, ownerPk);
454 childPk = convert(childFc, childPk);
455
456 Identity ownerId = pb.serviceIdentity().buildIdentity(null, ownerTopLevelClass, ownerPk);
457 Identity childId = pb.serviceIdentity().buildIdentity(null, childTopLevelClass, childPk);
458
459
460 Collection list = (Collection) ownerIdsToLists.get(ownerId);
461 Object child = childMap.get(childId);
462 list.add(child);
463 }
464
465
466 for (Iterator it = owners.iterator(); it.hasNext();)
467 {
468 Object result;
469 Object owner = it.next();
470 Identity ownerId = pb.serviceIdentity().buildIdentity(owner);
471
472 List list = (List) ownerIdsToLists.get(ownerId);
473
474 if ((collectionClass == null) && field.getType().isArray())
475 {
476 int length = list.size();
477 Class itemtype = field.getType().getComponentType();
478
479 result = Array.newInstance(itemtype, length);
480
481 for (int j = 0; j < length; j++)
482 {
483 Array.set(result, j, list.get(j));
484 }
485 }
486 else
487 {
488 ManageableCollection col = createCollection(cds, collectionClass);
489
490 for (Iterator it2 = list.iterator(); it2.hasNext();)
491 {
492 col.ojbAdd(it2.next());
493 }
494 result = col;
495 }
496
497 Object value = field.get(owner);
498 if ((value instanceof CollectionProxyDefaultImpl) && (result instanceof Collection))
499 {
500 ((CollectionProxyDefaultImpl) value).setData((Collection) result);
501 }
502 else
503 {
504 field.set(owner, result);
505 }
506 }
507
508 }
509 }