bnd is the Swiss army knife of OSGi, it is used for creating and working with OSGi bundles. Its primary goal is take the pain out of developing bundles. With OSGi you are forced to provide additional metadata in the JAR's manifest to verify the consistency of your "class path". This metadata must be closely aligned with the class files in the bundle and the policies that a company has about versioning. Maintaining this metdata is an error prone chore because many aspects are redundant.
bnd's raison d'etre is therefore to remove the chores and use the redundancy to create the manifest from the class files instead of maintaining it by hand. The core task is therefore to analyze the class files and find any dependencies. These dependencies are then merged with ''instructions'' supplied by the user. For example, adding a version to all imported packages from a specific library can be specified as:
Import-Package: com.library.*; version = 1.21
The OSGi manifest must explicitly mention a package, bnd allows the use of wildcards. bnd contains many more such conveniences. bnd roots are about 10 years old and bnd has therefore a large number of functions that remove such chores. These range from simplifying the use of OSGi Declarative Services, working with Spring and Blueprint, WAR and WAB files, version analysis, project dependencies, and much more.
Over time bnd started to appear in many different incarnations. It is an an ant task, a command line utility, and a bundle for Eclipse. Other projects have used bndlib to create a maven plugin, bndtools and Sigil both Eclipse IDEs, and others. By keeping the core library small and uncoupled (bnd has no external connections except Java 5), it is easy to embed the functionality in other projects.
1.1Workflow
Traditionally, JAR files were made with the JDK jar tool, the jar ant task, or the Maven packager. All these tools share the same concept. The developer creates a directory image of the jar by copying files to a directory; this directory is then jarred. This model can be called the ''push'' model. Obviously this method works well.
bnd works differently, it uses the ''pull'' model. Instructions in the bnd file describe the contents of the desired JAR file without writing this structure to disk. The contents from the output can come from the class path or from anywhere in the file system. For example, the following instruction includes the designated packages in the JAR:
Private-Package: com.example.*
bnd can create a JAR from packages the sources, directories or other JAR files. You never have to copy files around, the instructions that Bnd receives are sufficient to retrieve the files from their original location, preprocessing or filtering when required.
The Jar is constructed from 3 different arguments:
Export-Package
Private-Package
Include-Resource
Private-Package and Export-Package contain ''instructions''. Instructions are patterns + attributes and directives, looking like normal OSGi attributes and directives. For example:
Export-Package: com.acme.*;version=1.2
Each instruction is applied to each package on the classpath in the definition order. That is, if an earlier instruction matches, the later instruction never gets a chance to do its work. If an instruction matches its attributes and properties are applied to the packages. The difference between the Private-Package argument and the Export-Package arguments is that the export version selects the packages for export. If the packages overlap between the two, the export wins.
An instruction can also be negative when it starts with a '!'. In that case the package is excluded from the selection. For example:
Note that the instructions are applied in order. If the ! instruction was at the end in the previous example, it would not have done its work because the com.acme.* would already have matched.
The Include-Resource argument can be used to copy resources from the file system in the JAR. This is useful for licenses, images, etc. The instructions in the argument can be a directory, a file, or an inline JAR. The default JAR path is the the root for a directory or the filename for a file. The path can be overridden. Instructions that are enclosed in curly braces, like {license.txt}, are pre-processed, expanding any macros in the file.
Once the JAR is created, the bnd program analyzes the classes and creates an import list with all the packages that are not contained in the jar but which are referred to. This import list is matched against the Import-Package instructions. Normally, the Import-Package argument is *; all referred packages will be imported. However, sometimes it is necessary to ignore an import or provide attributes on the import statement. For example, make the import optional or discard the import:
The arguments to bnd are normal given as a set of properties. Properties that begin with an upper case are copied to the manifest (possibly after processing). Lower case properties are used for macro variables but are not set as headers in the manifest.
After the JAR is created, the bnd program will verify the result. This will check the resulting manifest in painstaking detail.
The bnd program works on a higher level then traditional jarring; this might take some getting used to. However, it is much more elegant to think in packages than that it is to think in files. The fact that bnd understand the semantics of a bundle allows it to detect many errors and allows bundles to be created with almost no special information.
bnd will not create an output file if none of the resources is newer than an existing output file.
The program is available in several forms: command line, ant task, maven plugin, and an Eclipse plugin.
1.2Tips
There are some common pitfalls that can be prevented by following the tips:
Keep it simple. bnd's defaults are pretty good and not specifying is usually the best solution. KISS!
Think packages ... yes it feels redundant to specify the packages that are in your source directory but your artifact will get a life of its own over time. Many IDEs and build tools restricted us to one artifact per project but bnd allows many artifacts, allowing the choice of granularity to you. As OSGi's packages can be easily refactored you can design the contents of your artifacts depending on the deployment needs. Think packages!
Private is always better than export, only use export when you absolute need it.
Not versioning an exported package is at your own peril. Sorry, that is false, it is at the peril of your users.
Do not use the Bundle-ClassPath, if you need to include whole JARs, see the @ option at Include-Resource
If you do not understand a header, remove it
If you have a problem, make an example that is as small as possible and send it to<EMAIL_ADDRESS>2Download
TODO download/install instructions
2.1Where bnd is Used
bnd is already used by several different projects.
Assume we need to create a bundle in Eclipse. Each Java project in Eclipse has a set of sources and a class path. bnd therefore knows, about all the classes. However, it does not know how you want to structure your JARs/Bundles. It therefore needs a description file, the ''bnd file''. If you create such a file, you should give it the same as name as the bundle symbolic name with a .bnd extension. For example aQute.example.bnd is a well chosen name. If the name is not bnd.bnd, the file name without the .bnd extension is the default for your bundle symbolic name.
Lets build a bundle for the aQute OSGi tutorial Chat example. This bundle has 2 packages.
aQute.service.channel
aQute.tutorial.chat
The aQute.service.channel package must be exported and the other package may remain private. All packages that are referred from the source code must be imported. To achieve this, the following manifest will suffice:
You can run the same command from the command line
$ bnd aQute.tutorial.chat.bnd
Now take a look at the JAR file's manifest. With the command line version of you can do this with bnd aQute.tutorial.chat.jar. Otherwise just open the JAR with WinZip.
As you can see, bnd filled in a number of headers. The first header, Manifest-Version is required by the JAR standard. Bundle-Name is derived from the Bundle-SymbolicName because we did not specify it. The Private-Package header specifies the packages that ended up not exported. The Import-Package header comes from the packages that were referred to from the contained packages (private and exported). As you can see, bnd picked up versions for the imported packages. These versions come from the manifest of the JARs that source these packages, or from the packageinfo file. The Export-Package shows the export of the service package. On top of this, bnd has verified that all your headers really match the OSGi specifications, or you will get errors and warnings.
4Overview
5Projects
5.1Project Properties
There are a number of built in properties that are set by bnd:
||!Property name ||!Description ||
||project||Name of the project. This is the name of the bnd file without the .bnd extension. If this name is bnd.bnd, then the directory name is used. ||
||project.file||Absolute path of the main bnd file. ||
||project.name||Just the name part of the file path ||
||project.dir||The absolute path of the directory in which the bnd file resides. ||
5.2Run instructions
Run instructions are used to start OSGi tests and OSGi runs.
Instructions
Argument
Description
(:cellnr:)-runbundles
LIST SPEC
Additional bundles that will be installed and started when the framework is launched. This property is normally part of the project's bnd.bnd file.
(:cellnr:)-runvm
PROPERTIES
Properties given to the VM before launching. This property is normally set in the cnf/build.bnd file and only in rare cases overridden in the bnd.bnd file.
(:cellnr:)-runproperties
PROPERTIES
Properties given to the framework when launching. Usually project specific.
(:cellnr:)-runsystempackages
PACKAGES
A declaration like Import-Package that specifies additional system packages to import from the class path. Usually given in the cnf/build.bnd file.
(:cellnr:)-runpath
LIST SPEC
A path description of artifacts that must be on the classpath of the to be launched framework. Usually given in the cnf/build.bnd file. This path should contain the framework. Any packages that a bundle on the -runpath should specify should be listed in the export attribute.
(:cellnr:)-runtrace
true|'''false'''
Trace the startup of the framework to the console. Usually used during testing and development so project specific.
(:cellnr:)-runframework
none|'''services'''
NONE indicates that a mini built in framework should be used. SERVICES indicates that the META-INF/services model must be followed for the org.osgi.framework.launch.FrameworkFactory class. Project specific.
(:cellnr:)-testpath
LIST SPEC
A path used to specify the test plugin
(:tableend:)
5.3Launching
Launching is needed when the project's run action or test action is executed. The project creates a Project Launcher. A Project Launcher must launch a new VM and set up this VM correctly. The VM is launched with the following information.
java - The command to launch a new VM is bu default java. However, this can be overridden by setting a property called java.
classpath - The classpath set for the VM is derived from the -runpath property. Notice that this is supposed to contain the JAR with the framework. The -runpath requires bundle symbolic names for the JAR and an optional version range. bnd will use the latest version in the repository. Any packages that should be exported by the system bundle should have an export attribute containing the exported packages, like `junit.osgi;version=3.8;export="junit.framework;version=3.8,junit.misc;version=3.8".
vm options - These options can be set in the -runvm property. They are usually in the form of -Dxya=15 or -X:agent=bla. Options should be separated by commas.
main - The class implementing the main type is defined by the launcher plugin.
Debugging launching is greatly simplified with the -runtrace property set to true. This provides a lot of feedback what the launcher is doing.
>Access to arguments
When the launcher is ready it will register itself as a service with the following properties:
||launcher.arguments||The command line arguments||
||launcher.ready||Indicating the launcher is read||
>Access to main thread
In certain cases it is necessary to grab the main thread after launching. The default launcher will launch all the bundles and then wait for any of those bundles to register a Runnable service with a service property main.thread=true. If such service is registered, the launcher will call the run method and exit when this method returns.
>Timeout
The launcher will timeout after an hour. There is currently no way to override this timeout.
>Mini Framework
The bnd launcher contains a mini framework that implements the bare bones of an OSGi framework. The purpose of this mini framework is to allow tests and runs that want to launch their own framework. A launch that wants to take advantage of this can launch with the following property:
-runframework: none
>Ant
In ant, the following task provides the run facility.
These targets provide commands for ant run.
5.4Testing
Testing is in principle the same as launching, it actually uses the launcher. Testing commences with the test action in the project. This creates a Project Tester. bnd carries a default Project Tester but this can be overridden.
The basic model of the default Project Tester plugin is to look for bundles that have a Test-Cases manifest header after launching. The value of this header is a comma separated list of JUnit test case class names. For example:
Test-Cases: test.LaunchTest, test.OtherTest
Maintaining this list can be cumbersome and for that reason the ${classes} macro can be used to calculate its contents:
See [classes macro][Macros#classes] for more information.
>Ant
5.5Overriding the plugins
Both the Project launcher and Project Tester are plugins. Defaults are provided by bnd itself (bnd carries a mini cache repo that is expanded in the cnf director), it is possible to add new launchers and testers as needed.
Plugins are found on the -runpath or the -testpath properties respectively. bnd will look for an appropriate manifest header. The header has a class name as value. It will then instantiate the class and use as launcher/tester. The classes must extend an abstract base class. Each plugin has access to the Project object, containing all the details of the project.
||Plugin ||Manifest header||Base Class||Where||
||Project Launcher ||Launcher-Plugin||ProjectLauncher||-runpath||
||Project Test ||Tester-Plugin||ProjectLauncher||-testpath||
The plugin gets complete control and can implement many different strategies.
6Building Jars
7Versioning
Requires 1.15
Versioning is probably the most painful part of developing real software. Where toys and prototypes can be developed ignoring evolution, real software requires a migration path to an unknown future.
The OSGi has defined a versioning policy that is described in the [Semantic Versioning whitepaper][http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf]. bnd fully supports this model and provides many shortcuts. The goal of bnd is remove any manual work from versioning bundles as well as packages.
The key concept to version in OSGi is the ''package''. Bundles are an ''aggregate'' and therefore must move as fast as the fastest moving exported packages they contain. For example, if a bundle contains two exported packages foo and bar and foo is not changed but bar has a major change, then the bundle version needs to also have a major change. This requires an unnecessary update for a bundle that only depended on foo. Aggregating dependencies increases the fan out of the transitive dependencies. The result is that systems can only evolve when everything is updated simultaneously. The result is that the system as a whole becomes brittle.
In contrast, versioning the packages and using Import-Package, bundles can be refactored and versioned independently.
7.1Best Practices
Version on packages, not on bundles
Create a packageinfo file with "version 1.0" in each package directory and maintain it meticuously for each change to the package. Any change that breaks consumers, increment major. Changes that break providers (if any), increment minor. Other changes micro. bnd will then properly version this package when exported
If you provide an API (as defined in te Semantic Versioning whitepaper) export the API package even if it is not in your project and put the provide:=true directive on the package export, e.g. Export-Package: org.osgi.service.event; provide:=true.
Every time when you release a bundle to the external world, bump the minor part of the bundle version. For internal development releases, bump the micro part of the bundle version.
7.2Versions in OSGi
A version in OSGi has 4 parts:
major 1
minor 1.1
micro 1.1.1
qualifier 1.1.1.qualifier
To survive versioning, one must have a ''version policy''. A version policy puts semantics on the version numbers. The ''recommended'' policy in OSGi is changing the part when there is:
major a breaking change
minor a backward compatible changes
micro a bug fix (no API change)
qualifier a new build
In OSGi, the decision was taken to have a single export version. The import statement allows a version range to be set. For example:
The semantic versioning white paper introduces two terms that are orthogonal to the imports and exports as well as implementing or delegating:
Provide an API - Provide the functionality defined in an API
Consume an API - Consume the functionality defined in an API
Provide and consume is orthogonal to implementing an interface and delegating. For example, the Configuration Admin service has the ConfigurationAdmin interface that is implemented by the Provider of an API but the ConfigurationListener interface is implemented by the Consumer of the API.
The reason for the providers and consumer terms is that version policies are different. A change in an API almost always affects the provider but with careful API design it is often possible to make a change backward compatible for consumers.
7.3Versioning Packages
If you have a package that is containing implementation code that is supposed to be directly used by the consumers then this is a ''library''.
A library package is not an API that can be implemented by other bundles, it is the implementation. Then the versioning of library packages is relatively straightforward: Any change that breaks a consumer of that package must increment the major version number. For example, if the popular ASM library would add a method to the MethodVisitor class then it must increment the major version number of the org.objectweb.asm package because all existing consumers of this library would then be broken.
If however a package contains an API that is provided and consumed by others the situation is more complex. In such a case, the provider should export the API package and the consumers should import it.
bnd explicitly allows the inclusion of packages that come from other projects. It is just good practice to include an API package in your bundle if you are the provider of that API. However, this means that maintaining the version of the package in the manifest is ''wrong'', it would have to be maintained in several places, which is very error prone.
For this reason, bnd provides a way to store the version of the package together with the package itself. One with annotations and one without when annotations are not possible.
The @Version annotation is placed on the package. Since Java 5 it is possible to create a package-info.java file that can be used to annotate packages:
A non-annotation based alternative is the packageinfo file. When bnd scans the Java archives it will look in each package for this packageinfo file. The format of this file is very simple:
packageinfo:
version 1.2.0.v${workspace}/cnf
In either case, the value for the version may contain macros.
If you now export the package (from any bundle that has the package on its class path), it will be properly versioned.
If you export a a package from another bundle, bnd will also look in the manifest of that other bundle for a version.
Using packageinfo (or the @Version annotation) is highly recommended.
7.4Import Version Policy
If you import a package bnd will look at the exported version of that package. This version is not directly suitable for the import because it is usually too specific, it needs a policy to convert this export version to an import version.
An importer that provides the functionality of an API package is much closer tied to that package than a client. The whitepaper recommends binding to the major.minor part of the version for a provider. That is, any change in the minor part of the version breaks the compatibility. This makes sense, the provider of an API must implement the contract and is therefore not backward compatible for any change in the API. A consumer of the API only has to be bound to the major part because it is much more relaxed for the backward compatibility.
For example, a new method is added to an interface that is implemented by the provider of the API. Old clients have no visibility of this method because when they compiled it did not exist. However, the provider of the API must be modified to implement this method otherwise more modern clients would break.
This asymmetry creates the need for two version policies:
The given values are the defaults. The value of the version policy will be used calculate the import based on the exported package. The [${range}][Macros#range] macro provides a convenient shortcut to do this using a version mask.
For example, a bundle that implements the OSGi Event Admin service can use the following bnd file:
How does bnd know if a bundle is a provider or a consumer of a specific package? Well, the default is the consumer policy but this can be overridden with the provide:=true directive that works on the Import-Package clauses as well as on the Export-Package clauses.
The provide: directive indicates to bnd that the given package contains API that is provided by this bundle. The (strongly) recommended way is to put the provide:=true directive on the Export-Package header, even if the package comes from another bundle. This way the bundle contains a copy of the package that is by default imported with the proper provider policy range.
For example, an implementation of the OSGi Event Admin specification could use the following bnd file:
If for some reason it is not desirable to export the API package in the implementation bundle, then the provide: directive can also be applied on the Import-Package header:
A key aspect of OSGi is that a package can be both imported and exported. The reason is that this feature allows a framework more leeway during resolving without creating multiple unconnected class spaces.
After the bundle has been created and analyzed bnd will see if an exported package is eligible for import. An export is automatically imported when the following are true:
There exists at least one reference to the exported package from a private package
The exported package has no references to any private packages
The exported package does not have a -noimport: directive.
If a package is imported it will use the version as defined by the version policy.
7.6Versioning Bundles
Versioning bundles usually requires bumping the version every time it is placed in a repository. When package versioning is used, the bundle version is only important for tracking an artifact.
! Baselining
Requires 2.2.0
Baselining compares the public API of a bundle with the public API of another bundle. It can be run from the command line (see bnd help baseline) or always after a project is build. For a project, the previous version of a bundle is found in the ''baseline repository'', this is called the ''baseline''.
APIs are compared for backward compatibility using the semantic versioning rules defined in this chapter. Baselining is aware of the @ConsumerType and @ProviderType rules. Proper versions are calculated and suggested.
It is possible to baseline a project with the following instructions:
||-baseline||PARAMETERS||The parameters specify glob patterns matched agains the bsns. The version attribute can indicate a version. A project is only baselined if the name of the parameter matches and an appropriate version can be found in the baseline repo or the the release repo||
||-baselinerepo||Repo name||The repository that must be used for baselining||
||-releaserepo||Repo name||Repository to use when no -baselinerepo is specified.||
>Example baselining Project Instructions
Bundle-Version: 1.0.2
-baseline: *
-baselinerepository: Released
In this example, the last version in the Released repository for the project's bsn is supposed to be the previous version. Make sure you do not always release snapshot versions to this repository since this will create false changes. During a development cycle, the baseline version must remain constant until the current development bundle is released, at which points it becomes the baseline of the next cycle.
Since an error is raised when the baselining detects an semantic version violation it is possible to release a snapshot in a build only when there is a correctly baselined bundle built.
8Service Components
''Version 1.42''
The Service-Component header is compatible with the standard OSGi header syntax. Any element in the list that does not have attributes must have a resource in the JAR and is copied as is to the manifest. However, simple components can also be defined inline, and it is even possible to pickup annotations.
reference ::= '='
( '(' ')')? cardinality?
cardinality ::= '?' | '' | '+' | '~'
provide ::= 'provide:=' LIST
multiple ::= 'multiple:=' LIST
optional ::= 'optional:=' LIST
dynamic ::= 'dynamic:=' LIST
designate ::= ( 'designate' | 'designateFactory' ) CLASS
factory ::= 'factory:=' true | false
servicefactory := 'servicefactory:=' true | false
immediate ::= 'immediate:=' true | false
enabled ::= 'enabled:=' true | false
configuration-policy ::= "configuration-policy:='
( 'optional' | 'require' | 'ignore' )
activate ::= 'activate:=' METHOD
modified ::= 'modified:=' METHOD
deactivate::= 'deactivate:=' METHOD
implementation::= 'implementation:='
properties::= 'properties:=' key '=' value [=\=]
( ',' key '=' value ) *
key ::= NAME (( '@' | ':' ) type )?
value ::= value ( '|' value )
If the name of the component maps to a resource, or ends in XML, or there are attributes set, then that clause is copied to the output Service-Component header.
If the name can be expanded to one or more classes that have component annotations (they must be inside the JAR), then each of those classes is analyzed for its component annotations. These annotations are then merged with the attributes from the header, where the header attributes override annotations. The expansion uses the normal wildcard rules. For example, biz.aQute.components.* will search for component annotated classes in the biz.aQute.components package or one of its descendants. The classes must be present in the JAR. If no classes with annotations can be found for the name then it is assumed to be name or implementation class name without annotations.
The name of the component is also the implementation class (unless overridden by the implementation: directive). It is then followed with a number of references and directives. A reference defines a name that can be used with the locateService method from the ComponentContext class. If the name starts with a lower case character, it is assume to be a bean property. In that case the reference is augmented with a set<Name> and unset<Name> method according to the standard bean rules. Bnd will interpret the header, read the annotations if possible, and create the corresponding resources in the output jar under the name OSGI-INF/<id>.xml.
Annotations are only recognized on the component class, super classes are not inspected for the components.
The supported annotations in the aQute.bnd.annotations.component package are:
||!Component||
Annotated the class, indicates this class is required to be a component. It has the following properties:
|| provide||Class[]||Service interfaces, the default is all directly implemented interfaces||
||name ||String||Name of the component||
||factory ||Boolean||Factory component||
||servicefactory||Boolean||Service Factory||
||immediate||Boolean||Immediate activation||
||designate||CLASS||Designate a class as a [[MetaType]] interface used for configurations for unitary configurations, see [[#metatype]]. This changes the default of the configurationPolicy to require.||
||designateFactory||CLASS||Designate a class as a [[MetaType]] interface used for configurations for factory configurations, see [[#metatype]]. This changes the default of the configurationPolicy to require.||
||configurationPolicy||OPTIONAL, REQUIRE, IGNORE||Configuration Policy||
||enabled||Boolean||Enabled component||
||properties||String[]||Properties specified as an array of key=value. The property type can be specified in the key as name:Integer. The value can contain multiple values, the parts must then be separated by a vertical bar ('|') or a line feed (\n), for example properties = {"primes:Integer==1|2|3|5|7|11"}.||
||!Reference||
On a method. Indicates this method is the activate method. It has the following attributes
||name||String||Name of the reference. Default this is the name of the method without set on it.||
||service||Class||The service type, default is the argument type of the method. The unset method is derived from this name. I.e. setXX will have an unsetXX method to unset the reference.||
||type||Character||Standard cardinality type '?', '*', '+','~'||
||target||String||A filter expression applied to the properties of the target service||
||unbind||String||Optional name of the unbind method. By default this is the same name as the bind method name but with set/add replaced with unset/remove. E.g. setFoo() bind method becomes unsetFoo() unbind method.||
@Reference automatically sets the bind method. The unbind method is set by using a derived name from the bind method or providing it with the name of the unbind method. The following name patterns are supported:
||!bind||!unbind||
||setX ||unsetX||
||addX ||removeX||
||xxxX ||unxxxX||
For example:
@Reference
protected void setFoo(LogService l) { ... }
protected void unsetFoo(LogService l) { ... }
If you want to override this, use
@Reference(unbind="IRefuseToCallMyMethodUnFoo");
protected void foo(LogService l) {}
protected void IRefuseToCallMyMethodUnFoo(LogService l) {}
Unfortunately Java has no method references so it is not type safe.A non existent @UnReference annotation is not very useful because that still requires linking it up symbolically to the associated @Reference.
||!Activate, Modified, and Deactivate||
The life cycle methods. These annotations have no properties.
The Service Component Runtime (SCR) offers a variety of options on the reference. Some options like the target can be used by adding the target filter after the interface name (this likely requires putting quotes around the interface name+filter).
References can be suffixed with the following characters to indicate their cardinality:
The previous example will result in the following service component in the resource OSGI-INF/aQute.tutorial.component.World.xml:
The description also supports the immediate, enabled, factory, target, servicefactory, configuration-policy, activate, deactivate, and modified attributes. Refer to the Declarative Services definition for their semantics.
If any feature of the V1.1 namespace is used, then bnd will declare the namespace in the component element. A specific namespace version can be set with the version directive. This detection only works when components are used.
Bnd also supports setting the policy and cardinality through the following directives:
multiple:= LIST names of references that have x..n
optional:= LIST names of references that have 0..x
dynamic:= LIST names of references that are dynamic
8.1Components and Metatype
The Service Component Runtime works closely together with the Configuration Admin to allow the components to be controlled through configuration. Configuration Admin knows two types of configuration:
Unitary
Factory
A unitary configuration can be set and changed but there is at most one of them. A Factory configuration can be used to create multiple instances of the same component. A component has a configuration policy that defines when no configuration is set.
optional - If no configuration is set (either unitary or factory) then the component is still created.
require - This requires a unitary configuration to be set or one or more factory configurations before a component is created.
ignore - Ignore configuration information
A related standard is the Metatype standard. The Metatype Service provides a repository of property descriptors. Bundles can provide these descriptors in their bundles in the OSGI-INF/metatype directory. There are tools, like the [Felix Webconsole][http://felix.apache.org/site/apache-felix-web-console.html], that can provide an editing window for a configuration that is typed with a metatype description.
In practice, this is a powerful model that provides a lot of configurability for your components with easy editing but getting it all right is not trivial. To make this easier, bnd has made it ease to use configurations.
In this model, configurations are declared in an interface. For example, the following interface defines a simple message:
interface Config {
String message(); // message to give
}
To create a component that can work with this config, we need to designate that interface as the configuration interface for a component.
@Component(designate=Config.class)
public class BasicComponent {
Config config;
This is an immediate component because it does not implement a service interface. It also requires a configuration because we have not specified this explicitly. When you use designate (or designateFactory) the default becomes require. This means that your component will only be created when there is actually configuration for it set.
To run this component, make sure you have the Felix Webconsole running and the MetaType service installed. In the Webconsole, you can click on
'''Configuration''', your component should be listed on this page. By Clicking on the component with the name '''Basic Component Config''' you get an editor window.
The editor is aware of the proper types, it uses the [[MetaType]] standard to describe the properties. bnd uses the type information on the interface as well as the optional Metadata annotations to create a rich description that allows the web console to provide a good editor.
You can fill in the message in the ''Message'' field. If you save the editor, your component prints the message with "Hi" in front of it. Deleting the configuration will print the message with "Bye".
If you change the message, you will see that the component is first deactivated and then reactivated again. This is the only possibility for the SCR because the component has not implemented a modified method. Adding the following method will change this, now changes to the configuration are signaled to the component and the component can continue to work. This is more complicated then recycling the component but it can create a more optimized system.
It is also possible to take advantage of the configuration factories. In this model
An example, that implements a simple socket server on a configurable port and returns a message when a telnet session is opened to that port can be found on [Github][https://github.com/bnd/aQute/blob/master/aQute.metatype/src/aQute/metatype/components/ServerSocketComponent.java].
9Metatype
''Version 1.42''
The OSGi Metatype specification provides a language to describe configuration information in an XML file. However, XML is cumbersome to use and eXtreMeLy error prone, and refactoring often finds it hard to change references in XML text files. Especially with DS components managing the relations can be complex, see [[Components]]
For this reason, bnd provides annotations to define the XML based on a ''configuration'' interface. For example, the following interface defines a simple metatype:
To turn this into an XML file, the bnd file must contain:
-metatype: *
The wild card will search through the whole bundle but it is possible to limit this to a restricted set of packages to speed up the processing. For example:
-metatype: Metatype, com.libs.metatypes
If the previous Config interface is present in the output, the output will also contain an XML file at OSGI-INF/metatype/com.acme.Config.xml. This file will look as follows:
bnd leverages the rich type information the Java class files contain. It inspects the returns types and from this it automatically calculates the AD type as well as the cardinality. For example, a method like:
bnd attempts to make the names of the OCD and AD human readable by un-camel-casing the id. This means that it uses the upper cases in the id to decide where to use spaces. It also attempts to replace '_' characters with spaces and removes '$'. If the result is not what is wanted, the name can always be explicitly set with the AD.name() field.
The id of the properties is by default derived from the method name. The name space of methods is restricted by the Java language both in character set as well as by the reserved keywords. Therefore, bnd mangles the name of the method to allow the method name to be adapted to common practices in proeprty names.
'$' is removed from the name unless it is followed by another '$', in that case it is a single '$'. This can be used to use Java keywords as a name. For example, $new maps to the new name. To make the name $x, use a method with the name $$x.
'' is replaced with '.' unless it is followed by another '', in that case it becomes a single '_'. This is useful for dotted names (a.b.c comes from a_b_c) and to indicate private properties, that is properties that start with a '.'. For example, _secret maps to .secret and this will be a property that is not registered as a service.
For example:
@OCD
interface Config {
String _password(); // .password - will not be registered as a service
String $new(); // new - keyword
}
<EMAIL_ADDRESS>The OCD annotation is necessary to know that an interface is a Metatype interface. It should be used preferably without any parameters (they all have good defaults). However, each default is possible to override. The following table discusses the fields:
||name||String||A human readable name of the component, can be localized if it starts with a % sign. The default is a string derived from the id where _, $, or camel casing is used to provide spaces.||
||id||String||The id of the OCD, this will also be used for the pid of the Designate element.||
||localization||String||The localization id of the metatype. This refers to a properties file in the OSGI-INF/i10l/.properties file that can be augmented with locale information.||
||description||String||A human readable description that can be localized. Default is empty.||
||factory||String||Will treat this OCD as intended to be for a factory configuration. The default is false||
<EMAIL_ADDRESS>The AD is an optional annotation on methods of a OCD interface. The annotation makes it possible to override the defaults and provide extra information.
||name||String||A human readable name of the attribute, can be localized if it starts with a % sign. The default is a string derived from the method name where , $, or camel casing is used to provide spaces.||
||id||String||The id of the attribute. By default this is the name of the method||
||description||String||A human readable description that can be localized. Default is empty.||
||type||String||The type of the attribute. This must be one of the types defined in the Metatype specification. By default the type will be derived from the return type of the method. If no applicable type can be found then the String type is used as final default.||
||cardinality||int||The cardinality of the attribute. If this is negative its absolute indicates maximum number of elements in a Vector. If it is positive it indicates the maximum number of values in an array. Zero indicates a scalar. If not provided, bnd will calculate the cardinality based on the return type. Collections will have a negative large value and arrays have a positive large value.||
||min||String||The minimum value allowed for this attribute. There is no default.||
||max||String||The maximum value allowed for this attribute. There is no default.||
||deflt||String||The default initial value. The default for this is an empty String||
||required||boolean||Indicates if this attribute is required. The default is that attributes are required.||
||optionLabels||String[]||Labels for any values specified in optionValues. The default value is unset if there are no optionValues are defined. If these are defined, then the labels are calculated from the values by making , $ into spaces and providing spaces between camel cased words in the values.||
||optionValues||String[]||Optional values. If this field is not set and the return type is an enum type then the values are calculated from the enum members.||
9.4Runtime conversions
The type support the OSGi Metatype specification is limited to the primitives and strings. So what happens when you use another type? During the build phase, bnd will revert to a 'String' Metatype type. This means that those special types are going to be strings in the dictionary. However, the aQute.bnd.annotation.metatype package contains a helper class that simplifies the usage of properties in runtime. It has a @createConfigurable(Class c, Map,?> props)`. This method returns an object that implements the given configuration interface. The implementation of these methods uses the properties to provide a value. That is, calling the method abc() on this interface will attempt to find the property "abc". It will then use the actual return type of the method to do conversion from the type in the properties to the return type. This takes generic information into account when present.
For example:
@Meta.OCD
interface Config {
URI[] uris();
}
public void updated( Map props) {
config = Configurable.createConfigurable(Config.class,props);
for ( URI URI : config.uris() ) {
...
}
}
The Metatype specification does not support URIs, so how does this work? Lets first look at the AD:
Any editor will therefore put an array of strings (String[]) in the properties. When the proxy gets the string, it will therefore have to convert from the String[] -> URI[]. In this case, the URI has a String constructor and is used to do the conversion from String to URI. The converter can handle general array to collection, collection to array, and as indicated, any conversion to an object that has a String constructor.
For convenience there are a number of built int conversions provided that cannot leverage the String constructor:
Pattern - Allows regular expression to be set
Class> - Tries to load a class through the class loader of the configuration interface
boolean - Converts wrappers and primitive boolean to 0 (false) or non-0 (true) and vice versa.
Numbers - Converts any known Number subclass to another Number subclass, including the primitive types.
Enums - If the return type is an enum, it will use the valueOf method to get an instance.
9.5Example
The following example shows a very simple metatype configuration interface:
package aQute.metatype.samples;
import aQute.bnd.annotation.metatype.Meta.*;
@OCD
public interface Config {
int port();
}
If the bnd.bnd file contains:
-metatype: *
Then bnd will detect this class as a Metatype and it generates the following XML in `OSGi-INF/metatype/aQute.metatype.samples.Config.xml
localization='aQute.metatype.samples.Config'>
As usual, XML does an outstanding job in obfuscating the interesting parts. If you're using the Apache Felix Webconsole (and if not, why not?) then you can edit this metatype on the web:
The editor can get quite rich with the metatype information. For example:
http://www.aqute.biz/uploads/Bnd/complex.png
This information came from the following Meta interface:
interface SampleConfig {
String _secret();
String $new();
String name();
enum X { A, B, C; }
X x();
int birthYear();
URI uri();
URI[] uris();
Collection curis();
Collection ints(); // fails on webconsole
}
Though this is a big savings over normal fudging with properties, it gets better. The metatyping is fully integrated with DS. In this example, we're using DS to register the Managed Service but this is not necessary because DS will automatically use the name of a component as the PID. So with a component life can be as easy as:
No more strings. Components and metatypes are extensively explained in [[Components]].
10Contracts
11Launcher
bnd integrates an OSGi launcher. This launcher will start a framework and then install and start a list of bundles. The launching environment is described with a number of instructions that start with -run.
-runfw — Specify the run framework in repository format
-runsystemcapabilities —
-runbundles — A list of bundles to install in repository format
-runvm — VM options. Use a comma to separate different options. E.g. -Dx=4, -Dy=5.
-runproperties — System properties for the framework to create
-runpath — A list of jars (not required to be bundles) that are put on the classpath and available from the system bundle. Any Export-Package headers are exported.
-runsystempackages — An Export-Package list for packages exported by the system bundle.
12Testing
This section describes how bnd implements a pluggable testing framework. With most tools that use bnd this information is hidden behind a pleasant GUI (sometimes). However, in certain cases it is necessary to understand how bnd handles testing.
12.1Model
In the classic way testing consists of launching a new VM, dynamically loading the classes to be tested and then running the test framework on those. As this violates module boundaries as if they did not exist there is another way.
In bnd there is a header that allows a bundle to define what tests it contains:
Test-Cases ::= fqn+
Such a bundle therefore exports a number of test cases to the environment. These test cases can then be executed by the tester. The default tester in bnd is the biz.aQute.junit bundle, but this can be overridden because the launcher and the tester are pluggable.
The default tester can run in ''one shot'' mode or in ''automatic'' mode. The one shot mode is used in build tools to fire a test and parse the result. In this mode, the build tool provides the class names to test.
In automatic mode, the default tester creates a list of available bundles with test cases and executes all of them. Automatic mode can then end or it can run in continuous mode. Every time a bundle is started it will run the tests again. Continuous mode is intended for developing test bundles. You just run a framework and edit your test bundle's code. Any changes are saved and deployed, triggering the tests.
12.2Framework Properties for the Default Tester
The default tester uses the project information to parametrize the tester's runtime component. However, it is also possible to set these runtime parameters explicitly with framework properties when you want to run the framework in automatic mode. The default tester obeys the following framework properties:
||!Property||!Default||!Description||
||tester.port||-||The port to send the JUnit information to in a format defined by Eclipse. If this property is not set, no information is send but tests are still run.||
||tester.host||localhost|| The host to send the JUnit information to in a formatted defined by Eclipse. If this property is not set localhost is assumed.||
||tester.names||||Fully qualified names of classes to test. If this property is null automatic mode is chosen, otherwise these classes are going to be tested and then the test ends.||
||tester.dir||testdir||A directory to put the test reports. If the directory does not exist, no reports are generated. The default is testdir in the default directory. This directory is not automatically created so to see the results it is necessary to ensure such a directory exists. the files in the test directory are usable in Hudson/Jenkins as test reports||
||tester.continuous||false||In automatic mode, no tester.names set, continue watching the bundles and re-run a bundle's tests when it is started.||
||tester.trace||false||Trace the test framework in detail. Default is false, must be set to true or false.||
12.3How to set the Test-Cases Macro Automatically
The Test-Cases macro can be set by hand but this can become a maintenance nightmare. A very useful macro is the ${classes} macro. This macro inspects the JAR and can find all classes that are considered test cases:
The example setup creates a bundle containing the org.example.tests package and sets the Test-Cases header to all testcases in that package. If you run this setup, it runs the project bundle with the biz.aQute.junit bundle. This tester bundle is parametrized with the tester.* properties to have trace on, test continuous, and put the test reports in ./testdir.
You can find a bndtools project that shows this at [Github][https://github.com/bnd/aQute/tree/master/aQute.testing].
12.5Other Tester Frameworks
The biz.aQute.junit is a normal bundle that gets started from the launcher framework. However, before bnd chooses the default tester, it scans the classpath of the launcher (set with -runpath) for JARs that have the following header set:
Tester-Plugin ::= fqn
The Tester-Plugin header points to a class that must extend the aQute.bnd.build.ProjectTester class. This class is loaded in the bnd environment and not in the target environment. This ProjectTester plugin then gets a chance to configure the launcher as it sees fit. It can get properties from the project and set these in the Project Launcher so they can be picked up in the target environment.
As this is a quite specific area the rest of the documentation is found in the source code.
13Error Handling
14Command Line
The command line tool can be invoked in several different ways:
bnd ''general-options'' ''cmd'' ''cmd-options''
bnd ''general-options'' ''.jar''
bnd ''general-options'' ''.bnd''
In this text bnd is used as if it is a command line program. This should be set up as:
java -jar .jar ...
Work is in progress to simplify this.
>General Options
||
||!General Option ||!Description ||
||-failok ||Same as the property -failok. The current run will create a JAR file even if there were errors. ||
||-exceptions ||Will print the exception when the software has ran into a bad exception and bails out. Normally only a message is printed. For debugging or diagnostic reasons, the exception stack trace can be very helpful. ||
The build function will assemble a bundle from the bnd specification. The default name of the output bundle is the name of the bnd file with a .jar extension.
-classpath - A list of JAR files and/or directories that should be placed on the class path before the calculation starts.
-eclipse - Parse the file as an Eclipse .classpath file, use the information to create an Eclipse's project class path. If this option is used, the default .classpath file is not read.
-noeclipse - Do not parse the .classpath file of an Eclipse project.
-output - Override the default output name of the bundle or the directory. If the output is a directory, the name will be derived from the bnd file name.
bnd buildx -classpath bin -noeclipse -output test.jar xyz.bnd
The wrap command takes an existing JAR file and guesses the manifest headers that will make this JAR useful for an OSGi Service Platform. If the output file is not overridden, the name of the input file is used with a .bar extension. The default bnd file for the header calculation is:
Export-Package: *
Import-Package:
If the target bundle has a manifest, the headers are merged with the properties.
The defaults can be overridden with a specific properties file.
-output - Set the output file or directory
-classpath - Sets the classpath as a comma separated list
-properties - Use a special property file for the manifest calculation.
-ignoremanifest - Do not include the manifest headers from the target bundle
bnd wrap -classpath osgi.jar *.jar
>eclipse
List the Eclipse information in the current directory.
bnd eclipse
[[#eclipse]]
14.1Eclipse Plugin
The bnd.jar file is a complete plugin. To install this plugin, place it in the eclipse/plugin directory (or extension directory) of your Eclipse installation and restart (!). The plugin will provides a 'Make Bundle' context menu when you select a file that ends with .bnd. Two menus are shown when you select a JAR file. You can 'Wrap JAR', turning it into a bundle with all imports and exports set (the extension will be .bar), or you can use 'Verify Bundle', and verify the bundle for compliance to the spec. Any errors or warnings are listed in a dialog box.
Additionally, the plugin registers an editor for JAR files. The editor shows the full output of the print command.
15Ant Tasks
The bnd.jar file can also be used as an ANT task. The following example shows how you can use it from an ANT file.
You can set the following attributes:
||
||!Attribute ||!Description ||
||classpath ||Comma separated list of file names. File paths are relative from the ant project file. ||
||eclipse ||True or false. True if the eclipse .classpath file should be read (default). ||
||failok ||Succeed even if there are errors. ||
||exceptions ||If errors occur, show the exception stack trace. ||
||files ||A comma separated list of bnd files ||
||sourcepath||A source path||
||output||Where the output should go||
The following tasks have also been added:
||task name||Class||attributes||
||bndeclipse||EclipseTask||prefix='project.'||
||bndexpand||ExpandPropertiesTask||propertyFile=''||
||bndwrap||WrapTask||jars='', output='', definitions='', classpath=''||
16Maven
The Maven plugin is described at [Felix maven plugin][http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html]. Defaults for Maven are:
Group ID: org.apache.felix
Artifact: maven-bundle-plugin
Other details are found at the Felix site, the plugin is independently maintained by Felix.
17Gradle
18bndtools
19Plugins
Plugins are objects that can extend the functionality of bnd. They are called from inside bnd when a certain action should take place. For example, bnd uses a repository and plugins provide the actual repository implementations. Or for example, the SpringComponent analyzes the Spring files and adds references found in that XML to the imports.
A plugin is defined as:
PLUGIN ::= FQN ( ';' )*
The following directive is defined for all plugin:
||path: ||A path to the jar file that contains the plugin. The directory/jar at that location is placed on your classpath for that plugin.||
bnd current supports the following plugin types:
/*
* An optional interface for plugins. If a plugin implements
* this interface then it can receive the remaining attributes
* and directives given in its clause as
* well as the reporter to use.
/
public interface Plugin {
/*
* Give the plugin the remaining properties.
* When a plugin is declared, the clause can contain
* extra properties. All the properties and directives
* are given to the plugin to use.
* @param map attributes and directives for this plugin's clause
/
void setProperties(Map map);
/**
* Set the current reporter. This is called at init time.
* This plugin should report all errors and warnings
* to this reporter.
* @param processor
*/
void setReporter(Reporter processor);
}
public interface AnalyzerPlugin {
/*
* This plugin is called after analysis. The plugin
* is free to modify the jar and/or change the classpath
* information (see referred, contained).
* This plugin is called after analysis of the JAR
* but before manifest generation.
*
* @param analyzer
* @return true if the classpace has been modified so that the bundle
* classpath must be reanalyzed
* @throws Exception
/
boolean analyzeJar(Analyzer analyzer) throws Exception;
}
public interface SignerPlugin {
/*
* Sign the current jar. The alias is the given certificate
* keystore.
*
* @param builder The current builder that contains the
jar to sign
* @param alias The keystore certificate alias
* @throws Exception When anything goes wrong
/
void sign(Builder builder, String alias) throws Exception;
}
public interface RepositoryPlugin {
/*
* Return a URL to a matching version of the given bundle.
*
* @param bsn
* Bundle-SymbolicName of the searched bundle
* @param range
* Version range for this bundle,"latest"
* if you only want the
* latest, or null when you want all.
* @return A list of URLs sorted on version, lowest version
* is at index 0.
* null is returned when no files with the given
* bsn ould be found.
* @throws Exception
* when anything goes wrong
/
File[] get(String bsn, String range) throws Exception;
/**
* Answer if this repository can be used to store files.
*
* @return true if writable
*/
boolean canWrite();
/**
* Put a JAR file in the repository.
*
* @param jar
* @throws Exception
*/
File put(Jar jar) throws Exception;
/**
* Return a list of bsns that are present in the repository.
*
* @param regex if not null, match against the bsn and if
* matches, return otherwise skip
* @return A list of bsns that match the regex parameter
* or all if regex is null
*/
List<String> list(String regex);
/**
* Return a list of versions.
*/
List<Version> versions(String bsn);
}
public interface MakePlugin {
/**
* This plugin is called when Include-Resource detects
* a reference to a resource that it can not find in the
* file system.
*
* @param builder The current builder
* @param source The source string (i.e. the place
* where bnd looked)
* @param arguments Any arguments on the clause in
* Include-Resource
* @return A resource or null if no resource
* could be made
* @throws Exception
*/
Resource make(Builder builder, String source,
Map<String,String> arguments) throws Exception;
}
[[#make]]
>Make
Make plugins kick in when the Include-Resource header tries to locate a resource but it cannot find that resource. The -make option defines a number of patterns that are mapped to a make instruction.
For example, if you have
Include-Resource: com.acme.Abc.ann
If no such resource is found, bnd will look in the -make instruction. This instruction associates a pattern with a plugin type. For example:
-make: (*.jar); type=xyz; abc=3; def="$1"
The first name part of the clause is matched against the unfound resource. All plugins are called sequentially until one returns non-null. The arguments on the -make clause are given as parameters to the make plugin. Normally all Make Plugins should verify the type field.
bnd has a bnd and a copy Make Plugin.
>Buildin Plugins
Some plugins are provided by bnd itself.
||aQute.lib.spring.SpringComponent||AnalyzerPlugin||This component will analyze the Spring XML for Spring DM and will add any classes in these files to the referred set of classes.||
||aQute.bnd.make.MakeBnd||MakePlugin||If Include-Resource can't find a referred resource it will use the make plugins to see if any of them can make the requested resource. The MakeBnd has type=bnd. This plugin can recursively call bnd to create embedded jars that are not created sequentially||
||aQute.bnd.make.MakeCopy||MakePlugin||Copies resources from other places in the file system||
||aQute.lib.deployer.FileRepo||RepositoryPlugin||Provides a file based repository.||
||aQute.bnd.maven.MavenRepository||RepositoryPlugin||Provides an interface to a the default maven repository in the user's home directory. Can be used with aQute.bnd.maven.MavenGroup to support converting bundle symbolic names to group and artifact id.||
20Wrapping
This is a simple example of wrapping a jar with bnd. The basic idea is to create a recipe (a .bnd file) that collects the different resources in the right way.
For example, you want to wrap the WebSocket server from https://github.com/TooTallNate/Java-WebSocket. Download the binary and the sources in Websocket.jar, Websocket-src.zip. Once you have these files, the following code will create the org.websocket bundle
21Wrapped version of Github project TooTallNate/Java-WebSocket
Bundle-SymbolicName: org.websocket
Bundle-DocURL: https://github.com/TooTallNate/Java-WebSocket
Bundle-License: https://github.com/TooTallNate/Java-WebSocket/
blob/8ef67b46ecc927d5521849dcc2d85d10f9789c20/LICENSE
Bundle-Description: This repository contains a barebones \
WebSocket server and client implementation written \
in 100% Java. The underlying classes are implemented \
using the Java ServerSocketChannel and SocketChannel \
classes, which allows for a non-blocking event-driven model \
(similar to the WebSocket API for web browsers). \
Implemented WebSocket protocol versions are: Hixie 75, \
Hixie 76, Hybi 10, and Hybi 17
The documentation headers are optional but very important, just spent the minute to document them since you'll be grateful later.
If the target project does not have a version, makeup a version and maintain it. Notice that in general the recipe will only be used once for each version, it is normally not used in continuous integration builds. However, you normally use it to convert the next version of the project. Crisp versioning is important.
The Include-Resource statement unrolls the jars we downloaded in the root of the JAR and in OSGI-OPT. Since the source code is in the src directory in the WebSocket-src.zip file, we put it in the new JAR under OSGI-OPT/src. This convention is supported by all IDEs to give you direct access to the bundle's source code. Since the binary and the source are kept together, you always have the correct source code available, and usually automatically. It is so convenient that once you're used to this it is hard to imagine a life without source code.
The binaries and sources are not in the final jar but bnd does not yet know what needs to be exported. This can be indicated with the -exportcontents instruction. It has the same syntax as Export-Package but does not copy from the classpath, it only applies the instruction to the content of the final JAR.
22.1Project
The easiest way to build these wrappers is to create a project in bndtools called wrappers and create a bnd descriptor for each one. They are then automatically build (look in generated) and you get a lot of help editing the bnd files.
You can also make an ant file but this is not described here (volunteer?). The other possibility is to use bnd from the [[CommandLine]]. In this case the command is:
bnd websocket.bnd
22.2Manifest
Applying this recipe gives the following manifest in a JAR named org.websocket.jar:
Manifest-Version: 1.0
Bnd-LastModified:<PHONE_NUMBER>969
Bundle-Description: This repository contains a barebones WebSocket serve
r and client implementation written in 100% Java. The underlying classe
s are implemented using the Java ServerSocketChannel and SocketChannel
classes, which allows for a non-blocking event-driven model (similar to
the WebSocket API for web browsers). Implemented WebSocket protocol ve
rsions are: Hixie 75, Hixie 76, Hybi 10, and Hybi 17
Bundle-DocURL: https://github.com/TooTallNate/Java-WebSocket
Bundle-License: https://github.com/TooTallNate/Java-WebSocket/blob/8ef67
b46ecc927d5521849dcc2d85d10f9789c20/LICENSE
Bundle-ManifestVersion: 2
Bundle-Name: org.websocket
Bundle-SymbolicName: org.websocket
Bundle-Version: 1.0.2
Created-By: 1.6.027 (Apple Inc.)
Export-Package: org.javawebsocket;version="1.0.2"
Include-Resource: @jar/WebSocket.jar<EMAIL_ADDRESS>Private-Package: org.javawebsocket.handshake,org.javawebsocket.drafts,
org.javawebsocket.exceptions,org.javawebsocket.util,org.java_websocke
t.framing
Tool: Bnd-1.51.0
22.3Extra entries on the Classpath
One of the great features of bnd is to use export version from other versions to generate the import ranges. This feature requires that the other JARs are on the classpath. In bndtools you can use the -buildpath. However, you always add entries on the class path per bnd descriptor with the -classpath instruction:
-classpath: dependency.jar, other.jar
23Instructions
The bnd format is very similar to the manifest. Though it is read with the Properties class, you can actually use the ':' as separator to make it look more like a manifest file. The only thing you should be aware of is that the line continuation method of the Manifest (a space as the first character on the line) is not supported. Line continuations are indicated with the backslash ('' \u005C) as the last character of the line. Lines may have any length.
The most common mistake is missing the escape. The following does not what people expect it to do:
Header: abc=def,
gih=jkl
This is actually defining 2 headers. You can fold lines by escaping the newline:
Header: abc=def, \\
gih=jkl
You can add comments with a # on the first character of the line:
# This is a comment
White spaces around the key and value are trimmed.
See [ Properties][http://java.sun.com/j2se/1.4.2/docs/api/java/util/Properties.html ] for more information about the format.
23.1Types of Instructions
There are different instructions in the properties file:
||
||!Type ||!Example ||!Description ||
||Manifest headers ||Bundle-Description: ... ||When the first character is a upper case character. These headers are copied to the manifest or augmented by bnd. ||
||Variables ||version=3.0 ||Variables are lower case headers. Headers can contain references to other headers using macro expansion. Variables are not copied to the manifest. See [Macros][#macros] ||
||Directives ||-include: deflts.bnd ||Directives start with a '-' sign. A directive is an instruction to bnd to do something special. See [Directives][#directives] ||
[[#directives]]
23.2Bnd Directives
||
||!Directive ||!Format ||!Description ||
||-classpath||[ LIST][#list ] ||Add the listed files to the current class path. The files must be addressed relative to the properties file. The files must be either a JAR file or a directory. For example:\
-classpath= acme.jar, junit.jar, bin ||
||-debug||true|false||Generate debugging information. This will save embedded jar files in the target directory when they are generated on the fly.||
||-donotcopy||[ REGEX][#regex ] ||During copying of files from the classpath, file system, or other places, this filter is used to prevent copies. For example, normally CVS and .svn directories should not be copied. The default is therefore (CVS|.svn). Example: \
-donotcopy= (CVS|.svn|.+.bak|~.+) ||
||-exportcontents||[ PATTERN][#LIST|LIST]] of [[#PATTERN ]||The content of this header augments the Export-Package header, but only for the manifest calculation. That is, Export-Package is used to calculate the contents of the JAR, but then this instruction can be used change or add instructions for the manifest generation.||
||-failok ||true | false ||In certain cases, errors should not abort the creation of the bundle. For example test cases often require the creation of an invalid JAR. If this flag is set to true, errors will create a target bundle (when possible) and errors are only listed. When failok is false, the default, any error will not create a target bundle and will delete the bundle file. Example: \
-failok= true ||
||-include ||[ LIST][#list ] ||This property will include the list of files in the given order. The files are relative from the bnd file itself. If this directive is used inside an included properties file, then the including file is the base. Includes are very useful to keep headers like Bundle-Vendor, Bundle-Copyright central. If the extension of the file is .mf, then the file is parsed as a manifest file. By default, a property defined in an include file override earlier definitions, this implies that any property in the bnd file is overridden if defined in an include file. The include files are read in the order they are listed where later files override earlier files. If there are multiple definitions for the same property, then the last definitions wins. If the path of an included file starts with a ~, then it will '''not''' override earlier set properties.\
You can use properties like /Users/aqute in file names. If the file does not exist, an error is generated. If the filename is prefixed with a '-' sign then no error is generated when the file is absent. For example: \
\
-include= ~/Users/aqute/deflts.bnd, META-INF/MANIFEST.MF\
-include= a.props, ~META-INF/MANIFEST.MF ||
||-manifest||FILE||Overrides the generation of a manifest and uses the given file instead.||
||-metatype||[Analyzes the classes in the JAR for metatype interfaces (Metadata.OCD annotation). See [[MetaType][#LIST | LIST]] of [[#PATTERN | PATTERN]]|].||
||-nomanifest||false|true||Generate a JAR without a manifest||
||-nodefaultversion||false|true||If true, do not make exported packages without a version inherit the bundle version. See [[Versioning]]||
||-nope||true|false||Do not build a bundle, deprecated use -nobundles=true||
||-nouses||true|false||Do not calculate the uses: directive.||
||-output||PATH||Store the file (if applicable) under the path||
||-plugin||[plugins][#LIST|LIST]] of [[#PLUGIN|PLUGIN]]||Define the plugins that bnd should use. A plugin is a class that is used at certain phases in the bundle generation. That place is defined by the interfaces it implements. Plugins are defined in [[#plugins].||
||-removeheaders||[LIST][#LIST] of string||Removes the given headers from the output manifest. This feature can be useful if you are wrapping a bundle and it contains for example a Require-Bundle header.||
||-snapshot||repl||Replacement for the .SNAPSHOT qualifier used in maven. If a Bundle version uses SNAPSHOT as the qualifier then bnd will replace this with whatever -snapshot is set to. For example:\
\
-snapshot:<PHONE_NUMBER>17\
\
This replaces the .SNAPSHOT qualifier with a timestamp. If -snapshot is not set the SNAPSHOT qualifier will not be replaced.||
||-sources||true|false||Include sources||
||-wab||[-wablib][#LIST|LIST]] of iclause||Turn a bundle into a Web Archive Bundle (WAB) that can also be used as a WAR, See [[#wab|-wab]] and [[#wablib]||
||-wablib||[-wablib][#LIST|LIST]] of [[#PATTERN|PATTERN]]||Turn a bundle into a Web Archive Bundle (WAB) that can also be used as a WAR, See [[#wab|-wab]] and [[#wablib]||
23.3Headers
||!Headers ||!Format ||!Description ||
||Bundle-ClassPath|| ||Defines the internal bundle class path, is taken into accont by bnd. That is, classes will be analyzed according to this path. The files/directories on the Bundle-ClassPath must be present in the bundle. Use Include-Resource to include these jars/directories in your bundle. In general you should not use Bundle-ClassPath since it makes things more complicated than necessary. Use the @ option in the Include-Resource to unroll the jars into the JAR.||
||Bundle-\\
ManifestVersion||2 ||The Bundle-ManifestVersion is always set to 2, there is no way to override this. ||
||Bundle-Name|| ||If the Bundle-Name is not set, it will default to the Bundle-SymbolicName. ||
||Bundle-\\
SymbolicName|| ||The Bundle-SymbolicName header can be set by the user. The default is the name of the main bnd file, or if the main bnd file is called bnd.bnd, it will be the name of the directory of the bnd file. An interesting variable is .name: that will be set to this default name. ||
||Bundle-Version||VERSION ||The version of the bundle. If no such header is provided, a version of 0 will be set. ||
||Conditional-Package||[PATTERN][#LIST|LIST]] of [[#PATTERN] || '''experimental''' Works as private package but will only include the packages when they are imported. When this header is used, bnd will recursively add packages that match the patterns until there are no more additions.||
||Export-Package||[See ExportPackage][#LIST | LIST]] of [[#PATTERN | PATTERN]] ||The Export-Package header lists the packages that the bundle should export, and thus contain. [[#export-package].||
||Fragment-Host|| ||Ignored by bnd||
||Import-Package||[See Import Package][#LIST | LIST]] of [[#PATTERN | PATTERN]] ||The Import-Package header lists the packages that are required by the contained packages. [[#import-package].||
||Include-Resource||[See Include Resource][#LIST|LIST]] of iclause||The Include-Resource instruction makes it possible to include arbitrary resources; it contains a list of resource paths. [[#include-resource].||
||Private-Package||[See Private Package][#LIST | LIST]] of [[#PATTERN | PATTERN]] ||The Private-Package header lists the packages that the bundle should contain but not export. [[#private-package].||
||Require-Bundle|| ||Ignored by bnd||
||Service-Component||[Service Component Header][#LIST | LIST]] of component || See [[#component].||
23.4Basic Types
||[[#list]][[#LIST]]LIST||A comma separated list. Items should be quoted with '"' if the contain commas. In general, a list item can also define attributes and directives on an item.||
||[[#pattern]][[#PATTERN]]PATTERN||A pattern matches some entity: a package, a directory, etc. Patterns are based on Java regular expressions but are preprocessed before compiled. Any dots ('.') are replaced with . to make them match the input and not act as the 'any character' operator. Any '?' or '' is prefixed with a dot to make it match any character. As an extra convenience, if the string ends with .., an additional pattern is added to match the complete string with out the ... The effect is that something like com.acme. matches com.acme and all its sub packages. It is also to negate a pattern by prefixing it with an exclamation mark ('!'). For example:\
Import-Package: !com.sun.*, * \
indicates that any imports to com.sun should not be imported.||
||[[#regex]]REGEX||A regular expressions||
[[#export-package]]
23.5Export-Package
The bnd definition allows the specification to be done using ''patterns'', a modified regular expression. All patterns in the definition are matched against every package on the [ class path][#CLASSPATH ]. If the pattern is a negating pattern (starts with !) and it is matched, then the package is completely excluded. Normal patterns cause the package to be included in the resulting bundle. Patterns can include both directives and attributes, these items will be copied to the output. The list is ordered, earlier patterns take effect before later patterns. The following examples copies everything on the class path except for packages starting with com. The default for Export-Package is "*", which can result in quite large bundles. If the source packages have an associated version (from their manifest of packageinfo file), then this version is automatically added to the clauses.
Export-Package= !com.*, *
Exports are automatically imported. This features can be disabled with a special directive on the export instruction: -noimport:=true. For example:
Bnd will automatically calculate the uses: directive. This directive is used by the OSGi framework to create a consistent class space for a bundle. The Export-Package statement allows this directive to be overridden on a package basis by specifying the directive in an Export-Package instruction.
However, in certain cases it is necessary to augment the uses clause. It is therefore possible to use the special name <<USES>> in the clause. Bnd will replace this special name with the calculated uses set. Bnd will remove any extraneous commas when the <<USES>> is empty.
Directives that are not part of the OSGi specification will give a warning unless they are prefixed with a 'x-'.
>Split packages
Bnd traverse the packages on the classpath and copies them to the output based on the instructions given by the Export-Package and Private-Package headers. This opens up for the possibility that there are multiple packages with the same name on the class path. It is better to avoid this situation because it means there is no cohesive definition of the package and it is just, eh, messy. However, there are valid cases that packages should be merged from different sources. For example, when a standard package needs to be merged with implementation code like the osgi packages sometimes (unfortunately) do. Without any extra instructions, bnd will merge multiple packages where the last one wins if the packages contain duplicate resources, but it will give a warning to notify the unwanted case of split packages.
The -split-package: directive on the Export-Package/Private-Package clause allows fine grained control over what should be done with split packages. The following values are architected:
||merge-first||Merge split packages but do not add resources that come later in the classpath. That is, the first resource wins. This is the default, although the default will generate a warning||
||merge-last||Merge split packages but overwrite resources that come earlier in the classpath. That is, the last resource wins.||
||first||Do not merge, only use the first package found||
||error||Generate an error when a split package is detected||
The method of inclusion is identical to the Export-Package header, the only difference is, is that these packages are not exported. This header will be copied to the manifest. If a package is selected by noth the export and private package headers, then the export takes precedence.
Private-Package= com.*
[[#import-package]]
23.7Import Package
The Import-Package header lists the packages that are required by the contained packages. The default for this header is "*", resulting in importing all referred packages. This header therefore rarely has to be specified. However, in certain cases there is an unwanted import. The import is caused by code that the author knows can never be reached. This import can be removed by using a negating pattern. A pattern is inserted in the import as an extra import when it contains no wildcards and there is no referral to that package. This can be used to add an import statement for a package that is not referred to by your code but is still needed, for example, because the class is loaded by name.
For example:
Import-Package: !org.apache.commons.log4j, com.acme.*,
com.foo.extra
During processing, bnd will attempt to find the exported version of imported packages. If no version or version range is specified on the import instruction, the exported version will then be used though the micro part and the qualifier are dropped. That is, when the exporter is 1.2.3.build123, then the import version will be 1.2. If a specific version (range) is specified, this will override any found version. This default an be overridden with the [-versionpolicy][#versionpolicy] command.
If an explicit version is given, then ${@} can be used to substitute the found version in a range. In those cases, the version macro can be very useful to calculate ranges or drop specific parts of the version. For example:
If an imported package uses mandatory attributes, then bnd will attempt to add those attributes to the import statement. However, in certain (bizarre!) cases this is not wanted. It is therefore possible to remove an attribute from the import clause. This is done with the -remove-attribute: directive or by setting the value of an attribute to !. The parameter of the -remove-attribute directive is an instruction and can use the standard options with !, *, ?, etc.
In the case of assignment or simple, the PATH parameter can point to a file or directory. It is also possible to use the name.ext path of a JAR file on the classpath, that is, ignoring the directory. The simple form will place the resource in the target JAR with only the file name, therefore without any path components. That is, including src/a/b.c will result in a resource b.c in the root of the target JAR.
If the PATH points to a directory, the directory name itself is not used in the target JAR path. If the resource must be placed in a subdirectory of the target jar, use the assignment form. If the file is not found, bnd will traverse the classpath to see of any entry on the classpath matches the given file name (without the directory) and use that when it matches. The inline requires a ZIP or JAR file, which will be completely expanded in the target JAR (except the manifest), unless followed with a file specification. The file specification can be a specific file in the jar or a directory followed by or . The indicates recursively and the * indicates one level. If just a directory name is given, it will mean *.
The simple and assigment forms can be encoded with curly braces, like {foo.txt}. This indicates that the file should be preprocessed (or filtered as it is sometimes called). Preprocessed files can use the same variables and macros as defined in the [macro section][#macros].
The recursive: directive indicates that directories must be recursively included.
The flatten: directive indicates that if the directories are recursively searched, the output must not create any directories. That is all resources are flattened in the output directory.
The filter: directive is an optional filter on the resources. This uses the same format as the instructions. Only the file name is verified against this instruction.
In OSGi Enterprise 4.2 the concept of Web Archive Bundles were introduced. Web Archive Bundles are 100% normal bundles following all the rules of OSGi. Their speciality is that they can be mapped to a web server following several of the rules of Java Enterprise Edition's Servlet model. The big difference is that the WARs of the servlet model have a rather strict layout of their archive because the servlet container also handles class loading. In OSGi, the class loading is very well specified and it would therefore be wrong to create special rules.
However, the OSGi supports the Bundle-Classpath header. This header allows the organization of the internal layout. It turns out that it is possible to create a valid Web Application Bundle (WAB) that is also a valid Web ARchive (WAR). Being deploy an archive both to OSGi and an application server obviously has advantages. bnd therefore supports a number of instructions that make it easy to create these dual mode archives.
The -wab instruction instructs bnd to move the root of the created archive to WEB-INF/classes. That is, you build your bundle in the normal way,not using the Bundle-ClassPath. The -wab command then moves the root of the archive so the complete class path for the bundle is no inside the WEB-INF/classes directory. It then adjusts the Bundle-ClassPath header to reflect this new location of the classes and resources.
The new root now only contains WEB-INF. In the Servlet specification, the root of the archive is mapped to the server's context URL. It is therefore often necessary to place static files in the root. For this reason, the -wab instruction has the same form as [Include-Resource][#include-resource] header, and performs the same function. However, it performs this function of copying resources from the file system after the classes and resources of the original bundle have been moved to WEB-INF.
For example, the following code creates a simple WAB/WAR:
WEB-INF/classes/com/example/impl/
WEB-INF/classes/com/example/service/myapi/
WEB-INF/classes/resources/
index.html // from static-pages
The Bundle-ClassPath is WEB-INF/classes.
WARs can carry a WEB-INF/lib directory. Any archive in this directory is mapped to the class path of the WAR. The OSGi specifications do not recognize directories with archives it is therefore necessary to list these archives also on the Bundle-ClassPath header. This is cumbersome to do by hand so the -wablib command will take a list of paths.
WEB-INF/classes/com/example/impl/
WEB-INF/classes/com/example/service/myapi/
WEB-INF/classes/resources/
WEB-INF/lib/
a.jar
b.jar
index.html ( from static-pages)
The Bundle-ClassPath is now set to WEB-INF/classes,WEB-INF/lib/a.jar,WEB-INF/lib/a.jar
24Macros
A simple macro processor is added to the header processing. Variables allow a single definition of a value, and the use of derivations. Each header is a macro that can be expanded. Notice that headers that do not start with an upper case character will not be copied to the manifest, so they can be used as working variables. Variables are expanded by enclosing the name of the variable in ${<name>} (curly braces) or ${<name>} (parenthesis). Additionally, square brackets [], angled brackets <>, double guillemets «», and single guillemets ‹› are also allowed for brackets. If brackets are nested, that is [cac] will return [cac].
There are also a number of macros that perform basic functions. All these functions have the following basic syntax:
macro ::= '${' function '}'
| '$\[' function '\]'
| '${' function '}'
| '${' function '}'
function ::= name ( ';' argument ) *
For example:
version=<IP_ADDRESS>109111023542
Bundle-Version= ${version}
Bundle-Description= This bundle has version ${version}
24.1Arguments
@Since("2.3") Macros can contain arguments. These arguments are available in the expansion as ${0} to ${9}. ${0} is the name of the macro, so the actual arguments start at 1. The name is also available as ${@}. The arguments as an array (without the name of the macro) is available as ${#}. The more traditional * could not be used because it clashes with wildcard keys, it means ALL values.
For example:
foo: Hello ${1} -> ${foo;Peter} -> "Hello Peter"
24.2Wildcarded Keys
Keys can be wildcarded. For example, if you want to set -plugin from different places, then you can set the plugin.xxx properties in different places and combine them with -plugins=.
24.3Types
@TODO
24.4Base Macros
The following macros are always available.
24.5Build Macros
>`bsn {#bsn}
Return the current Bundle Symbolic Name assumed by the code. This tries to load the current Bundle-SymblicName property, or reverts an inferred name from the file system.
local = ${bsn}
24.6Project Macros
basename;arg
arg ( ';' arg )*
Return a comma separated list with all the file names (not directory) of the arguments. Non existent files are skipped.
[[#cat]]cat
arg
If arg is a directory, return the contents of the directory. If it is a file, return the contents of the file.
[[#classes]]classes
QUERY
Provides a query function to find classes to fulfill certain criteria. See the [classes][#classesx] macro
[[#def]]def
arg
Provide the empty string if arg is not defined, otherwise it provides the value of the property arg.
[[#dir]]dir
`arg ( ';' arg ) *
Get the directory names of the arguments in a comma separated format. For example, should provide the directory path (absolute) of the directory that contains the project
[[#env]]env
; name
Provide the value of the given environment variable
[[#error]]error
arg ( ';' arg ) *
Generate an error for each arg.
[[#if]]if
; condition ; true ( ; false ) ?
If the condition is not empty, the true part is returned, else the false part is returned. If not false part is supplied, the empty string is returned. The condition is trimmed before tested. For example:
Comment: Ok
[[#isdir]]isdir
arg
Returns "true" when arg is an existing directory, otherwise "false".
[[#isfile]]isfile
arg
Returns "true" when arg is an existing file, otherwise "false".
[[#filter]]filter
';' list ';' regex
The filter macro iterates over the given list and only includes elements that match the given regular expression (regex). The following example includes only the jar files from the list: \
list= a,b,c,d,x.jar,z.jar \\
List=
[[#filterout]]filterout
; list ; regex
The filterout macro iterates over the given list and removes elements that match the given regular expression (regex). The following example strips the jar files from the list: \
Find the paths to any resources that matches the regular expression, replace the name with the replacement of the regex. Notice that the regex is only executed on the name of the resource, that is, without the slashes.
[[#findpath]]findpath
; regex [ ; replacement ]
Find the paths to any resources that matches the regular expression, replace the path with the replacement of the regex. Notice that the regex is executed on the path of the resource, that is, with the slashes.
[[#fmodified]]fmodified
; file-path-list
Return the highest modification time of the given file path. The returned value is based on the epoch of Java, it is therefore a long. \
Last-Modified: long2date;0)
[[#githead]]githead
Returns the SHA of the head. This is either HEAD or the contents of the sym-ref. \
Git-HEAD: ${githead}
2.3
[[#join]]join
( ; list ) *
Joins a number of lists into one. It may seem that this can be easily accomplished by just placing two macro expansions after each other. The result of this will not be a list, unless a ',' (colon) is placed in between. However, when one of the lists is empty, the colon will be superfluous. The join handles these cases correctly. Any number of lists may be given as arguments. \
List= a,b,c,d,e,f
[[#literal]]literal
arg
Provide a literal macro for arg. For example, ${"project"} results in ".name: ". Can be useful if information must be created for other systems that uses the macro syntax.
[[#lsa]]lsa
dir ( ';' PATTERN ( ',' PATTERN )* )?
Return the contents of the given directory filtered by the patterns. The result is a comma separated list of absolute file names.
[[#lsr]]lsr
dir ( ';' PATTERN ( ',' PATTERN )* )?
Return the contents of the given directory filtered by the patterns. The result is a comma separated list of relative file names.
[[#long2date]]long2date
; long
Parse the long and turn it into a date. \
Last-Modified: long2date:${fmodified:${files}})
[[#maven_version]]maven_version
version
Clean up a maven version so it conforms to the OSGi specification.
[[#now]]now
Returns the current Date as string. \
Created-When: Fri Dec 13 19:17:10 CET 2013
[[#osfile]]osfile
base (';' PATH )*
Return a comma separated list of absolute file paths in the current's OS' format. If the PATH is relative, it is calculated from the base directory.
[[#path]]path
LIST (';' LIST )*`
Return a platform specific path (File.pathSeparator) from the given lists.
[[#pathseparator]]pathseparator
Returns the current path separator as defined by File.pathSeparator
[[#permissions]]permissions
(all|packages|admin)+
Generates a permission file. If packages is specified, it provides PackagePermission for imports and exports. admin adds an AdminPermission, all adds them all
Create a version range from a version. The MASK is defined in [${version}][#version].
[[#replace]]replace
; list ; regex ; replacement
Replace all elements of the list that match the regular expression regex with the replacement. The replacement can use the ${0-9} back references defined in the regular expressions. The macro uses item.replaceAll(regex,replacement) method to do the replacement.For example, to add a .jar extension to all files listed, use the following: \
List = ${impls}.jar
[[#sort]]sort
; list
Sort the given list using string sorting collation. For example: \
Execute a command via System.exec and return the result as the macro's value.
[[#toclassname]]toclassname
; list
Replace a class path (with slashes and class at the end) to a class name (with dots).
[[#toclasspath]]toclasspath
; list [ ; suffix ]
Replace a class name (with dots) to a classpath (with slashes and suffix at the end). The default suffix is .class. The suffix may be empty
[[#tstamp]]tstamp
( date pattern )?
Answer a time stamp based on the pattern. The pattern is defined by the [SimpleDateFormat][http://download.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html]. The default pattern is yyyyMMddHHmm.
[[#unique]]unique
; list ( ; list ) *
Split all the given lists on their commas, combine them in one list and remove any duplicates. The ordering is not preserved, see [${sort}][#sort] For example:
${unique; 1,2,3,1,2; 1,2,4} ~ "2,4,3,1"
[[#version]]version
; mask ; version
This macro can modify a version by dropping parts from the end, incrementing parts, or decrementing parts. The mask is a string containing from 1 to 4 characters. The characters have the following meaning: \
= the actual version part \
+ increment the actual version part \
- decrement the actual version part \
For example, ${version;=+;1.2.3.q} will become 1.3.
[[#warning]]warning
arg ( ';' arg ) *
Generate a warning for each arg.
(:tableend:)
[[#classesx]]
24.7classes macro
The classes macro provides a query function in an analyzed bundle. While analyzing, the Analyzer stores each found class on the Bundle-Classpath with some key information. A simple query language is used to query this dictionary. For example, if you want to make a manifest header with all public classes in the bundle:
Public-Classes: ${classes;PUBLIC}
The query language is conjunctive, that is, all entries form an AND. For example, if you want to find all PUBLIC classes that are also not abstract you would do:
PublicConcrete-Classes: ${classes;CONCRETE}
The query can also parameters. This is a pattern that must match some aspect of the class. For example, it is possible to query for classes that extend a certain base class:
All pattern matching is based on fully qualified name and uses the globbing model.
The following table specifies what query options there are:
'''Query'''
'''Parameter'''
'''Description'''
IMPLEMENTS
PATTERN
The class must implement at least one interface that matches the given pattern. This takes inheritance into account as long as intermediates can be found the classpath
EXTENDS
PATTERN
The class must implement at least one interface that matches the given pattern. This takes inheritance into account as long as intermediates can be found the classpath.
IMPORTS
PATTERN
The class must use a type from another package that matches the given pattern
NAMED
PATTERN
The class fqn must match the given pattern.
ANY
Matches any class
VERSION
PATTERN
The class format of the given class must match the given version. The version is given as "/", like "49/0". To select classes that are Java 6, do ${classes;VERSION;49/*}
CONCRETE
Class must not be abstract
ABSTRACT
Class must be abstract
PUBLIC
Class must be public
ANNOTATION
PATTERN
The class must have an annotation that matches the pattern. The set of annotations is all annotations in the class, also the annotations on fields and methods.
(:tableend:)
>Caveat
bnd will attempt to use the resources on the classpath if a super class or interface that is referenced from an analyzed class is not in the class space. However, bnd does not require that all dependencies are available on the classpath. In such a case it is not possible to do a complete analysis. For example, if A extends B and B extends C then it can only be determined that A extends C if B can be analyzed.
25API
It is quite easy to use bnd from Java, you only need to include biz.aQute.bndlib on your class path. This chapter shows you some samples of how to use bndlib.
25.1Creating a Manifest
By default, bnd creates a container with resources and then calculates the manifest. However, these phases are separated although they use the same instructions. The following snippet therefore shows how you can create a manifest from an existing file or directory.
Analyzer analyzer = new Analyzer();
Jar bin = new Jar( new File("bin") ); // where our data is
analyzer.setJar( bin ); // give bnd the contents
// You can provide additional class path entries to allow
// bnd to pickup export version from the packageinfo file,
// Version annotation, or their manifests.
analyzer.addClasspath( new File("jar/spring.jar") );
[Why No Automatic Bundle-Activator][#automaticActivator]
[How to set the unbind method with @Reference?][#unbindMethod]
[packageinfo or package-info.java][#packageinfo]
[Why are super classes not inspected for annotations?][#supercomps]
[Where do the exported package versions come from?][#exportversions]
[Should I use the Bundle-ClassPath?][#bundleclasspath]
28.1[What Should I use instead of the Bundle-ClassPath?][#bundleclasspath2]
[[#howToAsk]]
28.2How to ask a question
You can send a mail to [mail me][http://groups.google.com/group/bndtools-users/|bndtools users]] or<EMAIL_ADDRESS>[[#tooManyImports]]
28.3Too Many Imports
Sometimes bnd reports imports that seem plain wrong. Believe me, they are almost always right. bnd does a thorough analysis of the byte codes in your class files and when it imports something it is almost sure to be a reference in your code. How can you find the culprit? [[Bndtools]] has tooling to drill down into your code. bnd also can print out the JAR and look at the [USEDBY] section to find the package(s) that cause the import.
If there is no package using the imported package, then look at the following places for imports:
Spring/Blueprint XML
Bundle Activator
Component annotations or Service-Component headers
In the likely case the import is real but unwanted, look at [Unwanted Imports][#removeUnwantedImports].
[[#importingDefaultPackage]]
28.4Importing the default package error
This usually indicates that:
You include classes that have compile errors. Some compilers still create class files on errors but they are invalid.
One of the imports caused by Spring, Blueprint, or Service Components are not proper.
[[#removeUnwantedImports]]
28.5Remove unwanted imports
If you have an unwanted import than you can remove it from the Import-Package manifest header with the '!' operator:
Import-Package: !com.unwanted.reference.*, *
A usually better way is to make the imports optional:
Note the end at the Import-Package statement, that wildcard '*' is crucial for remaining imports, see [No Imports Show Up][#noImports].
[[#noImports]]
28.6No Imports Show Up
The imports that show up in your Import-Package manifest header are controlled by the bnd file's Import-Package instruction. In bnd, the list is a set of patterns that are sequentially applied to your imports as calculated by bnd from the classes, resources, and headers in the JAR.
The default Import-Package bnd instruction is:
Import-Package: *
This imports all referred packages. The most common reasons imports do not appear in the manifest is that the default is overridden and the overrider forgot to add the wildcard '*' at the end. For example, the following is wrong:
Import-Package: com.example; version=1.2
This will create an import for com.example but it ignores all other imports.
Another reason is the exclude operator ('!') that will remove imports. If this is too wild, then no imports are left to insert in the manifest. So the following leads to no imports for any package starting with com.example.
Import-Package: !com.example.*, *
Last but not least, look at the [USEDBY] section of the JAR print out, make sure there are actually references.
[[#automaticActivator]]
28.7Why No Automatic Bundle-Activator
Many people are surprised that bnd does not automatically calculate the Bundle-Activator. Basically, there are the following issues:
Not all bundles have a bundle activator
Detecting an activator in the code does not always mean you want one
Detecting means you can find more than one
That said, it is possible to automate the Bundle-Activator:
However, if there are multiple Bundle-Activators you will get an error.
[[#unbindMethod]]
28.8How to assign an unbind method to a @Reference?
@Reference automatically sets the bind method but how is the unbind method set? Simple, you use a method with a similar name:
||!bind||!unbind||
||setX ||unsetX||
||addX ||removeX||
For example:
@Reference
protected void setFoo(LogService l) { ... }
protected void unsetFoo(LogService l) { ... }
If you want to override this, use
@Reference(unbind="IRefuseToCallMyMethodUnFoo");
protected void foo(LogService l) {}
protected void IRefuseToCallMyMethodUnFoo(LogService l) {}
Unfortunately Java has no method references so it is not type safe.A non existent @UnReference annotation is not very useful because that still requires linking it up symbolically to the associated @Reference.
[[#packageinfo]]
28.9packageinfo or package-info.java?
Inspired by the osgi-dev thread<EMAIL_ADDRESS>default version for Export-Package is 0.0.0, not bundle version?]] I'm just a little bit confused about the bnd approach with the file naming "packageinfo". The [[http://java.sun.com/docs/books/jls/third_edition/html/packages.html] already defines "package-info.java" for package relevant infos. Wouldn't it be simplier (less complex) to have only one file for package definitions? So, the bnd tool could manage the package version in "package-info.java", too.
You can use either file. The reason there are two options is that one constituency thinks annotations are the only solution and the other is running pre Java 5 ... Basically if I would have to choose it would be packageinfo because that works anywhere but I expect that you probably would not like that :-)
[[#supercomps]]
28.10Why are superclass not inspected for Component annotations?
Annotations are not inherited form the component's super classes. The problem is that bnd cannot in all cases can see super classes (and interfaces) because the super class does not have to be available in the build. In runtime you are sure the super class is there, at build time you do not have that luxury. So to make sure, always define your annotations on the actual component class.
[[#exportversions]]
28.11Can't find the source of the version on an Export-Package?
If no explicit export version is specified in the bnd file then bnd will look in the following places.
29packageinfo file in the package directory (recommended)
30package-info.java, bnd's Version annotation
31Manifest of the exporting JAR
There was a mis-feature in an [older version of the maven<EMAIL_ADDRESS>that appended the pom version to the exported packages. It looked professional but it was baloney. Versioning a bundle should not version a package automatically, try it and feel the pain. So if you can't find the source of an exported package version you might have an old maven bundle plugin.
[[#bundleclasspath]]
31.1Should I use the Bundle-ClassPath?
No. It creates unnecessary complexity, it is slower, and it is not necessary. It will also not be compatible with techniques like [PojoSR][http://code.google.com/p/pojosr], something that the OSGi is looking into standardizing.
[[#bundleclasspath2]]
31.2What should I use instead of the Bundle-ClassPath?
Just use Private-Package and Export-Package, know what goes into your JAR. If you really need to wrap one or more JARs, use the Include-Resource instruction, it has an option to unroll a JAR resource (see [@ option][#include-resource]). This will copy all its contents in the target JAR. The -exportcontents can then be used to export selected packages. Even better is of course to know
If an entry is wrong, send a<EMAIL_ADDRESS>with the JAR that has the problem. Preferably as small as possible.