Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...

This plugin for Maven 2 is based on the BND tool from Peter Kriens. The way BND works is by treating your project as a big collection of classes (e.g., project code, dependencies, and the class path). The way you create a bundle with BND is to tell it the content of the bundle's JAR file as a subset of the available classes. This plugin wraps BND to make it work specifically with the Maven 2 project structure and to provide it with reasonable default behavior for Maven 2 projects.

Info

If you have questions about the maven-bundle-plugin please read the FAQ first. If you still have questions you can ask them on the Felix user list.

NOTE: test scoped dependencies are not included in the classpath seen by BND.

Since the 1.4.0 release, this plugin also aims to automate OBR (OSGi Bundle Repository) management. It helps manage a local OBR for your local Maven repository, and also supports remote OBRs for bundle distribution. The plug-in automatically computes bundle capabilities and requirements, using a combination of Bindex and Maven metadata.

Tip

Standard Maven Documentation is now available for maven-bundle-plugin 2.3.7

Tip

A complete list of instructions and their format is available from the BND website

Anchor
simple-example
simple-example

...

  • <Bundle-SymbolicName> is computed using the shared Maven2OsgiConverter component, which uses the following algorithm:
    Get the symbolic name as groupId + "." + artifactId, with the following exceptions:
    • if artifact.getFile is not null and the jar contains a OSGi Manifest with Bundle-SymbolicName property then that value is returned
    • if groupId has only one section (no dots) and artifact.getFile is not null then the first package name with classes is returned. eg. commons-logging:commons-logging -> org.apache.commons.logging
    • if artifactId is equal to last section of groupId then groupId is returned. eg. org.apache.maven:maven -> org.apache.maven
    • if artifactId starts with last section of groupId that portion is removed. eg. org.apache.maven:maven-core -> org.apache.maven.core
  • <Export-Package> is assumed to be "<Bundle-SymbolicName>.*", unless <Private-Package> is specified, then <Export-Package> is assumed to be empty.
  • <Private-Package> is assumed to be empty by default.
  • <Import-Package> is assumed to be "*", which imports everything referred to by the bundle content, but not contained in the bundle.
  • <Include-Resource> is generated from the project's Maven resources, typically "src/main/resources/", which will copy the specified project directory hierarchy into the resulting bundle JAR file, mirroring standard Maven behavior.
  • <Bundle-Version> is assumed to be "${pom.version}" with '-' character separator of the qualifier replaced with a '.' character.
  • <Bundle-Name> is assumed to be "${pom.name}".
  • <Bundle-Description> is assumed to be "${pom.description}".
  • <Bundle-License> is assumed to be "${pom.licenses}".
  • <Bundle-Vendor> is assumed to be "${pom.organization.name}".
    • The computed symbolic name is also stored in the $(maven-symbolicname) property in case you want to add attributes or directives to it.
  • <Export-Package> is now assumed to be the set of packages in your local Java sources, excluding the default package '.' and any packages containing 'impl' or 'internal'.
    (before version 2 of the bundleplugin it was based on the symbolic name)
  • Since 2.2.0 you can also use {local-packages} inside <Export-Package> and it will be expanded to the set of local packages.
  • <Private-Package> is now assumed to be the set of packages in your local Java sources (note that any packages in both <Export-Package> and <Private-Package> will be exported).
    (before version 2 of the bundleplugin it was assumed to be empty by default)
  • <Import-Package> is assumed to be "*", which imports everything referred to by the bundle content, but not contained in the bundle.
    Any exported packages are also imported by default, to ensure a consistent class space.
  • <Include-Resource> is generated from the project's Maven resources, typically "src/main/resources/", which will copy the specified project directory hierarchy into the resulting bundle JAR file, mirroring standard Maven behavior.
  • <Bundle-Version> <Bundle-DocURL> is assumed to be "${pom.organization.urlversion}" .

