KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > core > QueryReferenceBroker


1 package org.apache.ojb.broker.core;
2
3 /* Copyright 2003-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import java.lang.reflect.Array JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collection JavaDoc;
21 import java.util.HashMap JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.apache.ojb.broker.Identity;
27 import org.apache.ojb.broker.ManageableCollection;
28 import org.apache.ojb.broker.PBLifeCycleEvent;
29 import org.apache.ojb.broker.PersistenceBrokerException;
30 import org.apache.ojb.broker.accesslayer.OJBIterator;
31 import org.apache.ojb.broker.accesslayer.PagingIterator;
32 import org.apache.ojb.broker.accesslayer.PlainPrefetcher;
33 import org.apache.ojb.broker.accesslayer.RelationshipPrefetcher;
34 import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
35 import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
36 import org.apache.ojb.broker.core.proxy.IndirectionHandler;
37 import org.apache.ojb.broker.core.proxy.MaterializationListener;
38 import org.apache.ojb.broker.core.proxy.ProxyHelper;
39 import org.apache.ojb.broker.metadata.ClassDescriptor;
40 import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
41 import org.apache.ojb.broker.metadata.CollectionDescriptor;
42 import org.apache.ojb.broker.metadata.FieldDescriptor;
43 import org.apache.ojb.broker.metadata.FieldHelper;
44 import org.apache.ojb.broker.metadata.MetadataException;
45 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
46 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
47 import org.apache.ojb.broker.query.Criteria;
48 import org.apache.ojb.broker.query.Query;
49 import org.apache.ojb.broker.query.QueryByCriteria;
50 import org.apache.ojb.broker.query.QueryFactory;
51 import org.apache.ojb.broker.util.BrokerHelper;
52 import org.apache.ojb.broker.util.collections.ManageableArrayList;
53 import org.apache.ojb.broker.util.collections.ManageableHashSet;
54 import org.apache.ojb.broker.util.collections.RemovalAwareCollection;
55 import org.apache.ojb.broker.util.collections.RemovalAwareList;
56 import org.apache.ojb.broker.util.collections.RemovalAwareSet;
57 import org.apache.ojb.broker.util.logging.Logger;
58 import org.apache.ojb.broker.util.logging.LoggerFactory;
59
60 /**
61  * Encapsulates 1:1 and 1:n references and collection references stuff.
62  *
63  * TODO: Should we made this class independend from PB implementation class
64  * and only use PB interface methods?
65  *
66  * @author <a HREF="mailto:armin@codeAuLait.de">Armin Waibel</a>
67  * @version $Id: QueryReferenceBroker.java,v 1.17.2.17 2005/12/21 22:25:00 tomdz Exp $
68  */

