You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openjpa.apache.org by "roger.keays" <ro...@ninthavenue.com.au> on 2007/03/20 04:26:17 UTC

Shared classloader and subclasses

Hi there,

I'm trying to move my openjpa libs from WEB-INF/lib to Tomcat's shared/lib,
but it seems I have a border case which makes this difficult.

The situation is that each instance of the webapp loads between 5 - 10
subclasses of an abstract Entity. Which classes are loaded is specified by
that instance's configuration file. This is done with some custom
bootstrapping code which ignores the normal JPA persistence.xml mechanisms.
Everything works fine when one instance is loaded, but when another is
loaded with a different set of subclasses, things get a bit hairy.

AFIACT, the problem is that the openjpa.enhance.PCRegistry class uses static
fields to store Meta information. When the second instance is loaded, the
PCRegistry has been initialized, but doesn't contain that instance's
subclasses and an exception is thrown. This is not a problem using the
WEB-INF/lib classloader of course because each instance has their own
PCRegistry class.

I'm wondering if anybody might be able to suggest a workaround. I'd be happy
if there was a way to load all the subclass metadata into the PCRegistry,
but I still need each instance of the webapp to only be aware of their own
subclasses.

Cheers,

Roger
-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9565638
Sent from the open-jpa-dev mailing list archive at Nabble.com.


Re: Shared classloader and subclasses

Posted by "roger.keays" <ro...@ninthavenue.com.au>.


Abe White wrote:
> 
> I've committed an equivalent patch to 0.9.7 in SVN revision 522623.   
> Can you confirm whether this fixes your problem and, if so, close any  
> CR you might have opened on this?
> 
I've tested with /branches/0.9.7-incubating:527748 and it seems fine.