Since the plugin creates bundles for OSGi R4, it hard-codes Bundle-ManifestVersion to be '2'. Additionally, it generates imports for every export to ensure package substitutability, which is very important when working with collaborating services. It is possible to override any of these values (except Bundle-ManifestVersion) just by specifying the desired value in the plugin configuration section of the POM file.

...

  • but is normalized to the OSGi version format of "MAJOR.MINOR.MICRO.QUALIFIER", for example "2.1-SNAPSHOT" would become "2.1.0.SNAPSHOT".
  • <Bundle-Name> is assumed to be "${pom.name}".
  • <Bundle-Description> is assumed to be "${pom.description}".
  • <Bundle-License> is assumed to be "${pom.licenses}".
  • <Bundle-Vendor> is assumed to be "${pom.organization.name}".
  • <Bundle-DocURL> is assumed to be "${pom.organization.url}".

Since the plugin creates bundles for OSGi R4, it hard-codes Bundle-ManifestVersion to be '2'. Additionally, it generates imports for every export to ensure package substitutability, which is very important when working with collaborating services. It is possible to override any of these values (except Bundle-ManifestVersion) just by specifying the desired value in the plugin configuration section of the POM file.

Anchor
how-to
how-to

Detailed "How To"

Get Maven2

The first step in the process of using the plugin is downloading and installing the latest version of the Maven2 runtime. The latest Maven2 release and instuctions for getting started with Maven2 can be found at the Maven website.

Using the Plugin

To use the maven-bundle-plugin, you first need to add the plugin and some appropriate plugin configuration to your bundle project's POM. Below is an example of a simple OSGi bundle POM for Maven2:

No Format

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>my-osgi-bundles</groupId>
  <artifactId>examplebundle</artifactId>
  

...

Detailed "How To"

Get Maven2

The first step in the process of using the plugin is downloading and installing the latest version of the Maven2 runtime. The latest Maven2 release and instuctions for getting started with Maven2 can be found at the Maven website.

Using the Plugin

To use the maven-bundle-plugin, you first need to add the plugin and some appropriate plugin configuration to your bundle project's POM. Below is an example of a simple OSGi bundle POM for Maven2:

No Format

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>my-osgi-bundles</groupId>
  <artifactId>examplebundle</artifactId>
  <packaging>bundle</packaging>    <!-- (1) -->
  <version>1.0</version>
  <name>Example Bundle</name>
  <dependencies>
    <dependency>
      <groupId>org.apache.felix</groupId>
      <artifactId>org.osgi.core</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>    <!-- (2) START -->
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Export-Package>com.my.company.api</Export-Package>
            <Private-Package>com.my.company.*</Private-Package>
            <Bundle-Activator>com.my.company.Activator</Bundle-Activator>
          </instructions>
        </configuration>
      </plugin>    <!-- (2) END -->
    </plugins>
  </build>
</project>

...

No Format
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.apache.felix</groupId>
  <artifactId>org.apache.felix.log</artifactId>
  <packaging>bundle</packaging>
  <name>Apache Felix Log Service</name>
  <version>0.8.0-SNAPSHOT</version>
  <description>
    This bundle provides an implementation of the OSGi R4 Log service.
  </description>
  <dependencies>
    <dependency>
      <groupId>${pom.groupId}</groupId>
      <artifactId>org.osgi.core</artifactId>
      <version>0.8.0-incubator</version>
    </dependency>
    <dependency>
      <groupId>${pom.groupId}</groupId>
      <artifactId>org.osgi.compendium</artifactId>
      <version>0.9.0-incubator-SNAPSHOT</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Export-Package>org.osgi.service.log</Export-Package>
            <Private-Package>org.apache.felix.log.impl</Private-Package>
            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
            <Bundle-Activator>${pom.artifactId}.impl.Activator</Bundle-Activator>
            <Export-Service>org.osgi.service.log.LogService,org.osgi.service.log.LogReaderService</Export-Service>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Notice that the <Export-Package> instruction specifies that the bundle exports the Log Service package, even though this package is not contained in the bundle project. By declaring this, the plugin will copy the Log Service package into the resulting bundle JAR file. This is useful in this case because now the bundle can resolve without having to download the entire compendium bundle. The resulting manifest for the Log Service bundle looks like this (notice how the imports/exports automatically have version information associated with them, which was obtained from packageinfo files in the source packages):

