The Mavenizer Plugin aims to facilitate the deployment of non-maven binaries into a maven repository while keeping the whole benefits of Maven dependency management. Below are the different goals and configurations for the plugin.
The easiest way to use this plug in is to use it with its own special lifecycle. To ensure that you will be using the mavenizer lifecyle, there is two steps:
Here is the minimal settings for completing these to requirement in your POM :
<project ...> ... <packaging>mavenize</packaging> ... <build> ... <plugins> ... <plugin> <groupId>lu.softec.maven</groupId> <artifactId>maven-mavenizer-plugin</artifactId> <version>1.0</version> <extensions>true</extensions> <configuration> ... </configuration> </plugin> ... </plugins> ... </build> ... <pluginRepositories> <pluginRepository> <id>softec-opensource</id> <url>http://nexus.softec.lu:8081/content/repositories/opensource</url> </pluginRepository> </pluginRepositories> ... </project>
To obtains the binaries that will be deployed, you have several options:
If you have your binaries in uncompressed form locally, you just have to define the folder where these binaries are located. The binaries does not need to be isolated and a selection may be applied latter, see below. This folder should not be located in the project build directory (target by default), or these may be deleted by the plugin in certain circonstances. You may also document the origin of these binaries using the ArchiveURL. This URL may be checked for updates but will never be downloaded.
Here is how to configure this:
... <configuration> ... <binariesBaseDir>/path/to/the/root/directory/containing/your/binaries</binariesBaseDir> ... <!-- Optional, only check, never download --> <archiveURL>http://your.server.com/path/to/the/archive.zip</archiveURL> ... </configuration> ...
If you have a local archive containing your binaries, you just have to define where this archive is located. The archive does not need to contains only the binaries and a selection may be applied latter, see below. The archive file should not be located in the project build directory (target by default), or it may be deleted by the plugin in certain circonstances. You may also document the origin of the archive using the ArchiveURL. This URL may be checked for updates but will never be downloaded. You may also define where the archive will be extracted, but this should be inside the project build directory (target by default). By default, the archive will be extracted in $project.build.directory/bin.
Here is how to configure this:
... <configuration> ... <archiveFile>/path/to/the/archive.zip</archiveFile> ... <!-- Optional, only check, never download --> <archiveURL>http://your.server.com/path/to/the/archive.zip</archiveURL> <!-- Optional--> <binariesBaseDir>${project.build.directory}/local/path/to/the/binaries</binariesBaseDir> ... </configuration> ...
If you have access to a remote archive containing your binaries, you just have to define the URL of the archive. The archive does not need to contains only the binaries and a selection may be applied latter, see below.
You may also define the location where the archive will be downloaded, but this should be inside the project build directory (target by default). By default, the archive will be downloaded in $project.build.directory/archive. You may also define where the archive will be extracted, but this should be inside the project build directory (target by default). By default, the archive will be extracted in $project.build.directory/bin.
Here is how to configure this:
... <configuration> ... <archiveURL>http://your.server.com/path/to/the/archive.zip</archiveFile> ... <!-- Optional --> <archiveBaseDir>${project.build.directory}/any/path</archiveBaseDir> <!-- OR --> <archiveFile>${project.build.directory}/local/path/to/the/archive.zip</archiveBaseDir> <!-- Optional--> <binariesBaseDir>${project.build.directory}/local/path/to/the/binaries</binariesBaseDir> ... </configuration> ...
The binaries directory, or the archive containing the binaries may contains 3 kind of files:
To define to which categories each file available is related, you may use the following selectors
These selectors support the /**/ wildcard to designate any subtree, as well as the usual * and ? wildcards. These are selector inside the binaries base directory and are obviously relative path selections. The default is to have no dependencies, and to use all JAR file provided.
Here is a sample of selection you may do:
... <configuration> ... <!-- Sample --> <libsIncludes> <libsInclude>lib/**/*.jar</libsInclude> </libsIncludes> <!-- and more --> <libsExcludes> <libsExclude>lib/**/*-meta.jar</libsExclude> </libsExcludes> <!-- Sample --> <depsIncludes> <depsInclude>deps/**/*.jar</depsInclude> </depsIncludes> <!-- and more --> <depsExcludes> <depsExclude>deps/**/*-meta.jar</depsExclude> </depsExcludes> ... </configuration> ...
Once you have defined your binaries location, you may launch an analysis without defining any further configuration. The analyzer will create the mavenizer configuration file for you. By default this file will be located in $project.build.directory/mavenizer.xml. You may overide this location, but if the location is not inside the project build directory no more analysis will be possible, and you will have to provide the configuration file manually.
To overide the location of the mavenizer configuration file, use:
... <configuration> ... <!-- Optional --> <mavenizerConfigFile>${project.build.directory}/config.xml</mavenizerConfigFile> <!-- OR --> <mavenizerConfigFile>/path/to/a/manually/written/mavenizer.xml</mavenizerConfigFile> ... </configuration> ...
Once you have defined the location of your binaries, you may launch a first analysis to discover possibly missing dependencies or wrongly identified artifacts. To launch this analysis using the mavenize lifecycle, just do:
mvn compile
The results of your analysis will be presented both in the log of your build and in the mavenizer configuration file ($project.build.directory/mavenizer.xml by default):
... [INFO] Unresolved classes: [INFO] com.google.common.collect.MapMaker (referenced by com.google.gdata.model.AttributeMetadataRegistry) [INFO] com.google.common.collect.MapMaker (referenced by com.google.gdata.model.ElementMetadataRegistry) [INFO] com.google.common.collect.MapMaker (referenced by com.google.gdata.wireformats.ObjectConverter) [INFO] com.google.common.collect.Maps (referenced by com.google.gdata.model.AdaptationRegistryFactory) [INFO] com.google.common.collect.Maps (referenced by com.google.gdata.model.AttributeMetadataRegistryBuilder) [INFO] com.google.common.collect.Maps (referenced by com.google.gdata.model.ElementCreatorImpl) ... [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ ...
<?xml version="1.0" encoding="UTF-8"?> <artifacts> <artifact name="gdata/java/lib/gdata-analytics-2.1.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-analytics</artifactid> <version>2.1</version> <dependencies> <dependency name="gdata/java/lib/gdata-core-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-core</artifactid> <version>1.0</version> </dependency> </dependencies> </artifact> ... <artifact name="gdata/java/lib/gdata-base-1.0.jar"> <groupid>com.google.api.gbase.client</groupid> <artifactid>gdata-base</artifactid> <version>1.0</version> <dependencies> <dependency name="gdata/java/lib/gdata-client-1.0.jar"> <groupid>com.google.gdata.data.extensions</groupid> <artifactid>gdata-client</artifactid> <version>1.0</version> </dependency> <dependency name="gdata/java/lib/gdata-core-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-core</artifactid> <version>1.0</version> </dependency> <dependency name="gdata/java/lib/gdata-media-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-media</artifactid> <version>1.0</version> </dependency> </dependencies> </artifact> ... </artifacts>
For each files analyzed, the analyzer will have determined the groupId, artifactId and version using native Maven Jar identification mechanism. Examining the byte code, it will have also established the cross-dependencies between analyzed files.
Currently, there is no way to refine the dependency analysis else than using a fixed configuration. But you may easily improve the identifiaction of you file using artifact hints, see below.
For fixing the list of unresolved dependencies, you have 2 options:
If the missing dependencies are available in maven, you may simply define them as dependencies of your current mavenize project. All dependencies defined in the POM will be downloaded and used during dependency resolution.
To solve the sample above regarding the missing google-collect dependencies, we may add the following to our mavenize project POM:
<dependencies> <dependency> <groupId>com.google.collections</groupId> <artifactId>google-collections</artifactId> <version>1.0-rc1</version> </dependency> </dependencies>
You may also provide additional binaries to deploy, or additional binaries as dependencies to be magically found (see above). (currently the magic does not really happen but this is not related to this plug in)
To solve the sample above regarding the missing google-collect dependencies, we may add the following to our plugin configuration:
... <configuration> ... <libsIncludes> <libsInclude>gdata/java/lib/**/*.jar</libsInclude> </libsIncludes> ... <!-- Since magic does not work, we also need that (see below) --> <artifacts> <artifact> <name>google-collect</name> <groupId>com.google.collections</groupId> <artifactId>google-collections</artifactId> </artifact> </artifacts> ... </configuration> ...
To signal the classes that should be considered as provided at runtime and ignore them during dependency analysis, you have two configuration options where you may define selector patterns of classes to ignore:
... <configuration> ... <jvmProvidedClasses> <jvmProvidedClass>java.**.*</jvmProvidedClass> <jvmProvidedClass>javax.**.*</jvmProvidedClass> <jvmProvidedClass>com.sun.**.*</jvmProvidedClass> <jvmProvidedClass>org.xml.sax.**.*</jvmProvidedClass> <jvmProvidedClass>org.w3c.dom.**.*</jvmProvidedClass> <jvmProvidedClass>org.ietf.jgss.*</jvmProvidedClass> <jvmProvidedClass>sunw.io.*</jvmProvidedClass> <jvmProvidedClass>sunw.util.*</jvmProvidedClass> </jvmProvidedClasses> ... </configuration> ...
All classes name that will match the above patterns will be ignored when another has them for dependencies.
If the analyzer as used wrong Maven coordinates to identify analyzed files, you may help the identification engine by providing some hints:
More precise definition is always use in priority to less precise one. So the global hint is a last resort, and will be overidden by an artifacts or file hint.
Here is some examples:
... <configuration> ... <artifacts> ... <!-- Define groupId and version of all identified artifacts not hinted anywhere else using the current project groupId and version. Perfect for most projects, and for our sample of Google GData API --> <artifact> <groupId>${project.groupId}</groupId> <version>${project.version}</version> </artifact> <!-- Define a partial overide of a given artifact not hinted as a file elsewhere, using the detected version --> <artifact> <name>artifact-id-identified-by-the-basic-analysis</name> <groupId>new.group.id</groupId> <artifactId>new-artifact-id</artifactId> </artifact> <!-- Define a complete overide of a given file --> <artifact> <name>name-of-file-without-extension</name> <groupId>group.id.for.this.file</groupId> <artifactId>artifact-id-for-this-file</artifactId> <version>version-for-this-file</version> </artifact> ... </artifacts> ... </configuration> ...
After providing additional dependencies or hints, you may lauch a new analysis by running the following command:
mvn mavenizer:clean-analyze compile
This will update the analysis results, so you can iterate until the results is precisely what you expect. With the above samples, after adding required dependency and hints, you have no more unresolved dependencies, and you get:
<?xml version="1.0" encoding="UTF-8"?> <artifacts> <artifact name="gdata/java/lib/gdata-analytics-2.1.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-analytics</artifactid> <version>1.41.5</version> <dependencies> <dependency name="gdata/java/lib/gdata-core-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-core</artifactid> <version>1.41.5</version> </dependency> </dependencies> </artifact> ... <artifact name="gdata/java/lib/gdata-base-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-base</artifactid> <version>1.41.5</version> <dependencies> <dependency> <groupid>com.google.collections</groupid> <artifactid>google-collections</artifactid> <version>1.0-rc1</version> </dependency> <dependency name="gdata/java/lib/gdata-client-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-client</artifactid> <version>1.41.5</version> </dependency> <dependency name="gdata/java/lib/gdata-core-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-core</artifactid> <version>1.41.5</version> </dependency> <dependency name="gdata/java/lib/gdata-media-1.0.jar"> <groupid>com.google.gdata</groupid> <artifactid>gdata-media</artifactid> <version>1.41.5</version> </dependency> </dependencies> </artifact> ... </artifacts>
Once the result of the analysis fulfil your requirements, you may easily create POM files by simply running the package phase.
You may define the directory where POM are created inside the project build directory:
... <configuration> ... <pomBaseDir>${project.build.directory}/path/to/pom</pomBaseDir> ... </configuration> ...
If you define the POM base directory outside of the project build directory, you will loose the benefit of the configuration since you will have to provide the POM yourself. This will defeat the whole purpose of this plugin.
To install the binary file defined in the mavenizer configuration file, it is really simple, you just need to run the install phase.
mvn install
You may decide whether to update the metadata to make installed artifacts a release version by defining updateReleaseInfo to true in the configuration of this plugin.
Before deploying artifacts, you need to define the remote repository where you expect artifact to be deployed. Currently, this plugin does not use DistributionManagement definition and require the configuration of the remote repository in its own configuration like this:
... <configuration> ... <repositoryId>my-repository-id</repositoryId> <repositoryUrl>http://my.repository.com/content/repositories/myrepository</repositoryUrl> ... </configuration> ...
To deploy the binary file defined in the mavenizer configuration file, it is now really simple, you just need to run the deploy phase.
mvn deploy
You may decide whether to update the metadata to make installed artifacts a release version by defining updateReleaseInfo to true in the configuration of this plugin.