Forum Discussion

escort's avatar
escort
New Contributor
14 years ago

Different custom components share one GroovyClassLoader

Dear all,

I am trying to implememt a test loader with some custom LoadUI component. I am testing my own external Java library. Now I have an issue.

I have more than one component to test. Some objects are being sent among these components via the "Message". For instance.

In component A, I created a object "ObjectA" and sent it to component B.
Component B receives it and can recogonizes it as correct class. But the problem is, the instance created in the component B can not be used with component A. I get following exception.

"client.active.channel.BaseMioSubscriptionListener@dc10b6","com.sun.jnlp.JNLPClassLoader@10fe2b9","class client.active.channel.DefaultActiveChannel","No signature of method:
client.active.channel.DefaultActiveChannel.subscribe() is applicable for argument types: (common.types.subscription.Subscription, client.active.channel.BaseMioSubscriptionListener) values: [common.types.subscription.Subscription@1c83981, client.active.channel.BaseMioSubscriptionListener@37785b]
Possible solutions: subscribe(common.types.subscription.Subscription, client.active.channel.MioSubscriptionListener), subscribe(java.lang.Class, client.active.channel.ClientTypeSubscription, client.active.channel.ClientTypeMioSubscriptionListener), unsubscribe(java.lang.String), isSubscribed(java.lang.String)
The following classes appear as argument class and as parameter class, but are defined by different class loader:
common.types.subscription.Subscription (defined by 'groovy.lang.GroovyClassLoader@bcf04e' and 'groovy.lang.GroovyClassLoader@d652c1')

If one of the method suggestions matches the method you wanted to call,
then check your class loader setup.","7","client.active.channel.DefaultActiveChannel@1edd411","common.types.subscription.Subscription@fde079","client.active.MioRemote@1ae24e3","groovy.lang.GroovyClassLoader$InnerLoader@19d6193","165007099"

I assume because Component A and Compoenent B are not using the same GroovyClassLoader. I tried to creat everything in Component A and pass all of them to Component B. It works. I am wondering, whether there is way to set the GroovyClassLoader for each Component ( Groovy script ). Or I really need to create everything from the one simple component.

I tried to GroovyClassLoader by this.class.getClassLoader() . but it returns the Java classloader instead of GroovyClassLoader

Thanks for your help in advance.
  • paulhanke's avatar
    paulhanke
    New Contributor
    I once wrote a work-around for sharing dynamically-generated classes across OSGi module boundaries ... the work-around may have been Felix-specific, but as far as I can tell loadUI uses Felix ... in a nutshell, the trick is to switch the current thread's class loader for as long as you need to create objects from another class loader ... in your case, it might go something like this (assuming that it is a channel that is being passed from A to B):

    ClassLoader threadLoader = Thread.currentThread().getContextClassLoader()
    Thread.currentThread().setContextClassLoader(channel.getClass().getClassLoader())
    // create/derive needed instances here
    Thread.currentThread().setContextClassLoader(threadLoader)

    Potential issues with this approach:

    - I've never tried it in Groovy
    - it may fail due to loadUI security restrictions
    - if your listener needs access to both class loaders you may need to store those loaders as fields and switch back and forth as needed
  • escort's avatar
    escort
    New Contributor
    Hi paulhanke,

    You are right, I am trying to pass one channel instance from Component A to component B. Some further operations would be done in component B. But the problem is that the other object instances that created in Component B are not compatible with this channel instance who is created in Component A. That's where I got this error.

    For your proposal, I already tried it. The return value of Thread.currentThread().getContextClassLoader() is a JavaClassLoader instead of GroovyClassLoader. If this problem could not be solved, my only choice is to make Factory component in the LoadUI who provides everyting to other component, on the level of design, it's not looking good~~

    Thanks for your reply
  • escort's avatar
    escort
    New Contributor
    My objects are not serializeable. Therefore I do not think that could be my solution. At this moment, my only choice is to make a Factory component who supplies the objects instance to the others.

    Is there any other proposals? Any idea is highly appreciated. Thanks a lot
  • One alternative, though it would require a lot more effort, is to create your own OSGi bundle which exposes your components. Unfortunately this means rewriting them in Java instead of Groovy, and a lot more configuration to expose ComponentDescriptors, loading and creating the components, interacting with OSGi, etc. All this is handled for you automatically by the loadui-groovy bundle, but as you see it comes with some limitations.

    Regards,
    Dain
    eviware.com
  • Can you give us some more details on what the individual components you are creating are supposed to do? Maybe if I understand more precisely what your goal is I can find a solution. I may have an idea...

    Regards,
    Dain
    eviware.com
  • escort's avatar
    escort
    New Contributor
    At this moment, I am building a test envrionment to test my channel and subscription engine. I have one Object called "remote" who can create channels to servers, the channel can submit the subscriptions to the server then receives the update information from server. My purpose is to test the loader capability for my "remote" object, channel. How many channels can a remote object holds, how many subscriptions can a channel holds. Therefore, my test piple is

    "Component Remote generator" ==> ' A remote instance ' ==> "Compoenent Channel generator" ==> 'A channel instance' ==> "Component subscription instance"

    The problem is, the remote instance created from Component A can not be used with other objects created in Component B and Component C.
  • Hi,

    Just wanted to post an update on this. Different components sharing one GroovyClassLoader will be supported in loadUI 1.5, so stay tuned!

    Regards,
    Dain
    eviware.com