No Format

Manifest-Version: 1
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Activator: org.apache.felix.log.impl.Activator
Import-Package: org.osgi.framework;version=1.3, org.osgi.service.log;v
 ersion=1.3
Include-Resource: src/main/resources
Export-Package: org.osgi.service.log;uses:=org.osgi.framework;version=
 1.3
Bundle-Version: 0.8.0.SNAPSHOT
Bundle-Name: Apache Felix Log Service
Bundle-Description: This bundle provides an implementation of the OSGi
  R4 Log service.
Private-Package: org.apache.felix.log.impl
Bundle-ManifestVersion: 2
Export-Service: org.osgi.service.log.LogService,org.osgi.service.log.L
 ogReaderService
Bundle-SymbolicName: org.apache.felix.log

The resulting bundle JAR file has the following content (notice how the LICENSE and NOTICE files were automatically copied from the src/main/resources/ directory of the project):

No Format

META-INF/MANIFEST.MF
LICENSE
META-INF/
META-INF/maven/
META-INF/maven/org.apache.felix/
META-INF/maven/org.apache.felix/org.apache.felix.log/
META-INF/maven/org.apache.felix/org.apache.felix.log/pom.properties
META-INF/maven/org.apache.felix/org.apache.felix.log/pom.xml
NOTICE
org/
org/apache/
org/apache/felix/
org/apache/felix/log/
org/apache/felix/log/impl/
org/apache/felix/log/impl/Activator.class
org/apache/felix/log/impl/Log.class
org/apache/felix/log/impl/LogEntryImpl.class
org/apache/felix/log/impl/LogException.class
org/apache/felix/log/impl/LogListenerThread.class
org/apache/felix/log/impl/LogNode.class
org/apache/felix/log/impl/LogNodeEnumeration.class
org/apache/felix/log/impl/LogReaderServiceFactory.class
org/apache/felix/log/impl/LogReaderServiceImpl.class
org/apache/felix/log/impl/LogServiceFactory.class
org/apache/felix/log/impl/LogServiceImpl.class
org/osgi/
org/osgi/service/
org/osgi/service/log/
org/osgi/service/log/LogEntry.class
org/osgi/service/log/LogListener.class
org/osgi/service/log/LogReaderService.class
org/osgi/service/log/LogService.class
org/osgi/service/log/package.html
org/osgi/service/log/packageinfo

Adding OSGi metadata to existing projects without changing the packaging type

If you want to keep your project packaging type (for example "jar") but would like to add OSGi metadata
you can use the manifest goal to generate a bundle manifest. The maven-jar-plugin can then be used to
add this manifest to the final artifact. For example:


        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Export-Package>org.osgi.service.log</Export-Package>
            <Private-Package>org.apache.felix.log.impl</Private-Package>
            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
            <Bundle-Activator>${pom.artifactId}.impl.Activator</Bundle-Activator>
            <Export-Service>org.osgi.service.log.LogService,org.osgi.service.log.LogReaderService</Export-Service>
          </instructions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Notice that the <Export-Package> instruction specifies that the bundle exports the Log Service package, even though this package is not contained in the bundle project. By declaring this, the plugin will copy the Log Service package into the resulting bundle JAR file. This is useful in this case because now the bundle can resolve without having to download the entire compendium bundle. The resulting manifest for the Log Service bundle looks like this (notice how the imports/exports automatically have version information associated with them, which was obtained from packageinfo files in the source packages):

No Format

Manifest-Version: 1
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Bundle-Activator: org.apache.felix.log.impl.Activator
Import-Package: org.osgi.framework;version=1.3, org.osgi.service.log;v
 ersion=1.3
