Adding third party jars to Cortex API
This section describes how to add third party jars as OSGi dependencies to Cortex.
Determining if a Bundle is OSGi Compliant
Before adding a bundle to Cortex, you must first determine whether it is OSGi compliant or requires work to become so.
There are two ways to determine if a bundle is OSGi compliant. Ideally, a bundle’s MANIFEST.MF
provides the information required, but if it does not, loading the bundle and building the Cortex webapp can provide information on a bundle’s compliance.
MANIFEST.MF
file
Determining Compliance via a Bundle’s The easiest way to determine if a bundle is OSGi compliant is by inspecting its 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
Determining Compliance via Console Output
Adding a non-OSGi compliant jar to Cortex causes a number of errors and exceptions at runtime, and prevents the webapp from starting up. Errors may range from BundleExceptions
to error messaging reading "could not start bundle...
", "unresolved requirement...
" or more. An example of a runtime error due to a non-OSGi compliant jar is below:
org.osgi.framework.BundleException: Unable to resolve com.elasticpath.rest.integration.epcommerce.ep-resource-orders-epcommerce [181](R 181.0): missing requirement [com.elasticpath.rest.integration.epcommerce.ep-resource-orders-epcommerce [181](R 181.0)] osgi.wiring.package; (osgi.wiring.package=com.does.not.exist) Unresolved requirements: [[com.elasticpath.rest.integration.epcommerce.ep-resource-orders-epcommerce [181](R 181.0)] osgi.wiring.package; (osgi.wiring.package=com.does.not.exist)]
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4114) ~[org.apache.felix.framework-5.2.0.jar:na]
at org.apache.felix.framework.Felix.startBundle(Felix.java:2111) ~[org.apache.felix.framework-5.2.0.jar:na]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:977) ~[org.apache.felix.framework-5.2.0.jar:na]
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:964) ~[org.apache.felix.framework-5.2.0.jar:na]
at org.apache.felix.webconsole.internal.core.BundlesServlet.doPost(BundlesServlet.java:365) ~[na:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650) [tomcat-embed-core-7.0.65.jar:7.0.65]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.felix.webconsole.internal.servlet.OsgiManager.service(OsgiManager.java:567) [org.apache.felix.webconsole-4.2.12.jar:na]
at org.apache.felix.webconsole.internal.servlet.OsgiManager$3.run(OsgiManager.java:465) [org.apache.felix.webconsole-4.2.12.jar:na]
at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_131]
at org.apache.felix.webconsole.internal.servlet.OsgiManager.service(OsgiManager.java:461) [org.apache.felix.webconsole-4.2.12.jar:na]
at org.apache.felix.http.base.internal.handler.ServletHandler.doHandle(ServletHandler.java:339) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.ServletHandler.handle(ServletHandler.java:300) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.ServletPipeline.handle(ServletPipeline.java:93) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:50) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:84) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at com.elasticpath.rest.relos.rs.authentication.springoauth2.filter.OAuth2TokenAuthenticationFilter.doFilter(OAuth2TokenAuthenticationFilter.java:81) [ep-rs-authentication-spring-oauth2-0-SNAPSHOT.jar:na]
at org.apache.felix.http.base.internal.handler.FilterHandler.doHandle(FilterHandler.java:108) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:80) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at com.elasticpath.rest.relos.rs.authentication.web.filter.HeadersRemoverFilter.doFilter(HeadersRemoverFilter.java:107) [ep-rs-authentication-resource-0-SNAPSHOT.jar:na]
at org.apache.felix.http.base.internal.handler.FilterHandler.doHandle(FilterHandler.java:108) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:80) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:84) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at com.elasticpath.rest.relos.rs.filter.CharsetEncodingFilter.doFilter(CharsetEncodingFilter.java:43) [ep-rs-jersey-integration-0-SNAPSHOT.jar:na]
at org.apache.felix.http.base.internal.handler.FilterHandler.doHandle(FilterHandler.java:108) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:80) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:84) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at com.elasticpath.rest.relos.rs.filter.ExceptionTranslatingFilter.doFilter(ExceptionTranslatingFilter.java:45) [ep-rs-jersey-integration-0-SNAPSHOT.jar:na]
at org.apache.felix.http.base.internal.handler.FilterHandler.doHandle(FilterHandler.java:108) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:80) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:46) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:31) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.FilterPipeline.dispatch(FilterPipeline.java:76) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.dispatch.Dispatcher.dispatch(Dispatcher.java:49) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at org.apache.felix.http.base.internal.DispatcherServlet.service(DispatcherServlet.java:67) [org.apache.felix.http.bridge-2.3.2.jar:2.3.2]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.felix.http.proxy.ProxyServlet.service(ProxyServlet.java:60) [org.apache.felix.http.proxy-2.3.2.jar:2.3.2]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625) [tomcat-embed-core-7.0.65.jar:7.0.65]
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) [tomcat-embed-core-7.0.65.jar:7.0.65]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_131]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-7.0.65.jar:7.0.65]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_131]
To identify specific OSGi issues, use the Apache Felix console to examine a project’s bundles. For more information on how to access Apache Felix and use it, see Apache Felix Web Console. In particular, a bundle’s status as listed in the Felix web console can offer insight: bundles with an Active state have started correctly, and bundles non-Active states may have had issues. Manually re-deploying specific non-Active bundles produces more console output which can help identify specifically why a bundle may have issues starting up.
Adding OSGi Compliant Jars
If the jar is OSGi compliant, add it to extensions/ext-cortex-webapp
's pom.xml
file. During the Webapp’s start up, this third party jar is included in Cortex and run as an OSGi bundle.
To add the third party jar to Cortex:
With a text editor, open the
extensions/ext-cortex-webapp/pom.xml
file.Add the jar as a dependency using the following declaration:
<dependencies> ... <dependency> <groupId>com.third.party.group</groupId> <artifactId>third-party-jar</artifactId> <version>1.0.0</version> </dependency> ... </dependencies>
Add the jar as an artifact item using the following declaration:
<plugin> <groupId>org.apache.maven.plugins</groupId> ... <artifactItems> ... <artifactItem> <groupId>com.third.party.group</groupId> <artifactId>third-party-jar</artifactId> </artifactItem> ... </artifactItems> ... </plugin>
Rebuild
extensions/ext-cortex-webapp
usingmvn clean install
, and run the Cortex Webapp.
Adding non-OSGi Compliant Jars
Occasionally you will have to add non-OSGi compliant jars to Cortex to support additional functionality. This section details strategies for using non-OSGi compliant bundles in an OSGi environment.
Finding an OSGi Compliant Version of the Jar
In general, this is the preferred method for handing non-OSGi compliant jars, and should be used whenever possible. Find an OSGi compliant version of the third party jar. There are sources to finding it, such as the central Maven repository.
Wrap the jar using bndtools
If there is no OSGi compliant version of the jar you require, you can create an OSGi compliant jar using bndtools wrap
command.
You can download bndtools here:
The wrap
command takes an existing jar, guesses the right headers for the jar’s manifest, and creates a new OSGi bundle jar.
To wrap an existing jar, run the following from the command line:
bnd wrap osgi.jar *.jar
Use OSGi Framework Properties
By using Cortex’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. In general, this method should only be used if the above methods did not work.
The OSGi framework properties we need to modify are:
org.osgi.framework.bootdelegation
Allows you 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 you 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’s OSGi framework:
With a text editor, open
ext-cortex-webapp/src/main/resources/spring/applicationContext.xml
Add the third party jar to the
org.osgi.framework.bootdelegation
list inext-cortex-webapp applicationContext.xml
file... <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, 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>
Add the third party jar to the
org.osgi.framework.system.packages.extra
list inext-cortex-webapp applicationContext.xml
file... <bean name="osgiFrameworkProperties" class="java.util.HashMap"> <constructor-arg> <map> ... <entry key="org.osgi.framework.system.packages.extra" value=" javax.inject;version=1.0, javax.jms;version=1.1.1, javax.validation;version=1.1.0, javax.validation.bootstrap, javax.validation.constraints, javax.validation.groups, javax.validation.metadata;version=1.1.0, javax.validation.spi, javax.servlet;javax.servlet.descriptor;javax.servlet.http;version=3.0, javax.servlet.annotation;version=3.0, sun.misc, org.w3c.dom.traversal, org.w3c.dom.ranges, org.slf4j;org.slf4j.spi;org.slf4j.helpers;version=1.7.12 "/> ... </bean>
Add the jar artifact as a dependency in
ext-cortex-webapp
's pom.xml file:<dependencies> ... <dependency> <groupId>com.third.party.group</groupId> <artifactId>third-party-jar</artifactId> <version>1.0.0</version> </dependency> ... </dependencies>
Rebuild
ext-cortex-webapp
usingmvn clean install
, and run the Cortex Webapp.
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.