Yeah, the bottom line is that the value of the TCCL is not defined by
the OSGi standards. You can define it yourself by setting it before you
call the relevant code but as said before this is ugly and it's actually
very error-prone because there's nothing in the API to remind you to do
it, so you might forget the odd time (it's effectively a hidden argument
to the API).
To make things even worse, there is a chance that the TCCL is not unset
after previous use which means that its value might happen to be correct
in some cases and incorrect in others - which is what the issue in the
post seems to be hitting.
I think making this part of the API explicit is the safest option. Yes,
it requires people to think about classloading who don't like to think
about classloading, but generally passing in getClass().getClassLoader()
is all that's needed to get the right one...
Just my 2c,
David
On 09/05/2011 18:01, Galder Zamarreño wrote:
Guys,
It's funny that we're talking about this but this appears to be precisely the use
case that we don't support as per user forum post in:
http://community.jboss.org/thread/166080?tstart=0
Pete, do we have a JIRA for this? If not, would you mind creating one?
Cheers,
On May 9, 2011, at 5:37 PM, Pete Muir wrote:
> Ok, let me stew on that ;-)
>
> On 9 May 2011, at 16:35, David Bosschaert wrote:
>
>> If you have a Bundle object or BundleContext object you can figure out what
classloader is associated with that. Also, if you have a class from a bundle you can find
out what it's classloader is (obviously).
>>
>> However, you need to have one of those things to find this out. There is nothing
magically available in the current context to tell you what the current Bundle is.
>> It's generally really easy for the caller though to find out what the
classloader is, though... If you have bundle X, you'd know a class from that bundle
a.b.c.D (any class will do). Then you can simply call D.class.getClassLoader() and
you've got the Bundle Classloader.
>>
>> Hope this helps,
>>
>> David
>>
>> On 09/05/2011 16:27, Pete Muir wrote:
>>> The issue that David raises is that in an OSGi env that this wouldn't be
done by OSGi so would be up to the user or would require some extra integration library.
I'm not even sure if this is possible in OSGi? David, is there anyway for a framework
to "find out" the current bundle classloader in OSGi rather than having to be
told it (i.e. push rather than pull)?
>>>
>>> The idea is that in AS that by doing (a) it would require the integration to
make sure the TCCL is set before Infinispan is called (this is the way many things are
integrated into GF for example).
>>>
>>> On 5 May 2011, at 20:05, Emmanuel Bernard wrote:
>>>
>>>> Quick question.
>>>> In case of 2.a (ie setting the TCCL), this is a requirement for
frameworks and libraries using Infinispan, right? Not / never for a user application using
Infinispan (in this case it seems that the application class loader will do the right
thing and is set as the TCCL by the AS environment)?
>>>>
>>>> Emmanuel
>>>>
>>>> On 5 mai 2011, at 10:55, Pete Muir wrote:
>>>>
>>>>> I talked about this with Emmanuel last night, and we were
>>>>>
>>>>> a) concerned about the pollution of the API that this implies
>>>>> b) not sure why we need to do this
>>>>>
>>>>> So I also spoke to Jason to understand his initial motivation, and
from this chat I think it's clear that things have gone off course here.
>>>>>
>>>>> Jason raised two issues with modularity/classloading in Infinispan:
>>>>>
>>>>> 1) Using the TCCL as the classloader to load Infinispan classes is a
bad idea. Instead we should use org.infinispan.foo.Bar.getClass().getClassLoader().
>>>>>
>>>>> 2) When we need to load application classes we need a different
approach to that used today. Most of the time the TCCL is perfect for this. However
*sometimes* Infinispan may be invoked outside of the application, when the TCCL may not be
set in AS7. Jason and I discussed three options:
>>>>>
>>>>> a) require (through a platform integration documentation contract)
that the TCCL must always be set when Infinispan is invoked.
>>>>> b) Have some sort of InvocationContext which knows what the correct
classloader to use is (aka Hibernate/Seam/Weld design where there is a per-application
construct based on a ThreadLocal). Given this hasn't been designed into the core, it
seems like a large retrofit
>>>>> c) Make users specify the CL (directly or indirectly) via the API (as
we discussed).
>>>>>
>>>>> Personally I think that (a) is the best approach right now, and is
not that onerous a requirement.
>>>>>
>>>>> We might want to make the TCCL usage pluggable for OSGI envs.
Cc'd David to get his feedback.
>>>>>
>>>>> On 4 May 2011, at 10:46, Dan Berindei wrote:
>>>>>
>>>>>> On Wed, May 4, 2011 at 5:09 PM, Pete Muir<pmuir(a)redhat.com>
wrote:
>>>>>>> On 4 May 2011, at 05:34, Dan Berindei wrote:
>>>>>>>
>>>>>>>> On Wed, May 4, 2011 at 10:14 AM, Galder
Zamarreño<galder(a)redhat.com> wrote:
>>>>>>>>> On May 3, 2011, at 2:33 PM, Sanne Grinovero wrote:
>>>>>>>>>
>>>>>>>>>> 2011/5/3 "이희승 (Trustin
Lee)"<trustin(a)gmail.com>:
>>>>>>>>>>> On 05/03/2011 05:08 AM, Sanne Grinovero
wrote:
>>>>>>>>>>>> 2011/5/2 Manik
Surtani<manik(a)jboss.org>:
>>>>>>>>>>>>> On 1 May 2011, at 13:38, Pete Muir
wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> As in, user API?
That's a little intrusive... e.g., put(K, V, cl) ?
>>>>>>>>>>>>>>> Not for put, since you have
the class, just get, and I was thinking
>>>>>>>>>>>>>>> something more like:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Foo foo = getUsing(key,
Foo.class)
>>>>>>>>>>>>>> This would be a pretty useful
addition to the API anyway to avoid user casts.
>>>>>>>>>>>>> Maybe as an "advanced" API,
so as not to pollute the basic API? A bit like:
>>>>>>>>>>>>>
>>>>>>>>>>>>> Foo f =
cache.getAdvancedCache().asClass(Foo.class).get(key);
>>>>>>>>>>>> doesn't look much better than a cast,
but is more cryptical :)
>>>>>>>>>>>>
>>>>>>>>>>>> getting back to the classloader issue,
what about:
>>>>>>>>>>>>
>>>>>>>>>>>> Cache c = cacheManager.getCache(
cacheName, classLoader );
>>>>>>>>>>>>
>>>>>>>>>>>> or
>>>>>>>>>>>> Cache c = cacheManager.getCache(
cacheName ).usingClassLoader(classLoader );
>>>>>>>>>>>>
>>>>>>>>>>>> BTW if that's an issue on the API,
maybe you should propose it to
>>>>>>>>>>>> JSR-107 as well ?
>>>>>>>>>>> We have a configurable Marshaller, right?
Then why don't we just use
>>>>>>>>>>> the class loader that the current Marshaller
uses?
>>>>>>>>>> +1
>>>>>>>>>> I like the clean approach, not sure how you
configure the "current
>>>>>>>>>> Marshaller" to use the correct CL ?
>>>>>>>>>> Likely hard to do via configuration file :)
>>>>>>>>> Well, the marshaller is a global component and so
it's a cache manager level. You can't make any assumptions about it's
classloader, particularly when lazy deserialization is configured and you want to make
sure that the data of the cache is deserialized with the correct classloader when the user
reads the data from the cache. This is gonna become even more important when we for
example move to having a single cache for all 2LC entities or all EJB3 SFSBs where
we'll definitely need multiple classloaders to access a single cache.
>>>>>>>>>
>>>>>>>> The current unmarshaller uses the TCCL, which is a great
idea for
>>>>>>>> non-modular environments and will still work in AS7 for
application
>>>>>>>> classes (so it's still a good default). It probably
won't work if
>>>>>>>> Hibernate wants to store its own classes in the cache,
because
>>>>>>>> Hibernate's internal classes may not be reachable
from the
>>>>>>>> application's classloader.
>>>>>>>>
>>>>>>>> It gets even trickier if Hibernate wants to store a
>>>>>>>> PrivateHibernateCollection class in the cache containing
instances of
>>>>>>>> application classes inside. Then I don't think there
will be any
>>>>>>>> single classloader that could reach both the Hibernate
classes and the
>>>>>>>> application classes so it can properly unmarshal both.
Perhaps that's
>>>>>>>> just something for the Hibernate folks to worry about? Or
maybe we
>>>>>>>> should allow the users to register more than one
classloader with a
>>>>>>>> cache?
>>>>>>> You need to use a bridge classloader in this case.
>>>>>> You're right of course, Hibernate must have received/guessed
the
>>>>>> application's classloader and so it is able to create a
bridge
>>>>>> classloader that "includes" both.
>>>>>>
>>>>>> And if the application classes include references to classes
from
>>>>>> another module(s), the application has to provide a bridge
classloader
>>>>>> to Hibernate anyway.
>>>>>>
>>>>>> _______________________________________________
>>>>>> infinispan-dev mailing list
>>>>>> infinispan-dev(a)lists.jboss.org
>>>>>>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
>>>>> _______________________________________________
>>>>> infinispan-dev mailing list
>>>>> infinispan-dev(a)lists.jboss.org
>>>>>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
>>>> _______________________________________________
>>>> infinispan-dev mailing list
>>>> infinispan-dev(a)lists.jboss.org
>>>>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
>>> _______________________________________________
>>> infinispan-dev mailing list
>>> infinispan-dev(a)lists.jboss.org
>>>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
>
> _______________________________________________
> infinispan-dev mailing list
> infinispan-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/infinispan-dev
--
Galder Zamarreño
Sr. Software Engineer
Infinispan, JBoss Cache