You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by mt...@apache.org on 2021/10/13 09:26:48 UTC

[maven] 02/03: [MNG-6389] Seperate module for toolchain builder

This is an automated email from the ASF dual-hosted git repository.

mthmulders pushed a commit to branch MNG-6389-introduce-seperate-toolchain-artifact
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 744d0a1216699d646adf0621b89f4f4e6b4b8623
Author: Giovanni van der Schelde <Gi...@infosupport.com>
AuthorDate: Wed Oct 13 09:10:52 2021 +0200

    [MNG-6389] Seperate module for toolchain builder
---
 maven-bom/pom.xml                                  |   5 +
 maven-core/pom.xml                                 |   4 +
 .../pom.xml                                        |  34 ++-
 .../building/DefaultToolchainsBuilder.java         |   0
 .../building/DefaultToolchainsBuildingRequest.java |   0
 .../building/DefaultToolchainsBuildingResult.java  |   6 +-
 .../toolchain/building/ToolchainsBuilder.java      |   0
 .../building/ToolchainsBuildingException.java      |   4 +-
 .../building/ToolchainsBuildingRequest.java        |   0
 .../building/ToolchainsBuildingResult.java         |   4 +-
 .../toolchain/io/DefaultToolchainsReader.java      |  15 +-
 .../toolchain/io/DefaultToolchainsWriter.java      |   0
 .../toolchain/io/ToolchainsParseException.java     |   0
 .../maven/toolchain/io/ToolchainsReader.java       |   4 +-
 .../maven/toolchain/io/ToolchainsWriter.java       |   0
 .../toolchain/merge/MavenToolchainMerger.java      |  10 +-
 .../building/DefaultToolchainsBuilderTest.java     | 283 +++++++++++++++++++++
 .../building/ToolchainsBuildingExceptionTest.java  |  73 ++++++
 .../toolchain/merge/MavenToolchainMergerTest.java  | 135 ++++++++++
 .../org/apache/maven/toolchain/global.xml          |  35 +++
 .../toolchain/model/toolchains-jdks-extend.xml     |  45 ++++
 .../toolchain/model/toolchains-jdks-extra.xml      |  45 ++++
 .../maven/toolchain/model/toolchains-jdks.xml      |  43 ++++
 .../resources/org/apache/maven/toolchain/user.xml  |  35 +++
 maven-toolchain-model/pom.xml                      |   3 +
 pom.xml                                            |   1 +
 26 files changed, 752 insertions(+), 32 deletions(-)

diff --git a/maven-bom/pom.xml b/maven-bom/pom.xml
index 2395531..75c5a69 100644
--- a/maven-bom/pom.xml
+++ b/maven-bom/pom.xml
@@ -135,6 +135,11 @@ under the License.
       </dependency>
       <dependency>
         <groupId>org.apache.maven</groupId>
+        <artifactId>maven-toolchain-builder</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
         <artifactId>maven-slf4j-wrapper</artifactId>
         <version>${project.version}</version>
       </dependency>
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index e91263a..1dac274 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -58,6 +58,10 @@ under the License.
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
+      <artifactId>maven-toolchain-builder</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
       <artifactId>maven-repository-metadata</artifactId>
     </dependency>
     <dependency>
diff --git a/maven-toolchain-model/pom.xml b/maven-toolchain-builder/pom.xml
similarity index 61%
copy from maven-toolchain-model/pom.xml
copy to maven-toolchain-builder/pom.xml
index e824643..5dcbea2 100644
--- a/maven-toolchain-model/pom.xml
+++ b/maven-toolchain-builder/pom.xml
@@ -29,26 +29,40 @@ under the License.
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>maven-toolchain-model</artifactId>
+    <artifactId>maven-toolchain-builder</artifactId>
+
+    <name>Maven Toolchain Builder</name>
+    <description>The effective toolchain builder.</description>
 
     <dependencies>
         <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-toolchain-model</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-builder-support</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.inject</groupId>
+            <artifactId>javax.inject</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.codehaus.plexus</groupId>
-            <artifactId>plexus-utils</artifactId>
+            <artifactId>plexus-interpolation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 
     <build>
         <plugins>
             <plugin>
