 ------
  Including Module Binaries
 ------
  John Casey
 ------
  2006-05-05
 ------

~~ Licensed to the Apache Software Foundation (ASF) under one
~~ or more contributor license agreements.  See the NOTICE file
~~ distributed with this work for additional information
~~ regarding copyright ownership.  The ASF licenses this file
~~ to you under the Apache License, Version 2.0 (the
~~ "License"); you may not use this file except in compliance
~~ with the License.  You may obtain a copy of the License at
~~
~~   http://www.apache.org/licenses/LICENSE-2.0
~~
~~ Unless required by applicable law or agreed to in writing,
~~ software distributed under the License is distributed on an
~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~~ KIND, either express or implied.  See the License for the
~~ specific language governing permissions and limitations
~~ under the License.

~~ NOTE: For help with the syntax of this file, see:
~~ https://maven.apache.org/doxia/references/apt-format.html

Including Module Binaries

* Warning

  <<Warning:>> Using the <<<binaries>>> section of a <<<moduleSet>>> definition
  involves some tricky considerations that are a result of the way Maven
  sorts and executes project builds within a multimodule context. Please
  read {{{../../faq.html#module-binaries}this FAQ entry}} if you decide to use them.
  
  <<NOTE:>> The new <<<useAllReactorProjects>>> flag in the <<<moduleSet>>> section
  allows you to consume module binaries from child modules in a multimodule build. This
  is an important to resolve the conflict between Maven's build ordering and the old
  approach to module binaries, where the assembly was build from the parent POM.
  Please read the FAQ entry above for more information, and read the documentation 
  below (carefully!) to see the new approach in action.
  
* Introduction

  It is common practice to create an assembly using the parent POM of a
  multimodule build. At times, you may want to ensure that this assembly also
  includes one or more of the module binaries.

  This example demonstrates how to include the artifact and dependencies of a
  module, under the directory <<<modules/\<module-name\>>>>.

* The Assembly Descriptor

  First, let's write an assembly descriptor to create this assembly. For the
  sake of clarity, this descriptor will be as simple as possible, only
  demonstrating the features described by this example.

+---+
<assembly xmlns="http://maven.apache.org/ASSEMBLY/${mdoVersion}"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/${mdoVersion} http://maven.apache.org/xsd/assembly-${mdoVersion}.xsd">
  <id>bin</id>
  <formats>
    <format>dir</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <moduleSets>
    <moduleSet>
    
      <!-- Enable access to all projects in the current multimodule build! -->
      <useAllReactorProjects>true</useAllReactorProjects>
      
      <!-- Now, select which projects to include in this module-set. -->
      <includes>
        <include>org.test:child1</include>
      </includes>
      <binaries>
        <outputDirectory>modules/${project.artifactId}</outputDirectory>
        <unpack>false</unpack>
      </binaries>
    </moduleSet>
  </moduleSets>
</assembly>
+---+

  This descriptor states that the assembly id should be <<<bin>>>, that the
  output format is a directory, and that the contents of the assembly should
  <<not>> be contained within a directory named after the finalName of the
  top-level project.

  Furthermore, it states that we wish to include the artifact files for the module
  with a groupId of <<<org.test>>> and an artifactId of <<<child1>>>, along with
  its dependency artifacts. These artifacts should be contained within the
  directory structure <<<modules/child1>>> for this module, since the
  outputDirectory expression will be interpolated on a module-by-module basis.
  
  <<Finally>>, notice the <<new>> <<<useAllReactorProjects>>> flag. This enables
  access to all projects in the current reactor (multimodule build), even from 
  a child module. Using this flag, it's now possible to use a child module - sorted
  to the end of the multimodule build process using appropriate dependency 
  declarations - to generate an assembly containing module binaries.

* The POM

  Now, let's review the POM configuration necessary to enable the building of
  this assembly via the <<<assembly:single>>> goal. First, let's look at the parent POM:

+---+
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.test</groupId>
  <artifactId>parent</artifactId>
  <version>1.0</version>

  <packaging>pom</packaging>

  <name>Parent</name>

  <modules>
    <module>child1</module>
    <module>child2</module>
    <module>child3</module>
    <module>distribution</module>
  </modules>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>${project.version}</version>
          <configuration>
            <descriptors>
              <descriptor>src/assembly/bin.xml</descriptor>
            </descriptors>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
+---+

  <<NOTE:>> The last module - <<<distribution>>> - is the child in which the assembly will be created.
  
  That POM looks like this:
  
+---+
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <parent>
    <groupId>org.test</groupId>
    <artifactId>parent</artifactId>
    <version>1.0</version>
  </parent>
  
  <artifactId>distribution</artifactId>

  <packaging>pom</packaging>

  <name>Distribution</name>
  
  <!-- NOTE: These dependency declarations are only required to sort this project to the 
       end of the line in the multimodule build. 
       
       Since we only include the child1 module in our assembly, we only need to ensure this
       distribution project builds AFTER that one...
  -->
  <dependencies>
    <dependency>
      <groupId>org.test</groupId>
      <artifactId>child1</artifactId>
      <version>1.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>distro-assembly</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptors>
                <descriptor>src/assembly/bin.xml</descriptor>
              </descriptors>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>
+---+

  This POM directs the Assembly Plugin to execute the <<<single>>> goal when the build reaches the 
  <<<package>>> phase, and tells it to use the <<<bin.xml>>> assembly descriptor when executing.

* Execute!

  To build the assembly, we issue the following command:

-----
mvn clean package
-----

  This will ensure that the output directory (normally, <<<target>>>), is
  removed before building the assembly directory.

  <<Note:>> Because of a quirk in Maven 2.0's execution model relating to
  aggregator goals and the inheritance hierarchy, we need to explicitly execute
  the package phase ahead of the assembly invocation, to ensure all modules have
  been built.

* Examining the Output

  When the Maven execution completes, the following directory structure should
  be left. Remember, our assembly format was <<<dir>>>, which is why the output
  is a directory and not an archive of some sort.
  
  Here are the directory contents:

-----
target/distribution/distribution-1.0-bin
`-- modules
    `-- child1
        |-- child1-1.0.jar
        `-- junit-3.8.1.jar
-----