69 public class QueryReferenceBroker
70 {
71     private Logger log = LoggerFactory.getLogger(QueryReferenceBroker.class);
72
73     private PersistenceBrokerImpl pb;
74     private HashMap JavaDoc m_retrievalTasks;
75     private ArrayList JavaDoc prefetchingListeners;
76     private final boolean batchRetrieval = true;
77     private final boolean prefetchProxies = true;
78     private Class JavaDoc classToPrefetch;
79     private PBLifeCycleEvent afterLookupEvent;
80
81     public QueryReferenceBroker(final PersistenceBrokerImpl pb)
82     {
83         this.pb = pb;
84         afterLookupEvent = new PBLifeCycleEvent(pb, PBLifeCycleEvent.Type.AFTER_LOOKUP);
85     }
86
87     /**
88      * retrieve a collection of itemClass Objects matching the Query query
89      * @param collectionClass type the collection to be returned
90      * @param itemClass Class of item in collection
91      * @param query the query
92      */

93     private ManageableCollection getCollectionByQuery(Class JavaDoc collectionClass, Class JavaDoc itemClass, Query query)
94             throws ClassNotPersistenceCapableException, PersistenceBrokerException
95     {
96         if (log.isDebugEnabled()) log.debug("getCollectionByQuery (" + collectionClass + ", " + itemClass + ", " + query + ")");
97
98         ClassDescriptor cld = pb.getClassDescriptor(itemClass);
99         ManageableCollection result = null;
100         OJBIterator iter = null;
101         int fullSize = -1;
102         int size = 0;
103
104         final boolean isRetrievalTasksCreated = batchRetrieval && m_retrievalTasks == null;
105         if (isRetrievalTasksCreated)
106         {
107             // Maps ReferenceDescriptors to HashSets of owners
108
m_retrievalTasks = new HashMap JavaDoc();
109         }
110
111         // ==> enable materialization cache
112
pb.getInternalCache().enableMaterializationCache();
113         try
114         {
115             result = (ManageableCollection) collectionClass.newInstance();
116             
117             // now iterate over all elements and add them to the new collection
118
// lifecycle events are disabled
119
iter = pb.getIteratorFromQuery(query, cld);
120             iter.disableLifeCycleEvents();
121
122             // BRJ : get fullSizefor Query
123
// to be removed when Query.fullSize is removed
124
if (iter instanceof PagingIterator)
125             {
126                 fullSize = iter.fullSize();
127             }
128
129             while (iter.hasNext())
130             {
131                 Object JavaDoc candidate = iter.next();
132
133                 /**
134                  * MBAIRD
135                  * candidate CAN be null in the case of materializing from an iterator based
136                  * on a query for a class that is mapped to a table that has other classes
137                  * mapped to that table as well, but aren't extents.
138                  */

139                 if (candidate != null)
140                 {
141                     IndirectionHandler handler = ProxyHelper.getIndirectionHandler(candidate);
142
143                     if ((handler != null) || itemClass.isAssignableFrom(candidate.getClass()))
144                     {
145                         result.ojbAdd(candidate);
146
147                         // BRJ: count added objects
148
// to be removed when Query.fullSize is removed
149
size++;
150                     }
151                     else
152                     {
153                         //warn the user
154
log.warn("Candidate object ["+candidate
155                                     +"] class ["+candidate.getClass().getName()
156                                     +"] is not a subtype of ["+itemClass.getName()
157                                     +"] or any type of proxy. NOT INCLUDED in result collection");
158                     }
159                     if (prefetchProxies && (handler != null)
160                             && (cld.getProxyPrefetchingLimit() > 0)
161                             && addRetrievalTask(candidate, this))
162                     {
163                         new PBMaterializationListener(candidate, m_retrievalTasks,
164                                 this, cld.getProxyPrefetchingLimit());
165                     }
166                 }
167             }
168
169             if (isRetrievalTasksCreated)
170             {
171                 // turn off auto prefetching for related proxies
172
final Class JavaDoc saveClassToPrefetch = classToPrefetch;
173                 classToPrefetch = null;
174                 try
175                 {
176                     performRetrievalTasks();
177                 }
178                 finally
179                 {
180                     classToPrefetch = saveClassToPrefetch;
181                 }
182             }
183
184             // BRJ: fire LifeCycleEvents after execution of RetrievalTasks
185
// to ensure objects are fully materialized
186
Iterator JavaDoc resultIter = result.ojbIterator();
187             while (resultIter.hasNext())
188             {
189                 Object JavaDoc obj = resultIter.next();
190                 afterLookupEvent.setTarget(obj);
191                 pb.fireBrokerEvent(afterLookupEvent);
192                 afterLookupEvent.setTarget(null);
193             }
194
195             // ==> disable materialization cache
196
pb.getInternalCache().disableMaterializationCache();
197         }
198         catch(RuntimeException JavaDoc e)
199         {
200             // ==> clear materialization cache
201
pb.getInternalCache().doLocalClear();
202             throw e;
203         }
204         catch (Exception JavaDoc ex)
205         {
206             // ==> clear materialization cache
207
pb.getInternalCache().doLocalClear();
208             log.error(ex);
209             throw new PersistenceBrokerException(ex);
210         }
211         finally
212         {
213             if (iter != null)
214             {
215                 iter.releaseDbResources();
216             }
217             if (isRetrievalTasksCreated)
218             {
219                 m_retrievalTasks = null;
220             }
221         }
222
223         // BRJ: store fullSize in Query to re-enable deprecated functionality
224
// to be removed when Query.fullSize is removed
225
if (fullSize < 0)
226         {
227             fullSize = size; // use size of result
228
}
229         query.fullSize(fullSize);
230         
231         return result;
232     }
233
234     /**
235      * retrieve a collection of type collectionClass matching the Query query
236      * if lazy = true return a CollectionProxy
237      *
238      * @param collectionClass
239      * @param query
240      * @param lazy
241      * @return ManageableCollection
242      * @throws PersistenceBrokerException
243      */

244     public ManageableCollection getCollectionByQuery(Class JavaDoc collectionClass, Query query, boolean lazy) throws PersistenceBrokerException
245     {
246         ManageableCollection result;
247
248         try
249         {
250             // BRJ: return empty Collection for null query
251
if (query == null)
252             {
253                 result = (ManageableCollection)collectionClass.newInstance();
254             }
255             else
256             {
257                 if (lazy)
258                 {
259                     result = pb.getProxyFactory().createCollectionProxy(pb.getPBKey(), query, collectionClass);
260                 }
261                 else
262                 {
263                     result = getCollectionByQuery(collectionClass, query.getSearchClass(), query);
264                 }
265             }
266             return result;
267         }
268         catch (Exception JavaDoc e)
269         {
270             if(e instanceof PersistenceBrokerException)
271             {
272                 throw (PersistenceBrokerException) e;
273             }
274             else
275             {
276                 throw new PersistenceBrokerException(e);
277             }
278         }
279     }
280
281     /**
282      * retrieve a collection of itemClass Objects matching the Query query
283      */

284     public Collection JavaDoc getCollectionByQuery(Query query, boolean lazy) throws PersistenceBrokerException
285     {
286         // thma: the following cast is safe because:
287
// 1. ManageableVector implements Collection (will be returned if lazy == false)
288
// 2. CollectionProxy implements Collection (will be returned if lazy == true)
289
return (Collection JavaDoc) getCollectionByQuery(RemovalAwareCollection.class, query, lazy);
290     }
291
292     
293     private Class JavaDoc getCollectionTypeClass(CollectionDescriptor cds) throws PersistenceBrokerException{
294         // BRJ: do not use RemovalAwareCollection for m:n relationships
295
// see http://db.apache.org/ojb/docu/guides/basic-technique.html#Mapping+m%3An+associations
296

297         Class JavaDoc fieldType = cds.getPersistentField().getType();
298         Class JavaDoc collType;
299
300         if (fieldType.isArray() || fieldType.isAssignableFrom(RemovalAwareCollection.class))
301         {
302             collType = cds.isMtoNRelation() ? ManageableArrayList.class : RemovalAwareCollection.class;
303         }
304         else if (fieldType.isAssignableFrom(RemovalAwareList.class))
305         {
306             collType = cds.isMtoNRelation() ? ManageableArrayList.class : RemovalAwareList.class;
307         }
308         else if (fieldType.isAssignableFrom(RemovalAwareSet.class))
309         {
310             collType = cds.isMtoNRelation() ? ManageableHashSet.class : RemovalAwareSet.class;
311         }
312         else if (ManageableCollection.class.isAssignableFrom(fieldType))
313         {
314             collType = fieldType;
315         }
316         else
317         {
318             throw new MetadataException("Cannot determine a default collection type for collection "+cds.getAttributeName()+" in type "+cds.getClassDescriptor().getClassNameOfObject());
319         }
320         return collType;
321     }
322     
323     
324     /**
325      * @return true if this is the first task for the given ObjectReferenceDescriptor
326      */

327     private boolean addRetrievalTask(Object JavaDoc obj, Object JavaDoc key)
328     {
329         ArrayList JavaDoc owners = (ArrayList JavaDoc) m_retrievalTasks.get(key);
330         boolean isFirst = false;
331
332         if (owners == null)
333         {
334             owners = new ArrayList JavaDoc();
335             m_retrievalTasks.put(key, owners);
336             isFirst = true;
337         }
338         owners.add(obj);
339         return isFirst;
340     }
341
342     /**
343      * Perform the stored retrieval tasks
344      * BRJ: made it public to access it from BasePrefetcher
345      * TODO: this is a quick fix !
346      */

347     public void performRetrievalTasks()
348     {
349         if (m_retrievalTasks == null)
350         {
351             return;
352         }
353
354         while (m_retrievalTasks.size() > 0)
355         {
356             HashMap JavaDoc tmp = m_retrievalTasks;
357             m_retrievalTasks = new HashMap JavaDoc();
358             // during execution of these tasks new tasks may be added
359

360             for (Iterator JavaDoc it = tmp.entrySet().iterator(); it.hasNext(); )
361             {
362                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
363                 Object JavaDoc key = entry.getKey();
364
365                 if (!(key instanceof ObjectReferenceDescriptor))
366                 {
367                     continue;
368                 }
369
370                 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) key;
371                 RelationshipPrefetcher prefetcher;
372                 ArrayList JavaDoc owners = (ArrayList JavaDoc) entry.getValue();
373
374 // if (ord instanceof SuperReferenceDescriptor || ord.isLazy() || (ord.getItemProxyClass() != null))
375
if (ord.isLazy() || (ord.getItemProxyClass() != null))
376                 {
377                     continue;
378                 }
379
380                 prefetcher = pb.getRelationshipPrefetcherFactory().createRelationshipPrefetcher(ord);
381                 prefetcher.prefetchRelationship(owners);
382                 it.remove();
383             }
384         }
385     }
386
387     /**
388      * Retrieve a single Reference.
389      * This implementation retrieves a referenced object from the data backend
390      * if <b>cascade-retrieve</b> is true or if <b>forced</b> is true.
391      *
392      * @param obj - object that will have it's field set with a referenced object.
393      * @param cld - the ClassDescriptor describring obj
394      * @param rds - the ObjectReferenceDescriptor of the reference attribute to be loaded
395      * @param forced - if set to true, the reference is loaded even if the rds differs.
396      */

397     public void retrieveReference(Object JavaDoc obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
398     {
399         PersistentField refField;
400         Object JavaDoc refObj = null;
401         
402         if (forced || rds.getCascadeRetrieve())
403         {
404             pb.getInternalCache().enableMaterializationCache();
405             try
406             {
407                 Identity id = getReferencedObjectIdentity(obj, rds, cld);
408                 boolean isRefObjDefined = true;
409
410                 if (id == null)
411                 {
412                     refObj = null;
413                 } //JMM : why not see if the object has already been loaded
414
else if ( pb.serviceObjectCache().lookup(id) != null )
415                 {
416                     refObj = pb.doGetObjectByIdentity(id);
417                     if (rds.isSuperReferenceDescriptor())
418                     {
419                         // walk the super-references
420
ClassDescriptor superCld = cld.getRepository().getDescriptorFor(rds.getItemClass());
421                         retrieveReferences(refObj, superCld, false);
422                         retrieveCollections(refObj, superCld, false);
423                     }
424                 }
425                 else if ((m_retrievalTasks != null)
426                         && !rds.isLazy()
427                         && (rds.getItemProxyClass() == null))
428                 {
429                     addRetrievalTask(obj, rds);
430                     isRefObjDefined = false;
431                 }
432                 else
433                 {
434                     refObj = getReferencedObject(id, rds);
435                 }
436
437                 if (isRefObjDefined)
438                 {
439                     refField = rds.getPersistentField();
440                     refField.set(obj, refObj);
441
442                     if ((refObj != null) && prefetchProxies
443                             && (m_retrievalTasks != null)
444                             && (rds.getProxyPrefetchingLimit() > 0))
445                     {
446                         IndirectionHandler handler = ProxyHelper.getIndirectionHandler(refObj);
447
448                         if ((handler != null)
449                                 && addRetrievalTask(obj, rds))
450                         {
451                             new PBMaterializationListener(obj, m_retrievalTasks,
452                                     rds, rds.getProxyPrefetchingLimit());
453                         }
454                     }
455                 }
456
457                 pb.getInternalCache().disableMaterializationCache();
458             }
459             catch(RuntimeException JavaDoc e)
460             {
461                 pb.getInternalCache().doLocalClear();
462                 throw e;
463             }
464         }
465     }
466     
467     /**
468      * Retrieve a single Reference.
469      * This implementation retrieves a referenced object from the data backend
470      * if <b>cascade-retrieve</b> is true or if <b>forced</b> is true.
471      *
472      * @param obj - object that will have it's field set with a referenced object.
473      * @param cld - the ClassDescriptor describring obj
474      * @param rds - the ObjectReferenceDescriptor of the reference attribute to be loaded
475      * @param forced - if set to true, the reference is loaded even if the rds differs.
476      */

477     public void retrieveProxyReference(Object JavaDoc obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
478     {
479         PersistentField refField;
480         Object JavaDoc refObj = null;
481
482             pb.getInternalCache().enableMaterializationCache();
483             try
484             {
485                 Identity id = getReferencedObjectIdentity(obj, rds, cld);
486                 if (id != null){
487                     refObj = pb.createProxy(rds.getItemClass(), id);
488                 }
489                 refField = rds.getPersistentField();
490                 refField.set(obj, refObj);
491
492                 if ((refObj != null) && prefetchProxies
493                         && (m_retrievalTasks != null)
494                         && (rds.getProxyPrefetchingLimit() > 0))
495                 {
496                     IndirectionHandler handler = ProxyHelper.getIndirectionHandler(refObj);
497
498                     if ((handler != null)
499                             && addRetrievalTask(obj, rds))
500                     {
501                         new PBMaterializationListener(obj, m_retrievalTasks,
502                                 rds, rds.getProxyPrefetchingLimit());
503                     }
504                 }
505                 
506
507                 pb.getInternalCache().disableMaterializationCache();
508             }
509             catch(RuntimeException JavaDoc e)
510             {
511                 pb.getInternalCache().doLocalClear();
512                 throw e;
513             }
514         
515     }
516
517     /**
518      * Retrieve all References
519      *
520      * @param newObj the instance to be loaded or refreshed
521      * @param cld the ClassDescriptor of the instance
522      * @param forced if set to true loading is forced even if cld differs.
523      */

524     public void retrieveReferences(Object JavaDoc newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
525     {
526         Iterator JavaDoc i = cld.getObjectReferenceDescriptors().iterator();
527
528         // turn off auto prefetching for related proxies
529
final Class JavaDoc saveClassToPrefetch = classToPrefetch;
530         classToPrefetch = null;
531
532         pb.getInternalCache().enableMaterializationCache();
533         try
534         {
535             while (i.hasNext())
536             {
537                 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next();
538                 retrieveReference(newObj, cld, rds, forced);
539             }
540
541             pb.getInternalCache().disableMaterializationCache();
542         }
543         catch(RuntimeException JavaDoc e)
544         {
545             pb.getInternalCache().doLocalClear();
546             throw e;
547         }
548         finally
549         {
550             classToPrefetch = saveClassToPrefetch;
551         }
552     }
553     
554     /**
555      * Retrieve all References
556      *
557      * @param newObj the instance to be loaded or refreshed
558      * @param cld the ClassDescriptor of the instance
559      * @param forced if set to true loading is forced even if cld differs.
560      */

561     public void retrieveProxyReferences(Object JavaDoc newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
562     {
563         Iterator JavaDoc i = cld.getObjectReferenceDescriptors().iterator();
564
565         // turn off auto prefetching for related proxies
566
final Class JavaDoc saveClassToPrefetch = classToPrefetch;
567         classToPrefetch = null;
568
569         pb.getInternalCache().enableMaterializationCache();
570         try
571         {
572             while (i.hasNext())
573             {
574                 ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next();
575                 retrieveProxyReference(newObj, cld, rds, forced);
576             }
577
578             pb.getInternalCache().disableMaterializationCache();
579         }
580         catch(RuntimeException JavaDoc e)
581         {
582             pb.getInternalCache().doLocalClear();
583             throw e;
584         }
585         finally
586         {
587             classToPrefetch = saveClassToPrefetch;
588         }
589     }
590
591    /**
592      * retrieves an Object reference's Identity.
593      * <br>
594      * Null is returned if all foreign keys are null
595      */

596     private Identity getReferencedObjectIdentity(Object JavaDoc obj, ObjectReferenceDescriptor rds, ClassDescriptor cld)
597     {
598         Object JavaDoc[] fkValues = rds.getForeignKeyValues(obj, cld);
599         FieldDescriptor[] fkFieldDescriptors = rds.getForeignKeyFieldDescriptors(cld);
600         boolean hasNullifiedFKValue = hasNullifiedFK(fkFieldDescriptors, fkValues);
601         /*
602         BRJ: if all fk values are null there's no referenced object
603
604         arminw: Supposed the given object has nullified FK values but the referenced
605         object still exists. This could happend after serialization of the main object. In
606         this case all anonymous field (AK) information is lost, because AnonymousPersistentField class
607         use the object identity to cache the AK values. But we can build Identity anyway from the reference
608         */

609         if (hasNullifiedFKValue)
610         {
611             if(BrokerHelper.hasAnonymousKeyReference(cld, rds))
612             {
613                 Object JavaDoc referencedObject = rds.getPersistentField().get(obj);
614                 if(referencedObject != null)
615                 {
616                     return pb.serviceIdentity().buildIdentity(referencedObject);
617                 }
618             }
619         }
620         else
621         {
622             // ensure that top-level extents are used for Identities
623
return pb.serviceIdentity().buildIdentity(rds.getItemClass(), pb.getTopLevelClass(rds.getItemClass()), fkValues);
624         }
625         return null;
626     }
627
628     // BRJ: check if we have non null fk values
629
// TBD we should also check primitives
630
// to avoid creation of unmaterializable proxies
631
private boolean hasNullifiedFK(FieldDescriptor[] fkFieldDescriptors, Object JavaDoc[] fkValues)
632     {
633         boolean result = true;
634         for (int i = 0; i < fkValues.length; i++)
635         {
636             if (!pb.serviceBrokerHelper().representsNull(fkFieldDescriptors[i], fkValues[i]))
637             {
638                 result = false;
639                 break;
640             }
641         }
642         return result;
643     }
644
645     /**
646      * retrieves an Object reference by its Identity.
647      * <br>
648      * If there is a Proxy-class is defined in the ReferenceDescriptor or
649      * if the ReferenceDescriptor is lazy, a Proxy-object is returned.
650      * <br>
651      * If no Proxy-class is defined, a getObjectByIdentity(...) lookup is performed.
652      */

653     private Object JavaDoc getReferencedObject(Identity id, ObjectReferenceDescriptor rds)
654     {
655         Class JavaDoc baseClassForProxy;
656
657         if (rds.isLazy())
658         {
659             /*
660             arminw:
661             use real reference class instead of the top-level class,
662             because we want to use a proxy representing the real class
663             not only the top-level class - right?
664             */

665             // referencedProxy = getClassDescriptor(referencedClass).getDynamicProxyClass();
666
//referencedProxy = rds.getItemClass();
667

668             /*
669              * andrew.clute:
670              * With proxy generation now handled by the ProxyFactory implementations, the class of the Item
671              * is now the nessecary parameter to generate a proxy.
672              */

673             baseClassForProxy = rds.getItemClass();
674         }
675         else
676         {
677             /*
678             * andrew.clute:
679             * If the descriptor does not mark it as lazy, then the class for the proxy must be of type VirtualProxy
680             */

681            baseClassForProxy = rds.getItemProxyClass();
682         }
683
684         if (baseClassForProxy != null)
685         {
686             try
687             {
688                 return pb.createProxy(baseClassForProxy, id);
689             }
690             catch (Exception JavaDoc e)
691             {
692                 log.error("Error while instantiate object " + id + ", msg: "+ e.getMessage(), e);
693                 if(e instanceof PersistenceBrokerException)
694                 {
695                     throw (PersistenceBrokerException) e;
696                 }
697                 else
698                 {
699                     throw new PersistenceBrokerException(e);
700                 }
701             }
702         }
703         else
704         {
705             return pb.doGetObjectByIdentity(id);
706         }
707     }
708     
709     /**
710      * Retrieve a single Collection on behalf of <b>obj</b>.
711      * The Collection is retrieved only if <b>cascade.retrieve is true</b>
712      * or if <b>forced</b> is set to true. *
713      *
714      * @param obj - the object to be updated
715      * @param cld - the ClassDescriptor describing obj
716      * @param cds - the CollectionDescriptor describing the collection attribute to be loaded
717      * @param forced - if set to true loading is forced, even if cds differs.
718      *
719      */

720     public void retrieveCollection(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
721     {
722         doRetrieveCollection(obj, cld, cds, forced, cds.isLazy());
723     }
724     
725     /**
726      * Retrieve a single Proxied Collection on behalf of <b>obj</b>.
727      * The Collection is retrieved only if <b>cascade.retrieve is true</b>
728      * or if <b>forced</b> is set to true. *
729      *
730      * @param obj - the object to be updated
731      * @param cld - the ClassDescriptor describing obj
732      * @param cds - the CollectionDescriptor describing the collection attribute to be loaded
733      * @param forced - if set to true a proxy will be placed, even if cds differs.
734      *
735      */

736     public void retrieveProxyCollection(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
737     {
738         doRetrieveCollection(obj, cld, cds, forced, true);
739     }
740     
741     private void doRetrieveCollection(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced, boolean lazyLoad)
742     {
743         if (forced || cds.getCascadeRetrieve())
744         {
745             if ((m_retrievalTasks != null) && !cds.isLazy()
746                     && !cds.hasProxyItems()
747                     && (cds.getQueryCustomizer() == null))
748             {
749                 addRetrievalTask(obj, cds);
750             }
751             else
752             {
753                 // this collection type will be used:
754
Class JavaDoc collectionClass = cds.getCollectionClass();
755                 PersistentField collectionField = cds.getPersistentField();
756                 Query fkQuery = getFKQuery(obj, cld, cds);
757                 Object JavaDoc value;
758
759                 pb.getInternalCache().enableMaterializationCache();
760                 try
761                 {
762                     if (collectionClass == null)
763                     {
764                         Collection JavaDoc result = (Collection JavaDoc)getCollectionByQuery(getCollectionTypeClass(cds), fkQuery, lazyLoad);
765
766                         // assign collection to objects attribute
767
// if attribute has an array type build an array, else assign collection directly
768
if (collectionField.getType().isArray())
769                         {
770                             int length = result.size();
771                             Class JavaDoc itemtype = collectionField.getType().getComponentType();
772                             Object JavaDoc resultArray = Array.newInstance(itemtype, length);
773                             int j = 0;
774                             for (Iterator JavaDoc iter = result.iterator(); iter.hasNext();j++)
775                             {
776                                 Array.set(resultArray, j, iter.next());
777                             }
778                             collectionField.set(obj, resultArray);
779                         }
780                         else
781                         {
782                             collectionField.set(obj, result);
783                         }
784                         value = result;
785                     }
786                     else
787                     {
788                         ManageableCollection result = getCollectionByQuery(collectionClass, fkQuery, lazyLoad);
789                         collectionField.set(obj, result);
790                         value = result;
791                     }
792
793                     if (prefetchProxies && (m_retrievalTasks != null)
794                             && (cds.getProxyPrefetchingLimit() > 0)
795                             && (cds.getQueryCustomizer() == null)
796                             && (ProxyHelper.isCollectionProxy(value)))
797                     {
798                         if (addRetrievalTask(obj, cds))
799                         {
800                             new PBCollectionProxyListener(obj,
801                                     m_retrievalTasks, cds, cds.getProxyPrefetchingLimit());
802                         }
803                     }
804
805                     pb.getInternalCache().disableMaterializationCache();
806                 }
807                 catch(RuntimeException JavaDoc e)
808                 {
809                     pb.getInternalCache().doLocalClear();
810                     throw e;
811                 }
812             }
813         }
814     }
815
816     /**
817      * Answer the foreign key query to retrieve the collection
818      * defined by CollectionDescriptor
819      */

820     private Query getFKQuery(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cds)
821     {
822         Query fkQuery;
823         QueryByCriteria fkQueryCrit;
824
825         if (cds.isMtoNRelation())
826         {
827             fkQueryCrit = getFKQueryMtoN(obj, cld, cds);
828         }
829         else
830         {
831             fkQueryCrit = getFKQuery1toN(obj, cld, cds);
832         }
833
834         // check if collection must be ordered
835
if (!cds.getOrderBy().isEmpty())
836         {
837             Iterator JavaDoc iter = cds.getOrderBy().iterator();
838             while (iter.hasNext())
839             {
840                 fkQueryCrit.addOrderBy((FieldHelper)iter.next());
841             }
842         }
843
844         // BRJ: customize the query
845
if (cds.getQueryCustomizer() != null)
846         {
847             fkQuery = cds.getQueryCustomizer().customizeQuery(obj, pb, cds, fkQueryCrit);
848         }
849         else
850         {
851             fkQuery = fkQueryCrit;
852         }
853
854         return fkQuery;
855     }
856
857     /**
858      * Get Foreign key query for m:n <br>
859      * supports UNIDIRECTIONAL m:n using QueryByMtoNCriteria
860      * @return org.apache.ojb.broker.query.QueryByCriteria
861      * @param obj the owner of the relationship
862      * @param cld the ClassDescriptor for the owner
863      * @param cod the CollectionDescriptor
864      */

865     private QueryByCriteria getFKQueryMtoN(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cod)
866     {
867         ValueContainer[] values = pb.serviceBrokerHelper().getKeyValues(cld, obj);
868         Object JavaDoc[] thisClassFks = cod.getFksToThisClass();
869         Object JavaDoc[] itemClassFks = cod.getFksToItemClass();
870         ClassDescriptor refCld = pb.getClassDescriptor(cod.getItemClass());
871         Criteria criteria = new Criteria();
872
873         for (int i = 0; i < thisClassFks.length; i++)
874         {
875             criteria.addEqualTo(cod.getIndirectionTable() + "." + thisClassFks[i], values[i].getValue());
876         }
877         for (int i = 0; i < itemClassFks.length; i++)
878         {
879             criteria.addEqualToField(cod.getIndirectionTable() + "." + itemClassFks[i],
880                     refCld.getPkFields()[i].getAttributeName());
881         }
882
883         return QueryFactory.newQuery(refCld.getClassOfObject(), cod.getIndirectionTable(), criteria);
884     }
885
886     /**
887      * Get Foreign key query for 1:n
888      * @return org.apache.ojb.broker.query.QueryByCriteria
889      * @param obj
890      * @param cld
891      * @param cod
892      */

893     private QueryByCriteria getFKQuery1toN(Object JavaDoc obj, ClassDescriptor cld, CollectionDescriptor cod)
894     {
895         ValueContainer[] container = pb.serviceBrokerHelper().getKeyValues(cld, obj);
896         ClassDescriptor refCld = pb.getClassDescriptor(cod.getItemClass());
897         FieldDescriptor[] fields = cod.getForeignKeyFieldDescriptors(refCld);
898         Criteria criteria = new Criteria();
899
900         for (int i = 0; i < fields.length; i++)
901         {
902             FieldDescriptor fld = fields[i];
903             criteria.addEqualTo(fld.getAttributeName(), container[i].getValue());
904         }
905
906         return QueryFactory.newQuery(refCld.getClassOfObject(), criteria);
907     }
908
909     /**
910      * Answer the primary key query to retrieve an Object
911      *
912      * @param oid the Identity of the Object to retrieve
913      * @return The resulting query
914      */

915     public Query getPKQuery(Identity oid)
916     {
917         Object JavaDoc[] values = oid.getPrimaryKeyValues();
918         ClassDescriptor cld = pb.getClassDescriptor(oid.getObjectsTopLevelClass());
919         FieldDescriptor[] fields = cld.getPkFields();
920         Criteria criteria = new Criteria();
921
922         for (int i = 0; i < fields.length; i++)
923         {
924             FieldDescriptor fld = fields[i];
925             criteria.addEqualTo(fld.getAttributeName(), values[i]);
926         }
927         return QueryFactory.newQuery(cld.getClassOfObject(), criteria);
928     }
929
930     /**
931      * Retrieve all Collection attributes of a given instance
932      *
933      * @param newObj the instance to be loaded or refreshed
934      * @param cld the ClassDescriptor of the instance
935      * @param forced if set to true, loading is forced even if cld differs
936      *
937      */

938     public void retrieveCollections(Object JavaDoc newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
939     {
940         doRetrieveCollections(newObj, cld, forced, false);
941     }
942     
943     /**
944      * Retrieve all Collection attributes of a given instance, and make all of the Proxy Collections
945      *
946      * @param newObj the instance to be loaded or refreshed
947      * @param cld the ClassDescriptor of the instance
948      * @param forced if set to true, loading is forced even if cld differs
949      *
950      */

951     public void retrieveProxyCollections(Object JavaDoc newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
952     {
953         doRetrieveCollections(newObj, cld, forced, true);
954     }
955     
956     private void doRetrieveCollections(Object JavaDoc newObj, ClassDescriptor cld, boolean forced, boolean forceProxyCollection) throws PersistenceBrokerException
957     {
958         Iterator JavaDoc i = cld.getCollectionDescriptors().iterator();
959
960         // turn off auto prefetching for related proxies
961
final Class JavaDoc saveClassToPrefetch = classToPrefetch;
962         classToPrefetch = null;
963
964         pb.getInternalCache().enableMaterializationCache();
965         try
966         {
967             while (i.hasNext())
968             {
969                 CollectionDescriptor cds = (CollectionDescriptor) i.next();
970                 if (forceProxyCollection){
971                     retrieveProxyCollection(newObj, cld, cds, forced);
972                 } else {
973                     retrieveCollection(newObj, cld, cds, forced);
974                 }
975             }
976             pb.getInternalCache().disableMaterializationCache();
977         }
978         catch (RuntimeException JavaDoc e)
979         {
980             pb.getInternalCache().doLocalClear();
981             throw e;
982         }
983         finally
984         {
985             classToPrefetch = saveClassToPrefetch;
986         }
987     }
988
989
990     /**
991      * remove all prefetching listeners
992      */

993     public void removePrefetchingListeners()
994     {
995         if (prefetchingListeners != null)
996         {
997             for (Iterator JavaDoc it = prefetchingListeners.iterator(); it.hasNext(); )
998             {
999                 PBPrefetchingListener listener = (PBPrefetchingListener) it.next();
1000                listener.removeThisListener();
1001            }
1002            prefetchingListeners.clear();
1003        }
1004    }
1005
1006    public Class JavaDoc getClassToPrefetch()
1007    {
1008        return classToPrefetch;
1009    }
1010
1011    //**********************************************************************
1012
// inner classes
1013
//**********************************************************************
1014

1015    class PBMaterializationListener extends PBPrefetchingListener implements MaterializationListener
1016    {
1017        private IndirectionHandler _listenedHandler;
1018
1019        PBMaterializationListener(Object JavaDoc owner,
1020                HashMap JavaDoc retrievalTasks, Object JavaDoc key, int limit)
1021        {
1022            super(owner, retrievalTasks, key, limit);
1023        }
1024
1025        protected void addThisListenerTo(Object JavaDoc owner)
1026        {
1027            _listenedHandler = ProxyHelper.getIndirectionHandler(owner);
1028
1029            if (_listenedHandler != null)
1030            {
1031                _listenedHandler.addListener(this);
1032            }
1033        }
1034
1035        protected void removeThisListener()
1036        {
1037            if (_listenedHandler != null)
1038            {
1039                _listenedHandler.removeListener(this);
1040                _listenedHandler = null;
1041            }
1042        }
1043
1044        protected RelationshipPrefetcher getPrefetcher(Object JavaDoc listenedObject)
1045        {
1046            if (_key instanceof ObjectReferenceDescriptor)
1047            {
1048                return pb.getRelationshipPrefetcherFactory().createRelationshipPrefetcher((ObjectReferenceDescriptor) _key);
1049            }
1050            else // PersistentBrokerImpl.this
1051
{
1052                // a special case: current collection being loaded contains proxies,
1053
// just load them without setting any fields
1054
IndirectionHandler handler = (IndirectionHandler) listenedObject;
1055                return new PlainPrefetcher(pb, handler.getIdentity().getObjectsTopLevelClass());
1056            }
1057        }
1058
1059        public void beforeMaterialization(IndirectionHandler handler, Identity oid)
1060        {
1061            prefetch(handler);
1062        }
1063
1064        public void afterMaterialization(IndirectionHandler handler, Object JavaDoc materializedObject)
1065        {
1066            //do nothing
1067
}
1068    }
1069
1070    abstract class PBPrefetchingListener
1071    {
1072        private HashMap JavaDoc _retrievalTasks;
1073        private int _limit;
1074        protected Object JavaDoc _key;
1075
1076        PBPrefetchingListener(Object JavaDoc owner, HashMap JavaDoc retrievalTasks,
1077                Object JavaDoc key, int limit)
1078        {
1079            _retrievalTasks = retrievalTasks;
1080            _key = key;
1081            _limit = limit + 1; // lestenedObject + next limit objects
1082
if (prefetchingListeners == null)
1083            {
1084                prefetchingListeners = new ArrayList JavaDoc();
1085            }
1086            addThisListenerTo(owner);
1087            prefetchingListeners.add(this);
1088        }
1089
1090        abstract protected void addThisListenerTo(Object JavaDoc owner);
1091
1092        abstract protected void removeThisListener();
1093
1094        abstract protected RelationshipPrefetcher getPrefetcher(Object JavaDoc listenedObject);
1095
1096        protected void prefetch(Object JavaDoc listenedObject)
1097        {
1098            ArrayList JavaDoc owners = (ArrayList JavaDoc) _retrievalTasks.get(_key);
1099            List JavaDoc toPrefetch;
1100            RelationshipPrefetcher prefetcher;
1101            boolean prefetchingAll;
1102
1103            removeThisListener();
1104
1105            if (owners == null)
1106            {
1107                return;
1108            }
1109
1110            prefetcher = getPrefetcher(listenedObject);
1111
1112            if (owners.size() <= _limit)
1113            {
1114                toPrefetch = owners;
1115                prefetchingAll = true;
1116            }
1117            else
1118            {
1119                toPrefetch = owners.subList(0, _limit);
1120                prefetchingAll = false;
1121            }
1122
1123            final Class JavaDoc saveClassToPrefetch = classToPrefetch;
1124            classToPrefetch = prefetcher.getItemClassDescriptor().getClassOfObject();
1125            try
1126            {
1127                prefetcher.prefetchRelationship(toPrefetch);
1128            }
1129            finally
1130            {
1131                classToPrefetch = saveClassToPrefetch;
1132            }
1133
1134            if (prefetchingAll)
1135            {
1136                _retrievalTasks.remove(_key);
1137            }
1138            else
1139            {
1140                // ArrayList documented trick:
1141
// "the following idiom removes a range of elements from a list:
1142
// list.subList(from, to).clear();
1143
toPrefetch.clear();
1144                addThisListenerTo(owners.get(0));
1145            }
1146        }
1147    }
1148
1149    class PBCollectionProxyListener extends PBPrefetchingListener
1150            implements CollectionProxyListener
1151    {
1152        CollectionProxyDefaultImpl _listenedCollection;
1153
1154        PBCollectionProxyListener(Object JavaDoc owner,
1155               HashMap JavaDoc retrievalTasks, CollectionDescriptor key, int limit)
1156        {
1157            super(owner, retrievalTasks, key, limit);
1158        }
1159
1160        protected void addThisListenerTo(Object JavaDoc owner)
1161        {
1162            PersistentField collectionField =
1163                    ((CollectionDescriptor) _key).getPersistentField();
1164            _listenedCollection = (CollectionProxyDefaultImpl) collectionField.get(owner);
1165            _listenedCollection.addListener(this);
1166        }
1167
1168        protected void removeThisListener()
1169        {
1170            if (_listenedCollection != null)
1171            {
1172                _listenedCollection.removeListener(this);
1173                _listenedCollection = null;
1174            }
1175        }
1176
1177        protected RelationshipPrefetcher getPrefetcher(Object JavaDoc listenedObject)
1178        {
1179            return pb.getRelationshipPrefetcherFactory().createRelationshipPrefetcher((CollectionDescriptor)_key);
1180        }
1181
1182        public void beforeLoading(CollectionProxyDefaultImpl col)
1183        {
1184            prefetch(col);
1185        }
1186
1187        public void afterLoading(CollectionProxyDefaultImpl col)
1188        {
1189            //do nothing
1190
}
1191    }
1192}
1193
Popular Tags