Announcement: You can find the guides for Commerce 7.5 and later on the new Elastic Path Documentation site. The Developer Center continues to support Commerce 6.13.0 through 7.4.1.Visit new site

Tutorial 6 - Adding third party jars to Cortex API

Tutorial 6 - Adding third party jars to Cortex API

This tutorial describes how to add third party jars as OSGi dependencies to Cortex API.

Warning: Before you begin

Make sure your development environment has been properly set up as described in Setting up your Developer Environment.

Adding OSGi Compliant Jars

If the jar is OSGi compliant, add it to cortex-dce-webapp's pom.xml. During the Webapp's start up, this third party jar is included in Cortex API and run as an OSGi bundle.

To add the third party jar to Cortex API:

  1. With a text editor, open Cortex-dce-webapp's pom.xml.
  2. Add the jar as a dependency:
    <dependencies>
    ...
            <dependency>
                <groupId>com.third.party.group</groupId>
                <artifactId>third-party-jar</artifactId>
    			<version>1.0.0</version>
            </dependency>
    ...
    </dependencies>
  3. Add the jar as an artifact item.
    <plugin>
    	<groupId>org.apache.maven.plugins</groupId>
    	...
            <artifactItems>
    		...
    		<artifactItem>
                    	<groupId>com.third.party.group</groupId>
                            <artifactId>third-party-jar</artifactId>
                    </artifactItem>
    		...
            </artifactItems>
    	...
    </plugin>
    
    
  4. Rebuild Cortex-dce-webapp and run Cortex API Webapp.

Adding non-OSGi Compliant Jars

Adding a non-OSGi compliant jar to Cortex API will display "could not start bundle... missing requirements" exceptions during start up. For example:

Output at run-time
         ...
RELOS: 2246   [      main] ERROR los.webapp.osgi.impl.JarBundleLoaderImpl - Could not start bundle com.elasticpath.rest.integration.epcommerce.ep-resource-purchases-epcommerce
org.osgi.framework.BundleException: Unresolved constraint in bundle com.elasticpath.rest.integration.epcommerce.ep-resource-purchases-epcommerce [8]: Unable to resolve 8.0: missing requirement [8.0] osgi.wiring.package; (osgi.wiring.package=com.elasticpath.commons.beanframework) [caused by: Unable to resolve 88.0: missing requirement [88.0] osgi.wiring.package; (osgi.wiring.package=org.apache.bval) [caused by: Unable to resolve 14.0: missing requirement [14.0] osgi.wiring.package; (osgi.wiring.package=javax.validation)]] 
...
RELOS: 2335   [      main] ERROR los.webapp.osgi.impl.JarBundleLoaderImpl - Could not start bundle org.apache.bval.org.apache.bval.bundle
org.osgi.framework.BundleException: Unresolved constraint in bundle org.apache.bval.org.apache.bval.bundle [14]: Unable to resolve 14.0: missing requirement [14.0] osgi.wiring.package; (osgi.wiring.package=javax.validation)
...
RELOS: 2449   [      main] ERROR los.webapp.osgi.impl.JarBundleLoaderImpl - Could not start bundle com.elasticpath.rest.integration.epcommerce.ep-resource-slots-epcommerce
org.osgi.framework.BundleException: Unresolved constraint in bundle com.elasticpath.rest.integration.epcommerce.ep-resource-slots-epcommerce [32]: Unable to resolve 32.0: missing requirement [32.0] osgi.wiring.package; (osgi.wiring.package=com.elasticpath.commons.constants) [caused by: Unable to resolve 88.0: missing requirement [88.0] osgi.wiring.package; (osgi.wiring.package=org.apache.bval) [caused by: Unable to resolve 14.0: missing requirement [14.0] osgi.wiring.package; (osgi.wiring.package=javax.validation)]] 
...
RELOS: 2567   [      main] ERROR los.webapp.osgi.impl.JarBundleLoaderImpl - Could not start bundle com.elasticpath.rest.integration.epcommerce.ep-resource-carts-epcommerce
org.osgi.framework.BundleException: Unresolved constraint in bundle com.elasticpath.rest.integration.epcommerce.ep-resource-carts-epcommerce [38]: Unable to resolve 38.0: missing requirement [38.0] osgi.wiring.package; (osgi.wiring.package=com.elasticpath.common.dto) [caused by: Unable to resolve 88.0: missing requirement [88.0] osgi.wiring.package; (osgi.wiring.package=org.apache.bval) [caused by: Unable to resolve 14.0: missing requirement [14.0] osgi.wiring.package; (osgi.wiring.package=javax.validation)]] 
...
<continued for other resources referencing javax.validation>

There are three ways to mitigate this issue:

Find an OSGi Compliant Version of the Jar

Find an OSGi compliant version of the third party jar. There are several sources to finding it; two good sources are listed below.

Make the Jar OSGi Compliant

Tools are available to make a jar OSGi compliant.The most popular tool is BND:

http://www.aqute.biz/Bnd/Bnd

BND's wrap command takes an existing jar, guesses the right headers for the jar's manifest, and creates a new OSGi bundle jar.

 bnd wrap osgi.jar *.jar

Use OSGi Framework Properties

By using Cortex API's OSGi framework properties, you can set OSGi to export packages of your non-OSGi compliant jars and include them in your Cortex API framework. The OSGi framework properties we need to modify are:

  • org.osgi.framework.bootdelegation - allows us to specify, at a global framework level, a list of packages to implicitly make available to all bundles in the framework. There is no need to declare the classes in the Import-Package headers of the bundles using them.
  • org.osgi.framework.system.packages.extra - allows us to add to the list of packages exported by the System Bundle (bundle id 0). Once exported, the packages are then available to the other bundles in the framework, but only if they are explicitly imported in the bundle's Import-Package headers.

