////
   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

     https://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.
////

= OSGi mapping

This page is a description of how OSGi(TM) dependencies are mapped into Apache Ivy(TM) ones

*Goal:* 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.


== Bundle Symbolic name / Ivy organisation and module


In OSGi a bundle is identified by its symbolic name. In Ivy there is a notion of organisation and module name.

The chosen mapping is:


* The organisation is "bundle" (transitive dependencies like packages or services have their own organisations, "package" and "service") +

* The module name is the symbolic name +



[]
|=======
| *OSGi* | *Ivy*
| `Bundle-SymbolicName: com.acme.product.plugin`
a|
[source, xml]
----
<info organisation="bundle" module="com.acme.product.plugin"/>
----

|=======



== Version and version range


The OSGi specification defines a version as a composition of 3 numbers and an arbitrary qualifier. This fits well into the lazy definition of Ivy. We will just have to use a special latest strategy in Ivy.

When it comes to version ranges, Ivy will correctly understand fully defined range as `[1.2.3,1.4.9)` or `(1.2.3,1.4.9]`. But for OSGi version range defined as `1.2.3`, it has to be transformed into `[1.2.3,)`


[]
|=======
| *OSGi* | *Ivy*
| `Bundle-Version: 3.3.3` | `revision="3.3.3"`
|`Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1"`
a|
[source, xml]
----
<dependency org="bundle" name="com.acme.product.plugin" rev="[3.2.1,)"/>
----


|=======



== Ivy configurations


Ivy has the concept of link:../terminology{outfilesuffix}#configurations[module configurations]. OSGi on the other hand, doesn't have such a concept. However, Ivy defines the following configurations, when it comes to dependency mapping for OSGi:


    * `default` : it will contain every required dependency (transitively)

    * `optional` : it will contain every optional dependency and every required dependency the the first degree dependencies.

    * `transitive-optional` : it will contain every optional dependency (optional transitively)


Additionally, Ivy defines some more configurations while dealing with the `use` parameter of the `Import-Package` OSGi manifest header. All of these kinds of configuration have their names starting with `use_`.


== OSGi capabilities


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 bundles 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 directly from the manifests passed directly to the Ivy resolver, no need to express them into ivy.xml, except for the Export-Package, see the next section.


=== Export-Package


Exported packages are declaring capabilities of the bundle in term of packages. But they also declare dependencies between the declared package via the parameter `use`. These dependencies have to be declared in the ivy.xml. And we will use Ivy link:../terminology{outfilesuffix}#configurations[module 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 `use_` and will end 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 corresponding to those packages.


[]
|=======
| *OSGi* | *Ivy*
| `Export-Package: com.acme.product.plugin.utils`
a|
[source, xml]
----
<configuration name="use_com.acme.product.plugin.utils" extends="default"/>
----


| `Export-Package: com.acme.product.plugin.utils,com.acme.product.plugin.common;use:=com.acme.product.plugin.utils`
a|
[source, 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"/>
----


|=======



== OSGi Requirements / Ivy dependencies


In OSGi there are different kinds of dependencies, which in an OSGi bundle repository documentation is called a "requirement". The problem is that Ivy understands only one kind of requirement, so we use here some extra attributes to declare those different kinds of dependencies.


=== Require-Bundle


The OSGi `Require-Bundle` is a requirement directly on a specific bundle. To map that, Ivy will just use the `osgi="bundle"` link:../concept{outfilesuffix}#extra[extra attribute].

If there is the OSGi `resolution` parameter specified to `optional`, then the dependency will be declared in the configuration `optional` and `transitive-optional`. Otherwise it will be declared in the `default` configuration.


[]
|=======
| *OSGi* | *Ivy*
| `Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1"`
a|
[source, xml]
----
<dependency osgi="bundle" org="" name="com.acme.product.plugin" rev="[3.2.1,)" conf="default->default"/>
----


| `Require-Bundle: com.acme.product.plugin;bundle-version="3.2.1";resolution:="optional"`
a|
[source, xml]
----
<dependency org="bundle" name="com.acme.product.plugin" rev="[3.2.1,)" conf="optional->default;transitive-optional->transitive-optional"/>
----


|=======



=== Import-Package


The OSGi `Import-Package` is a requirement on a package of a bundle. Ivy has no notion of package. So we will use the `osgi="pkg"` link:../concept{outfilesuffix}#extra[extra attribute].

If there is the OSGi `resolution` parameter specified to `optional`, then the dependency will be declared in the configuration `optional` and `transitive-optional`. Otherwise it will be declared in the `default` configuration.

As it is an import package, the configuration of the dependency will be the `use_XXX` one. This way, the transitive dependency via the `use` parameter will be respected in the dependency.


[]
|=======
| *OSGi* | *Ivy*
| `Import-Package: com.acme.product.plugin.utils;version="3.2.1"`
a|
[source, 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"/>
----


| `Import-Package: com.acme.product.plugin.utils;version="3.2.1";resolution:="optional"`
a|
[source, 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"/>
----


|=======



== Execution environment


The OSGi `Bundle-RequiredExecutionEnvironment` manifest attribute specifies which environment the bundle is expected to run. What that means in terms of dependency management is that some of the transitive dependencies won't be resolved within the OSGi space but will be provided by the JRE. While mapping this, Ivy will exclude from the dependency tree every requirement that will be provided by the environment.


[]
|=======
| *OSGi* | *Ivy*
| `Bundle-RequiredExecutionEnvironment: JavaSE-1.6`
a|
[source, xml]
----

<dependencies>
    <exclude org="package" module="javax.accessibility"/>
    <exclude org="package" module="javax.activation"/>
    <exclude org="package" module="javax.activity"/>
    ...
</dependencies>

----


|=======



== Bundle Fragment


Ivy doesn't support the header `Fragment-Host`.

The workaround is to manually specify, as dependencies in the ivy.xml, the bundles which would fit to be the extensions of the host bundle.
