You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by mk...@apache.org on 2005/03/03 22:45:26 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/broker/core/proxy CollectionProxyDefaultImpl.java

mkalen      2005/03/03 13:45:26

  Modified:    src/java/org/apache/ojb/broker/core/proxy Tag:
                        OJB_1_0_RELEASE CollectionProxyDefaultImpl.java
  Log:
  Ajust fix for re-activating proxy's metadata profile, to avoid stale local DescriptorRepository references in QueryReferenceBroker beeing used while loading data. (Solves MetadataMultithreadedTest#testCollectionProxySwapProfiles)
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.7.2.5   +58 -14    db-ojb/src/java/org/apache/ojb/broker/core/proxy/CollectionProxyDefaultImpl.java
  
  Index: CollectionProxyDefaultImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/proxy/CollectionProxyDefaultImpl.java,v
  retrieving revision 1.7.2.4
  retrieving revision 1.7.2.5
  diff -u -r1.7.2.4 -r1.7.2.5
  --- CollectionProxyDefaultImpl.java	25 Feb 2005 00:09:25 -0000	1.7.2.4
  +++ CollectionProxyDefaultImpl.java	3 Mar 2005 21:45:26 -0000	1.7.2.5
  @@ -90,13 +90,15 @@
       {
           MetadataManager mm = MetadataManager.getInstance();
           _perThreadDescriptorsEnabled = mm.isEnablePerThreadChanges();
  -        if (_perThreadDescriptorsEnabled) {
  +        if (_perThreadDescriptorsEnabled)
  +        {
               // mkalen:  To minimize memory footprint we remember only the OJB profile key
               //          (instead of all active class-mappings).
  -            Object key = mm.getCurrentProfileKey();
  -            if (key == null) {
  +            final Object key = mm.getCurrentProfileKey();
  +            if (key == null)
  +            {
                   // mkalen:  Unsupported: using proxies with per-thread metadata changes without profile keys.
  -                throw new MetadataException("Trying to create a dynamic proxy with per-thread metadata changes enabled, but no profile key.");
  +                throw new MetadataException("Trying to create a Collection proxy with per-thread metadata changes enabled, but no profile key.");
               }
               setProfileKey(key);
           }
  @@ -105,12 +107,18 @@
           setQuery(query);
       }
   
  +    /**
  +     * Reactivates metadata profile used when creating proxy, if needed.
  +     * Calls to this method should be guarded by checking
  +     * {@link #_perThreadDescriptorsEnabled} since the profile never
  +     * needs to be reloaded if not using pre-thread metadata changes.
  +     */
       protected void loadProfileIfNeeded()
       {
  -        Object key = getProfileKey();
  +        final Object key = getProfileKey();
           if (key != null)
           {
  -            MetadataManager mm = MetadataManager.getInstance();
  +            final MetadataManager mm = MetadataManager.getInstance();
               if (!key.equals(mm.getCurrentProfileKey()))
               {
                   mm.loadProfile(key);
  @@ -120,7 +128,7 @@
   
       /**
        * Determines whether the collection data already has been loaded from the database.
  -     * 
  +     *
        * @return <code>true</code> if the data is already loaded
        */
       public boolean isLoaded()
  @@ -139,9 +147,6 @@
           PersistenceBroker broker = getBroker();
           try
           {
  -            if (_perThreadDescriptorsEnabled) {
  -                loadProfileIfNeeded();
  -            }
               return broker.getCount(getQuery());
           }
           catch (Exception ex)
  @@ -183,9 +188,6 @@
               }
               else if (_size != 0)
               {
  -                if (_perThreadDescriptorsEnabled) {
  -                    loadProfileIfNeeded();
  -                }
                   // TODO: returned ManageableCollection should extend Collection to avoid
                   // this cast
                   result = (Collection) broker.getCollectionByQuery(getCollectionClass(), getQuery());
  @@ -432,6 +434,48 @@
        */
       protected synchronized PersistenceBroker getBroker() throws PBFactoryException
       {
  +        /*
  +            mkalen:
  +            NB! The loadProfileIfNeeded must be called _before_ acquiring a broker below,
  +            since some methods in PersistenceBrokerImpl will keep a local reference to
  +            the descriptor repository that was active during broker construction/refresh
  +            (not checking the repository beeing used on method invocation).
  +
  +            PersistenceBrokerImpl#getClassDescriptor(Class clazz) is such a method,
  +            that will throw ClassNotPersistenceCapableException on the following scenario:
  +
  +            (All happens in one thread only):
  +            t0: activate per-thread metadata changes
  +            t1: load, register and activate profile A
  +            t2: load object O1 witch collection proxy C to objects {O2} (C stores profile key K(A))
  +            t3: close broker from t2
  +            t4: load, register and activate profile B
  +            t5: reference O1.getO2Collection, causing C loadData() to be invoked
  +            t6: C calls getBroker
  +                broker B is created and descriptorRepository is set to descriptors from profile B
  +            t7: C calls loadProfileIfNeeded, re-activating profile A
  +            t8: C calls B.getCollectionByQuery
  +            t9: B gets callback (via QueryReferenceBroker) to getClassDescriptor
  +                the local descriptorRepository from t6 is used!
  +                => We will now try to query for {O2} with profile B
  +                    (even though we re-activated profile A in t7)
  +                    => ClassNotPersistenceCapableException
  +
  +            Keeping loadProfileIfNeeded() at the start of this method changes everything from t6:
  +            t6: C calls loadProfileIfNeeded, re-activating profile A
  +            t7: C calls getBroker,
  +                broker B is created and descriptorRepository is set to descriptors from profile A
  +            t8: C calls B.getCollectionByQuery
  +            t9: B gets callback to getClassDescriptor,
  +                the local descriptorRepository from t6 is used
  +                => We query for {O2} with profile A
  +                    => All good :-)
  +        */
  +        if (_perThreadDescriptorsEnabled)
  +        {
  +            loadProfileIfNeeded();
  +        }
  +
           PersistenceBroker broker;
           if (getBrokerKey() == null)
           {
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org