Search code examples
osgiapache-felix

Deploying OSGi bundle starts another one


I have one OSGi bundle (BundleA) for Sling that I deploy in Felix. This bundle loads initial Sling content and then through an activator executes some operations on this content (sets permissions and sorts nodes). That works well, I build it with the Felix maven-bundle-plugin and I've put a bundle event listener in the activator:

@Override
public void bundleChanged(BundleEvent event) {
  if (BundleEvent.STARTED == event.getType()) {
    logger.info("Bundle A has started");
    BundleContext context = event.getBundle().getBundleContext();
  }
}  

But I have another bundle (BundleB) that when deployed, somehow triggers BundleA's activator. Consequently, the code is executed again and I don't want that.

I didn't find any documentation about "linked" bundles. But I'm not familiar with Felix/OSGi so I don't really know what to look for. The BundleA has BundleB has a Maven dependency, scope provided, because it uses some Constants from it. Otherwise, I have no idea what could link the two of them.

Any hint about what can trigger another bundle's activator would be really helpful to understand how it works. I can post more code/info if needed. Thank you

EDIT: This is the cycle raising the issue, when using CI

  1. Deploy BundleB (sling-core): contains an enum class to store constants
  2. Deploy BundleA (sling-content): loads Sling initial content, and with an activator automatically sets permissions and sort nodes using the Jackrabbit API. This codes uses enums stored in BundleA.
  3. Re-deploy BundleB (sling-core) because some changes were pushed
  4. Issue: BundleA also restarts and then re-do permissions and nodes sorting, which I do not want

Solution

  • With very short words:

    A Bundle (A) is started if

    • it is set to be automatically started, and the start level of the bundle is lower than the start level of the framework
    • another bundle (B) is started that uses classes from the bundle A

    I guess your bundle B uses classes from Bundle A, so Bundle A will be started before Bundle B is started.

    You probably want to divide Bundle A to two bundles. You can create a new Bundle that contains only the Activator, so when Bundle B is started, this new Bundle will be not started automatically (as no classes are used from this new Bundle).

    If you want to have a deeper understand, I suggest that you should read that you should read chapter 4.3 together with some other chapters linked from this one of OSGi Core specification.

    Btw.: I have never had to use lazy starting policy, or non-started bundles in any of my projects. If you start using a component model like Declarative Services and make the component instantiation logic based on configuration via ConfigAdmin, you might not have issues like this anymore. You will not really have the necessity to implement Bundle Activators.

    Edit

    Based on the new information in the question:

    As Bundle B is updated and the bundles are refreshed, Bundle A is re-wired to BundleB and then started again. You should think of dividing Bundle B into two separate bundles. One part is more constant (e.g.: B-API) and the other part is not that constant (B-IMPL). Bundle A should use B-API only and you will not have re-wiring when B-IMPL is updated.

    First it seems to make you more work, but this is the real separation of logic. We have many bundles that contain only 1-2 class files, but they are stable and have no new version since a long time.