7

I am trying to convert my project into an OSGI application. I have few doubts. Suppose ModuleA in my application is dependent on external jars jarA and jarB. Now to make ModeuleA run, I am embedding both the jars using embed-dependency property of maven-bundle-plugin. Now suppose I have another module ModuleB which is also dependent on jarA. So this module also embeds the jarA. My project ends up having jarA being embedded 2 times which will unnecessarily bloat the size of project.

Is there any way to tell OSGI to load jarA only once and provide it to both the modules.

If converting these jars to OSGI bundles is the only solution, I have few more questions:

  1. What is the easiest way to convert jar to a bundle. BND tool looks like a good solution but I am not able to find proper documentation about it.

  2. jarA will also have some dependent jars. So do I need to convert all the dependent jars to bundles also. My project has more than 100 jars. How can I automate this process.

Thanks in advance :)

Uday Ogra
  • 71
  • 1
  • 2
  • If the >100 jars are externally created dependencies (not your own), a lot of them are probably OSGi bundles already. Open or unpack them (I find emacs convenient), and see inside the META-INF/MANIFEST.MF file for OSGi headers. If there are OSGi headers, there is no need to repackage. – gjoranv Jun 22 '19 at 18:24
  • Yes most of them have that. So do we need to start each of these bundles(external jars) followed by starting the main bundle (whose dependencies are these jars)? If we had embedded jars, we need not to start each of these bundles – Uday Ogra Jun 25 '19 at 09:02
  • Yes, they should be started in correct order. The bundle with no deps first, and your bundle last. – gjoranv Jun 25 '19 at 09:25

1 Answers1

4

There are actually to solutions to this, both a little bit different from what you are doing right now:

  1. Build one "third party dependencies" bundle, which will embed all of the non OSGi dependencies your project has.
  2. Convert every non OSGi dependency to a OSGi bundle.

Option 1 is easier to handle so I think most projects do this. I, personally, prefer option 2. We have a Maven "pom.xml" template that we use to convert those dependencies.

The "pom.xml" looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <properties>
        <library.groupId></library.groupId>
        <library.artifactId></library.artifactId>
        <library.version></library.version>
    </properties>

    <artifactId></artifactId>
    <packaging>bundle</packaging>

    <name></name>
    <description>${library.groupId}:${library.artifactId}:${library.version}</description>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Import-Package>*;resolution:=optional</Import-Package>
                        <Export-Package>*</Export-Package>
                        <Embed-Dependency>*;scope=compile|runtime;inline=true</Embed-Dependency>
                        <Embed-Transitive>true</Embed-Transitive>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>${library.groupId}</groupId>
            <artifactId>${library.artifactId}</artifactId>
            <version>${library.version}</version>
        </dependency>
    </dependencies>

</project>

This does:

  1. Add the non OSGi library as dependency
  2. Tell maven-bundle-plugin to embed this dependency (transitive)
  3. Tell maven-bundle-plugin to export all of the dependencies packages

I left some things blank that you have to set like library.groupId, library.artifactId and library.version. And somethings we need to tweak the configuration of the maven-bundle-plugin. But this is our starting point. Somethings for example, you do not want to export all packages etc.

If you really have 100+ dependencies that you need to convert you might be better of using this template and just adding all of your 100 dependencies as dependency and build one big bundle with all of them inside.

You can find the documentation for the maven-bundle-plugin here:

https://felix.apache.org/documentation/subprojects/apache-felix-maven-bundle-plugin-bnd.html

At this point I also want to mention that there is a new bundle plugin that you might want to consider for this: bnd-maven-plugin.

See: https://github.com/bndtools/bnd/tree/master/maven/bnd-maven-plugin

Jens
  • 20,533
  • 11
  • 60
  • 86
  • I was already using maven-bundle-plugin only. I was asking for the alternative of it. Embedding the dependencies in single bundle is not the ideal solution we are looking for. Our aim is break this big application into multiple modules. Out clients will download smaller application depending upon what modules they would need. – Uday Ogra Jun 21 '19 at 18:54
  • Anyways I am using BND tool to convert each dependency jar into an OSGI bundle.I am starting them first before starting the module which require those dependencies. Internally we are maintaining module vs dependency-jars map. Like : ModuleA --> jarA, jarB ; ModuleB --> jarB, jarC So if we need to start ModuleA, we will first start jarA and jarB (both converted to OSGI bundle) and then we will start ModuleA. – Uday Ogra Jun 21 '19 at 18:54
  • @UdayOgra You can create a bundle with just a single dependency in it. That's what we are doing. We have several projects with a POM like I have described and then deploy all of those bundles. – Jens Jun 21 '19 at 19:11