Coverage Report - org.apache.ojb.broker.core.QueryReferenceBroker
 
Classes in this File Line Coverage Branch Coverage Complexity
QueryReferenceBroker
N/A
N/A
4.07
QueryReferenceBroker$PBCollectionProxyListener
N/A
N/A
4.07
QueryReferenceBroker$PBMaterializationListener
N/A
N/A
4.07
QueryReferenceBroker$PBPrefetchingListener
N/A
N/A
4.07
 
 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;
 19  
 import java.util.ArrayList;
 20  
 import java.util.Collection;
 21  
 import java.util.HashMap;
 22  
 import java.util.Iterator;
 23  
 import java.util.List;
 24  
 import java.util.Map;
 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.1 2007-08-24 22:17:35 ewestfal Exp $
 68  
  */
 69  
 public class QueryReferenceBroker
 70  
 {
 71  
     private Logger log = LoggerFactory.getLogger(QueryReferenceBroker.class);
 72  
 
 73  
     private PersistenceBrokerImpl pb;
 74  
     private HashMap m_retrievalTasks;
 75  
     private ArrayList prefetchingListeners;
 76  
     private final boolean batchRetrieval = true;
 77  
     private final boolean prefetchProxies = true;
 78  
     private Class 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 collectionClass, Class 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();
 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 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 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 resultIter = result.ojbIterator();
 187  
             while (resultIter.hasNext())
 188  
             {
 189  
                 Object 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 e)
 199  
         {
 200  
             // ==> clear materialization cache
 201  
             pb.getInternalCache().doLocalClear();
 202  
             throw e;
 203  
         }
 204  
         catch (Exception 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 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 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 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) getCollectionByQuery(RemovalAwareCollection.class, query, lazy);
 290  
     }
 291  
 
 292  
     
 293  
     private Class 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 fieldType = cds.getPersistentField().getType();
 298  
         Class 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 obj, Object key)
 328  
     {
 329  
         ArrayList owners = (ArrayList) m_retrievalTasks.get(key);
 330  
         boolean isFirst = false;
 331  
 
 332  
         if (owners == null)
 333  
         {
 334  
             owners = new ArrayList();
 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 tmp = m_retrievalTasks;
 357  
             m_retrievalTasks = new HashMap();
 358  
             // during execution of these tasks new tasks may be added
 359  
 
 360  
             for (Iterator it = tmp.entrySet().iterator(); it.hasNext(); )
 361  
             {
 362  
                 Map.Entry entry = (Map.Entry) it.next();
 363  
                 Object key = entry.getKey();
 364  
 
 365  
                 if (!(key instanceof ObjectReferenceDescriptor))
 366  
                 {
 367  
                     continue;
 368  
                 }
 369  
 
 370  
                 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) key;
 371  
                 RelationshipPrefetcher prefetcher;
 372  
                 ArrayList owners = (ArrayList) 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 obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
 398  
     {
 399  
         PersistentField refField;
 400  
         Object 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 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 obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
 478  
     {
 479  
         PersistentField refField;
 480  
         Object 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 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 newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
 525  
     {
 526  
         Iterator i = cld.getObjectReferenceDescriptors().iterator();
 527  
 
 528  
         // turn off auto prefetching for related proxies
 529  
         final Class 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 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 newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
 562  
     {
 563  
         Iterator i = cld.getObjectReferenceDescriptors().iterator();
 564  
 
 565  
         // turn off auto prefetching for related proxies
 566  
         final Class 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 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 obj, ObjectReferenceDescriptor rds, ClassDescriptor cld)
 597  
     {
 598  
         Object[] 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 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[] 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 getReferencedObject(Identity id, ObjectReferenceDescriptor rds)
 654  
     {
 655  
         Class 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 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 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 obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
 737  
     {
 738  
         doRetrieveCollection(obj, cld, cds, forced, true);
 739  
     }
 740  
     
 741  
     private void doRetrieveCollection(Object 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 collectionClass = cds.getCollectionClass();
 755  
                 PersistentField collectionField = cds.getPersistentField();
 756  
                 Query fkQuery = getFKQuery(obj, cld, cds);
 757  
                 Object value;
 758  
 
 759  
                 pb.getInternalCache().enableMaterializationCache();
 760  
                 try
 761  
                 {
 762  
                     if (collectionClass == null)
 763  
                     {
 764  
                         Collection result = (Collection)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 itemtype = collectionField.getType().getComponentType();
 772  
                             Object resultArray = Array.newInstance(itemtype, length);
 773  
                             int j = 0;
 774  
                             for (Iterator 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 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 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 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 obj, ClassDescriptor cld, CollectionDescriptor cod)
 866  
     {
 867  
         ValueContainer[] values = pb.serviceBrokerHelper().getKeyValues(cld, obj);
 868  
         Object[] thisClassFks = cod.getFksToThisClass();
 869  
         Object[] 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 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[] 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 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 newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
 952  
     {
 953  
         doRetrieveCollections(newObj, cld, forced, true);
 954  
     }
 955  
     
 956  
     private void doRetrieveCollections(Object newObj, ClassDescriptor cld, boolean forced, boolean forceProxyCollection) throws PersistenceBrokerException
 957  
     {
 958  
         Iterator i = cld.getCollectionDescriptors().iterator();
 959  
 
 960  
         // turn off auto prefetching for related proxies
 961  
         final Class 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 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 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 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 owner,
 1020  
                 HashMap retrievalTasks, Object key, int limit)
 1021  
         {
 1022  
             super(owner, retrievalTasks, key, limit);            
 1023  
         }
 1024  
 
 1025  
         protected void addThisListenerTo(Object 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 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 materializedObject)
 1065  
         {
 1066  
             //do nothing            
 1067  
         }
 1068  
     }
 1069  
 
 1070  
     abstract class PBPrefetchingListener
 1071  
     {
 1072  
         private HashMap _retrievalTasks;
 1073  
         private int _limit;
 1074  
         protected Object _key;
 1075  
 
 1076  
         PBPrefetchingListener(Object owner, HashMap retrievalTasks,
 1077  
                 Object 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();
 1085  
             }
 1086  
             addThisListenerTo(owner);
 1087  
             prefetchingListeners.add(this);
 1088  
         }
 1089  
 
 1090  
         abstract protected void addThisListenerTo(Object owner);
 1091  
 
 1092  
         abstract protected void removeThisListener();
 1093  
 
 1094  
         abstract protected RelationshipPrefetcher getPrefetcher(Object listenedObject);
 1095  
 
 1096  
         protected void prefetch(Object listenedObject)
 1097  
         {
 1098  
             ArrayList owners = (ArrayList) _retrievalTasks.get(_key);
 1099  
             List 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 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 owner,
 1155  
                HashMap retrievalTasks, CollectionDescriptor key, int limit)
 1156  
         {
 1157  
             super(owner, retrievalTasks, key, limit);
 1158  
         }
 1159  
 
 1160  
         protected void addThisListenerTo(Object 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 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  
 }