Service Listener not being informed of Service changes

6 views
Skip to first unread message

Thomas Pfau

unread,
Jul 13, 2016, 8:50:15 AM7/13/16
to cytoscap...@googlegroups.com
Hi,

I recently posted a question, and noticed, that I seem to have replied
to an old thread instead of creating a new one (simply clicking reply to
an earlier email I got).
So I'm reposting it (all three initial posts into one though), since it
might allow some people to notice it, who otherwise would not see it
(and maybe someone has an idea).

I have some code that relies on other apps. Now, I would like it to work
regardless on whether someone installs/disables the other app.
So what I'm currently ding is:
a: on activation check whether the appropriate Classes are available
(and if they are set the corresponding service object in my class).
b: When the respective service gets unregistered, I remove the reference
from my own class setting the corresponding object to null

Now I have the following issue:
-> I start up cytoscape, my app gets loaded before the other app.
No problem so far as my servicelistener catches the start of the other
app and sets the appropriate object. The same is true, when the other
app gets loaded before my app, in which instance I can simply use the
service that app registered.
-> I disable the other app
Still Fine, my listener properly sets the object to 0 and I can keep on
working with this setting.
-> I reactivate the other app
For some reason my servicelistener does not get a service event for the
class I need any more.
In fact, there is no service event at all being fired that would
indicate that this service is now available.

I would have expected something like I find the class but get a class
cast exception (which would require some unget for the service to get it
out of my classloader, which I'm actually not sure how to do with
cytoscape). But not getting any event leaves me puzzled as I don't get
any other error neither.

Does anyone know what could cause this issue?



A small update:

I tried to see, whether the event was no longer fired or whether my app
was just not informed about the event.
From what I can determine, it's the latter.
A different app thats just listening to the events does get the event,
it's only my app that is left "in the dark".

I think, what I need is to listen to a class, that is not yet available,
but I have no clue how to do this.
If I use registerServiceListener, I get a NoClassDefFound Error (which
is to be expected) when the other app is not yet loaded.
If the other app was loaded previously, everything seems fine initially
and I have a listener for the class.

If after this initial integration the app is deactivated, it is
(manually) unregistered) from my app, i.e. the respective objects are
removed, but I have the impression, that e.g. classes used still remain
in my bundle.
This seems to interfere with any service listening, as I'm now listening
to a class that (while having the same name) has a different class
loader (in fact one, thats no longer existing).
From some googling I got the impression, that the only way to get the
old stuff (from the previous activation) out of my bundles scope is to
call a rewiring on the framework.
However this seems to be something that will probably result in a
complete reset of my app (whih is not really what I would like).

Anyone with an idea how this could be solved without completely
restarting the app every time an optional dependency is activated?

Second update:

From all I could figure out, the issue is, that the framework for some
obscure reason is not propagating the Servicechanged event to my app
once the other app got disabled.
The event is still fired, and can be logged with a different app, its
just hidden from my app.
I currently assume that this happens due to some imports my app uses
from the other app, but I'm not sure, how to solve this.

Best

Thomas






--
Université du Luxembourg
Faculté des Sciences, de la Technologie et de la Communication
Campus Belval, Biotech II 423
6 avenue du Swing
L-4367 Belvaux
Tel: (+352) 46 66 44 5309
Email: thoma...@uni.lu

Thomas Pfau

unread,
Jul 14, 2016, 2:43:16 AM7/14/16
to cytoscap...@googlegroups.com
And a last update:

I think I now have an explanation what is going on here, and I have one
possible solution (which could work in my instance, but not necessarily
for others).
The problem stems from OSGI not unwiring the classes provided by a
bundle (A) that gets unloaded from other bundles (B,C) that imported
classes from bundle A.
From all I understand to do this, it would be necessary to refresh the
dependent bundles (and this could mean that those bundles would be
restarted, loosing their current state)
A short example:
If bundle B optionally depends on bundle A, and has optional imports
from the packages exported by bundle A, than, if bundle A is or becomes
available, those packages will be imported.
Now, if bundle A gets removed again, the imported packages in bundle B
stay active and are not removed from the classloader in bundle B.
Thus, when bundle A gets reinstalled, bundle B already has the classes
loaded and will not reload them again, which leads to conflicting
classes between bundle A and bundle B, as A now has a new classloader
that is not the classloader used to provide the classes to B.
I assume (and this is a wild guess), that a ServiceListener from bundle
B, will cause a classcast exception if a class from the new installation
of bundle A gets registered as a service to the framework, with a class
that is conflicting with the class from bundle B, and this is probably
addressed in the framework by not informing bundle B about this new
conflicting service.

In conclusion I have the impression, that between app dependency works
fine for fixed dependencies, and is also working ok for optional
dependencies, if the bundles that another app depends on are (in the
case of an optional dependency) not deactivated/activated during the
life time of the dependent app. For a mandatory dependence, there is no
issue, as the dependent app will be put into a "on hold" state, as it
can no longer be used (at least thats how I understand it), and thus
will be rewired as soon as the app it depends on becomes available again.

The only way I see, how an optionally dependent app can circumvent this
is by extensive use of reflections, and even there, problems can easily
arise.

I hope this could help future developers to avoid hours of trying to
find solutions for this kind of issue.

Any comments are highly appreciated

Best,

Thomas

Alexander Pico

unread,
Jul 14, 2016, 2:56:38 PM7/14/16
to cytoscape-discuss
Ah, we missed this one too!  We only have a simple screening process that looks for threads with no reply. So, when you reply to your own post before getting a response you might not get another.  I wish Google Groups provided better screening tools, but that's all we've got.

In any case, I went ahead and posted this as a new thread in our new cytoscape-app-dev list, which will have much more focus and attention on questions like yours. I recommend joining that group. Expect a response soon...

https://groups.google.com/forum/#!topic/cytoscape-app-dev/TAJvLIih_i4


Cheers,
 Alex
Reply all
Reply to author
Forward
0 new messages