I have been converting an existing application into a set OSGI modules along with their innumerable dependencies.
After tracking them all down, creating new bundles out existing jars with bnd, I finally have everything loaded into Felix. All of the bundles are activating.
I then created a simple activator that called my MainClass.main static method to see if it would fire up.
Amazingly, it seems to work.
But I'm getting this when my activator is fired.
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
After it prints that, later I get this:
INFO: Registered provider org.slf4j.simple.SimpleServiceProvider of service org.slf4j.spi.SLF4JServiceProvider in bundle slf4j.simple
That means SLF4J is starting, and I know I had to jump through some hoops in install the OSGI plumbing to support SLF4J (Aries service provider support). But, it's starting after my activator is called, and SLF4J doesn't seem to "know" that Simple is installed.
Now, my code is not using any of the OSGI service frameworks logic. At this stage, I'm just using OSGI as an elaborate class loader. My code is just using SLF4J like a normal application, rather than the OSGI Logger system.
I tried adding a ServiceTracker to not start mine up until SLF4J appears as a service, but getting the same result. Likely this is because its one thing to wait for formal OSGI service, but that's quite different from having internal classpaths all configured up. That happens right away, and it's clearly not finding the SLF4J provider. I even changed one of the modules to require the SLF4J provider as an Import-Package, but to no affect.
Edit:
Here is a sample java module, including the Activator and the Service
willh@iMac-2 LogTestOsgi % cat src/main/java/pkg/logtestosgi/Activator.java
package pkg.logtestosgi;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Activator implements BundleActivator {
Logger l = LoggerFactory.getLogger(this.getClass());
public void start(BundleContext context) throws Exception {
context.registerService(MyService.class.getName(), new MyServiceImpl(), null);
System.out.println("Activating myservice");
l.info("activating log info");
}
public void stop(BundleContext context) throws Exception {
System.out.println("deactivating myservice");
l.info("deactivating log info");
}
}
The service interface:
willh@iMac-2 LogTestOsgi % cat src/main/java/pkg/logtestosgi/MyService.java
package pkg.logtestosgi;
public interface MyService {
public void go();
}
And the service:
willh@iMac-2 LogTestOsgi % cat src/main/java/pkg/logtestosgi/MyServiceImpl.java
package pkg.logtestosgi;
public class MyServiceImpl implements MyService {
public void go() {
System.out.println("My Service says hello");
}
}
This is the POM file. Note that it copies all of the required modules into the target/lib directory.
willh@iMac-2 LogTestOsgi % cat pom.xml
<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>
<groupId>pkg</groupId>
<artifactId>LogTestOsgi</artifactId>
<version>1.2.3</version>
<packaging>bundle</packaging>
<name>LogTestOsgi OSGi Bundle</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.7</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.aries.spifly</groupId>
<artifactId>org.apache.aries.spifly.dynamic.bundle</artifactId>
<version>1.3.6</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.aries</groupId>
<artifactId>org.apache.aries.util</artifactId>
<version>1.1.3</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.5</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-analysis</artifactId>
<version>9.5</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>9.5</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.5</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>9.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-Activator>pkg.logtestosgi.Activator</Bundle-Activator>
<Export-Package/>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeGroupIds>org.osgi</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
From the project root, here's a simple shell script to move everything into place. It assumes that the Felix installation archive is in my Downloads directory.
willh@iMac-2 LogTestOsgi % cat go.sh
set -x
rm -rf felix-framework-7.0.5
unzip ~/Downloads/org.apache.felix.main.distribution-7.0.5.zip
cp target/lib/* felix-framework-7.0.5/bundle
cp target/LogTestOsgi-1.2.3.jar felix-framework-7.0.5/bundle
It copies all of the modules into the Felix's bundle directory so that they will auto install and start when Felix starts.
Here's the test:
willh@iMac-2 LogTestOsgi % cd felix-framework-7.0.5
willh@iMac-2 felix-framework-7.0.5 % java -jar bin/felix.jar
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
Activating myservice
Jan 31, 2024 11:41:39 AM org.apache.aries.spifly.BaseActivator log
INFO: Registered provider org.slf4j.simple.SimpleServiceProvider of service org.slf4j.spi.SLF4JServiceProvider in bundle slf4j.simple
____________________________
Welcome to Apache Felix Gogo
g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (7.0.5)|7.0.5
1|Active | 1|LogTestOsgi OSGi Bundle (1.2.3)|1.2.3
2|Active | 1|org.objectweb.asm (9.5.0)|9.5.0
3|Active | 1|org.objectweb.asm.tree.analysis (9.5.0)|9.5.0
4|Active | 1|org.objectweb.asm.commons (9.5.0)|9.5.0
5|Active | 1|org.objectweb.asm.tree (9.5.0)|9.5.0
6|Active | 1|org.objectweb.asm.util (9.5.0)|9.5.0
7|Active | 1|jansi (1.18.0)|1.18.0
8|Active | 1|JLine Bundle (3.13.2)|3.13.2
9|Active | 1|Apache Aries SPI Fly Dynamic Weaving Bundle (1.3.6)|1.3.6
10|Active | 1|Apache Aries Util (1.1.3)|1.1.3
11|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
12|Active | 1|Apache Felix Gogo Command (1.1.2)|1.1.2
13|Active | 1|Apache Felix Gogo JLine Shell (1.1.8)|1.1.8
14|Active | 1|Apache Felix Gogo Runtime (1.1.4)|1.1.4
15|Active | 1|slf4j-api (2.0.7)|2.0.7
16|Active | 1|slf4j-simple (2.0.7)|2.0.7
All bundles are active and there are no dependency warnings.
The activator is trying to use the SLFJ logger, but this triggers the
No SLF4J providers were found. warning. But, SLF4J and SLF4J simple are included in the collection of bundles.
This is not about how to use SLF4J as part of the OSGI Logging Service, this is about getting a legacy module that uses SLF4J internally to have it properly discover a provider (in this case SLF4J-simple).
SLF4J, as I understand it, relies on the Java ServiceLoader framework, which is why the Aries and ASM modules are included (as, to my understanding, these provide the necessary glue for OSGI to work in the ServiceLoader world).
But clearly something is missing.