Skip to content

Instantly share code, notes, and snippets.

@ahoffer
Last active September 18, 2021 17:33
Show Gist options
  • Save ahoffer/b9691a80d60cf1677b25c646961f770c to your computer and use it in GitHub Desktop.
Save ahoffer/b9691a80d60cf1677b25c646961f770c to your computer and use it in GitHub Desktop.
OSGi best practices in 2021

OSGi

The Promise

About six years ago I took a new job and started working with a large application that took advantage of an OSGi implementation and Karaf. OSGi offers some amazing benefits over baseline Java.

  • Runtime upgradability
  • Finer grained (package-level) dependencies
  • Escape from classpath problem
  • SOA inside of a single JVM

The Reality

I spent 80% of the next six years fighting dependencies loading issues, missing requirements, version mismatches, and upgrades. I've watched the fear around upgrading Karaf because it meant someone had to spend a week debugging boot features failures that do not write anything to the logs. As much as I liked the idea of OSGi, I spent a lot more time fighting it than benefiting it.

Self-inflicted Wounds

A lot of the pain was self-inflicted. A lot of mistakes were made early in the project. It turns out that there are many, many wrong ways to use OSGi and Karaf.

Why is it so Easy to Shoot Yourself in the Foot?

I could argue that a weakness of the OSGi specification is that it is so very easy to shoot yourself in the foot. And the leg. And the arm. And to keep shooting yourself year after year.

The OSGi model is probably a victim of its era. Version 1 was published in the year 2000. I remember the philosophy in those days was to make software maximally configurable. Configurations that the user or developer could not alter were almost considered bugs.

Things have changed since then. Ideas like "convention over configuration," "YAGNI," and "opinionated software" have entered our vocabulary. Software developers just look at things differently than they did 20 years ago.

The Missing Manual: How Not to Shoot Yourself in the Foot

I think there is a missing OSGi companion. The companion would be a highly opinonated guide to building an application around OSGi (and Karaf). I'm not the right person to write the manual-- I don't know a tenth of what a potential author would need to know. But I do recognize the need.

OSGi Best Practices

Given my limited understanding (and limited success with OSGi), I can't say these are definitive best practices. They may not even be good practices. In any case, guidelines and best practices are always subject to debate.

  1. Use Maven.
  2. Don't use the maven-bundle-plugin. Instead, use the bnd-baseline-maven-plugin and bnd-baseline-maven-plugin.
  3. Put the bnd plugins in the root POM.
  4. Put your global API dependencies in the POM.
  5. Use the OSGi R7 annotations.
  6. Use Maven's <provided> scope.
  7. I'm told this is a good example to follow: Example OSGi Project
  8. Don't use Pax Exam, Pax Web, Pax Logging, or other OPS4J libraries. No disrespect is intended to the hard-working and selfless authors of this software. Unfortunately, incorporating these libraries in your application is an insidious way to shoot yourself in the foot. You won't realize why they problematic until a few years into your project. You will track down weird issues specific to your environment, you will discover the abstractions they provide do not align entirely with the libraries they wrap, and you will have suffered several painful upgrade cycles. Once you have identified the source of your pain, the framework is too deeply embedded to remove, and you are stuck with the pain.
  9. ServiceMix. ServiceMix brings in the things you need to write an enterprise grade application. Generally, that is a good thing. However, you will probably discover that you are now tied to their release cycle. And Service Mix is downstream of its dependencies, so the software it pulls in can be behind in versions. That mean security fixes, bugs fixes, and new features can lag behind their general availability. That's a problem. Also, because ServiceMix brings in so many things, upgrading can be a real chore. Upgrading Camel, CXF, Karaf, and ActiveMQ all at the same time has caused us to avoid upgrading for a long, long time. It also constrains your choices. What if you want to switch over from ActiveMQ to Artemis? I think we use some feature to blacklist bundles when that happens. I'm not sure. It's probably painful. It probably has a lot of unintended consequences.
  10. Do not "split-packages". The same package should never be found in two different Maven JARs. That's bad juju.
  11. Use OSGi annotations to version packages individually. Do not tie all the packages in the same JAR to the JAR's Maven version number. I suppose you could also restrict yourself to ONLY one package in a JAR file. Then it would be safe
  12. to use the JAR's Maven version. In general, the smaller the bundle, the more room you have to wiggle. The larger the bundle, the more you back yourself into a corner.
  13. Always create a separate API bundle for a service. Never, never put the interface and it's implementation into the same bundle.
  14. Try to avoid embedding artifacts. Take the hit upfront and create a new bundle, or wrap a third-party JAR as a bundle for the dependency.
  15. In an ideal world, you would only export the packages you create. All third-party packages only export their API. In short, do not export transitive dependencies.
  16. Someday I'll spend the time to understand this article and my usage of OSGi will improve.

<TODO: Finish the Eclipsecon presentation and add his best practices.>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment