OSGi Module Development - appendix

  Written by The Jahia Team
 
Developers
   Estimated reading time:

Appendix 1 - Configuring a module that extends the system

Some modules might use frameworks provided by the Digital Experience Manager system and need to extend them.

For example, your module might use some sub projects from the Spring framework. Spring framework is highly configurable and can handle that some jars are present or not in the system.

In your module, you need to embed some jars and add some inside Digital Experience Manager WEB-INF/lib

Here are the dependencies we want to add to our module:

<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-core</artifactId>
    <version>${spring-social.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-web</artifactId>
    <version>${spring-social.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-facebook</artifactId>
    <version>${spring-social-facebook.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.social</groupId>
    <artifactId>spring-social-twitter</artifactId>
    <version>${spring-social-twitter.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-crypto</artifactId>
    <version>${spring-security-crypto.version}</version>
</dependency>

To embed some jars in your project you need to add a line like this in your pom.xml

<Embed-Dependency>*;groupId=org.springframework.social|org.springframework.security; scope=compile; type=!pom; inline=false</Embed-Dependency>

This will restrain the scope of the embedded jars to the one we are declaring as we do not want to embed all of org.springframework.social transitive dependencies (most of them are related to spring framework which is already part of the system).

This example introduce some JSON frameworks (org.codehaus.jackson) that is used both by the social module and by springframework web this means we have a transitive dependency that needs to be added to our system as spring framework web is a system one.

To find our dependencies we can use the plugin dependency from Maven :

mvn -o dependency:tree

This return something like :

[INFO] --- maven-dependency-plugin:2.6:tree (default-cli) @ socialNetworkConnector ---
[INFO] org.jahia.modules.socialNetworkConnector:socialNetworkConnector:bundle:2.0-SNAPSHOT
[INFO] +- org.springframework:spring-tx:jar:3.0.5.RELEASE:compile
[INFO] |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  \- org.springframework:spring-aop:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-orm:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-core:jar:3.0.5.RELEASE:compile
[INFO] |  +- org.springframework:spring-asm:jar:3.0.5.RELEASE:compile
[INFO] |  \- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- org.springframework:spring-web:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:3.0.5.RELEASE:compile
[INFO] |  \- org.springframework:spring-expression:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-context-support:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-jdbc:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework.social:spring-social-core:jar:1.0.3.RELEAE:compile
[INFO] +- org.springframework.social:spring-social-web:jar:1.0.3.RELEASE:compile
[INFO] |  \- javax.inject:javax.inject:jar:1:compile
[INFO] +- org.springframework.social:spring-social-facebook:jar:1.0.3.RELEASE:compile
[INFO] |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.9:compile
[INFO] +- org.springframework.social:spring-social-twitter:jar:1.0.5.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-crypto:jar:3.1.3.RELEASE:compile
[INFO] +- org.jahia.server:jahia-impl:jar:7.0.0.0-SNAPSHOT:provided
...
[INFO] |  +- org.springframework.webflow:spring-js:jar:2.3.2.RELEASE:provided
[INFO] |  |  \- org.springframework.webflow:spring-js-resources:jar:2.3.2.RELEASE:provided
[INFO] |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.9:compile
...
[INFO] +- org.springframework.social:spring-social-facebook:jar:1.0.3.RELEASE:compile
[INFO] |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.9:compile
[INFO] +- org.springframework.social:spring-social-twitter:jar:1.0.5.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-crypto:jar:3.1.3.RELEASE:compile
[INFO] +- org.jahia.server:jahia-impl:jar:7.0.0.0-SNAPSHOT:provided

As all other packages are transitive dependencies from org.jahia.server

Now we see as a transitive that we depend on org.codehaus.jackson :

[INFO] +- org.springframework.social:spring-social-facebook:jar:1.0.3.RELEASE:compile
[INFO] |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.9:compile

Let’s see if we find other dependencies towards org.codehaus.jackson on the list , the command can be written as is :

mvn -o dependency:tree -Dincludes=org.codehaus.jackson,org.springframework,org.jahia

result :

[INFO] --- maven-dependency-plugin:2.6:tree (default-cli) @ socialNetworkConnector ---
[INFO] org.jahia.modules.socialNetworkConnector:socialNetworkConnector:bundle:2.0-SNAPSHOT
[INFO] +- org.springframework:spring-tx:jar:3.0.5.RELEASE:compile
[INFO] |  \- org.springframework:spring-aop:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-orm:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-core:jar:3.0.5.RELEASE:compile
[INFO] |  \- org.springframework:spring-asm:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:3.0.5.RELEASE:compile
[INFO] |  \- org.springframework:spring-expression:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-context-support:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework:spring-jdbc:jar:3.0.5.RELEASE:compile
[INFO] +- org.springframework.social:spring-social-facebook:jar:1.0.3.RELEASE:compile
[INFO] |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.9:compile
[INFO] \- org.jahia.server:jahia-impl:jar:7.0.0.0-SNAPSHOT:provided
[INFO]    \- org.codehaus.jackson:jackson-core-asl:jar:1.9.9:compile

This means that Digital Experience Manager system has also some dependencies towards org,codehaus.jackson, so we need to add org.codehaus.jackson in WEB-INF/lib to make it available for Digital Experience Manager itself.

Now those classes will also be used inside our module so we need to tell our OSGI container (Felix) that those classes are system classes and need to be shared with the bundles.

To do so we need to modify WEB-INF/etc/config/felix-framework.properties and add all the packages we want to make available to bundles in that file.

org.codehaus.jackson;version\="1.9.9",\
org.codehaus.jackson.annotate;version\="1.9.9",\
org.codehaus.jackson.format;version\="1.9.9",\
org.codehaus.jackson.impl;version\="1.9.9",\
org.codehaus.jackson.io;version\="1.9.9",\
org.codehaus.jackson.map;version\="1.9.9",\
org.codehaus.jackson.map.annotate;version\="1.9.9",\
org.codehaus.jackson.map.deser;version\="1.9.9",\
org.codehaus.jackson.map.deser.impl;version\="1.9.9",\
org.codehaus.jackson.map.deser.std;version\="1.9.9",\
org.codehaus.jackson.map.exc;version\="1.9.9",\
org.codehaus.jackson.map.ext;version\="1.9.9",\
org.codehaus.jackson.map.introspect;version\="1.9.9",\
org.codehaus.jackson.map.jsontype;version\="1.9.9",\
org.codehaus.jackson.map.jsontype.impl;version\="1.9.9",\
org.codehaus.jackson.map.module;version\="1.9.9",\
org.codehaus.jackson.map.ser;version\="1.9.9",\
org.codehaus.jackson.map.ser.impl;version\="1.9.9",\
org.codehaus.jackson.map.ser.std;version\="1.9.9",\
org.codehaus.jackson.map.type;version\="1.9.9",\
org.codehaus.jackson.map.util;version\="1.9.9",\
org.codehaus.jackson.node;version\="1.9.9",\
org.codehaus.jackson.schema;version\="1.9.9",\
org.codehaus.jackson.sym;version\="1.9.9",\
org.codehaus.jackson.type;version\="1.9.9",\
org.codehaus.jackson.util;version\="1.9.9",\

Right now, there is no easy way to list those packages with version number so you need to generate that list by hand (jar tf on jar file will list all files).

Now you need to specify the import needed by your module to work. Digital Experience Manager will try to detect those packages as much as possible, to do so include that in your Import-Package directive in your pom.xml file:

<Import-Package>
    ${jahia.plugin.importPackage}
</Import-Package>

Now you can deploy your module and start your jahia (needed to take your new libs and properties into account)

If your module does not start you might be missing some imports, add them to your configuration.

Following our example, you end with something like that,

<Import-Package>
    ${jahia.modules.importPackage},
    javax.crypto,
    javax.crypto.spec,
    javax.servlet.http,
    net.sf.cglib.core,
    net.sf.cglib.proxy,
    org.apache.http,
    org.apache.http.client,
    org.apache.http.client.methods,
    org.apache.http.entity,
    org.apache.http.impl.conn.tsccm,
    org.apache.http.conn.scheme,
    org.apache.http.conn,
    org.apache.http.conn.ssl,
    org.apache.http.impl.client,
    org.apache.http.impl,
    org.apache.http.params,
    org.apache.http.util,
    org.apache.log4j,
    org.codehaus.jackson,
    org.codehaus.jackson.annotate,
    org.codehaus.jackson.format,
    org.codehaus.jackson.impl,
    org.codehaus.jackson.io,
    org.codehaus.jackson.sym,
    org.codehaus.jackson.type,
    org.codehaus.jackson.util,
    org.codehaus.jackson.map,
    org.codehaus.jackson.map.module,
    org.jahia.bin,
    org.springframework.util,
    org.springframework.web.util,
    org.springframework.web.client,
    org.springframework.http,
    org.springframework.http.client,
    org.springframework.beans.factory,
    org.springframework.http.converter,
    org.springframework.core,
    org.springframework.http.converter.json,
    org.slf4j,
    org.slf4j.impl,
    org.slf4j.spi,
    org.json
</Import-Package>

To find packages in a jar file you can use this line of command by providing the path to the jars you want to analyze:

mvn -o jahia:osgi-inspect -DjarBundles=/home/rincevent/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.9/jackson-core-asl-1.9.9.jar,/home/rincevent/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.9.9/jackson-mapper-asl-1.9.9.jar -DdumpHeaderOnly=false

This will dump the headers from the manifest file, option ‘dumpHeaderOnly’ allows analyzing the jar and listing the packages found in it if this is not an OSGI bundle.

Here an excerpt of the output:

[INFO] /home/rincevent/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.9/jackson-core-asl-1.9.9.jar header dump:
Bnd-LastModified: 1343496987929
Built-By: tsaloranta
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: Jackson JSON processor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
    JavaSE-1.6
Bundle-SymbolicName: jackson-core-asl
Bundle-Vendor: http://fasterxml.com
Bundle-Version: 1.9.9
Created-By: 1.6.0_33 (Apple Inc.)
Export-Package: org.codehaus.jackson.format; version=1.9.9; uses:=org.codehaus.jackson.io,org.codehaus.jac...
    org.codehaus.jackson.io; version=1.9.9; uses:=org.codehaus.jackson.util,org.codehaus.j...
    org.codehaus.jackson.sym; version=1.9.9; uses:=org.codehaus.jackson.util
    org.codehaus.jackson.util; version=1.9.9; uses:=org.codehaus.jackson.io,org.codehaus.jac...
    org.codehaus.jackson.annotate; version=1.9.9
    org.codehaus.jackson.impl; version=1.9.9; uses:=org.codehaus.jackson.format,org.codehaus...
    org.codehaus.jackson; version=1.9.9; uses:=org.codehaus.jackson.format,org.codehaus...
    org.codehaus.jackson.type; version=1.9.9
Implementation-Title: Jackson JSON processor
Implementation-Vendor: http://fasterxml.com
Implementation-Version: 1.9.9
Import-Package: org.codehaus.jackson; version=1.9.9
    org.codehaus.jackson.annotate; version=1.9.9
    org.codehaus.jackson.format; version=1.9.9
    org.codehaus.jackson.impl; version=1.9.9
    org.codehaus.jackson.io; version=1.9.9
    org.codehaus.jackson.sym; version=1.9.9
    org.codehaus.jackson.type; version=1.9.9
    org.codehaus.jackson.util; version=1.9.9
Manifest-Version: 1.0
Specification-Title: JSON - JavaScript Object Notation
Specification-Vendor: http://www.ietf.org/rfc/rfc4627.txt
Specification-Version: 1.0
Tool: Bnd-unknown version

[INFO] List of package from jar file : /home/rincevent/.m2/repository/org/codehaus/jackson/jackson-core-asl/1.9.9/jackson-core-asl-1.9.9.jar
[INFO] org.codehaus.jackson;version=1.9.9
[INFO] org.codehaus.jackson.annotate;version=1.9.9
[INFO] org.codehaus.jackson.format;version=1.9.9
[INFO] org.codehaus.jackson.impl;version=1.9.9
[INFO] org.codehaus.jackson.io;version=1.9.9
[INFO] org.codehaus.jackson.sym;version=1.9.9
[INFO] org.codehaus.jackson.type;version=1.9.9
[INFO] org.codehaus.jackson.util;version=1.9.9

[INFO] /home/rincevent/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.9.9/jackson-mapper-asl-1.9.9.jar header dump:
Bnd-LastModified: 1343496988957
Built-By: tsaloranta
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-ManifestVersion: 2
Bundle-Name: Data mapper for Jackson JSON processor
Bundle-RequiredExecutionEnvironment: J2SE-1.5
    JavaSE-1.6
Bundle-SymbolicName: jackson-mapper-asl
Bundle-Vendor: http://fasterxml.com
Bundle-Version: 1.9.9
Created-By: 1.6.0_33 (Apple Inc.)
DynamicImport-Package: org.joda.time
    org.joda.time.format
    org.w3c.dom.ls
    org.w3c.dom.bootstrap
Export-Package: org.codehaus.jackson.schema; version=1.9.9; uses:=org.codehaus.jackson.node,org.codehaus.j...
    org.codehaus.jackson.map.deser.impl; version=1.9.9; uses:=org.codehaus.jackson.map.type,org.codeha...
    org.codehaus.jackson.map.exc; version=1.9.9; uses:=org.codehaus.jackson.map,org.codehaus.ja...
    org.codehaus.jackson.map.annotate; version=1.9.9; uses:=org.codehaus.jackson.map,org.codehaus.ja...
    org.codehaus.jackson.map.ser.impl; version=1.9.9; uses:=org.codehaus.jackson.io,org.codehaus.jac...
    org.codehaus.jackson.map.ser.std; version=1.9.9; uses:=org.codehaus.jackson.schema,org.codehaus...
    org.codehaus.jackson.map.type; version=1.9.9; uses:=org.codehaus.jackson.map,org.codehaus.ja...
    org.codehaus.jackson.map.module; version=1.9.9; uses:=org.codehaus.jackson.map.deser,org.codeh...
    org.codehaus.jackson.node; version=1.9.9; uses:=org.codehaus.jackson.io,org.codehaus.jac...
    org.codehaus.jackson.map; version=1.9.9; uses:=org.codehaus.jackson.format,org.codehaus...
    org.codehaus.jackson.map.deser; version=1.9.9; uses:=org.codehaus.jackson.map.exc,org.codehau...
    org.codehaus.jackson.map.introspect; version=1.9.9; uses:=org.codehaus.jackson.map.annotate,org.co...
    org.codehaus.jackson.map.jsontype; version=1.9.9; uses:=org.codehaus.jackson.map,org.codehaus.ja...
    org.codehaus.jackson.map.util; version=1.9.9; uses:=org.codehaus.jackson.io,org.codehaus.jac...
    org.codehaus.jackson.map.deser.std; version=1.9.9; uses:=org.codehaus.jackson.map.deser.impl,org....
    org.codehaus.jackson.map.jsontype.impl; version=1.9.9; uses:=org.codehaus.jackson.annotate,org.codeha...
    org.codehaus.jackson.map.ser; version=1.9.9; uses:=org.codehaus.jackson.map.annotate,org.co...
Implementation-Title: Data mapper for Jackson JSON processor
Implementation-Vendor: http://fasterxml.com
Implementation-Version: 1.9.9
Import-Package: javax.xml.datatype
    javax.xml.namespace
    javax.xml.parsers
    org.codehaus.jackson; version=1.9.9
    org.codehaus.jackson.annotate; version=1.9.9
    org.codehaus.jackson.format; version=1.9.9
    org.codehaus.jackson.impl; version=1.9.9
    org.codehaus.jackson.io; version=1.9.9
    org.codehaus.jackson.type; version=1.9.9
    org.codehaus.jackson.util; version=1.9.9
    org.w3c.dom
    org.xml.sax
Manifest-Version: 1.0
Private-Package: org.codehaus.jackson.map.ext
Tool: Bnd-unknown version

[INFO] List of package from jar file : /home/rincevent/.m2/repository/org/codehaus/jackson/jackson-mapper-asl/1.9.9/jackson-mapper-asl-1.9.9.jar
[INFO] org.codehaus.jackson.map;version=1.9.9
[INFO] org.codehaus.jackson.map.annotate;version=1.9.9
[INFO] org.codehaus.jackson.map.deser;version=1.9.9
[INFO] org.codehaus.jackson.map.deser.impl;version=1.9.9
[INFO] org.codehaus.jackson.map.deser.std;version=1.9.9
[INFO] org.codehaus.jackson.map.exc;version=1.9.9
[INFO] org.codehaus.jackson.map.ext;version=1.9.9
[INFO] org.codehaus.jackson.map.introspect;version=1.9.9
[INFO] org.codehaus.jackson.map.jsontype;version=1.9.9
[INFO] org.codehaus.jackson.map.jsontype.impl;version=1.9.9
[INFO] org.codehaus.jackson.map.module;version=1.9.9
[INFO] org.codehaus.jackson.map.ser;version=1.9.9
[INFO] org.codehaus.jackson.map.ser.impl;version=1.9.9
[INFO] org.codehaus.jackson.map.ser.std;version=1.9.9
[INFO] org.codehaus.jackson.map.type;version=1.9.9
[INFO] org.codehaus.jackson.map.util;version=1.9.9
[INFO] org.codehaus.jackson.node;version=1.9.9
[INFO] org.codehaus.jackson.schema;version=1.9.9

With those information you can modify your file WEB-INF/etc/config/felix-framework.properties to add those packages.

Appendix 2- Additional resources

1 OSGi Glossary

1.1 General OSGi terms

  • OSGi Core specification – This is the core specification of how class loaders work with bundles, how bundles are specified, how services are registered and how their life cycle works.
  • OSGi Compendium specification - the compendium defines specific services such as the declarative services specification, the configuration admin service, remote services spec, etc...
  • OSGi Enterprise specification - introduces enterprise specific notions such as persistence support, transactions, the OSGI Blueprint specification based on Spring Dynamic modules to enable powerful dependency injection, etc.

1.2 OSGi core implementations

  • Apache Felix - the OSGi implementation at Apache. This project is the "minimal" OSGi implementation, and most advanced features are now moved to other project such as Apache Karaf or Apache Aries. Felix is embedded in Apache Sling, Karaf, ServiceMix, Adobe’s CRX, and many other servers.
  • Eclipse Equinox - the Eclipse implementation of the OSGi framework. This is historically the first implementation of the OSGi specification and therefore usually the most complete. Apache Felix is usually lagging a bit in terms of features behind the Equinox implementation but this is not necessarily a bad thing since it focuses on being minimal. Equinox is embedded in the Eclipse IDE as well as the WebSphere Application server.

1.3 OSGi compendium frameworks & implementations

  • OSGi Declarative Services - initial dependency injection framework based on XML descriptors and implemented in Apache Felix under the name SCR. Has plugins to use annotations. This is historically the oldest dependency framework and therefore the most mature in terms of implementations, but is also quite limited and tedious to work with.
  • OSGi Blueprint - dependency injection framework for OSGi based on the initial work done by Spring Dynamic Modules. The reference implementation of the Blueprint specification is actually the Spring DM implementation, which was now donated to Eclipse under the name Eclipse Gemini Blueprint project.
  • Apache Aries - also includes another implementation of the OSGi Blueprint specification, and is implementing the Enterprise OSGi specification more globally (such as persistence or transactions), using some services from other projects such as Apache ServiceMix or Apache Geronimo.

1.4 Other important frameworks

Apache Felix iPOJO - an alternative to OSGi Declarative Service or OSGi Blueprint, this is another dependency framework that was not standardized but that is compatible with multiple OSGi framework implementations. It is also quite well documented. Here is a comparison between the three dependency framework implementations :

http://felix.apache.org/site/ipojo-faq.html#iPOJOFAQ-HowdoesiPOJOcomparetoDeclarativeServicesorBlueprint%253F

http://felix.apache.org/site/ipojo-faq.html - iPOJOFAQ-HowdoesiPOJOcomparetoDeclarativeServicesorBlueprint%253F

Apache Karaf - designed to be a lightweight OSGi platform that includes useful features out of the box for developers and production. This is designed to be used as a generic OSGi server, whereas Apache Felix is just the basic code. For example, Apache Karaf can deploy “packs of bundles” called “features” making it easier to deploy a real-world application than deploying all bundles manually on Apache Felix. Karaf is also designed to run as a service on an operating system and provides shell scripts and documentation on how to do this. Also, the command line on Karaf is much more powerful than the Apache Felix one. So when would you prefer using Felix instead of Karaf ? Well mostly when you want to embed an OSGi framework and want precise control over what you include or not. For example, in our Jahia Config Tool project we chose to use Felix directly since we were embedding it as a standalone Java application. This doesn’t mean we can’t deploy Apache Karaf bundles inside Felix, quite the opposite in fact, but requires more developer setup while Karaf includes a lot of functionality out of the box. If you are looking to develop a web application, it would make more sense to use Apache Karaf, you’ll be much more productive.

Apache ServiceMix - a flexible, open-source integration container that unifies the features and functionality of Apache ActiveMQ, Camel, CXF, ODE, Karaf into a powerful runtime platform you can use to build your own integrations solutions. It provides a complete, enterprise ready ESB exclusively powered by OSGi.

1.5 Other terms

MANIFEST-FIRST development - OSGi development with the Eclipse IDE is done a little differently than when using Maven.

2 Web references

Best practices for developing and working with OSGi applications, http://www.ibm.com/developerworks/websphere/techjournal/1007_charters/1007_charters.html