-                <groupId>org.codehaus.modello</groupId>
-                <artifactId>modello-maven-plugin</artifactId>
-                <configuration>
-                    <version>1.1.0</version>
-                    <models>
-                        <model>src/main/mdo/toolchains.mdo</model>
-                    </models>
-                </configuration>
+                <groupId>org.eclipse.sisu</groupId>
+                <artifactId>sisu-maven-plugin</artifactId>
             </plugin>
         </plugins>
     </build>
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
index 2d07a4a..fd96162 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
@@ -19,12 +19,12 @@ package org.apache.maven.toolchain.building;
  * under the License.
  */
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.apache.maven.building.Problem;
 import org.apache.maven.toolchain.model.PersistedToolchains;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Holds the result of the merged toolchains and holds the problems during this build, if any.
  *
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
index ccd354b..dce9e5c 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
@@ -19,13 +19,13 @@ package org.apache.maven.toolchain.building;
  * under the License.
  */
 
+import org.apache.maven.building.Problem;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.maven.building.Problem;
-
 /**
  * @author Robert Scholte
  * @since 3.3.0
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
index f7c5f71..4ec3ee6 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
@@ -19,11 +19,11 @@ package org.apache.maven.toolchain.building;
  * under the License.
  */
 
-import java.util.List;
-
 import org.apache.maven.building.Problem;
 import org.apache.maven.toolchain.model.PersistedToolchains;
 
+import java.util.List;
+
 /**
  * Collects the output of the toolchains builder.
  *
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
similarity index 99%
rename from maven-core/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
index 2522551..4d766a1 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
@@ -19,6 +19,13 @@ package org.apache.maven.toolchain.io;
  * under the License.
  */
 
+import org.apache.maven.toolchain.model.PersistedToolchains;
+import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -26,14 +33,6 @@ import java.io.Reader;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
 /**
  * Handles deserialization of toolchains from the default textual format.
  *
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
index 44dc2bd..306b832 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
@@ -19,14 +19,14 @@ package org.apache.maven.toolchain.io;
  * under the License.
  */
 
+import org.apache.maven.toolchain.model.PersistedToolchains;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 import java.util.Map;
 
