How to use Ivy to manage your OSGi bundle dependen

Intro

This tutorial provides an example of how to setup your OSGi project and manage your bundle dependencies using Ant and Ivy. The code and config samples are based on a Eclipse RCP project, but should apply equally to any OSGi project. php

The main problem with using Ivy with OSGi bundles, at the time of writing this tutorial, is that many open source project don't ship up-to-date bundles (there are a few exceptions, such as SLF4J). Also, Ivy piggy-backs off Maven repos, which do contain some bundles, but it is still a bit ad-hoc and incomplete. html

Another problem is when building an Eclipe RCP application, if you want to create your own Target Platform, you either dump all the RCP SDK bundles into a directory, or you copy them over individually by hand. Both of these methods can be fine for one-off projects, but if you have many projects on the go, each with different dependencies, it all starts to get a bit messy. spring

This tutorial doesn't go into the detail of how to compile your bundle with Ant, it is assumed you are either using the Eclipse PDE or have already rolled your own build script. apache

Ant, Ivy and Bundles

The tutorial application will use the following project layout. Thecoyote-bundleandroadrunner-bundleare provided as stubs for the main project implementation, and outside the scope of this tutorial. app

Thelibdirectory is used to contain the Antlib-build.xml, which manages the external bundle dependencies for the project. This script is intended as a utility script that will be imported by the two project bundles, rather than being a standalone build script. eclipse

  • acme-project
    • coyote-bundle/
      • build.xml
      • ivy.xml
      • ...
    • roadrunner-bundle/
      • build.xml
      • ivy.xml
      • ...
    • lib/
      • bundles/
      • lib-build.xml
      • ivysettings.xml

To add Ivy support, thelib-build.xmlcontains the following targets. maven

<!-- Provide relative access the lib and bundles dirs from the bundle build scripts. --> <property name="lib.dir" value="${basedir}/../lib"/> <property name="bundles.dir" value="${basedir}/../lib/bundles"/> <!-- Initialize Ivy with our project-wide settings file. --> <target name="lib-init">     <ivy:settings file="${lib.dir}/ivysettings.xml" /> </target> <target name="lib-install-bundles" depends="lib-init">     <mkdir dir="${bundles.dir}"/>     <!-- Load and resolve the ivy dependencies. -->     <ivy:resolve file="${basedir}/ivy.xml"/>     <!-- Retrieve the dependencies -->     <ivy:retrieve pattern="${bundles.dir}/[artifact]-[revision].[ext]" /> </target>

When new bundle dependencies are added to theivy.xmlfile, thelib-install-bundlestarget is used to build theacme-project/lib/bundlesdirectory. This directory can also be used as the root directory for a Target Platform, when developing with the Eclipse PDE. ide

This is where things start to get a little tricky. Ivy was not really intended to be used for OSGi bundles, because it doesn't support introspection of the bundle meta-data to determine external dependencies. flex

Thankfully, the Ivy tool is very flexible and transparent, and can fairly easily be made to support bundle dependencies. This is also made easier by the great work done on the SpringSource Enterprise Bundle Repository, where many common open source projects are provided as bundles, and with Ivy<dependency/>snippets to add to yourivy.xmlfiles. ui

The following shows the content of theivysettings.xmlfile, foracme-project, which uses the Spring framework, and other dependencies provided by the SpringSource repo.

<ivysettings>     <property name="local-cache.dir" value="/workspace/osgi/ivy/local-cache" />     <property name="spring-repo.url" value="http://repository.springsource.com/ivy/bundles" />         <!-- Create a local cache of any downloads, and never delete them. -->     <caches default="localcache">         <cache name="localcache" basedir="${local-cache.dir}">             <ttl duration="0d" />         </cache>     </caches>         <resolvers>         <!-- Build a chain on resolvers, each one is tried in order. -->         <chain name="default" returnFirst="true">             <!-- First try our local cache -->             <filesystem name="local-cache-repo">                 <ivy pattern="${local-cache.dir}/[organisation]/[module]/ivy-[revision].xml" />                 <artifact pattern="${ivy-repo.dir}/[organisation]/[module]/[artifact]-[revision].[ext]" />             </filesystem>                         <!-- Then try  -->             <url name="spring-release-repo">                 <ivy pattern="${spring-repo.url}/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />                 <artifact pattern="${spring-repo.url}/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />             </url>                         <url name="spring-external-repo">                 <ivy pattern="${spring-repo.url}/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />                 <artifact pattern="${spring-repo.url}/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />             </url>         </chain>     </resolvers> </ivysettings>

Finally, we can declare our project dependencies and Ivy can start to do its thing. Here is the content of theivy.xmlfile for thecoyote-bundle:

<ivy-module>     <info organisation="acme" module="${module.name}" />     <dependencies>                 <dependency org="org.apache.commons" name="com.springsource.org.apache.commons.logging" rev="1.1.1"/>         <dependency org="org.apache.log4j" name="com.springsource.org.apache.log4j" rev="1.2.15"/>         <dependency org="org.aopalliance" name="com.springsource.org.aopalliance" rev="1.0.0" />         <dependency org="org.springframework" name="org.springframework.beans" rev="2.5.5.A"/>         <dependency org="org.springframework" name="org.springframework.context" rev="2.5.5.A"/>         <dependency org="org.springframework" name="org.springframework.context.support" rev="2.5.5.A"/>         <dependency org="org.springframework" name="org.springframework.core" rev="2.5.5.A"/>         <dependency org="org.springframework" name="org.springframework.aop" rev="2.5.5.A" />         <dependency org="org.springframework.osgi" name="org.springframework.osgi.core" rev="1.1.0"/>         <dependency org="org.springframework.osgi" name="org.springframework.osgi.extender" rev="1.1.0"/>         <dependency org="org.springframework.osgi" name="org.springframework.osgi.io" rev="1.1.0"/>     </dependencies> </ivy-module>

As you can see in the above, thecoyote-bundlenow has the dependencies required to create a bundle using Spring. As powerful as Spring is, you are still probably going to need more external dependencies if you are building a 'real world' application, especially if it's based on Eclipse RCP.

At this time, there is no Ivy repo that contains up-to-date Eclipse RCP bundles (well, certainly any that I know of). So, as mentioned in the Intro, the options are to download the RCP SDK and dump all the files into theacme-project/lib/bundles, or copy them by hand if you prefer to be a little more precise.

相關文章
相關標籤/搜索