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