blob: 324ecb0570f2066a9aac2e32883983cd366a18b1 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<html>
<head>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<script type="text/javascript">var xookiConfig = {level: 1};</script>
<script type="text/javascript" src="../xooki/xooki.js"></script>
</head>
<body>
<textarea id="xooki-source">
This page is a description of how OSGi&#153; dependencies are mapped into Apache Ivy&#153; ones
<u>Goal:</u> the purpose of this mapping is to transform an OSGi manifest into an ivy.xml, so Ivy can understand OSGi bundles and resolve them. We don't want to do the reverse here.
<h2>Bundle Symbolic name / Ivy organisation and module</h2>
In OSGi a bundle is identified by its symbolic name. In Ivy there is a notion of organisation and module name.
The choosen mapping is:
<ul>
<li>The organisation is "bundle" (transitive dependencies like pakages or services have their own organisations, "package" and "service")</li>
<li>The module name is the symbolic name</li>
</ul>
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Bundle-SymbolicName: com.acme.product.plugin</tt> </td>
<td>
<code type="xml">
<info organisation="bundle" module="com.acme.product.plugin" />
</code>
</td>
</tr>
</table>
<h2>Version and version range</h2>
The OSGi specification is defining a version as a composition of 3 numbers and an arbitrary qualifier. This fit well into the lazy definition of Ivy. We will just have to use a special latest strategy in Ivy.
Then about version range, Ivy will understand correctly fully defined range as <tt>[1.2.3,1.4.9)</tt> or <tt>(1.2.3,1.4.9]</tt>. But for OSGi version range defined as in <tt>1.2.3</tt>, it has to be transformed into <tt>[1.2.3,)</tt>
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Bundle-Version: 3.3.3</tt> </td>
<td> <tt>revision="3.3.3"</tt> </td>
</tr>
<tr>
<td><tt>Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1"</tt> </td>
<td>
<code type="xml">
<dependency org="bundle" name="com.acme.product.plugin" rev="[3.2.1,)" />
</code>
</td>
</tr>
</table>
<h2>Ivy configurations</h2>
The Ivy configuration is a notion that doesn't exist explicitely in OSGi, but some notion of the latter can be expressed with that configurations.
First the mapping is defining three configurations:
<ul>
<li><tt>default</tt> : it will contain every required dependency (transitively)</li>
<li><tt>optional</tt> : it will contain every optional dependency and every required depedency the the first degree dependencies.</li>
<li><tt>transitive-optional</tt> : it will contain every optional dependency (optional transitively)</li>
</ul>
Then there will be some configurations used for the <tt>use</tt> parameter of the <tt>Import-Package</tt> OSGi manifest header. All of these kinds of configuration have their names starting with "use_". See in the next section.
<h2>OSGi capabilities</h2>
Generally speaking, declaring capabilities in an ivy.xml is useless (in the scope of this mapping which is to transform an OSGi manifest into an ivy.xml and not the reverse). In the resolve process we want to find the bundle which have the capability matching the expected requirement. In Ivy, if we are about to get the ivy.xml of a module, we are getting the bundle so we already have reached the requirement.
So OSGi capabilities of bundles in a repo will be gathered direclty from the manifests to passed directly to the Ivy resolver, no need to express them into ivy.xml, except for the Export-Package, see the next section.
<h3>Export-Package</h3>
Exported package are declaring capabilities of the bundle in term of package. But they also declare dependencies between the declared package via the parameter <tt>use</tt>. These dependencies have to be declared in the ivy.xml. And we will use Ivy configurations for that.
First, each exported package will be declared in the ivy.xml as a configuration. The name of the configuration will start will <tt>use_</tt> and will finished with the name of that package.
Then each time an exported package is declared to use some other one, it will be mapped as a dependency between the Ivy configurations coresponding to those packages.
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Export-Package: com.acme.product.plugin.utils</tt> </td>
<td>
<code type="xml">
<configuration name="use_com.acme.product.plugin.utils" extends="default" />
</code>
</td>
</tr>
<tr>
<td> <tt>Export-Package: com.acme.product.plugin.utils,com.acme.product.plugin.common;use:=com.acme.product.plugin.utils</tt> </td> <td>
<code type="xml">
<configuration name="use_com.acme.product.plugin.utils" extends="default" />
<configuration name="use_com.acme.product.plugin.common" extends="default,use_com.acme.product.plugin.utils" />
</code>
</td>
</tr>
</table>
<h2>OSGi Requirements / Ivy dependencies</h2>
In OSGi there are different kind of dependencies, which is an OSGi bundle repository documentation is called a "requirement". The problem is that Ivy is understanding only one kind of requirement, so we use here some extra attribute to declare those different kind of dependency.
<h3>Require-Bundle</h3>
The OSGi <tt>Require-Bundle</tt> is some a requirement directly on a specific bundle. Ivy does it too. So we just use the <tt>osgi="bundle"</tt> extra attribute.
If there is the OSGi <tt>resolution</tt> parameter specified to <tt>optional</tt>, then the dependency will be declared in the configuration <tt>optional</tt> and <tt>transitive-optional</tt>. Otherwise it will be declared in the <tt>default</tt> configuration.
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1"</tt>
</td>
<td>
<code type="xml">
<dependency osgi="bundle" org="" name="com.acme.product.plugin" rev="[3.2.1,)" conf="default->default" />
</code>
</td>
</tr>
<tr>
<td> <tt>Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1";resolution:="optional"</tt> </td>
<td>
<code type="xml">
<dependency org="bundle" name="com.acme.product.plugin" rev="[3.2.1,)" conf="optional->default;transitive-optional->transitive-optional" />
</code>
</td>
</tr>
</table>
<h3>Import-Package</h3>
The OSGi <tt>Import-Package</tt> is some a requirement on a package of a bundle. Ivy has no notion of package. So we will use the <tt>osgi="pkg"</tt> extra attribute.
If there is the OSGi <tt>resolution</tt> parameter specified to <tt>optional</tt>, then the dependency will be declared in the configuration <tt>optional</tt> and <tt>transitive-optional</tt>. Otherwise it will be declared in the <tt>default</tt> configuration.
As it is an import package the configuration of the dependency will be the <tt>use_XXX</tt> one. So that transitive dependency via the use parameter will be respected in the dependency.
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Import-Package: com.acme.product.plugin.utils;version="3.2.1"</tt>
</td>
<td>
<code type="xml">
<dependency org="package" name="com.acme.product.plugin.utils" rev="[3.2.1,)" conf="default->default;use_com.acme.product.plugin.utils->use_com.acme.product.plugin.utils" />
</code>
</td>
</tr>
<tr>
<td> <tt>Import-Package: com.acme.product.plugin.utils;version="3.2.1";resolution:="optional"</tt> </td>
<td>
<code type="xml">
<dependency org="package" name="com.acme.product.plugin.utils" rev="[3.2.1,)" conf="optional->default;transitive-optional->transitive-optional;use_com.acme.product.plugin.utils->use_com.acme.product.plugin.utils" />
</code>
</td>
</tr>
</table>
<h2>Execution environment</h2>
The OSGi <tt>Bundle-RequiredExecutionEnvironment</tt> manifest attribute is specifing is which environment the bundle is expected to run. In our problematic of dependency management it means that some of the transitive dependencies won't be resolved within the OSGi space but will be provided by the JRE. So we have to exclude from the dependency tree every requirement that will be provided by the environment. Basically it will be about excluding the packaged declared in the JRE.
<table border="1" cellspacing="1" cellpadding="4">
<tr>
<td> <b>OSGi</b> </td>
<td> <b>Ivy</b> </td>
</tr>
<tr>
<td> <tt>Bundle-RequiredExecutionEnvironment: JavaSE-1.6</tt> </td>
<td>
<code type="xml">
<dependencies>
<exclude org="package" module="javax.accessibility" />
<exclude org="package" module="javax.activation" />
<exclude org="package" module="javax.activity" />
...
</dependencies>
</code>
</td>
</tr>
</table>
<h2>Bundle Fragment</h2>
Ivy doesn't support the header <tt>Fragment-Host</tt>.
The work around is to manually specify as dependencies in the ivy.xml the bundles which would fit to be the extensions of the host bundle.
</textarea>
<script type="text/javascript">xooki.postProcess();</script>
</body>
</html>