To add the jar to Cortex API's OSGi framework:

  1. With a text editor, open cortex-dce-webapp/src/main/resources/spring/applicationContext.xml
  2. Add the third party jar to the org.osgi.framework.bootdelegation list:
    cortex-dce-webapp applicationContext.xml
    ...
    <bean name="osgiFrameworkProperties" class="java.util.HashMap">
            <constructor-arg>
                <map>
    ...
    				<entry key="org.osgi.framework.bootdelegation"
                            value="org.w3c.dom.ranges,
                                    org.w3c.dom.traversal,
                                    org.w3c.dom.bootstrap,
                                    org.w3c.dom.events,
                                    org.w3c.dom.ls,
                                    javax.xml.parsers,
                                    sun.reflect,
                                    weblogic.xml.jaxp,
                                    org.apache.xerces.jaxp,
                                    javax.inject,
                                    javax.net.ssl,
                                    javax.validation,
                                    javax.validation.bootstrap,
                                    javax.validation.spi,
                                    javax.validation.metadata,
                                    javax.management,
                                    oracle.sql"/>
                </map>
            </constructor-arg>
    ...
    </bean>
  3. Add the third party jar to the org.osgi.framework.system.packages.extra list:
    cortex-dce-webapp applicationContext.xml
    ...
    <bean name="osgiFrameworkProperties" class="java.util.HashMap">
            <constructor-arg>
                <map>
    ...
    				<entry key="org.osgi.framework.system.packages.extra"
                            value="javax.inject,
                                        javax.net.ssl,
                                        javax.validation,
                                        javax.validation.bootstrap,
                                        javax.validation.constraints,
                                        javax.validation.groups,
                                        javax.validation.metadata,
                                        javax.validation.spi,
                                        javax.servlet;
                                        javax.servlet.http;version=2.5,
                                        sun.reflect,
                                        org.slf4j;
                                        org.slf4j.spi;
                                        org.slf4j.helpers;version=1.7.5"/>
    ...
    </bean>
  4. Add the jar artifact as a dependency under Cortex-dce-webapp pom.xml:
    <dependencies>
    ...
            <dependency>
                <groupId>com.third.party.group</groupId>
                <artifactId>third-party-jar</artifactId>
    			<version>1.0.0</version>
            </dependency>
    ...
    </dependencies>
  5. Rebuild cortex-dce-webapp and run theCortex API Webapp

Note: General Rule for Declaring Bundles

If your bundle has an Import-Package declaration for a jar, simply declaring the bundle in org.osgi.framework.bootdelegation will not be enough since it only makes the package available in the class loader. You must also declare the package in the org.osgi.framework.system.packages.extra for the bundle to be differentiated from the system bundle.

The general rule is use org.osgi.framework.bootdelegation when you don't have control over the manifest of the problematic bundle and you don't mind exposing the package to every other bundle. Use org.osgi.framework.system.packages.extra when a bundle imports a package and you expect the system bundle (not another bundle) to provide it.

How to tell if your dependency is OSGi compliant

Expand the dependency's jar file, and find the META-INF/MANIFEST.MF file. Non-OSGi compliant jars don't have bundle key/value tags inside the manifest, while OSGi compliant jars do.

A non OSGi compliant dependency manifest
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: hardy
Build-Jdk: 1.5.0_20
An OSGi compliant manifest
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven Bundle Plugin
Built-By: hen
Build-Jdk: 1.5.0_22
Implementation-Build: UNKNOWN_BRANCH@r??????; 2011-11-09 22:58:07-0800
Implementation-Title: Commons Lang
Implementation-Vendor: The Apache Software Foundation
Implementation-Vendor-Id: org.apache
Implementation-Version: 3.1
Specification-Title: Commons Lang
Specification-Vendor: The Apache Software Foundation
Specification-Version: 3.1
X-Compile-Source-JDK: 1.5
X-Compile-Target-JDK: 1.5
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Include-Resource: templates/release-notes.vm=src/main/resources/templa
 tes/release-notes.vm,META-INF/LICENSE.txt=LICENSE.txt,META-INF/NOTICE
 .txt=NOTICE.txt
Bnd-LastModified: 1320908300777
Export-Package: org.apache.commons.lang3.event;version="3.1",org.apach
 e.commons.lang3.mutable;version="3.1",org.apache.commons.lang3.tuple;
 version="3.1",org.apache.commons.lang3.time;version="3.1",org.apache.
 commons.lang3.concurrent;version="3.1",org.apache.commons.lang3.text.
 translate;version="3.1",org.apache.commons.lang3.text;version="3.1",o
 rg.apache.commons.lang3.math;version="3.1",org.apache.commons.lang3;v
 ersion="3.1",org.apache.commons.lang3.exception;version="3.1",org.apa
 che.commons.lang3.reflect;version="3.1",org.apache.commons.lang3.buil
 der;version="3.1"
Bundle-Version: 3.1.0
Bundle-Name: Commons Lang
Bundle-Description: Commons Lang, a package of Java utility classes fo
 r the  classes that are in java.lang's hierarchy, or are considered t
 o be so  standard as to justify existence in java.lang.
Private-Package: templates
Bundle-DocURL: http://commons.apache.org/lang/
Bundle-Vendor: The Apache Software Foundation
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.apache.commons.lang3
Tool: Bnd-1.15.0