Include-Resource: src/main/resources
Export-Package: org.osgi.service.log;uses:=org.osgi.framework;version=
 1.3
Bundle-Version: 0.8.0.SNAPSHOT
Bundle-Name: Apache Felix Log Service
Bundle-Description: This bundle provides an implementation of the OSGi
  R4 Log service.
Private-Package: org.apache.felix.log.impl
Bundle-ManifestVersion: 2
Export-Service: org.osgi.service.log.LogService,org.osgi.service.log.L
 ogReaderService
Bundle-SymbolicName: org.apache.felix.log

The resulting bundle JAR file has the following content (notice how the LICENSE and NOTICE files were automatically copied from the src/main/resources/ directory of the project):

No Format

META-INF/MANIFEST.MF
LICENSE
META-INF/
META-INF/maven/
META-INF/maven/org.apache.felix/
META-INF/maven/org.apache.felix/org.apache.felix.log/
META-INF/maven/org.apache.felix/org.apache.felix.log/pom.properties
META-INF/maven/org.apache.felix/org.apache.felix.log/pom.xml
NOTICE
org/
org/apache/
org/apache/felix/
org/apache/felix/log/
org/apache/felix/log/impl/
org/apache/felix/log/impl/Activator.class
org/apache/felix/log/impl/Log.class
org/apache/felix/log/impl/LogEntryImpl.class
org/apache/felix/log/impl/LogException.class
org/apache/felix/log/impl/LogListenerThread.class
org/apache/felix/log/impl/LogNode.class
org/apache/felix/log/impl/LogNodeEnumeration.class
org/apache/felix/log/impl/LogReaderServiceFactory.class
org/apache/felix/log/impl/LogReaderServiceImpl.class
org/apache/felix/log/impl/LogServiceFactory.class
org/apache/felix/log/impl/LogServiceImpl.class
org/osgi/
org/osgi/service/
org/osgi/service/log/
org/osgi/service/log/LogEntry.class
org/osgi/service/log/LogListener.class
org/osgi/service/log/LogReaderService.class
org/osgi/service/log/LogService.class
org/osgi/service/log/package.html
org/osgi/service/log/packageinfo

Adding OSGi metadata to existing projects without changing the packaging type

If you want to keep your project packaging type (for example "jar") but would like to add OSGi metadata
you can use the manifest goal to generate a bundle manifest. The maven-jar-plugin can then be used to
add this manifest to the final artifact. For example:

Code Block
xml
xml

<plugin>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>  
      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
    </archive> 
  </configuration>
</plugin>  
<plugin>   
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <executions>
    <execution>
      <id>bundle-manifest</id>
      <phase>process-classes</phase>
      <goals>    
        <goal>manifest</goal>
      </goals>   
    </execution>
  </executions>
</plugin>

If you want to use packaging types other than "jar" and "bundle" then you also need to enable support
for them in the bundleplugin configuration, for example if you want to use the plugin with WAR files:

Code Block
xml
xml

<plugin>
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <executions>
    <execution>
      <id>bundle-manifest</id>
      <phase>process-classes</phase>
      <goals>
        <goal>manifest</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <supportedProjectTypes>
      <supportedProjectType>jar</supportedProjectType>
      <supportedProjectType>bundle</supportedProjectType>
      <supportedProjectType>war</supportedProjectType>
    </supportedProjectTypes>
    <instructions>
      <!-- ...etc... -->
    </instructions>
  </configuration>
</plugin>

You'll also need to configure the other plugin to pick up and use the generated manifest, which is written to ${project.build.outputDirectory}/META-INF/MANIFEST.MF by default (unless you choose a different manifestLocation in the maven-bundle-plugin configuration). Continuing with our WAR example:

Code Block

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <configuration>
    <archive>
      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
    </archive>
  </configuration>
Code Block
xmlxml

