Tuning OSGi metadata

In most circumstances, the cordapp-cpk plugin correctly generates the OSGi metadata. However, the cordapp-cpk plugin also extends Gradle’s jar task with an osgi block. This can be used to tune the OSGi metadata.

The cordapp-cpk plugin automatically adds these dependencies to the CorDapp:

compileOnly "biz.aQute.bnd:biz.aQute.bnd.annotation:$bndVersion"
compileOnly "org.osgi:osgi.annotation:7.0.0"

These annotations control how Bnd will generate OSGi metadata for the main .jar file. In practice, the plugin already tries to handle the typical cases for creating CorDapps.

Package exports

The cordapp-cpk plugin creates a Bnd -exportcontents command to generate the main .jar file’s OSGi Export-Package header. By default, it will automatically add every package inside the main .jar file to this -exportcontents command. The assumption here is that a CorDapp will not have a complicated package structure, and that Corda’s OSGi sandboxes will provide additional CorDapp isolation anyway.

CorDapp developers who wish to configure their package exports more precisely can disable this default behaviour from the jar task:

tasks.named('jar', Jar) {
    osgi {
        autoExport = false
    }
}

You can then apply @org.osgi.annotation.bundle.Export annotations to selected package-info.java files.

You can also export package names explicitly, although applying @Export annotations would still be better:

tasks.named('jar', Jar) {
    osgi {
        exportPackage 'com.example.cordapp', 'com.example.cordapp.foo'
    }
}

Package imports

Normally, Bnd generates the correct OSGi Import-Package manifest header automatically. Occasionally, Bnd will notice unexpected package references from unused code-paths within the byte-code.

The cordapp-cpk plugin provides the following options to override the detected package settings:

tasks.named('jar', Jar) {
    osgi {
        // Declares that this CorDapp requires the OSGi framework to provide the 'com.example.cordapp' package.
        // This value is passed straight through to Bnd.
        importPackage 'com.example.cordapp'

        // Declares that this CorDapp uses the 'com.example.cordapp.foo' package.
        // However, Corda will not complain if no one provides it at runtime. This
        // assumes that the missing package isn't really required at all.
        optionalImport 'com.example.cordapp.foo'

        // Like `optionalImport`, except that it also assigns this package an empty
        // version range. This is useful when the unused package doesn't have a version
        // range of its own because it does not belong to another OSGi bundle.
        suppressImportVersion 'com.example.cordapp.bar'
    }
}

ServiceLoader

Bundles that use java.util.ServiceLoader require special handling to support their META-INF/services/ files. Bnd provides @ServiceProvider and @ServiceConsumer annotations to ensure that the bundle respects OSGi’s Service Loader Mediator Specification .

Corda metadata

The plugin will generate the following tags in the “main” .jar’s MANIFEST.MF by default:

  • Corda-Contract-Classes
  • Corda-Flow-Classes
  • Corda-MappedSchema-Classes
  • Corda-Service-Classes

Each tag contains a list of the classes within the .jar file that have been identified as being a Corda contract, a Corda flow, and so on. Each of these classes has also been confirmed as being public, static and non-abstract, which allows Corda to instantiate them. Empty tags are excluded from the final manifest, and so not every tag is guaranteed to be present.

The plugin generates these lists using Bnd’s ${classes} macro. However, R3 may also need to update these macros as Corda evolves, and would prefer not to need to update the cordapp-cpk plugin at the same time. R3 can therefore update the macros by modifying the net/corda/cordapp/cordapp-configuration.properties file inside the net.corda.cordapp.cordapp-configuration Gradle plugin, and then developers can apply this new plugin to the CorDapps’s root project. (The cordapp-configuration plugin is part of the Corda repository, and new versions of it will be released as part of Corda, of course.) Any property key inside this file that matches Corda-*-Classes defines a filter to generate a new manifest tag (or replace an existing tag). For example:

Corda-Contract-Classes=IMPLEMENTS;net.corda.v10.ledger.contracts.Contract

The cordapp-cpk plugin will append additional clauses to each filter to ensure that it still only selects public static non-abstract classes, since we don’t expect this requirement to change.

Dynamic imports

The .cpk needs to declare imports for these packages so that OSGi can create lazy proxies for any JPA entities the bundle may contain:

  • org.hibernate.proxy
  • javaassist.util.proxy

R3 must also allow the bundle to import this package, which contains Hibernate-specific annotations:

  • org.hibernate.annotations

R3 declares all these packages as dynamic imports to avoid binding the .cpk to a specific version of Hibernate, which should make it easier for Corda itself to evolve without breaking everyone’s CorDapps. (Future versions of Hibernate are also likely not to use Javassist.)

The plugin will declare these packages using the OSGI DynamicImport-Package header.

If necessary, R3 can update these package names via the cordapp-configuration.properties file by adding a comma-separated list to the Required-Packages key:

Required-Packages=org.foo,org.bar

Was this page helpful?

Thanks for your feedback!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.

We're sorry this page wasn't helpful. Let us know how we can make it better!

Chat with us

Chat with us on our #docs channel on slack. You can also join a lot of other slack channels there and have access to 1-on-1 communication with members of the R3 team and the online community.

Create an issue

Create a new GitHub issue in this repository - submit technical feedback, draw attention to a potential documentation bug, or share ideas for improvement and general feedback.

Propose documentation improvements directly

Help us to improve the docs by contributing directly. It's simple - just fork this repository and raise a PR of your own - R3's Technical Writers will review it and apply the relevant suggestions.