>> This works for me :) Here's a patch for 0.9.6 source. I've gone for  
>> the
>> simplest solution, but it might be improved by looping over pcNames  
>> instead
>> of _registered (?).
>>
>> http://www.nabble.com/file/7398/openjpa-diff openjpa-diff
>>
>> Index: MetaDataRepository.java
>> ===================================================================
>> --- MetaDataRepository.java
>> (.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
>> (revision 3)
>> +++ MetaDataRepository.java
>> (.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/ 
>> apache/openjpa/meta)
>> (working copy)
>> @@ -302,7 +302,7 @@
>>              return null;
>>
>>          // check cache
>> -        processRegisteredClasses();
>> +        processRegisteredClasses(envLoader);
>>          List classList = (List) _aliases.get(alias);
>>
>>          // multiple classes may have been defined with the same  
>> alias: we
>> @@ -928,7 +928,7 @@
>>          }
>>
>>          // check cache
>> -        processRegisteredClasses();
>> +        processRegisteredClasses(envLoader);
>>          Class cls = (Class) _oids.get(oid.getClass());
>>          if (cls != null)
>>              return getMetaData(cls, envLoader, mustExist);
>> @@ -944,7 +944,7 @@
>>          // if still not match, register any classes that look  
>> similar to
>> the
>>          // oid class and check again
>>          resolveIdentityClass(oid);
>> -        if (processRegisteredClasses().length > 0) {
>> +        if (processRegisteredClasses(envLoader).length > 0) {
>>              cls = (Class) _oids.get(oid.getClass());
>>              if (cls != null)
>>                  return getMetaData(cls, envLoader, mustExist);
>> @@ -1262,7 +1262,7 @@
>>       * Parses the metadata for all registered classes.
>>       */
>>      private void loadRegisteredClassMetaData(ClassLoader envLoader) {
>> -        Class[] reg = processRegisteredClasses();
>> +        Class[] reg = processRegisteredClasses(envLoader);
>>          for (int i = 0; i < reg.length; i++) {
>>              try {
>>                  getMetaData(reg[i], envLoader, false);
>> @@ -1276,7 +1276,7 @@
>>      /**
>>       * Updates our datastructures with the latest registered classes.
>>       */
>> -    Class[] processRegisteredClasses() {
>> +    Class[] processRegisteredClasses(ClassLoader envLoader) {
>>          if (_registered.isEmpty())
>>              return EMPTY_CLASSES;
>>
>> @@ -1289,9 +1289,18 @@
>>          }
>>
>>          Collection failed = null;
>> +        Collection pcNames = getPersistentTypeNames(false,  
>> envLoader);
>>          for (int i = 0; i < reg.length; i++) {
>>              try {
>> -                processRegisteredClass(reg[i]);
>> +
>> +                /*
>> +                 * Only process classes known to this  
>> MetaDataRepository,
>> +                 * since _registered contains all classes loaded by
>> +                 * PCRegistry.
>> +                 */
>> +                if (pcNames.contains(reg[i].getName())) {
>> +                    processRegisteredClass(reg[i]);
>> +                }
>>              } catch (Throwable t) {
>>                  if (!_conf.getRetryClassRegistration())
>>                      throw new
>> MetaDataException(_loc.get("error-registered",
>> Index: ClassMetaData.java
>> ===================================================================
>> --- ClassMetaData.java
>> (.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
>> (revision 4)
>> +++ ClassMetaData.java
>> (.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/ 
>> apache/openjpa/meta)
>> (working copy)
>> @@ -309,7 +309,7 @@
>>          if (_owner != null)
>>              return _repos.EMPTY_CLASSES;
>>
>> -        _repos.processRegisteredClasses();
>> +        _repos.processRegisteredClasses(getEnvClassLoader());
>>          if (_subs == null) {
>>              Collection subs = _repos.getPCSubclasses(_type);
>>              _subs = (Class[]) subs.toArray(new Class[subs.size()]);
>>
>> -- 
>> View this message in context: http://www.nabble.com/Shared- 
>> classloader-and-subclasses-tf3431312.html#a9655900
>> Sent from the open-jpa-dev mailing list archive at Nabble.com.
>>
> 
> _______________________________________________________________________
> Notice:  This email message, together with any attachments, may contain
> information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
> entities,  that may be confidential,  proprietary,  copyrighted  and/or
> legally privileged, and is intended solely for the use of the individual
> or entity named in this message. If you are not the intended recipient,
> and have received this message in error, please immediately return this
> by email and then delete it.
> 
> 

-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9952092
Sent from the open-jpa-dev mailing list archive at Nabble.com.


Re: Shared classloader and subclasses

Posted by Abe White <aw...@bea.com>.
I've committed an equivalent patch to 0.9.7 in SVN revision 522623.   
Can you confirm whether this fixes your problem and, if so, close any  
CR you might have opened on this?

> This works for me :) Here's a patch for 0.9.6 source. I've gone for  
> the
> simplest solution, but it might be improved by looping over pcNames  
> instead
> of _registered (?).
>
> http://www.nabble.com/file/7398/openjpa-diff openjpa-diff
>
> Index: MetaDataRepository.java
> ===================================================================
> --- MetaDataRepository.java
> (.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
> (revision 3)
> +++ MetaDataRepository.java
> (.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/ 
> apache/openjpa/meta)
> (working copy)
> @@ -302,7 +302,7 @@
>              return null;
>
>          // check cache
> -        processRegisteredClasses();
> +        processRegisteredClasses(envLoader);
>          List classList = (List) _aliases.get(alias);
>
>          // multiple classes may have been defined with the same  
> alias: we
> @@ -928,7 +928,7 @@
>          }
>
>          // check cache
> -        processRegisteredClasses();
> +        processRegisteredClasses(envLoader);
>          Class cls = (Class) _oids.get(oid.getClass());
>          if (cls != null)
>              return getMetaData(cls, envLoader, mustExist);
> @@ -944,7 +944,7 @@
>          // if still not match, register any classes that look  
> similar to
> the
>          // oid class and check again
>          resolveIdentityClass(oid);
> -        if (processRegisteredClasses().length > 0) {
> +        if (processRegisteredClasses(envLoader).length > 0) {
>              cls = (Class) _oids.get(oid.getClass());
>              if (cls != null)
>                  return getMetaData(cls, envLoader, mustExist);
> @@ -1262,7 +1262,7 @@
>       * Parses the metadata for all registered classes.
>       */
>      private void loadRegisteredClassMetaData(ClassLoader envLoader) {
> -        Class[] reg = processRegisteredClasses();
> +        Class[] reg = processRegisteredClasses(envLoader);
>          for (int i = 0; i < reg.length; i++) {
>              try {
>                  getMetaData(reg[i], envLoader, false);
> @@ -1276,7 +1276,7 @@
>      /**
>       * Updates our datastructures with the latest registered classes.
>       */
> -    Class[] processRegisteredClasses() {
> +    Class[] processRegisteredClasses(ClassLoader envLoader) {
>          if (_registered.isEmpty())
>              return EMPTY_CLASSES;
>
> @@ -1289,9 +1289,18 @@
>          }
>
>          Collection failed = null;
> +        Collection pcNames = getPersistentTypeNames(false,  
> envLoader);
>          for (int i = 0; i < reg.length; i++) {
>              try {
> -                processRegisteredClass(reg[i]);
> +
> +                /*
> +                 * Only process classes known to this  
> MetaDataRepository,
> +                 * since _registered contains all classes loaded by
> +                 * PCRegistry.
> +                 */
> +                if (pcNames.contains(reg[i].getName())) {
> +                    processRegisteredClass(reg[i]);
> +                }
>              } catch (Throwable t) {
>                  if (!_conf.getRetryClassRegistration())
>                      throw new
> MetaDataException(_loc.get("error-registered",
> Index: ClassMetaData.java
> ===================================================================
> --- ClassMetaData.java
> (.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
> (revision 4)
> +++ ClassMetaData.java
> (.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/ 
> apache/openjpa/meta)
> (working copy)
> @@ -309,7 +309,7 @@
>          if (_owner != null)
>              return _repos.EMPTY_CLASSES;
>
> -        _repos.processRegisteredClasses();
> +        _repos.processRegisteredClasses(getEnvClassLoader());
>          if (_subs == null) {
>              Collection subs = _repos.getPCSubclasses(_type);
>              _subs = (Class[]) subs.toArray(new Class[subs.size()]);
>
> -- 
> View this message in context: http://www.nabble.com/Shared- 
> classloader-and-subclasses-tf3431312.html#a9655900
> Sent from the open-jpa-dev mailing list archive at Nabble.com.
>

_______________________________________________________________________
Notice:  This email message, together with any attachments, may contain
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
entities,  that may be confidential,  proprietary,  copyrighted  and/or
legally privileged, and is intended solely for the use of the individual
or entity named in this message. If you are not the intended recipient,
and have received this message in error, please immediately return this
by email and then delete it.

Re: Shared classloader and subclasses

Posted by "roger.keays" <ro...@ninthavenue.com.au>.

Abe White wrote:
> 
>>> I see.  Here's a proposal: in the MetaDataRepository's implementation
>>> of the RegisterClassListener interface, the repository only registers
>>> the given class if either the user has not specified a persistent
>>> types list (which we allow and in which case we attempt to lazily
>>> discover persistent types), or if the class name appears in the
>>> list.  That way if you follow JPA guidelines and specify your
>>> persistent class list properly, subclasses left off the list won't
>>> even get registered with the metadata repository.
>>>
>> That sounds about right. I tried something similar using
>> MetaDataFactory.getPersistentTypeNames(), but this method requires a
>> classloader to be passed to it. Using the thread's classloader  
>> didn't seem
>> right (and didn't work anyway). Is there another way to find this  
>> list?
> 
> Good point.  I guess we can't exclude the classes in the register  
> class listener method itself, but we can do so when we  
> processRegisteredClasses().  This method is only ever called from  
> places where we have the proper classloader (the same one we pass to  
> getPersistentTypeNames()). 
> 
This works for me :) Here's a patch for 0.9.6 source. I've gone for the
simplest solution, but it might be improved by looping over pcNames instead
of _registered (?).

http://www.nabble.com/file/7398/openjpa-diff openjpa-diff 

Index: MetaDataRepository.java
===================================================================
--- MetaDataRepository.java
(.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
(revision 3)
+++ MetaDataRepository.java
(.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
(working copy)
@@ -302,7 +302,7 @@
             return null;
 
         // check cache
-        processRegisteredClasses();
+        processRegisteredClasses(envLoader);
         List classList = (List) _aliases.get(alias);
 
         // multiple classes may have been defined with the same alias: we
@@ -928,7 +928,7 @@
         }
 
         // check cache
-        processRegisteredClasses();
+        processRegisteredClasses(envLoader);
         Class cls = (Class) _oids.get(oid.getClass());
         if (cls != null)
             return getMetaData(cls, envLoader, mustExist);
@@ -944,7 +944,7 @@
         // if still not match, register any classes that look similar to
the
         // oid class and check again
         resolveIdentityClass(oid);
-        if (processRegisteredClasses().length > 0) {
+        if (processRegisteredClasses(envLoader).length > 0) {
             cls = (Class) _oids.get(oid.getClass());
             if (cls != null)
                 return getMetaData(cls, envLoader, mustExist);
@@ -1262,7 +1262,7 @@
      * Parses the metadata for all registered classes.
      */
     private void loadRegisteredClassMetaData(ClassLoader envLoader) {
-        Class[] reg = processRegisteredClasses();
+        Class[] reg = processRegisteredClasses(envLoader);
         for (int i = 0; i < reg.length; i++) {
             try {
                 getMetaData(reg[i], envLoader, false);
@@ -1276,7 +1276,7 @@
     /**
      * Updates our datastructures with the latest registered classes.
      */
-    Class[] processRegisteredClasses() {
+    Class[] processRegisteredClasses(ClassLoader envLoader) {
         if (_registered.isEmpty())
             return EMPTY_CLASSES;
 
@@ -1289,9 +1289,18 @@
         }
 
         Collection failed = null;
+        Collection pcNames = getPersistentTypeNames(false, envLoader);
         for (int i = 0; i < reg.length; i++) {
             try {
-                processRegisteredClass(reg[i]);
+              
+                /*
+                 * Only process classes known to this MetaDataRepository,
+                 * since _registered contains all classes loaded by
+                 * PCRegistry.
+                 */
+                if (pcNames.contains(reg[i].getName())) {
+                    processRegisteredClass(reg[i]);
+                }
             } catch (Throwable t) {
                 if (!_conf.getRetryClassRegistration())
                     throw new
MetaDataException(_loc.get("error-registered",
Index: ClassMetaData.java
===================================================================
--- ClassMetaData.java
(.../tags/0.9.6/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
(revision 4)
+++ ClassMetaData.java
(.../branches/0.9.6-ninthavenue/openjpa-kernel/src/main/java/org/apache/openjpa/meta)
(working copy)
@@ -309,7 +309,7 @@
         if (_owner != null)
             return _repos.EMPTY_CLASSES;
 
-        _repos.processRegisteredClasses();
+        _repos.processRegisteredClasses(getEnvClassLoader());
         if (_subs == null) {
             Collection subs = _repos.getPCSubclasses(_type);
             _subs = (Class[]) subs.toArray(new Class[subs.size()]);

-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9655900
Sent from the open-jpa-dev mailing list archive at Nabble.com.


Re: Shared classloader and subclasses

Posted by Abe White <aw...@bea.com>.
>> I see.  Here's a proposal: in the MetaDataRepository's implementation
>> of the RegisterClassListener interface, the repository only registers
>> the given class if either the user has not specified a persistent
>> types list (which we allow and in which case we attempt to lazily
>> discover persistent types), or if the class name appears in the
>> list.  That way if you follow JPA guidelines and specify your
>> persistent class list properly, subclasses left off the list won't
>> even get registered with the metadata repository.
>>
> That sounds about right. I tried something similar using
> MetaDataFactory.getPersistentTypeNames(), but this method requires a
> classloader to be passed to it. Using the thread's classloader  
> didn't seem
> right (and didn't work anyway). Is there another way to find this  
> list?

Good point.  I guess we can't exclude the classes in the register  
class listener method itself, but we can do so when we  
processRegisteredClasses().  This method is only ever called from  
places where we have the proper classloader (the same one we pass to  
getPersistentTypeNames()). 
_______________________________________________________________________
Notice:  This email message, together with any attachments, may contain
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
entities,  that may be confidential,  proprietary,  copyrighted  and/or
legally privileged, and is intended solely for the use of the individual
or entity named in this message. If you are not the intended recipient,
and have received this message in error, please immediately return this
by email and then delete it.

Re: Shared classloader and subclasses

Posted by "roger.keays" <ro...@ninthavenue.com.au>.


Abe White wrote:
> 
>> In the case above, another webapp has loaded the forums module,  
>> causing this
>> webapp to look for the mappings in that module even though they aren't
>> available.
>>
>> I had difficulty trying to figure out how to restrict which  
>> subclasses are
>> 'seen'. Ideally I think it'd be done in the  
>> MetaDataRepository#register()
>> method, but no metadata seems to be available at this time.
> 
> I see.  Here's a proposal: in the MetaDataRepository's implementation  
> of the RegisterClassListener interface, the repository only registers  
> the given class if either the user has not specified a persistent  
> types list (which we allow and in which case we attempt to lazily  
> discover persistent types), or if the class name appears in the  
> list.  That way if you follow JPA guidelines and specify your  
> persistent class list properly, subclasses left off the list won't  
> even get registered with the metadata repository.
> 
That sounds about right. I tried something similar using
MetaDataFactory.getPersistentTypeNames(), but this method requires a
classloader to be passed to it. Using the thread's classloader didn't seem
right (and didn't work anyway). Is there another way to find this list?

Thanks,

Roger
-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9604668
Sent from the open-jpa-dev mailing list archive at Nabble.com.


Re: Shared classloader and subclasses

Posted by Abe White <aw...@bea.com>.
> In the case above, another webapp has loaded the forums module,  
> causing this
> webapp to look for the mappings in that module even though they aren't
> available.
>
> I had difficulty trying to figure out how to restrict which  
> subclasses are
> 'seen'. Ideally I think it'd be done in the  
> MetaDataRepository#register()
> method, but no metadata seems to be available at this time.

I see.  Here's a proposal: in the MetaDataRepository's implementation  
of the RegisterClassListener interface, the repository only registers  
the given class if either the user has not specified a persistent  
types list (which we allow and in which case we attempt to lazily  
discover persistent types), or if the class name appears in the  
list.  That way if you follow JPA guidelines and specify your  
persistent class list properly, subclasses left off the list won't  
even get registered with the metadata repository.
_______________________________________________________________________
Notice:  This email message, together with any attachments, may contain
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
entities,  that may be confidential,  proprietary,  copyrighted  and/or
legally privileged, and is intended solely for the use of the individual
or entity named in this message. If you are not the intended recipient,
and have received this message in error, please immediately return this
by email and then delete it.

Re: Shared classloader and subclasses

Posted by "roger.keays" <ro...@ninthavenue.com.au>.


Abe White wrote:
> 
>> AFIACT, the problem is that the openjpa.enhance.PCRegistry class  
>> uses static
>> fields to store Meta information. When the second instance is  
>> loaded, the
>> PCRegistry has been initialized, but doesn't contain that instance's
>> subclasses and an exception is thrown
> 
> The PCRegistry has to use static members because each persistent  
> class registers itself with the registry in its static initializer.   
> There is no way for a persistent class to access a specific registry  
> instance when it is loaded into the JVM.
> 
> I don't think the proposed patch is viable, because there are cases  
> where we lazily-load metadata, and we don't want to leave out  
> subclasses just because we haven't parsed their metadata yet.  What  
> is the exception you're seeing?
> 
<4|true|0.9.6-incubating> org.apache.openjpa.persistence.ArgumentException:
No m
etadata was found for type "class figbird.forums.entities.Topic". The class
does
 not appear in the list of persistent types:
[figbird.lists.entities.Newsletter,
 figbird.lists.entities.MailingList, mlynch.entities.Flyer,
figbird.cms.entities
.File, figbird.lists.entities.Email, figbird.cms.entities.News,
figbird.cms.enti
ties.Blob, figbird.cms.entities.IFrame, figbird.cms.entities.Redirect,
figbird.c
ms.entities.Article, figbird.cms.entities.Comment,
figbird.cms.entities.Fragment
, figbird.cms.entities.Content, figbird.lists.entities.Delivery,
figbird.cms.ent
ities.Privilege, figbird.cms.entities.Page].
        at
org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataReposi
tory.java:278)
        at
org.apache.openjpa.meta.ClassMetaData.getPCSubclassMetaDatas(ClassMet
aData.java:337)
        at
org.apache.openjpa.meta.ClassMetaData.getMappedPCSubclassMetaDatas(Cl
assMetaData.java:351)
        at
org.apache.openjpa.jdbc.meta.ClassMapping.getMappedPCSubclassMappings
(ClassMapping.java:575)
        at
org.apache.openjpa.jdbc.meta.ClassMapping.getIndependentAssignableMap
pings(ClassMapping.java:614)
        at
org.apache.openjpa.jdbc.meta.ValueMappingImpl.getIndependentTypeMappi
ngs(ValueMappingImpl.java:345)
        at
org.apache.openjpa.jdbc.meta.FieldMapping.getIndependentTypeMappings(
FieldMapping.java:964)
        at
org.apache.openjpa.jdbc.meta.strats.RelationFieldStrategy.supportsSel
ect(RelationFieldStrategy.java:351)
        at
org.apache.openjpa.jdbc.meta.FieldMapping.supportsSelect(FieldMapping
.java:692)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.createEagerSelects(JD
BCStoreManager.java:928)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.createEagerSelects(JD
BCStoreManager.java:910)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreManager.select(JDBCStoreManag
er.java:876)
        at
org.apache.openjpa.jdbc.sql.SelectImpl.select(SelectImpl.java:762)
        at
org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect.select(LogicalUn
ion.java:585)
        at
org.apache.openjpa.jdbc.sql.LogicalUnion$UnionSelect.selectIdentifier
:
        at
org.apache.openjpa.jdbc.kernel.exps.SelectConstructor.select(SelectCo
nstructor.java:263)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreQuery.populateSelect(JDBCStor
eQuery.java:265)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreQuery.access$000(JDBCStoreQue
ry.java:70)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreQuery$1.select(JDBCStoreQuery
.java:237)
        at
org.apache.openjpa.jdbc.sql.LogicalUnion.select(LogicalUnion.java:280
)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreQuery.populateUnion(JDBCStore
Query.java:235)
        at
org.apache.openjpa.jdbc.kernel.JDBCStoreQuery.executeQuery(JDBCStoreQ
uery.java:183)
        at
org.apache.openjpa.kernel.ExpressionStoreQuery$DataStoreExecutor.exec
uteQuery(ExpressionStoreQuery.java:672)
        at
org.apache.openjpa.datacache.QueryCacheStoreQuery$QueryCacheExecutor.
executeQuery(QueryCacheStoreQuery.java:305)
        at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:977)
        at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:789)
        at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:759)
        at org.apache.openjpa.kernel.QueryImpl.execute(QueryImpl.java:755)
        at
org.apache.openjpa.kernel.DelegatingQuery.execute(DelegatingQuery.jav
a:512)
        at
org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:213)
        at
org.apache.openjpa.persistence.QueryImpl.getSingleResult(QueryImpl.ja
va:268)
        at figbird.cms.application.DAO.getRootItem(DAO.java:149)
 
In the case above, another webapp has loaded the forums module, causing this
webapp to look for the mappings in that module even though they aren't
available.

I had difficulty trying to figure out how to restrict which subclasses are
'seen'. Ideally I think it'd be done in the MetaDataRepository#register()
method, but no metadata seems to be available at this time.

Thanks for your help,

Roger
-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9582982
Sent from the open-jpa-dev mailing list archive at Nabble.com.


Re: Shared classloader and subclasses

Posted by Abe White <aw...@bea.com>.
> AFIACT, the problem is that the openjpa.enhance.PCRegistry class  
> uses static
> fields to store Meta information. When the second instance is  
> loaded, the
> PCRegistry has been initialized, but doesn't contain that instance's
> subclasses and an exception is thrown

The PCRegistry has to use static members because each persistent  
class registers itself with the registry in its static initializer.   
There is no way for a persistent class to access a specific registry  
instance when it is loaded into the JVM.

I don't think the proposed patch is viable, because there are cases  
where we lazily-load metadata, and we don't want to leave out  
subclasses just because we haven't parsed their metadata yet.  What  
is the exception you're seeing?
_______________________________________________________________________
Notice:  This email message, together with any attachments, may contain
information  of  BEA Systems,  Inc.,  its subsidiaries  and  affiliated
entities,  that may be confidential,  proprietary,  copyrighted  and/or
legally privileged, and is intended solely for the use of the individual
or entity named in this message. If you are not the intended recipient,
and have received this message in error, please immediately return this
by email and then delete it.

Re: Shared classloader and subclasses

Posted by "roger.keays" <ro...@ninthavenue.com.au>.

I've been able to patch MetaDataRepository#getPCSubclasses() to work around
this problem (see below), but I'm a bit unsure about whether statics should
be used in PCRegistry or not. The listeners are stored in a static field,
which means they collect information about every application which loads
PCRegistry with the same class loader. Wouldn't the Broker object be a more
appropriate location for a PCRegistry without static fields?

Roger


Begin patch (from 0.9.6 source)

Index: src/main/java/org/apache/openjpa/meta/MetaDataRepository.java
===================================================================
--- src/main/java/org/apache/openjpa/meta/MetaDataRepository.java      
(revision 474176)
+++ src/main/java/org/apache/openjpa/meta/MetaDataRepository.java      
(working copy)
@@ -1243,7 +1243,16 @@
         Collection subs = (Collection) _subs.get(cls);
         if (subs == null)
             return Collections.EMPTY_LIST;
-        return subs;
+        
+        /* only return subclasses we have metadata for */
+        Collection result = new LinkedList();
+        for (Iterator i = subs.iterator(); i.hasNext();) {
+            Class c = (Class) i.next();
+            if (_metas.containsKey(c) && _metas.get(c) != null) {
+                result.add(c);
+            }
+        }
+        return result;
     }



roger.keays wrote:
> 
> Hi there,
> 
> I'm trying to move my openjpa libs from WEB-INF/lib to Tomcat's
> shared/lib, but it seems I have a border case which makes this difficult.
> 
> The situation is that each instance of the webapp loads between 5 - 10
> subclasses of an abstract Entity. Which classes are loaded is specified by
> that instance's configuration file. This is done with some custom
> bootstrapping code which ignores the normal JPA persistence.xml
> mechanisms. Everything works fine when one instance is loaded, but when
> another is loaded with a different set of subclasses, things get a bit
> hairy.
> 
> AFIACT, the problem is that the openjpa.enhance.PCRegistry class uses
> static fields to store Meta information. When the second instance is
> loaded, the PCRegistry has been initialized, but doesn't contain that
> instance's subclasses and an exception is thrown. This is not a problem
> using the WEB-INF/lib classloader of course because each instance has
> their own PCRegistry class.
> 
> I'm wondering if anybody might be able to suggest a workaround. I'd be
> happy if there was a way to load all the subclass metadata into the
> PCRegistry, but I still need each instance of the webapp to only be aware
> of their own subclasses.
> 
> Cheers,
> 
> Roger
> 

-- 
View this message in context: http://www.nabble.com/Shared-classloader-and-subclasses-tf3431312.html#a9567668
Sent from the open-jpa-dev mailing list archive at Nabble.com.