<plugin>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>  
      <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
    </archive> 
  </configuration>
</plugin>  
<plugin>   
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <executions>
    <execution>
      <id>bundle-manifest</id>
      <phase>process-classes</phase>
      <goals>    
        <goal>manifest</goal>
      </goals>   
    </execution>
  </executions>
</plugin>

Building the Plugin

...

  • bundle - build an OSGi bundle jar for the current project
    configuration options:
    • manifestLocation defaults to ${project.build.outputDirectory}/META-INF
    • unpackBundle unpack bundle contents to output directory, defaults to false
    • excludeDependencies comma-separated list of dependency artifactIds to exclude from the classpath passed to Bnd (use "true" to exclude everything)
    • supportedProjectTypes defaults to "jar","bundle"
    • Bnd, use "true" to exclude everything.
      Version 2 of the bundleplugin now supports the same style of filter clauses in excludeDependencies as Embed-Dependency.
    • classifier attach bundle to the project using the given classifier
    • supportedProjectTypes defaults to "jar","bundle"
  • bundleall - build OSGi bundle jars for all transitive dependencies
    configuration options:
    • wrapImportPackage defaults to "*"
    • supportedProjectTypes defaults to "jar","bundle"
    • wrapImportPackage defaults to "*"
  • wrap - as above, but limited to the first level of dependencies
    configuration options:
    • wrapImportPackage defaults to "*"
    • supportedProjectTypes defaults to "jar","bundle"
    • wrapImportPackage defaults to "*"
  • manifest - create an OSGi manifest for the current project
    configuration options:
    • manifestLocation defaults to ${project.build.outputDirectory}/META-INF
    • supportedProjectTypes defaults to "jar","bundle"
  • install - adds the current bundle project to the local OBR
    configuration options:
    • obrRepository path to local OBR, defaults to <local-maven-repository>/repository.xml
    • supportedProjectTypes defaults to "jar","bundle"

More GOALs are available in the 1.4.0 release:

...

  • deploy - adds the current bundle project to a remote OBR
    configuration options:
    • remoteOBR name of remote OBR, defaults to NONE (which means no remote OBR deployment)
    • obrRepository used when the remoteOBR name is blank, defaults to repository.xml
    • prefixUrl optional public URL prefix for the remote repository
    • bundleUrl optional public URL where the bundle has been deployed
    • altDeploymentRepository alternative remote repository, id::layout::url
    • obrDeploymentRepository optional OBR specific deployment repository.
    • ignoreLock ignore remote locking when updating the OBR
    • supportedProjectTypes defaults to "jar","bundle"
  • deploy-file - adds a local bundle file to a remote OBR
    configuration options:
    • remoteOBR name of remote OBR, defaults to an empty string
    • obrRepository used when the remoteOBR name is blank, defaults to repository.xml
    • repositoryId optional repository id, used to lookup authentication settings
    • url remote repository transport URL, like
      No Format
      scpexe://host/path/to/obr
      
    • bundleUrl public URL of deployed bundle, like
      No Format
      http://www.foo.org/bundles/foo.jar
      
    • groupId Maven groupId for the bundle, taken from pomFile if given
    • artifactId Maven artifactId for the bundle, taken from pomFile if given
    • version Maven version for the bundle, taken from pomFile if given
    • packaging Maven packaging type for the bundle, taken from pomFile if given
    • classifier Maven classifier type, defaults to none
    • pomFile optional Pom file describing the bundle
    • file bundle file, defaults to the bundle from the local Maven repository
    • obrXml optional additional properties for the bundle
    • ignoreLock ignore remote locking when updating the OBR
  • clean - cleans the local OBR, removing missing bundles
    configuration options:
    • obrRepository path to local OBR, defaults to <local-maven-repository>/repository.xmlrepository>/repository.xml
  • remote-clean - cleans a remote OBR, removing missing bundles
    configuration options:
    • remoteOBR name of remote OBR, defaults to NONE (which means no remote cleaning)
    • obrRepository used when the remoteOBR name is blank, defaults to repository.xml
    • prefixUrl optional public URL prefix for the remote repository
    • altDeploymentRepository alternative remote repository, id::layout::url
    • obrDeploymentRepository optional OBR specific deployment repository.
    • ignoreLock ignore remote locking when updating the OBR

