The assembly
descriptor is an XML-based configuration, which defines how to build an assembly and how its content should be structured.
If we go back to our example, the attached
goal of the assembly
plugin creates a binary distribution according to the assembly
descriptor, both in the test
and package
phases of the default
Maven lifecycle. The assembly
descriptors for each phase can be specified under the descriptors
element. As in this particular example, there can be multiple descriptor
elements defined under the descriptors
parent element. For the package
phase, it has the following three assembly descriptors:
<descriptors> <descriptor>src/assembly/bin.xml</descriptor> <descriptor>src/assembly/src.xml</descriptor> <descriptor>src/assembly/docs.xml</descriptor> </descriptors>
Each descriptor
element instructs the assembly
plugin where to load the descriptor, and each descriptor
file will be executed sequentially in the defined order.
Let's have a look at the src/assembly/bin.xml
file, shown as follows. The file path is given relative to the root POM file under the distribution
module. You can find the complete bin.xml
file at https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/products/is/5.0.0/modules/distribution/src/assembly/bin.xml:
<assembly> <formats> <format>zip</format> </formats>
The value of the format
element specifies the ultimate type of the artifact to be produced. It can be zip
, tar
, tar.gz
, tar.bz2
, jar
, dir
, or war
. You can use the same assembly descriptor to create multiple formats. In this case, you can include multiple format
elements under the formats
parent element.
Even though you can specify the format of the assembly in the assembly
descriptor, it is recommended that you do this via the plugin configuration itself. In the plugin configuration, you can define different formats for your assembly shown as follows. The benefit here is that you can have multiple Maven profiles to build different archive types. We will be talking about Maven profiles in Chapter 9, Best Practices:
<configuration> <formats> <format>zip</format> </formats> </configuration>
<includeBaseDirectory>false</includeBaseDirectory>
When the value of the includeBaseDirectory
element is set to false
, the artifact will be created with no base directory. If this is set to true
, which is the default value, the artifact will be created under a base directory. You can specify a value for the base directory under the baseDirectory
element. In most of the cases, the value of includeBaseDirectory
is set to false
so that the final distribution unit directly packs all the artifacts right under it, without having another root directory.
<fileSets> <fileSet> <directory>target/wso2carbon-core-4.2.0</directory> <outputDirectory>wso2is-${pom.version}</outputDirectory> <excludes> <exclude>**/*.sh</exclude>
Each fileSet
element under the fileSets
parent element specifies the set of files to be assembled to build the final archive. The first fileSet
element instructs to copy all the content from the directory
(which is target/wso2carbon-core-4.2.0
) to the output directory specified under the outputDirectory
configuration element, excluding all the files defined under each exclude
element. If no exclusions are defined, then all the content inside directory
will be copied to the outputDirectory
. In this particular case, the value of ${pom.version}
will be replaced the by version
of the artifact, which is defined in the pom.xml
file under the distribution
module.
The exclude
element instructs not to copy any file that has the .sh
extension from anywhere inside target/wso2carbon-core-4.2.0
to the outputDirectory
.
<exclude>**/wso2server.bat</exclude> <exclude>**/axis2services/sample01.aar</exclude>
The exclude
element instructs not to copy the sample01.aar
file inside a directory called axis2services
from anywhere inside target/wso2carbon-core-4.2.0
to outputDirectory
.
<exclude>**/axis2services/Echo.aar</exclude> <exclude>**/axis2services/Version.aar</exclude> <exclude>**/pom.xml</exclude> <exclude>**/version.txt</exclude> <exclude>**/README*</exclude> <exclude>**/carbon.xml</exclude> <exclude>**/axis2/*</exclude> <exclude>**/LICENSE.txt</exclude> <exclude>**/INSTALL.txt</exclude> <exclude>**/release-notes.html</exclude> <exclude>**/claim-config.xml</exclude> <exclude>**/log4j.properties</exclude> <exclude>**/registry.xml</exclude> </excludes> </fileSet> <fileSet> <directory>../p2-profile-gen/target/wso2carbon-core- 4.2.0/repository/conf/identity </directory> <outputDirectory>wso2is-${pom.version}/repository/ conf/identity </outputDirectory> <includes> <include>**/*.xml</include> </includes>
The include
element instructs to copy only the files that have the .xml
extension from anywhere inside the ../p2-profile-gen/target/wso2carbon-core-4.2.0/repository/conf/identity
directory to the outputDirectory
. If no include
element is defined, everything will be included.
</fileSet> <fileSet> <directory>../p2-profile-gen/target/wso2carbon-core- 4.2.0/repository/resources/security/ldif </directory> <outputDirectory>wso2is-${pom.version}/repository/ resources/security/ldif </outputDirectory> <includes> <include>identityPerson.ldif</include> <include>scimPerson.ldif</include> <include>wso2Person.ldif</include> </includes>
The include
element instructs to copy only the files having specific names from anywhere inside the ../p2-profile-gen/target/wso2carbon-core/4.2.0/repository/resources/security/ldif
directory to the outputDirectory
.
</fileSet> <fileSet> <directory>../p2-profile-gen/target/wso2carbon-core- 4.2.0/repository/deployment/server/webapps </directory> <outputDirectory>${pom.artifactId}-${pom.version} /repository/deployment/server/webapps </outputDirectory> <includes> <include>oauth2.war</include> </includes>
The include
element instructs to copy only the WAR file with the name oauth2.war
from anywhere inside the ../p2-profile-gen/target/wso2carbon-core/4.2.0/repository/resources/deployment/server/webappas
directory to the outputDirectory
.
</fileSet> <fileSet> <directory>../p2-profile-gen/target/wso2carbon-core- 4.2.0/repository/deployment/server/webapps </directory> <outputDirectory>${pom.artifactId}-${pom.version} /repository/deployment/server/webapps </outputDirectory> <includes> <include>authenticationendpoint.war</include> </includes> </fileSet> <fileSet> <directory>../styles/service/src/main/resources /web/styles/css </directory> <outputDirectory>${pom.artifactId}-${pom.version} /resources/allthemes/Default/admin </outputDirectory> <includes> <include>**/**.css</include> </includes>
The include
element instructs to copy any file with the .css
extension from anywhere inside the ../styles/service/src/main/resources/web/styles/css
directory to the outputDirectory
.
</fileSet> <fileSet> <directory>../p2-profile-gen/target/WSO2-CARBON-PATCH- 4.2.0-0006 </directory> <outputDirectory>wso2is- ${pom.version}/repository/components/patches/ </outputDirectory> <includes> <include>**/patch0006/*.*</include> </includes>
The include
element instructs to copy all the files inside the patch006
directory from anywhere inside the ../p2-profile-gen/target/WSO2-CARBON-PATCH-4.2.0-0006
directory to the outputDirectory
.
</fileSet> </fileSets> <files>
The file
element is very similar to the fileSet
element in terms of the key functionality. Both can be used to control the content of the assembly.
The fileMode
element in the following snippet defines a set of permissions to be attached to the copied file. The permissions are defined as per the four-digit octal notation. You can read more about the four-digit octal notation from http://en.wikipedia.org/wiki/File_system_permissions#Octal_notation_and_additional_permissions:
<file> <source>../p2-profile-gen/target/WSO2-CARBON-PATCH- ${carbon.kernel.version}- 0006/lib/org.wso2.ciphertool-1.0.0-wso2v2.jar </source> <outputDirectory>${pom.artifactId}-${pom.version}/lib/ </outputDirectory> <filtered>true</filtered> <fileMode>644</fileMode> </file> <files> </assembly>
There are three descriptor
elements defined under the assembly
plugin for the package
phase. The one we just discussed earlier will create the binary distribution, while the src/assembly/src.xml
and src/assembly/docs.xml
files will create the source distribution and the documentation distribution, respectively.
Let's also look at the assembly
descriptor defined for the test
phase:
<descriptors> <descriptor>src/assembly/dist.xml</descriptor> </descriptors>
This is quite short and only includes the configuration required to build the initial distribution of WSO2 Identity Server. Even though this project does this at the test
phase, it seems like it has no value in doing this. In this case, it seems like maven-antrun-plugin
, which is also associated with the package
phase but prior to the definition of the assembly
plugin, needs the ZIP file distribution. Ideally, you should not have the assembly
plugin run at the test
phase unless there is a very strong reason. You might need the distribution ready to run the integration tests; however, the integration tests should be executed in the integration-test
phase, which comes after the package
phase. In most of the cases, the assembly
plugin is associated with the package
phase of the Maven default
lifecycle.
<assembly> <formats> <format>zip</format> </formats> <includeBaseDirectory>false</includeBaseDirectory> <fileSets> <!-- Copying p2 profile and osgi bundles--> <fileSet> <directory>../p2-profile-gen/target/wso2carbon-core- 4.2.0/repository/components </directory> <outputDirectory>wso2is-${pom.version}/repository/components </outputDirectory> <excludes> <exclude>**/eclipse.ini</exclude> <exclude>**/*.lock</exclude> <exclude>**/.data</exclude> <exclude>**/.settings</exclude> </excludes> </fileSet> </fileSets> <dependencySets> <dependencySet> <outputDirectory>wso2is-${pom.version}/repository/ deployment/client/modules </outputDirectory> <includes> <include>org.apache.rampart:rampart:mar</include> </includes> </dependencySet> </dependencySets> </assembly>
This configuration introduces a new element that we have not seen before: dependencySet
. The dependencySet
element lets you include/exclude project dependencies to/from the final assembly that we are building. In the previous example, it adds the rampart
module into the outputDirectory
. The value of the include
element should be in the groupdId:artifactId:type[:classifier][:version]
format. Maven will look for this artifact with the defined coordinates in its local Maven repository first, and if found, it will copy the artifact to the outputDirectory
element.
Unlike the fileSet
or file
configuration, dependencySet
does not define a concrete path to pick and copy the dependency from. Maven finds artifacts via the defined coordinates. If you want to include a dependency just by its groupId
and the artifactId
, then you can follow the groupdId:artifactId
pattern. The particular artifact should be defined in the POM file, which has the assembly
plugin defined under the dependencies
section. You can find the following dependency definition for the rampart
module in the POM file under the distribution
module. If two versions of the same dependency are being defined in the same POM file (rather unlikely), then the last in the order will be copied.
<dependency> <groupId>org.apache.rampart</groupId> <artifactId>rampart</artifactId> <type>mar</type> <version>1.6.1-wso2v12</version> </dependency>
You can also include a dependency by its groupId
, artifactId
, and type
elements, as shown in the following configuration. Then, you can follow the groupdId:artifactId:type[:classifier]
pattern. This is the exact pattern followed in the previous example:
<includes> <include>org.apache.rampart:rampart:mar</include> </includes>
If you want to be more precise, you can also include the version in the pattern. Then, it will look like this:
<includes> <include>org.apache.rampart:rampart:mar:1.6.1-wso2v12 </include> </includes>
Most of the time, we talk about four Maven coordinates; however, to be precise there are five. A Maven artifact can be uniquely identified by these five coordinates: groupdId:artifactId:type[:classifier]:version
. We have already discussed about the four main coordinates, but not about the classifier. This is very rarely used; it can be quite useful in a scenario where we build an artifact out of the same POM file but with multiple target environments. We will discuss classifiers
in detail in Chapter 9, Best Practices.
The previous example only covered a very little subset of the assembly
descriptor. You can find all available configuration options at http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html, which is a quite exhausting list.
Let's have a look at another real-world example with Apache Axis2. Axis2 is an open source project released under the Apache 2.0 license. Axis2 has three types of distributions: a binary distribution as a ZIP file, a WAR file distribution, and a source distribution as a ZIP file. The binary ZIP distribution of Axis2 can be run on its own, while the WAR distribution must be deployed in a Java EE application server.
All three Axis2 distributions are created from the POM file inside the distribution
module, which can be found at http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/distribution/pom.xml. This POM file associates the single
goal of the Maven assembly
plugin with the project, which initiates the process of creating the final distribution artifacts. The assembly configuration points to three different assembly
descriptors: one for the ZIP distribution, another for the WAR distribution, and a third one for the source code distribution.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <id>distribution-package</id> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <finalName>axis2-${project.version}</finalName> <descriptors> <descriptor>src/main/assembly/war-assembly.xml </descriptor> <descriptor>src/main/assembly/src-assembly.xml </descriptor> <descriptor>src/main/assembly/bin-assembly.xml </descriptor> </descriptors> </configuration> </execution> </executions> </plugin>
Let's have a look at the bin-assembly.xml
file, which is the assembly
descriptor that builds the ZIP distribution:
<assembly>
<id>bin</id>
<includeBaseDirectory>true</includeBaseDirectory>
<baseDirectory>axis2-${version}</baseDirectory>
<formats>
<!--<format>tar.gz</format>
//uncomment,if tar.gz archive needed-->
<format>zip</format>
</formats>
This is exactly what we discussed earlier and exactly what we wanted to avoid due to the same reason as in the comment. If we want to build a tar.gz
distribution, then we need to modify the file. Instead of doing this, we should have moved the format
configuration element out of the assembly
descriptor to the plugin configuration defined in the pom.xml
file. Then, you can define multiple profiles and configure the archive type based on the profile.
<fileSets>
</fileSets>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
The useProjectArtifact
configuration element instructs the plugin whether or not to include the artifact produced in this project build into the dependencySet
element. By setting the value to false
, we avoid it.
<outputDirectory>lib</outputDirectory> <includes> <include>*:*:jar</include> </includes> <excludes> <exclude>org.apache.geronimo.specs: geronimo-activation_1.1_spec:jar </exclude> </excludes> </dependencySet> <dependencySet> <useProjectArtifact>false</useProjectArtifact> <outputDirectory>lib/endorsed</outputDirectory> <includes> <include>javax.xml.bind:jaxb-api:jar</include> </includes> </dependencySet> <dependencySet> <useProjectArtifact>false</useProjectArtifact> <includes> <include>org.apache.axis2:axis2-webapp</include> </includes>
The includes
and excludes
configuration elements will make sure that all the JAR files defined under the dependencies
section of the distribution/pom.xml
file will be included in the assembly, except the JAR files defined under the excludes
configuration element. If you do not have any include
elements, all the dependencies defined in the POM file will be included in the assembly, except what is defined under the excludes
section.
<unpack>true</unpack>
Once the unpack
configuration element is set to true
, all the dependencies defined under the include
elements will be unpacked to the outputDirectory
. The plugin is capable of unpacking the jar
, zip
, tar.gz
, and tar.bz2
archives. The unpackOptions
configuration element, can be used to filter out the content of the dependencies getting unpacked. According to the following configuration, only the files defined under the include
elements under the unpackOptions
element will be included; the rest will be ignored and won't be included in the assembly. In this particular case, axis2-webapp
is a WAR file and the distributions/pom.xml
file has a dependency to it. This web app will be exploded, and then all the files inside the WEB-INF/classes
and axis2-web
directories will be copied into the webapp
directory of the ZIP distribution along with the WEB-INF/web.xml
file:
<outputDirectory>webapp</outputDirectory> <unpackOptions> <includes> <include>WEB-INF/classes/**/*</include> <include>WEB-INF/web.xml</include> <include>axis2-web/**/*</include> </includes> </unpackOptions> </dependencySet> </dependencySets> </assembly>
Now, let's have a look at war-assembly.xml
, which is the assembly descriptor that builds the WAR distribution. There is nothing new in this configuration, except the outputFileNameMapping
configuration element. As the value of the format
element is set to zip
, this assembly
descriptor will produce an archive file conforming to the ZIP file specification. The value of the outputFileNameMapping
configuration element gets applied to all the dependencies. The default value is parameterized, that is, ${artifactId}-${version}${classifier?}.${extension}
. In this case, it's hardcoded to axis2.war
, so the axis2-webapp
artifact will be copied to outputDirectory
as axis2.war
. As there is no value defined for the outputDirectory
element, the files will be copied to the root location.
<assembly>
<id>war</id>
<includeBaseDirectory>false</includeBaseDirectory>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<includes>
<include>org.apache.axis2:axis2-webapp</include>
</includes>
<outputFileNameMapping>axis2.war</outputFileNameMapping>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>../..</directory>
<outputDirectory></outputDirectory>
<includes>
<include>LICENSE.txt</include>
<include>NOTICE.txt</include>
<include>README.txt</include>
<include>release-notes.html</include>
</includes>
<filtered>true</filtered>
</fileSet>
</fileSets>
</assembly>
18.190.217.253