Bnd - Bundle Tool Chinese
Read this very interesting introduction into bnd by Costin Leau, Creating OSGi bundles
Introduction
The bnd tool helps you create and diagnose OSGi R4 bundles. The key functions are:
- Show the manifest and JAR contents of a bundle
- Wrap a JAR so that it becomes a bundle
- Create a Bundle from a specification and a class path
- Verify the validity of the manifest entries
The tool is capable of acting as:
Table Of Contents
Background
Traditionally, JAR files are made with the SUN 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. Obviously this method works well.
The Bnd tool works different, it recognizes Java classes and packages and constructs the JAR from the classpath. It 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:
Export-Package: !com.acme.impl, com.acme.*;version=1.2
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:
Import-Package: !com.acme.*, *;resolution:=optional
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.
Quick Start
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:
Export-Package: aQute.service.channel; version=1.0 Private-Package: aQute.tutorial.chat
This is all you need! In Eclipse, you can select the bnd file and run the Make Bundle command. This will create a JAR with the proper content:
META-INF MANIFEST.MF aQute/service/channel Channel.class aQute/tutorial/chat Chat$ChannelTracker.class Chat.class
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.
Manifest-Version: 1 Bundle-Name: aQute.tutorial.chat Private-Package: aQute.tutorial.chat Import-Package: aQute.service.channel;version=1.0, org.osgi.framework; version=1.3, org.osgi.util.tracker;version=1.3 Bundle-ManifestVersion: 2 Bundle-SymbolicName: aQute.tutorial.chat Export-Package: aQute.service.channel;version=1.0 Bundle-Version: 0
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.
Bnd file format
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 contination 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. White spaces around the key and value are trimmed. See Properties for more information about the format.
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 |
| Directives | -include: deflts.bnd | Directives start with a '-' sign. A directive is an instruction to bnd to do something special. See Directives |
Bnd Directives
| Instruction | Format | Description |
|---|---|---|
-classpath | 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 |
-donotcopy | 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|~.+) |
| -include | 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 ${user.home} 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= ~${user.home}/deflts.bnd, META-INF/MANIFEST.MF |
-include= a.props, ~META-INF/MANIFEST.MF ||
-exportcontents | 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 |
-removeheaders | 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. |
-nouses | true|false | Do not calculate the uses: directive. |
-sources | true|false | Include sources |
Export-Package | LIST of PATTERN | The Export-Package header lists the packages that the bundle should export, and thus contain. See ExportPackage. |
Include-Resource | LIST of iclause | The Include-Resource instruction makes it possible to include arbitrary resources; it contains a list of resource paths. See Include Resource. |
Private-Package | LIST of PATTERN | The Private-Package header lists the packages that the bundle should contain but not export. See Private Package. |
Import-Package | LIST of PATTERN | The Import-Package header lists the packages that are required by the contained packages. See Import Package. |
Conditional-Package | 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. |
Bundle- | 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 ${project} that will be set to this default name. | |
Bundle-Name | If the Bundle-Name is not set, it will default to the Bundle-SymbolicName. | |
Bundle- | 2 | The Bundle-ManifestVersion is always set to 2, there is no way to override this. |
Bundle-Version | VERSION | The version of the bundle. If no such header is provided, a version of 0 will be set. |
Service-Component | LIST of component | See Service Component Header. |
Export-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. 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 packaginfo 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:
Export-Package= com.acme.impl.*;-noimport:=true, *
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.
Export-package = com.acme.impl.*;uses="my.special.import"
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.
Export-package = com.acme.impl.*;uses="my.special.import,<<USES>>"
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 |
For example:
Private-Package: test.pack;-split-package:=merge-first
Private Package
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
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.3. If a specific version (range) is specified, this will override any found version. However, ${@} can be used to substitute the found version in a range.
Import-Package: org.osgi.framework;version="[1.3,2.0)"
Import-Package: org.osgi.framework;version="[${@},2.0)"
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.
Import-Package: org.eclipse.core.runtime;-remove-attribute:common,*
Or
Import-Package: org.eclipse.core.runtime;common=!,*
Include Resource
The resources will be copied into the target jar file. The iclause can have the following forms:
iclause ::= inline | copy
copy ::= '{' process '}' | process
process ::= assignment | simple
assignment ::= PATH '=' PATH
simple ::= PATH
inline ::= '@' PATH ( '!/' PATH? ('/**' | '/*')? )?
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.
Include-Resource: @osgi.jar,
{LICENSE.txt},
acme/Merge.class=src/acme/Merge.class
Service-Component Header
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. The syntax for these component definitions is:
component ::= <implementation-class> ( ';' parameter ) *
parameter ::= provide | reference | multiple | optional
| reference | properties | factory | servicefactory
| immediate | enabled
reference ::= <name> '=' <interface-class> ( '(' <target-filter> ')')?
provide ::= 'provide:=' LIST
multiple ::= 'multiple:=' LIST
optional ::= 'optional:=' LIST
dynamic ::= 'dynamic:=' LIST
factory ::= 'factory:=' true | false
servicefactory := 'servicefactory:=' true | false
immediate ::= 'immediate:=' true | false
enabled ::= 'enabled:=' true | false
properties::= 'properties:=' key '=' value \
( ',' key '=' value ) *
The name of the component is also the implementation class. It is then followed with a number of references. 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 and create a resource in the output jar under the name OSGI-INF/<id>.xml. The following example shows a component that is bound to the log service via the setLog method:
Service-Component=aQute.tutorial.component.World; \
log=org.osgi.service.log.LogService
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). Others like the policy and cardinality are supported via directives. If a reference is optional, it should be listed in the optional directive. This will mean the cardinality will start with 0. If it is possible to have multiple instances (the set method is called multiple times with different objects, the name of the reference should be listed in the multiple directive. The policy is reflected in the dynamic directive, add the name of a dynamic reference to the dynamic directive. The defaults are therefore aligned with the SCR: a cardinality of 1..1, and static policy. For a more complex example:
Service-Component=aQute.tutorial.component.World; \
log=org.osgi.service.log.LogService; \
http=org.osgi.service.http.HttpService; \
dynamic:='log,http'; \
optional:=log; \
PROCESSORS="xierpa.service.processor.Processor(priority>1)"; \
multiple:=PROCESSORS; \
properties:="wazaabi=true"
The previous example will result in the following service component in the resource OSGI-INF/aQute.tutorial.component.World.xml:
<?xml version="1.0" encoding="utf-8" ?>
<component name="aQute.tutorial.component.World">
<implementation class="aQute.tutorial.component.World" />
<reference name="log"
interface="org.osgi.service.log.LogService"
cardinality="0..1"
bind="setLog"
unbind="unsetLog"
policy="dynamic" />
<reference name="http"
interface="org.osgi.service.http.HttpService"
bind="setHttp"
unbind="unsetHttp"
policy="dynamic" />
<reference name="PROCESSORS"
interface="xierpa.service.processor.Processor"
cardinality="1..n"
target="(priority>1)" />
</component>
The description also supports the immediate, enabled, factory, target, and servicefactory attributes. Refer to the Declarative Services definition for their semantics.
Macros
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 replace;acaca;a(.*)a;[$1] will return [cac].
For example:
version=1.23.87.200109111023542
Bundle-Version= ${version}
Bundle-Description= This bundle has version ${version}
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. |
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 '»'
| '$‹' function '›'
function ::= name ( ':' argument ) *
| Function | Arguments | Description |
|---|---|---|
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 |
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: list= a,b,c,d,x.jar,z.jar |
sort | ; list | Sort the given list using string sorting collation. For example: List= ${sort:acme.jar, harry.jar, runner.jar, alpha.jar, bugs.jar} |
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= ${join;a,b,c;d,e,f} |
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: ${if;${version};Ok;Version is NOT set!!!!} |
now | Returns the current Date as string. Created-When: ${now} | |
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;${fmodified;${files}}) |
long2date | ; long | Parse the long and turn it into a date. Last-Modified: ${long2date:${fmodified:${files}}) |
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 = ${replace;${impls};$;.jar} |
toclassname | ; list | Replace a class path (with slashes and class at the end) to a class name (with dots). |
toclasspath | ; list | Replace a class name (with dots) to a classpath (with slashes and .class at the end) |
findname | ; regex [ ; replacement ] | 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 | ; 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. |
Command Line
The command line tool can be invoked in several different ways:
- bnd general-options cmd cmd-options
- bnd general-options <file>.jar
- bnd general-options <file>.bnd
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. |
print ( -verify | -manifest | -list | - all ) * <file>.jar +
The print function will take a list of JAR file and print one or more aspect of the JAF riles. The following aspects can be added.
- -verify - Verify the JAR for consistency with the specification. The print will exit with an error if the verify fails.
- -manifest - Show the manifest
- -list - List the entries in the JAR file
- -all - Do all (this is the default.
bnd print -verify *.jar
build ( -classpath LIST | -eclipse <file> | -noeclipse | -output <file> ) * <file>.bnd +
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 build -classpath bin -noeclipse -output test.jar xyz.bnd
wrap ( -classpath (<file>(','<file>)*)-output <file|dir> | -properties <file> ) *
-ignoremanifest? <file>.jar *
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: <packages inside the target jar>
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 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.
Ant Task
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.
<target name="build">
<taskdef resource="aQute/bnd/ant/taskdef.properties"
classpath="bnd.jar"/>
<bnd
classpath="src"
eclipse="true"
failok="false"
exceptions="true"
files="test.bnd"/>
</target>
You can set the following attributes:
| Attribute | Description |
|---|---|
| classpath | Command 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='<file>' |
| bndwrap | WrapTask | jars='<list>', output='<dir>', definitions='<dir>', classpath='<file-list>' |
Maven
The Maven plugin is described at Felix maven plugin. Defaults for Maven are:
Bundle-SymbolicName: <groupId>.<artifactId>
Bundle-Name: project.getName();
Bundle-Version: <version>
Import-Package: *
Export-Package: <groupId>.<artifactId>.* (unless Private-package is set)
Bundle-Description: project.getDescription()
Bundle-License: project.getLicenses())
Bundle-Vendor: project.getOrganization();
Include-Resource: src/main/resources
Errors and Warnings
There are many errors and warnings. The messages should be self explanatory.