There are also new instructions available from the underlying BND tool, which continues to be improved independently; for the latest see BND documentation.

...

No Format
dependencies ::= clause ( ',' clause ) *
clause ::= MATCH ( ';' attr '=' MATCH | ';inline=true' inline )
attr ::= 'groupId' | 'artifactId' | 'version' | 'scope' | 'type' | 'classifier' | 'optional'
inline ::= 'true' | 'false' | PATH ( '|' PATH ) *
MATCH ::= <globbed regular expressions>expression>
PATH ::= <Ant-style path expression>

The plugin uses the <Embed-Dependency> instruction to transform the project dependencies into <Include-Resource> and <Bundle-ClassPath> clauses, which are then appended to the current set of instructions and passed onto BND. If you want the embedded dependencies to be at the start or middle of <Include-Resource> or <Bundle-ClassPath> then you can use {maven-dependencies}, which will automatically expand to the relevant clauses.

The MATCH section accepts alternatives, separated by |, and can be negated by using ! at the beginning of the MATCH. Use * to represent zero or more unknown characters and ? to represent a single unknown zero or one character. You can also use standard Java regexp constructs. There is no need to escape the . character inside MATCH. The first MATCH in a clause will filter against the artifactId.

...

Code Block
xml
xml
<!-- embed all compile and runtime scope dependencies -->
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>

<!-- embed any dependencies with artifactId junit and scope testruntime -->
<Embed-Dependency>junit;scope=test<runtime</Embed-Dependency>

<!-- inline all non-pom dependencies, except those with scope testruntime -->
<Embed-Dependency>*;scope*;scope=!runtime;type=!testpom;inline=true</Embed-Dependency>

<!-- embed all compile and runtime scope dependencies, except those with artifactIds in the given list -->
<Embed-Dependency>*;scope=compile|runtime;inline=false;artifactId=!cli|lang|runtime|tidy|jsch</Embed-Dependency>

<!-- inline contents of selected folders from all dependencies -->
<Embed-Dependency>*;inline=images/**|icons/**</Embed-Dependency>

examples of using {maven-dependencies}:

...

Sometimes you would like to clean your local OBR because it contains bundles that are no longer in your local Maven repository. This case often occurs when artifacts were deleted manually. The maven-bundle-plugin provides a simple goal to check for missing bundles, and remove them from the local OBR.and remove them from the local OBR.

configuration:

  • obrRepository path to local OBR, defaults to <local-maven-repository>/repository.xml

Example:

No Format

mvn bundle:clean

bundle:index

The index goal allows the creation of an OBR repository based on a set of jars in a maven repository.

Configurationconfiguration:

  • obrRepository path to local OBR, defaults to <local-maven-repository>/repository.xml

Example:

...

  • urlTemplate template for generating urls for OBR resources
  • mavenRepository path to the maven repository, defaults to <local-maven-repository>

Possible values for the urlTemplate are:

  • maven this will create a maven based url such as mvn:groupid/artifactid/version
  • pattern with the following placeholders:
    • %v bundle version
    • %s bundle symbolic name
    • %f file name
    • %p file path

Concurrent updates

With a remote OBR, several uploads may occur at the same time. However, the remote OBR is centralized in one file, so concurrent modification must be avoided. To achieve this, the plug-in implements a locking system. Each time the plug-in tries to modify the file it sets a file based lock. If it can't take the lock, it will wait and retry. After 3 attempts the upload process fails. To bypass this lock add -DignoreLock to the command-line (or add <ignoreLock>true<ignoreLock> to the configuration section of your Pom).

...