-import org.apache.maven.toolchain.model.PersistedToolchains;
-
 /**
  * Handles deserialization of toolchains from some kind of textual format like XML.
  *
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
similarity index 100%
rename from maven-core/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
similarity index 99%
rename from maven-core/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
rename to maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
index 9b6596e..b477f82 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
@@ -19,14 +19,14 @@ package org.apache.maven.toolchain.merge;
  * under the License.
  */
 
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
 import org.apache.maven.toolchain.model.PersistedToolchains;
 import org.apache.maven.toolchain.model.ToolchainModel;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 /**
  *
  * @author Robert Scholte
@@ -100,4 +100,4 @@ public class MavenToolchainMerger
         return model;
     }
 
-}
\ No newline at end of file
+}
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java
new file mode 100644
index 0000000..6460aaf
--- /dev/null
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java
@@ -0,0 +1,283 @@
+package org.apache.maven.toolchain.building;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.building.StringSource;
+import org.apache.maven.toolchain.io.DefaultToolchainsReader;
+import org.apache.maven.toolchain.io.DefaultToolchainsWriter;
+import org.apache.maven.toolchain.io.ToolchainsParseException;
+import org.apache.maven.toolchain.model.PersistedToolchains;
+import org.apache.maven.toolchain.model.ToolchainModel;
+import org.codehaus.plexus.interpolation.os.OperatingSystemUtils;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatchers;
+import org.mockito.InjectMocks;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+public class DefaultToolchainsBuilderTest
+{
+    private static final String LS = System.lineSeparator();
+
+    @Spy
+    private DefaultToolchainsReader toolchainsReader;
+
+    @Spy
+    private DefaultToolchainsWriter toolchainsWriter;
+
+    @InjectMocks
+    private DefaultToolchainsBuilder toolchainBuilder;
+
+    @BeforeEach
+    public void onSetup()
+    {
+        MockitoAnnotations.initMocks( this );
+
+        Map<String, String> envVarMap = new HashMap<>();
+        envVarMap.put("testKey", "testValue");
+        envVarMap.put("testSpecialCharactersKey", "<test&Value>");
+        OperatingSystemUtils.setEnvVarSource(new TestEnvVarSource(envVarMap));
+    }
+
+    @Test
+    public void testBuildEmptyRequest()
+        throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        assertNotNull( result.getEffectiveToolchains() );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testBuildRequestWithUserToolchains()
+        throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setUserToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains userResult = new PersistedToolchains();
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType( "TYPE" );
+        toolchain.addProvide( "key", "user_value" );
+        userResult.addToolchain(  toolchain );
+        doReturn(userResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        assertNotNull( result.getEffectiveToolchains() );
+        assertEquals( 1, result.getEffectiveToolchains().getToolchains().size() );
+        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
+        assertEquals( "user_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testBuildRequestWithGlobalToolchains()
+        throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setGlobalToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains globalResult = new PersistedToolchains();
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType( "TYPE" );
+        toolchain.addProvide( "key", "global_value" );
+        globalResult.addToolchain(  toolchain );
+        doReturn(globalResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        assertNotNull( result.getEffectiveToolchains() );
+        assertEquals( 1, result.getEffectiveToolchains().getToolchains().size() );
+        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
+        assertEquals( "global_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testBuildRequestWithBothToolchains()
+        throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setGlobalToolchainsSource( new StringSource( "" ) );
+        request.setUserToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains userResult = new PersistedToolchains();
+        ToolchainModel userToolchain = new ToolchainModel();
+        userToolchain.setType( "TYPE" );
+        userToolchain.addProvide( "key", "user_value" );
+        userResult.addToolchain(  userToolchain );
+
+        PersistedToolchains globalResult = new PersistedToolchains();
+        ToolchainModel globalToolchain = new ToolchainModel();
+        globalToolchain.setType( "TYPE" );
+        globalToolchain.addProvide( "key", "global_value" );
+        globalResult.addToolchain(  globalToolchain );
+        doReturn(globalResult).doReturn(userResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        assertNotNull( result.getEffectiveToolchains() );
+        assertEquals( 2, result.getEffectiveToolchains().getToolchains().size() );
+        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
+        assertEquals( "user_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(1).getType() );
+        assertEquals( "global_value", result.getEffectiveToolchains().getToolchains().get(1).getProvides().getProperty( "key" ) );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testStrictToolchainsParseException() throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setGlobalToolchainsSource( new StringSource( "" ) );
+        ToolchainsParseException parseException = new ToolchainsParseException( "MESSAGE", 4, 2 );
+        doThrow(parseException).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        try
+        {
+            toolchainBuilder.build( request );
+        }
+        catch ( ToolchainsBuildingException e )
+        {
+            assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
+                "[FATAL] Non-parseable toolchains (memory): MESSAGE @ line 4, column 2" + LS, e.getMessage() );
+        }
+    }
+
+    @Test
+    public void testIOException() throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setGlobalToolchainsSource( new StringSource( "", "LOCATION" ) );
+        IOException ioException = new IOException( "MESSAGE" );
+        doThrow(ioException).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        try
+        {
+            toolchainBuilder.build( request );
+        }
+        catch ( ToolchainsBuildingException e )
+        {
+            assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
+                "[FATAL] Non-readable toolchains LOCATION: MESSAGE" + LS, e.getMessage() );
+        }
+    }
+
+    @Test
+    public void testEnvironmentVariablesAreInterpolated()
+            throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setUserToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType( "TYPE" );
+        toolchain.addProvide( "key", "${env.testKey}" );
+
+        Xpp3Dom configurationChild = new Xpp3Dom("jdkHome");
+        configurationChild.setValue("${env.testKey}");
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        configuration.addChild(configurationChild);
+        toolchain.setConfiguration(configuration);
+        persistedToolchains.addToolchain( toolchain );
+        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        String interpolatedValue = "testValue";
+        assertEquals(interpolatedValue, result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        Xpp3Dom toolchainConfiguration = (Xpp3Dom) result.getEffectiveToolchains().getToolchains().get(0).getConfiguration();
+        assertEquals(interpolatedValue, toolchainConfiguration.getChild("jdkHome").getValue());
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testNonExistingEnvironmentVariablesAreNotInterpolated()
+            throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setUserToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType( "TYPE" );
+        toolchain.addProvide( "key", "${env.testNonExistingKey}" );
+
+        persistedToolchains.addToolchain( toolchain );
+        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        assertEquals("${env.testNonExistingKey}", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    @Test
+    public void testEnvironmentVariablesWithSpecialCharactersAreInterpolated()
+            throws Exception
+    {
+        ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
+        request.setUserToolchainsSource( new StringSource( "" ) );
+
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType( "TYPE" );
+        toolchain.addProvide( "key", "${env.testSpecialCharactersKey}" );
+
+        persistedToolchains.addToolchain( toolchain );
+        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        String interpolatedValue = "<test&Value>";
+        assertEquals(interpolatedValue, result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
+        assertNotNull( result.getProblems() );
+        assertEquals( 0, result.getProblems().size() );
+    }
+
+    static class TestEnvVarSource implements OperatingSystemUtils.EnvVarSource {
+        private final Map<String, String> envVarMap;
+
+        TestEnvVarSource(Map<String, String> envVarMap) {
+            this.envVarMap = envVarMap;
+        }
+
+        public Map<String, String> getEnvMap() {
+            return envVarMap;
+        }
+    }
+
+}
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java
new file mode 100644
index 0000000..0ad1087
--- /dev/null
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java
@@ -0,0 +1,73 @@
+package org.apache.maven.toolchain.building;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.building.Problem;
+import org.apache.maven.building.ProblemCollector;
+import org.apache.maven.building.ProblemCollectorFactory;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ToolchainsBuildingExceptionTest
+{
+    private static final String LS = System.lineSeparator();
+
+    @Test
+    public void testNoProblems()
+    {
+        ToolchainsBuildingException e = new ToolchainsBuildingException( Collections.<Problem>emptyList() );
+        assertEquals( "0 problems were encountered while building the effective toolchains" + LS, e.getMessage() );
+    }
+
+    @Test
+    public void testOneProblem()
+    {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
+        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", 3, 5, new Exception() );
+        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
+        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
+                      "[ERROR] MESSAGE @ line 3, column 5" + LS, e.getMessage() );
+    }
+
+    @Test
+    public void testUnknownPositionAndSource()
+    {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
+        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception() );
+        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
+        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
+                      "[ERROR] MESSAGE" + LS, e.getMessage() );
+    }
+
+    @Test
+    public void testUnknownPosition()
+    {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
+        problemCollector.setSource( "SOURCE" );
+        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception() );
+        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
+        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
+                      "[ERROR] MESSAGE @ SOURCE" + LS, e.getMessage() );
+    }
+
+}
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java
new file mode 100644
index 0000000..7bed9a9
--- /dev/null
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java
@@ -0,0 +1,135 @@
+package org.apache.maven.toolchain.merge;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.toolchain.model.PersistedToolchains;
+import org.apache.maven.toolchain.model.ToolchainModel;
+import org.apache.maven.toolchain.model.TrackableBase;
+import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.junit.jupiter.api.Test;
+
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class MavenToolchainMergerTest
+{
+    private MavenToolchainMerger merger = new MavenToolchainMerger();
+
+    private MavenToolchainsXpp3Reader reader = new MavenToolchainsXpp3Reader();
+
+    @Test
+    public void testMergeNulls()
+    {
+        merger.merge( null, null, null );
+
+        PersistedToolchains pt = new PersistedToolchains();
+        merger.merge( pt, null, null );
+        merger.merge( null, pt, null );
+    }
+
+    @Test
+    public void testMergeJdk()
+        throws Exception
+    {
+        try ( InputStream isDominant = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
+              InputStream isRecessive = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" ) )
+        {
+            PersistedToolchains dominant = reader.read( isDominant );
+            PersistedToolchains recessive = reader.read( isRecessive );
+            assertEquals( 2, dominant.getToolchains().size() );
+
+            merger.merge( dominant, recessive, TrackableBase.USER_LEVEL );
+            assertEquals( 2, dominant.getToolchains().size() );
+        }
+    }
+
+    @Test
+    public void testMergeJdkExtra()
+        throws Exception
+    {
+        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
+              InputStream jdksExtraIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extra.xml" ) )
+        {
+            PersistedToolchains jdks = reader.read( jdksIS );
+            PersistedToolchains jdksExtra = reader.read( jdksExtraIS );
+            assertEquals( 2, jdks.getToolchains().size() );
+
+            merger.merge( jdks, jdksExtra, TrackableBase.USER_LEVEL );
+            assertEquals( 4, jdks.getToolchains().size() );
+            assertEquals( 2, jdksExtra.getToolchains().size() );
+        }
+        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
+              InputStream jdksExtraIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extra.xml" ) )
+        {
+            PersistedToolchains jdks = reader.read( jdksIS );
+            PersistedToolchains jdksExtra = reader.read( jdksExtraIS );
+            assertEquals( 2, jdks.getToolchains().size() );
+
+            // switch dominant with recessive
+            merger.merge( jdksExtra, jdks, TrackableBase.USER_LEVEL );
+            assertEquals( 4, jdksExtra.getToolchains().size() );
+            assertEquals( 2, jdks.getToolchains().size() );
+        }
+    }
+
+    @Test
+    public void testMergeJdkExtend()
+        throws Exception
+    {
+        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
+              InputStream jdksExtendIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extend.xml" ) )
+        {
+            PersistedToolchains jdks = reader.read( jdksIS );
+            PersistedToolchains jdksExtend = reader.read( jdksExtendIS );
+            assertEquals( 2, jdks.getToolchains().size() );
+
+            merger.merge( jdks, jdksExtend, TrackableBase.USER_LEVEL );
+            assertEquals( 2, jdks.getToolchains().size() );
+            Xpp3Dom config0 = (Xpp3Dom) jdks.getToolchains().get( 0 ).getConfiguration();
+            assertEquals( "lib/tools.jar", config0.getChild( "toolsJar" ).getValue() );
+            assertEquals( 2, config0.getChildCount() );
+            Xpp3Dom config1 = (Xpp3Dom) jdks.getToolchains().get( 1 ).getConfiguration();
+            assertEquals( 2, config1.getChildCount() );
+            assertEquals( "lib/classes.jar", config1.getChild( "toolsJar" ).getValue() );
+            assertEquals( 2, jdksExtend.getToolchains().size() );
+        }
+        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
+              InputStream jdksExtendIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extend.xml" ) )
+        {
+            PersistedToolchains jdks = reader.read( jdksIS );
+            PersistedToolchains jdksExtend = reader.read( jdksExtendIS );
+            assertEquals( 2, jdks.getToolchains().size() );
+
+            // switch dominant with recessive
+            merger.merge( jdksExtend, jdks, TrackableBase.USER_LEVEL );
+            assertEquals( 2, jdksExtend.getToolchains().size() );
+            Xpp3Dom config0 = (Xpp3Dom) jdksExtend.getToolchains().get( 0 ).getConfiguration();
+            assertEquals( "lib/tools.jar", config0.getChild( "toolsJar" ).getValue() );
+            assertEquals( 2, config0.getChildCount() );
+            Xpp3Dom config1 = (Xpp3Dom) jdksExtend.getToolchains().get( 1 ).getConfiguration();
+            assertEquals( 2, config1.getChildCount() );
+            assertEquals( "lib/classes.jar", config1.getChild( "toolsJar" ).getValue() );
+            assertEquals( 2, jdks.getToolchains().size() );
+        }
+    }
+
+}
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/global.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/global.xml
new file mode 100644
index 0000000..cd9be74
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/global.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF8"?>
+
+<!--
+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.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>basic</type>
+     <configuration>
+       <global>true</global>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>rare</type>
+     <configuration>
+       <global>true</global>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml
new file mode 100644
index 0000000..64de88a
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF8"?>
+
+<!--
+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.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.5</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+        <toolsJar>lib/tools.jar</toolsJar>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.6</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+        <toolsJar>lib/classes.jar</toolsJar>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml
new file mode 100644
index 0000000..35c3217
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF8"?>
+
+<!--
+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.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.4</version>
+         <vendor>sun</vendor>
+         <!-- no id, so it's considered 'default' -->
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.7</version>
+         <vendor>ibm</vendor>
+         <id>ibm_17</id>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml
new file mode 100644
index 0000000..5233a33
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF8"?>
+
+<!--
+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.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.5</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.6</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/user.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/user.xml
new file mode 100644
index 0000000..d11181f
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/user.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF8"?>
+
+<!--
+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.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>basic</type>
+     <configuration>
+       <user>true</user>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>rare</type>
+     <configuration>
+       <user>true</user>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-model/pom.xml b/maven-toolchain-model/pom.xml
index e824643..cf32371 100644
--- a/maven-toolchain-model/pom.xml
+++ b/maven-toolchain-model/pom.xml
@@ -31,6 +31,9 @@ under the License.
 
     <artifactId>maven-toolchain-model</artifactId>
 
+    <name>Maven Toolchain Model</name>
+    <description>Maven Toolchain model.</description>
+
     <dependencies>
         <dependency>
             <groupId>org.codehaus.plexus</groupId>
diff --git a/pom.xml b/pom.xml
index 818d70b..ac74dcf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,6 +100,7 @@ under the License.
     <module>maven-wrapper</module>
     <module>apache-maven/maven-wrapper.pom</module>
     <module>maven-toolchain-model</module>
+    <module>maven-toolchain-builder</module>
   </modules>
 
   <scm>