osgilog4j2osgi-bundlemaven-bundle-plugin

Using a 3rd party dependency within a Maven OSGi bundle


After feeling like I had a grasp on how OSGi is utilized, I tried to go about adding a 3rd party dependency, specifically log4j2, to my application that is utilizing apache felix and bundling with the maven-bundle-plugin. Unfortunately, it seems as if I am stuck in dependency hell.

I have tried using numerous maven-bundle tactics like Import-Package, Embed-Dependency, wrapImportPackage, Embed-Transitive, and setting specific version numbers just to name a few. Below is what my pom looks like for this plugin:

<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>

<parent>
    <artifactId>ParentId</artifactId>
    <groupId>ParentGroupId</groupId>
    <version>x.x.x</version>
</parent>

<groupId>ParentGroupId.ParentId</groupId>
<artifactId>thisModule</artifactId>
<packaging>bundle</packaging>

<name>thisModule</name>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.osgi</groupId>
        <artifactId>org.osgi.core</artifactId>
        <version>6.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>AM</artifactId>
        <version>${project.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.12.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.12.1</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <version>3.5.1</version>
            <extensions>true</extensions>
            <configuration>
                <instructions>
                    <Bundle-SymbolicName>${project.name}</Bundle-SymbolicName>
                    <Bundle-Activator>moduleActivator</Bundle-Activator>
                    <Embed-Dependency>
                        AM,
                        gson,
                        log4j-api,
                        log4j-core
                    </Embed-Dependency>
                </instructions>
            </configuration>
        </plugin>
    </plugins>
    <finalName>${project.artifactId}</finalName>
</build>

The most progress I feel like I have had is with the above pom, where I am embedding the log4j api and core directly into the bundle, but it seems as if OSGi is incapable of downloading and bundling the compile dependencies that the log4j api and core are dependent on. It successfully builds using maven but then when I deploy the EAR and JAR I get this error at runtime (when the plugin is trying to boot up):

Caused By: org.osgi.framework.BundleException: Unresolved constraint in bundle thisModule [2]: Unable to resolve 2.0: missing requirement [2.0] package; (package=com.conversantmedia.util.concurrent)

error that will name a specific dependency that log4j needs. What I DON'T want to do is include every single dependency and their mother inside the Embed-Dependency tag.

What am I doing wrong here?

Also note: Due to constraints, my only option here is to use apache felix and OSGi.


Below are other examples of modifications I made to the above POM and their resulting outputs:

Caused By: org.osgi.framework.BundleException: Unresolved constraint in bundle thisModule [2]: Unable to resolve 2.0: missing requirement [2.0] package; (&(package=org.apache.logging.log4j)(version>=2.12.0)(!(version>=3.0.0)))

Caused By: org.osgi.framework.BundleException: Unresolved constraint in bundle thisModule [2]: Unable to resolve 2.0: missing requirement [2.0] package; (package=android.dalvik)


Solution

  • Embedding a logging libary is a bad idea. After all you want to configure the logging in a central place which is very hard when each bundle embeds a logging framework.

    In most cases the safe bet is to simple keep the maven-bundle-plugin config empty and let it do its thing.

    I personally always use slf4j for logging in OSGi. You simply depend on the slf4j-api. The maven-bundle-plugin creates the import package statements automatically.

    Then at runtime you simply deploy a logging framework that supports the logging api you want.

    For apache karaf this is already the case by default. If you use bndtools or your own application assembly based on plain felix then check out my osgi best practices example. It shows how to use slf4j-api in your own bundles and also how to configure the log system in karaf and bndtools based applications.