Search code examples
javamavenosgiapache-felix

Felix not starting bundle


Can not load a bundle into felix. I downloaded Felix 6.0.1, run using

> java -jar bin/felix.jar
____________________________
Welcome to Apache Felix Gogo

g! 

I create a MavenProject TestA in eclipse:

  1. I add a dependency to felix (6.0.1) as provided.
  2. I create a class in TestA/src/main/java/testa/impl/Activator.java.
  3. I extend the class testa.impl.Activator to org.osgi.framework.BundleActivator.
  4. I overwrite the public void start(BundleContext bc) throws Exception to print out Hello World!.

This is the java source:

package testa.impl;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class Activator implements BundleActivator {

    public void start(BundleContext arg0) throws Exception {
        System.out.println("Hello World!");
    }

    public void stop(BundleContext arg0) throws Exception {
        System.out.println("stop");
    }
}

This is my 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>test</groupId>
    <artifactId>testa</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.felix</groupId>
            <artifactId>org.apache.felix.main</artifactId>
            <version>6.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>clean install org.apache.felix:maven-bundle-plugin:bundle</defaultGoal>
    </build>
</project>

Then I compile to jar using mvn and load using

g! install file:/C:/xxx/TestA/target/testa-0.0.1-SNAPSHOT.jar                              
Bundle ID: 20

Then I list all bundles using lb

g! lb                                                                                                           15:51:56
START LEVEL 1
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (6.0.1)|6.0.1
    1|Active     |    1|jansi (1.17.1)|1.17.1
    2|Active     |    1|JLine Bundle (3.7.0)|3.7.0
    3|Active     |    1|Apache Felix Bundle Repository (2.0.10)|2.0.10
    4|Active     |    1|Apache Felix Gogo Command (1.0.2)|1.0.2
    5|Active     |    1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
    6|Active     |    1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
   20|Installed  |    1|testa (0.0.1.SNAPSHOT)|0.0.1.SNAPSHOT
g!                                                                                                              

Anyway I start the bundle using start:

g! start 20
g!

I expected to have "Hello World" printed but nothing shows up!

I am confused now and try to find out if the bundle realy has started.

g! lb                                                                                                           15:51:56
START LEVEL 1
   ID|State      |Level|Name
    0|Active     |    0|System Bundle (6.0.1)|6.0.1
    1|Active     |    1|jansi (1.17.1)|1.17.1
    2|Active     |    1|JLine Bundle (3.7.0)|3.7.0
    3|Active     |    1|Apache Felix Bundle Repository (2.0.10)|2.0.10
    4|Active     |    1|Apache Felix Gogo Command (1.0.2)|1.0.2
    5|Active     |    1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
    6|Active     |    1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
   20|Active     |    1|testa (0.0.1.SNAPSHOT)|0.0.1.SNAPSHOT
g!                                                                                                              15:51:58

Its started but my code has not been executed.

Question

Why is Hello World not printed on the console?


Solution

  • Hello World is not printed on the console, because the jar you created is not actually a bundle. Oddly, felix allows you to start a jar that doesn't have any OSGI related information in the manifest. It is unclear to me what starting such a bundle means? Maybe the classes get published, maybe they don't.

    Most java frameworks scan the files in a jar and use reflection or byte code analysis to find relevant classes. For normal frameworks, the overhead of scanning jars is incurred only once, on startup. OSGI was designed to be lightweight and is also used on mobile. Moreover, since in OSGI bundles can come and go, they designed a more efficient approach. OSGI bundles store the metadata in the manifest. This is a simple text file that is always in the same location (in the jar): "META-INF/MANIFEST.MF". If you use a zip tool to inspect the file in the jar, you should see something like this:

    Manifest-Version: 1.0
    Archiver-Version: Plexus Archiver
    Created-By: Apache Maven
    Built-By: Peter Rader
    Build-Jdk: 1.8.0_111
    

    For future OSGI troubleshooting I would suggest you inspect (and post) the manifest that is created.

    A valid OSGI manifest would look something like this:

    Manifest-Version: 1.0
    Archiver-Version: Plexus Archiver
    Created-By: Apache Maven
    Built-By: Peter Rader
    Build-Jdk: 1.8.0_111
    Bundle-Name: testa
    Bundle-SymbolicName: testa.impl
    Bundle-Version: 1.0.0
    Bundle-Activator: testa.impl.Activator
    Import-Package: org.osgi.framework
    

    When felix reads this manifest it uses the "Bundle-Activator" entry to find the activator (if any). Replace the manifest and the bundle should be deployed normally.
    Simply create a text file named "META-INF/MANIFEST.MF" containing the text above in a location relative to the jar. Next replace the manifest file in the jar with the following linux command (or your favorite zip tool):

    zip testa-0.0.1-SNAPSHOT.jar -u META-INF/*
    

    expected output from the zip command:

    updating: META-INF/MANIFEST.MF (deflated 36%)
    

    Be sure to open the jar with a zip file and check that the contents have changed. Now if you install and start the bundle it should print "Hello World!".

    Although this fixes the problem, it's not a very clean solution.
    The jar specification has some rather odd rules, as to how entries in the manifest should be formatted:
    https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Manifest_Specification
    Most notably:

    No line may be longer than 72 bytes (not characters), in its UTF8-encoded form.
    If a value would make the initial line longer than this, 
    it should be continued on extra lines (each starting with a single SPACE).
    

    Therefore, you don't want to be editing this file by hand. As others have remarked, you have various options for generating an OSGI manifest automatically. As before, you can check the manifest in the generated jar to verify that it is being generated correctly.