How to add library dependencies to your OSGi bundle app
Nearly all apps require functionality provided by third party libraries to do things like parse JSON, make HTTP requests, or do high-performance mathematical computations. This guide will explain how to add your library dependencies to your app.
Important: Do not depend on Cytoscape's third party libraries. Cytoscape's core bundles depend on third party libraries and are included with Cytoscape. You may find that your app also happens to depend on the same libraries. Your app should not depend on Cytoscape's third party libraries. Your app ought to include the library in its bundle even if the same library is provided by Cytoscape. Cytoscape's third party libraries are part of its implementation. These libraries could change in minor version updates of Cytoscape and would break your app.
Configuring your Maven pom file
We'll assume that you are using Maven to build your app and that you are listing all third party library dependencies (along with Cytoscape API dependencies) in your Maven pom file.
Tell maven-bundle-plugin to embed your dependencies
Configure maven-build-plugin (shown below) so that it embeds your dependencies with your bundle jar. By embedding, the dependencies will be included in your bundle jar in tact. This is different from shading, which combines jars into one single jar file.
<build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>2.3.7</version> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName> <Bundle-Version>${project.version}</Bundle-Version> <Bundle-Name>${bundle.name}</Bundle-Name> <Private-Package>${bundle.namespace}.internal.*,${bundle.namespace}.impl.*</Private-Package> <Export-Package>${bundle.namespace}</Export-Package> <Bundle-Activator>${bundle.namespace}.internal.CyActivator</Bundle-Activator> <Embed-Dependency>*;scope=!provided|test;groupId=!org.cytoscape</Embed-Dependency> <Embed-Transitive>true</Embed-Transitive> <Import-Package>*;resolution:=optional</Import-Package> </instructions> </configuration> </plugin> </plugins> </build>
The most important lines are the Embed-Dependency, Embed-Transitive, and Import-Package directives.
Update the scope for Cytoscape & OSGi API dependencies
Set the scope to provided for all Cytoscape and OSGi API dependencies, like so:
<dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> <version>4.2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.cytoscape</groupId> <artifactId>service-api</artifactId> <version>${cytoscape.api.version}</version> <scope>provided</scope> </dependency>
This will tell the maven-bundle-plugin to not include the Cytoscape and OSGi API dependencies with your bundle jar. Your app won't obviously need them when loaded with Cytoscape.
Mark your third party library dependencies as optional
Mark your third party library dependencies as optional, like so:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>com.springsource.org.apache.commons.httpclient</artifactId> <version>3.1.0</version> <optional>true</optional> </dependency>
This tells OSGi that packages needed by transitive dependencies do not need to be fulfilled for your app to work.
At this point you should be able to run mvn clean install successfully and get an OSGi bundle app with your third party library dependencies included.
Tips
Ensure that library dependencies were included
After building your app, you can see if all the libraries you expect were included by running this command:
unzip -l target/MyApp.jar | grep jar
This command will print out the names of all libraries included in your app.
Debugging your app
If your app won't load in Cytoscape, you should see first if the issue is OSGi related. To do so:
- Run Cytoscape from the command line.
After Cytoscape has started, the command line will have an OSGi prompt. Run the osgi:list command. This will print out all bundles and their ID numbers. If your app bundle's status is Active, that means OSGi was successfully able to load your app.
If OSGi could not load your app, try reloading it: osgi:reload <id-number>. This will print an error message explaining the underlying problem.
Try the osgi:headers <id-number> command. This will print out a list of all packages your app expects and whether the package requirement was met.