Our plugin Structure integrates with GreenHopper by optionally importing API packages through Import-Package OSGi instruction. Everything works fine - but only if plugins are installed in the correct order.
If GreenHopper is installed first, and then Structure is installed, the packages are successfully imported. If Structure is installed first, package import is not done and Structure cannot talk to GreenHopper. Disable/enable does not help - the only thing that helps is reinstall of Structure or JIRA restart, because then all bundles will be re-resolved.
I think it used to work in the previous versions of the UPM, but with UPM 2.7.6 (JIRA 5.2-rc1) it no longer works.
It there any gotchas to make this happen or at least an API to force re-resolution of a bundle?
For the record, here are our our OSGi instructions:
<instructions> <Export-Package> com.almworks.jira.structure.api*;version="${structure.api.version}", com.almworks.jira.structure.util;version="${structure.api.version}", com.almworks.integers*;version="${integers.version}", org.jetbrains.annotations;version="${jetbrains.annotations.version}" </Export-Package> <!-- Important: the only reason to import com.atlassian.upm.api.util is - to force dependency on the UPM plugins, which is a workaround for the issue - http://jira.almworks.com/browse/HJ-680 --> <Import-Package> com.almworks.integers*;version="${integers.version}", com.almworks.jira.structure.api*;version="${structure.api.version}", com.almworks.jira.structure.util;version="${structure.api.version}", org.jetbrains.annotations;version="${jetbrains.annotations.version}";resolution:=optional, javax.ws.rs*;version="[1,2)", javax.servlet*;version="[2.3,3)", javax.xml.bind*;version="[2.1,3)", com.atlassian.greenhopper.service;version="5.8";resolution:=optional, com.atlassian.greenhopper.service.rank;version="5.8";resolution:=optional, com.atlassian.greenhopper.model.validation;version="5.8";resolution:=optional, com.atlassian.greenhopper.api.rank;version="5.10.6";resolution:=optional, com.atlassian.upm.api.util;version="0";resolution:=optional, *;version="0";resolution:=optional </Import-Package> <Spring-Context>*;timeout:=60</Spring-Context> </instructions>
Community moderators have prevented the ability to post new answers.
Ok, after some source digging, here's how I solved this. I hoped it would be something easier.
Let's say plugin B depends on plugin A: B => A, and the dependency is optional.
1. The problem happens if plugin A is installed (not upgraded) when plugin B is already installed, and the B's bundle is resolved. (And optional packages from A are not resolved.)
2. The problem does not happen if A and B are installed and wired, and then A is getting uninstalled. The plugin manager (as of JIRA 5.1) is smart enough it stop plugin B too and refresh the framework.
3. Part of the problem is that the admin does not have a simple way to re-resolve the plugin - only JIRA restart or plugin B reinstallation.
4. Solution (entirely within plugin B) includes two parts: a) detecting that the B should be re-resolved (refreshed); b) refreshing B.
5. Detecting that B should be refreshed: I) we take a sample package that we import from A and verify through org.osgi.service.packageadmin.PackageAdmin that, if an export of that package exists, our bundle B imports it; II) the check is made on B start and also when plugin events like PluginEnabledEvent are received; III) the instances of Plugin need to be case to OsgiPlugin to get a hold of Bundle and underlying framework.
6) Refreshing B: I) start a new thread for that; II) disable the plugin through PluginController; III) get a hold of PackageAdmin and call refreshPackages() passing your bundle; IV) enable plugin back. Note that before anything you'll need to preload all classes that you will need later in that thread because the classloader won't be able to load anything new.
Luckily, PluginManager manages transitive dependencies and stops all other plugins that depend on B when B stops, otherwise it would be a lot more work.
Phew. I hope this helps someone.
Cheers,
Igor
Hey Igor, meant to reply to this, it is surely to come in handy, er, for me actually, as I will probably come accross this in the near future, the description is great a good walkthrough, can you post anything, would be a timesaver!?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Andy - sorry I just saw your comment! If you mean posting the source, yes, I think that's a good idea - I'll think about how we can share pieces of source on our website. Meanwhile I can send it to you directly if you need it.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Igor, I wonder if DynamicImports would help, however, note also the cost of doing this.
- https://answers.atlassian.com/questions/32693/how-can-i-configure-component-imports-as-optional
- https://developer.atlassian.com/display/UPM/Using+the+Hidden+OSGI+Feature
- http://wiki.osgi.org/wiki/DynamicImport-Package
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hey Andy, thanks for the pointers. Good instructions from Don there, we'll try those if nothing better comes up. (Although not DynamicImport, but a ServiceTracker should help.)
My point is, it used to work fine with the normal imports with the earlier UPM - somehow it figured out our plugin also had to be rewired after GH installation. I think it is much better way than using ServiceTracker.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Yes, I think more visibility of changes affecting dependency resolution workings would be good, its not really doucmented AFAICT (sure, could look at the source, but ...) . I had some breakages in 5.2rc1 (JRA-30451) but details were thin on the ground, and it was platform specific, not GH. When you say it worked before, was that in 5.1.x ? that was my experience, wonder if its related.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Last time we checked with 5.0.x, I believe.
One other thought about dynamic linking via ServiceTracker - then we'll have to use reflection, which sucks. GreenHopper has published API artifact, which I'm happy to use - but cannot if we use ServiceTracker, and therefore are ready for the service to come and go.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.