You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2022/11/21 08:51:34 UTC

[maven] branch master updated: [MNG-7580] Introduce new SettingsBuilder and ToolchainsBuilder services (#852)

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

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new dc88c6193 [MNG-7580] Introduce new SettingsBuilder and ToolchainsBuilder services (#852)
dc88c6193 is described below

commit dc88c6193c4f5b92ca715d2996c9726943d1cc83
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Mon Nov 21 09:51:28 2022 +0100

    [MNG-7580] Introduce new SettingsBuilder and ToolchainsBuilder services (#852)
---
 ...jectBuilderProblem.java => BuilderProblem.java} |  41 ++++-
 .../apache/maven/api/services/ProjectBuilder.java  |   4 +-
 .../maven/api/services/ProjectBuilderRequest.java  |  14 +-
 .../maven/api/services/ProjectBuilderResult.java   |   2 +-
 .../apache/maven/api/services/SettingsBuilder.java |  71 +++++++
 ...Severity.java => SettingsBuilderException.java} |  20 +-
 .../maven/api/services/SettingsBuilderRequest.java | 204 +++++++++++++++++++++
 ...erException.java => SettingsBuilderResult.java} |  36 ++--
 .../{ProjectBuilderSource.java => Source.java}     |   2 +-
 .../api/services/ToolchainManagerException.java    |   4 +-
 ...anagerException.java => ToolchainsBuilder.java} |  22 +--
 ...eption.java => ToolchainsBuilderException.java} |  11 +-
 .../api/services/ToolchainsBuilderRequest.java     | 196 ++++++++++++++++++++
 ...Exception.java => ToolchainsBuilderResult.java} |  35 ++--
 .../maven/internal/impl/DefaultProjectBuilder.java |  17 +-
 .../internal/impl/DefaultSettingsBuilder.java      | 188 +++++++++++++++++++
 .../internal/impl/DefaultToolchainsBuilder.java    | 187 +++++++++++++++++++
 .../org/apache/maven/internal/impl/TestApi.java    |   7 +
 18 files changed, 977 insertions(+), 84 deletions(-)

diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java
similarity index 70%
rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java
rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java
index fef6ceae0..d1bcf501b 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblem.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java
@@ -20,6 +20,9 @@ package org.apache.maven.api.services;
  */
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * Describes a problem that was encountered during project building. A problem can either be an exception that was
@@ -28,7 +31,8 @@ import org.apache.maven.api.annotations.Experimental;
  * @since 4.0
  */
 @Experimental
-public interface ProjectBuilderProblem
+@Immutable
+public interface BuilderProblem
 {
 
     /**
@@ -37,15 +41,16 @@ public interface ProjectBuilderProblem
      * track the problem back to its origin. A concrete example for such a source hint can be the file path or URL from
      * which the settings were read.
      *
-     * @return The hint about the source of the problem or an empty string if unknown, never {@code null}.
+     * @return the hint about the source of the problem or an empty string if unknown, never {@code null}
      */
+    @Nonnull
     String getSource();
 
     /**
      * Gets the one-based index of the line containing the problem. The line number should refer to some text file that
      * is given by {@link #getSource()}.
      *
-     * @return The one-based index of the line containing the problem or a non-positive value if unknown.
+     * @return the one-based index of the line containing the problem or a non-positive value if unknown
      */
     int getLineNumber();
 
@@ -53,7 +58,7 @@ public interface ProjectBuilderProblem
      * Gets the one-based index of the column containing the problem. The column number should refer to some text file
      * that is given by {@link #getSource()}.
      *
-     * @return The one-based index of the column containing the problem or non-positive value if unknown.
+     * @return the one-based index of the column containing the problem or non-positive value if unknown
      */
     int getColumnNumber();
 
@@ -62,29 +67,47 @@ public interface ProjectBuilderProblem
      * {@link #getSource()}, {@link #getLineNumber()} and {@link #getColumnNumber()}. The exact syntax of the returned
      * value is undefined.
      *
-     * @return The location of the problem, never {@code null}.
+     * @return the location of the problem, never {@code null}
      */
+    @Nonnull
     String getLocation();
 
     /**
      * Gets the exception that caused this problem (if any).
      *
-     * @return The exception that caused this problem or {@code null} if not applicable.
+     * @return the exception that caused this problem or {@code null} if not applicable
      */
+    @Nullable
     Exception getException();
 
     /**
      * Gets the message that describes this problem.
      *
-     * @return The message describing this problem, never {@code null}.
+     * @return the message describing this problem, never {@code null}
      */
+    @Nonnull
     String getMessage();
 
     /**
      * Gets the severity level of this problem.
      *
-     * @return The severity level of this problem, never {@code null}.
+     * @return the severity level of this problem, never {@code null}
      */
-    ProjectBuilderProblemSeverity getSeverity();
+    @Nonnull
+    Severity getSeverity();
 
+    /**
+     * The different severity levels for a problem, in decreasing order.
+     *
+     * @since 4.0
+     */
+    @Experimental
+    enum Severity
+    {
+
+        FATAL, //
+        ERROR, //
+        WARNING //
+
+    }
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
index 85b9efeee..303cdb342 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
@@ -51,13 +51,13 @@ public interface ProjectBuilder extends Service
      * Creates a {@link org.apache.maven.api.Project} from a POM file.
      *
      * @param session the {@link Session}, must not be {@code null}
-     * @param source the {@link ProjectBuilderSource}, must not be {@code null}
+     * @param source The {@link Source}, must not be {@code null}
      * @throws ProjectBuilderException if the project cannot be created
      * @throws IllegalArgumentException if an argument is {@code null} or invalid
      * @see #build(ProjectBuilderRequest)
      */
     @Nonnull
-    default ProjectBuilderResult build( @Nonnull Session session, @Nonnull ProjectBuilderSource source )
+    default ProjectBuilderResult build( @Nonnull Session session, @Nonnull Source source )
     {
         return build( ProjectBuilderRequest.build( session, source ) );
     }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
index 2e259091a..174bcadbd 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -52,7 +52,7 @@ public interface ProjectBuilderRequest
     Optional<Path> getPath();
 
     @Nonnull
-    Optional<ProjectBuilderSource> getSource();
+    Optional<Source> getSource();
 
     @Nonnull
     Optional<Artifact> getArtifact();
@@ -69,7 +69,7 @@ public interface ProjectBuilderRequest
     boolean isResolveDependencies();
 
     @Nonnull
-    static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull ProjectBuilderSource source )
+    static ProjectBuilderRequest build( @Nonnull Session session, @Nonnull Source source )
     {
         return builder()
                 .session( nonNull( session, "session cannot be null" ) )
@@ -115,7 +115,7 @@ public interface ProjectBuilderRequest
     {
         Session session;
         Path path;
-        ProjectBuilderSource source;
+        Source source;
         Artifact artifact;
         ArtifactCoordinate coordinate;
         boolean allowStubModel;
@@ -139,7 +139,7 @@ public interface ProjectBuilderRequest
             return this;
         }
 
-        public ProjectBuilderRequestBuilder source( ProjectBuilderSource source )
+        public ProjectBuilderRequestBuilder source( Source source )
         {
             this.source = source;
             return this;
@@ -179,7 +179,7 @@ public interface ProjectBuilderRequest
             implements ProjectBuilderRequest
         {
             private final Path path;
-            private final ProjectBuilderSource source;
+            private final Source source;
             private final Artifact artifact;
             private final ArtifactCoordinate coordinate;
             private final boolean allowStubModel;
@@ -190,7 +190,7 @@ public interface ProjectBuilderRequest
             @SuppressWarnings( "checkstyle:ParameterNumber" )
             DefaultProjectBuilderRequest( @Nonnull Session session,
                                           @Nullable Path path,
-                                          @Nullable ProjectBuilderSource source,
+                                          @Nullable Source source,
                                           @Nullable Artifact artifact,
                                           @Nullable ArtifactCoordinate coordinate,
                                           boolean allowStubModel,
@@ -218,7 +218,7 @@ public interface ProjectBuilderRequest
 
             @Nonnull
             @Override
-            public Optional<ProjectBuilderSource> getSource()
+            public Optional<Source> getSource()
             {
                 return Optional.ofNullable( source );
             }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
index 7664da7a1..0019b66aa 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
@@ -70,7 +70,7 @@ public interface ProjectBuilderResult
      * @return the problems that were encountered during the project building, can be empty but never {@code null}
      */
     @Nonnull
-    Collection<ProjectBuilderProblem> getProblems();
+    Collection<BuilderProblem> getProblems();
 
     /**
      * Gets the result of the dependency resolution for the project.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
new file mode 100644
index 000000000..624a74f91
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
@@ -0,0 +1,71 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 java.nio.file.Path;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Builds the effective settings from a user settings file and/or a global settings file.
+ */
+public interface SettingsBuilder extends Service
+{
+
+    /**
+     * Builds the effective settings of the specified settings files.
+     *
+     * @param request the settings building request that holds the parameters, must not be {@code null}
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    SettingsBuilderResult build( @Nonnull SettingsBuilderRequest request );
+
+    /**
+     * Builds the effective settings of the specified settings sources.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build( @Nonnull Session session,
+                                         @Nonnull Source globalSettingsSource,
+                                         @Nonnull Source userSettingsSource )
+    {
+        return build( SettingsBuilderRequest.build( session, globalSettingsSource, userSettingsSource ) );
+    }
+
+    /**
+     * Builds the effective settings of the specified settings paths.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build( @Nonnull Session session,
+                                         @Nonnull Path globalSettingsPath,
+                                         @Nonnull Path userSettingsPath )
+    {
+        return build( SettingsBuilderRequest.build( session, globalSettingsPath, userSettingsPath ) );
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
similarity index 68%
rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java
rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
index 6af025709..665b9086e 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderProblemSeverity.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
@@ -9,7 +9,7 @@ package org.apache.maven.api.services;
  * "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
+ *  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
@@ -22,16 +22,22 @@ package org.apache.maven.api.services;
 import org.apache.maven.api.annotations.Experimental;
 
 /**
- * The different severity levels for a problem, in decreasing order.
+ * The Exception class throw by the {@link SettingsBuilder}.
  *
  * @since 4.0
  */
 @Experimental
-public enum ProjectBuilderProblemSeverity
+public class SettingsBuilderException
+    extends MavenException
 {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public SettingsBuilderException( String message, Exception e )
+    {
+        super( message, e );
+    }
 
-    FATAL, //
-    ERROR, //
-    WARNING //
-
+    // TODO: add SettingsBuilderResult
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
new file mode 100644
index 000000000..0523f4d23
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
@@ -0,0 +1,204 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * Collects settings that control the building of effective settings.
+ */
+@Experimental
+@Immutable
+public interface SettingsBuilderRequest
+{
+
+    @Nonnull
+    Session getSession();
+
+    /**
+     * Gets the global settings path.
+     *
+     * @return the global settings path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getGlobalSettingsPath();
+
+    /**
+     * Gets the global settings source.
+     *
+     * @return the global settings source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getGlobalSettingsSource();
+
+    /**
+     * Gets the user settings path.
+     *
+     * @return the user settings path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getUserSettingsPath();
+
+    /**
+     * Gets the user settings source.
+     *
+     * @return the user settings source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getUserSettingsSource();
+
+    @Nonnull
+    static SettingsBuilderRequest build( @Nonnull Session session,
+                                         @Nonnull Source globalSettingsSource,
+                                         @Nonnull Source userSettingsSource )
+    {
+        return builder()
+                .session( nonNull( session, "session cannot be null" ) )
+                .globalSettingsSource( nonNull( globalSettingsSource, "globalSettingsSource cannot be null" ) )
+                .userSettingsSource( nonNull( userSettingsSource, "userSettingsSource cannot be null" ) )
+                .build();
+    }
+
+    @Nonnull
+    static SettingsBuilderRequest build( @Nonnull Session session,
+                                         @Nonnull Path globalSettingsPath,
+                                         @Nonnull Path userSettingsPath )
+    {
+        return builder()
+                .session( nonNull( session, "session cannot be null" ) )
+                .globalSettingsPath( nonNull( globalSettingsPath, "globalSettingsPath cannot be null" ) )
+                .userSettingsPath( nonNull( userSettingsPath, "userSettingsPath cannot be null" ) )
+                .build();
+    }
+
+    @Nonnull
+    static SettingsBuilderRequestBuilder builder()
+    {
+        return new SettingsBuilderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class SettingsBuilderRequestBuilder
+    {
+        Session session;
+        Path globalSettingsPath;
+        Source globalSettingsSource;
+        Path userSettingsPath;
+        Source userSettingsSource;
+
+        public SettingsBuilderRequestBuilder session( Session session )
+        {
+            this.session = session;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder globalSettingsPath( Path globalSettingsPath )
+        {
+            this.globalSettingsPath = globalSettingsPath;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder globalSettingsSource( Source globalSettingsSource )
+        {
+            this.globalSettingsSource = globalSettingsSource;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder userSettingsPath( Path userSettingsPath )
+        {
+            this.userSettingsPath = userSettingsPath;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder userSettingsSource( Source userSettingsSource )
+        {
+            this.userSettingsSource = userSettingsSource;
+            return this;
+        }
+
+        public SettingsBuilderRequest build()
+        {
+            return new DefaultSettingsBuilderRequest( session,
+                    globalSettingsPath, globalSettingsSource,
+                    userSettingsPath, userSettingsSource );
+        }
+
+        private static class DefaultSettingsBuilderRequest extends BaseRequest
+                implements SettingsBuilderRequest
+        {
+            private final Path globalSettingsPath;
+            private final Source globalSettingsSource;
+            private final Path userSettingsPath;
+            private final Source userSettingsSource;
+
+            @SuppressWarnings( "checkstyle:ParameterNumber" )
+            DefaultSettingsBuilderRequest( @Nonnull Session session,
+                                           @Nullable Path globalSettingsPath,
+                                           @Nullable Source globalSettingsSource,
+                                           @Nullable Path userSettingsPath,
+                                           @Nullable Source userSettingsSource )
+            {
+                super( session );
+                this.globalSettingsPath = globalSettingsPath;
+                this.globalSettingsSource = globalSettingsSource;
+                this.userSettingsPath = userSettingsPath;
+                this.userSettingsSource = userSettingsSource;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getGlobalSettingsPath()
+            {
+                return Optional.ofNullable( globalSettingsPath );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getGlobalSettingsSource()
+            {
+                return Optional.ofNullable( globalSettingsSource );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getUserSettingsPath()
+            {
+                return Optional.ofNullable( userSettingsPath );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getUserSettingsSource()
+            {
+                return Optional.ofNullable( userSettingsSource );
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
similarity index 51%
copy from api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
index 2c8a2bd8f..8cd1fc575 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
@@ -19,24 +19,30 @@ package org.apache.maven.api.services;
  * under the License.
  */
 
-import org.apache.maven.api.annotations.Experimental;
+import java.util.List;
 
-/**
- * The Exception class throw by the {@link ToolchainManager}.
- *
- * @since 4.0
- */
-@Experimental
-public class ToolchainManagerException
-    extends MavenException
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.settings.Settings;
+
+public interface SettingsBuilderResult
 {
+
+    /**
+     * Gets the assembled settings.
+     *
+     * @return the assembled settings, never {@code null}
+     */
+    @Nonnull
+    Settings getEffectiveSettings();
+
     /**
-     * @param message The message to give.
-     * @param e The {@link Exception}.
+     * Gets the problems that were encountered during the settings building. Note that only problems of severity
+     * {@link BuilderProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause
+     * the settings builder to fail with a {@link SettingsBuilderException}.
+     *
+     * @return the problems that were encountered during the settings building, can be empty but never {@code null}
      */
-    public ToolchainManagerException( String message, Exception e )
-    {
-        super( message, e );
-    }
+    @Nonnull
+    List<BuilderProblem> getProblems();
 
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java
similarity index 96%
rename from api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java
rename to api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java
index 1add18cb1..08eea48c3 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderSource.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java
@@ -30,7 +30,7 @@ import org.apache.maven.api.annotations.Experimental;
  * @since 4.0
  */
 @Experimental
-public interface ProjectBuilderSource
+public interface Source
 {
     InputStream getInputStream() throws IOException;
 
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
index 2c8a2bd8f..eb5438180 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
@@ -31,8 +31,8 @@ public class ToolchainManagerException
     extends MavenException
 {
     /**
-     * @param message The message to give.
-     * @param e The {@link Exception}.
+     * @param message the message to give
+     * @param e the {@link Exception}
      */
     public ToolchainManagerException( String message, Exception e )
     {
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java
similarity index 60%
copy from api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java
index 2c8a2bd8f..5e57291cf 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java
@@ -19,24 +19,24 @@ package org.apache.maven.api.services;
  * under the License.
  */
 
+import org.apache.maven.api.Service;
 import org.apache.maven.api.annotations.Experimental;
 
 /**
- * The Exception class throw by the {@link ToolchainManager}.
- *
- * @since 4.0
+ * Builds the effective toolchains from a user toolchains file and/or a global toolchains file.
  */
 @Experimental
-public class ToolchainManagerException
-    extends MavenException
+
+public interface ToolchainsBuilder extends Service
 {
+
     /**
-     * @param message The message to give.
-     * @param e The {@link Exception}.
+     * Builds the effective toolchains of the specified toolchains files.
+     *
+     * @param request the toolchains building request that holds the parameters, must not be {@code null}
+     * @return the result of the toolchains building, never {@code null}
+     * @throws ToolchainsBuilderException if the effective toolchains could not be built
      */
-    public ToolchainManagerException( String message, Exception e )
-    {
-        super( message, e );
-    }
+    ToolchainsBuilderResult build( ToolchainsBuilderRequest request );
 
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
similarity index 77%
copy from api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
index 2c8a2bd8f..19bd724ed 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
@@ -22,21 +22,22 @@ package org.apache.maven.api.services;
 import org.apache.maven.api.annotations.Experimental;
 
 /**
- * The Exception class throw by the {@link ToolchainManager}.
+ * The Exception class throw by the {@link ToolchainsBuilder}.
  *
  * @since 4.0
  */
 @Experimental
-public class ToolchainManagerException
+public class ToolchainsBuilderException
     extends MavenException
 {
     /**
-     * @param message The message to give.
-     * @param e The {@link Exception}.
+     * @param message the message to give
+     * @param e the {@link Exception}
      */
-    public ToolchainManagerException( String message, Exception e )
+    public ToolchainsBuilderException( String message, Exception e )
     {
         super( message, e );
     }
 
+    // TODO: add ToolchainsBuilderResult
 }
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
new file mode 100644
index 000000000..085950b2f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
@@ -0,0 +1,196 @@
+package org.apache.maven.api.services;
+
+/*
+ * 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 java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+public interface ToolchainsBuilderRequest
+{
+    @Nonnull
+    Session getSession();
+
+    /**
+     * Gets the global Toolchains path.
+     *
+     * @return the global Toolchains path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getGlobalToolchainsPath();
+
+    /**
+     * Gets the global Toolchains source.
+     *
+     * @return the global Toolchains source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getGlobalToolchainsSource();
+
+    /**
+     * Gets the user Toolchains path.
+     *
+     * @return the user Toolchains path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getUserToolchainsPath();
+
+    /**
+     * Gets the user Toolchains source.
+     *
+     * @return the user Toolchains source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getUserToolchainsSource();
+
+    @Nonnull
+    static ToolchainsBuilderRequest build( @Nonnull Session session,
+                                         @Nonnull Source globalToolchainsSource,
+                                         @Nonnull Source userToolchainsSource )
+    {
+        return builder()
+                .session( nonNull( session, "session cannot be null" ) )
+                .globalToolchainsSource( nonNull( globalToolchainsSource, "globalToolchainsSource cannot be null" ) )
+                .userToolchainsSource( nonNull( userToolchainsSource, "userToolchainsSource cannot be null" ) )
+                .build();
+    }
+
+    @Nonnull
+    static ToolchainsBuilderRequest build( @Nonnull Session session,
+                                         @Nonnull Path globalToolchainsPath,
+                                         @Nonnull Path userToolchainsPath )
+    {
+        return builder()
+                .session( nonNull( session, "session cannot be null" ) )
+                .globalToolchainsPath( nonNull( globalToolchainsPath, "globalToolchainsPath cannot be null" ) )
+                .userToolchainsPath( nonNull( userToolchainsPath, "userToolchainsPath cannot be null" ) )
+                .build();
+    }
+
+    @Nonnull
+    static ToolchainsBuilderRequestBuilder builder()
+    {
+        return new ToolchainsBuilderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class ToolchainsBuilderRequestBuilder
+    {
+        Session session;
+        Path globalToolchainsPath;
+        Source globalToolchainsSource;
+        Path userToolchainsPath;
+        Source userToolchainsSource;
+
+        public ToolchainsBuilderRequestBuilder session( Session session )
+        {
+            this.session = session;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder globalToolchainsPath( Path globalToolchainsPath )
+        {
+            this.globalToolchainsPath = globalToolchainsPath;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder globalToolchainsSource( Source globalToolchainsSource )
+        {
+            this.globalToolchainsSource = globalToolchainsSource;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder userToolchainsPath( Path userToolchainsPath )
+        {
+            this.userToolchainsPath = userToolchainsPath;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder userToolchainsSource( Source userToolchainsSource )
+        {
+            this.userToolchainsSource = userToolchainsSource;
+            return this;
+        }
+
+        public ToolchainsBuilderRequest build()
+        {
+            return new ToolchainsBuilderRequestBuilder.DefaultToolchainsBuilderRequest( session,
+                    globalToolchainsPath, globalToolchainsSource,
+                    userToolchainsPath, userToolchainsSource );
+        }
+
+        private static class DefaultToolchainsBuilderRequest extends BaseRequest
+                implements ToolchainsBuilderRequest
+        {
+            private final Path globalToolchainsPath;
+            private final Source globalToolchainsSource;
+            private final Path userToolchainsPath;
+            private final Source userToolchainsSource;
+
+            @SuppressWarnings( "checkstyle:ParameterNumber" )
+            DefaultToolchainsBuilderRequest( @Nonnull Session session,
+                                             @Nullable Path globalToolchainsPath,
+                                             @Nullable Source globalToolchainsSource,
+                                             @Nullable Path userToolchainsPath,
+                                             @Nullable Source userToolchainsSource )
+            {
+                super( session );
+                this.globalToolchainsPath = globalToolchainsPath;
+                this.globalToolchainsSource = globalToolchainsSource;
+                this.userToolchainsPath = userToolchainsPath;
+                this.userToolchainsSource = userToolchainsSource;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getGlobalToolchainsPath()
+            {
+                return Optional.ofNullable( globalToolchainsPath );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getGlobalToolchainsSource()
+            {
+                return Optional.ofNullable( globalToolchainsSource );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getUserToolchainsPath()
+            {
+                return Optional.ofNullable( userToolchainsPath );
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getUserToolchainsSource()
+            {
+                return Optional.ofNullable( userToolchainsSource );
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
similarity index 50%
copy from api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
copy to api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
index 2c8a2bd8f..5be2cea19 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
@@ -19,24 +19,29 @@ package org.apache.maven.api.services;
  * under the License.
  */
 
-import org.apache.maven.api.annotations.Experimental;
+import java.util.List;
 
-/**
- * The Exception class throw by the {@link ToolchainManager}.
- *
- * @since 4.0
- */
-@Experimental
-public class ToolchainManagerException
-    extends MavenException
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+
+public interface ToolchainsBuilderResult
 {
     /**
-     * @param message The message to give.
-     * @param e The {@link Exception}.
+     * Gets the assembled toolchains.
+     *
+     * @return the assembled toolchains, never {@code null}
+     */
+    @Nonnull
+    PersistedToolchains getEffectiveToolchains();
+
+    /**
+     * Gets the problems that were encountered during the settings building. Note that only problems of severity
+     * {@link BuilderProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause
+     * the settings builder to fail with a {@link ToolchainsBuilderException}.
+     *
+     * @return the problems that were encountered during the settings building, can be empty but never {@code null}
      */
-    public ToolchainManagerException( String message, Exception e )
-    {
-        super( message, e );
-    }
+    @Nonnull
+    List<BuilderProblem> getProblems();
 
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
index 959f8fc69..4944df135 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
@@ -40,11 +40,10 @@ import org.apache.maven.api.annotations.Nonnull;
 import org.apache.maven.api.services.DependencyCollectorResult;
 import org.apache.maven.api.services.ProjectBuilder;
 import org.apache.maven.api.services.ProjectBuilderException;
-import org.apache.maven.api.services.ProjectBuilderProblem;
-import org.apache.maven.api.services.ProjectBuilderProblemSeverity;
+import org.apache.maven.api.services.BuilderProblem;
 import org.apache.maven.api.services.ProjectBuilderRequest;
 import org.apache.maven.api.services.ProjectBuilderResult;
-import org.apache.maven.api.services.ProjectBuilderSource;
+import org.apache.maven.api.services.Source;
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.model.building.ModelProblem;
@@ -91,7 +90,7 @@ public class DefaultProjectBuilder implements ProjectBuilder
             }
             else if ( request.getSource().isPresent() )
             {
-                ProjectBuilderSource source = request.getSource().get();
+                Source source = request.getSource().get();
                 ModelSource modelSource = new ModelSource()
                 {
                     @Override
@@ -153,14 +152,14 @@ public class DefaultProjectBuilder implements ProjectBuilder
 
                 @Nonnull
                 @Override
-                public Collection<ProjectBuilderProblem> getProblems()
+                public Collection<BuilderProblem> getProblems()
                 {
                     return new MappedCollection<>( res.getProblems(), this::toProblem );
                 }
 
-                private ProjectBuilderProblem toProblem( ModelProblem problem )
+                private BuilderProblem toProblem( ModelProblem problem )
                 {
-                    return new ProjectBuilderProblem()
+                    return new BuilderProblem()
                     {
                         @Override
                         public String getSource()
@@ -228,9 +227,9 @@ public class DefaultProjectBuilder implements ProjectBuilder
                         }
 
                         @Override
-                        public ProjectBuilderProblemSeverity getSeverity()
+                        public Severity getSeverity()
                         {
-                            return ProjectBuilderProblemSeverity.valueOf( problem.getSeverity().name() );
+                            return Severity.valueOf( problem.getSeverity().name() );
                         }
                     };
                 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
new file mode 100644
index 000000000..8b7f598cb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
@@ -0,0 +1,188 @@
+package org.apache.maven.internal.impl;
+
+/*
+ * 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 javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.SettingsBuilder;
+import org.apache.maven.api.services.SettingsBuilderException;
+import org.apache.maven.api.services.SettingsBuilderRequest;
+import org.apache.maven.api.services.SettingsBuilderResult;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.api.settings.Settings;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingResult;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.settings.building.SettingsSource;
+
+@Named
+@Singleton
+public class DefaultSettingsBuilder implements SettingsBuilder
+{
+
+    private final org.apache.maven.settings.building.SettingsBuilder builder;
+
+    @Inject
+    public DefaultSettingsBuilder( org.apache.maven.settings.building.SettingsBuilder builder )
+    {
+        this.builder = builder;
+    }
+
+    @Nonnull
+    @Override
+    public SettingsBuilderResult build( SettingsBuilderRequest request )
+            throws SettingsBuilderException, IllegalArgumentException
+    {
+        DefaultSession session = ( DefaultSession ) request.getSession();
+        try
+        {
+            DefaultSettingsBuildingRequest req = new DefaultSettingsBuildingRequest();
+            req.setUserProperties( toProperties( session.getUserProperties() ) );
+            req.setSystemProperties( toProperties( session.getSystemProperties() ) );
+            if ( request.getGlobalSettingsSource().isPresent() )
+            {
+                req.setGlobalSettingsSource( new MappedSettingsSource( request.getGlobalSettingsSource().get() ) );
+            }
+            if ( request.getGlobalSettingsPath().isPresent() )
+            {
+                req.setGlobalSettingsFile( request.getGlobalSettingsPath().get().toFile() );
+            }
+            if ( request.getUserSettingsSource().isPresent() )
+            {
+                req.setUserSettingsSource( new MappedSettingsSource( request.getUserSettingsSource().get() ) );
+            }
+            if ( request.getUserSettingsPath().isPresent() )
+            {
+                req.setUserSettingsFile( request.getUserSettingsPath().get().toFile() );
+            }
+            SettingsBuildingResult result = builder.build( req );
+            return new SettingsBuilderResult()
+            {
+                @Override
+                public Settings getEffectiveSettings()
+                {
+                    return result.getEffectiveSettings().getDelegate();
+                }
+
+                @Override
+                public List<BuilderProblem> getProblems()
+                {
+                    return new MappedList<>( result.getProblems(), MappedBuilderProblem::new );
+                }
+            };
+        }
+        catch ( SettingsBuildingException e )
+        {
+            throw new SettingsBuilderException( "Unable to build settings", e );
+        }
+    }
+
+    private Properties toProperties( Map<String, String> map )
+    {
+        Properties properties = new Properties();
+        properties.putAll( map );
+        return properties;
+    }
+
+    private static class MappedSettingsSource implements SettingsSource
+    {
+        private final Source source;
+
+        MappedSettingsSource( Source source )
+        {
+            this.source = source;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException
+        {
+            return source.getInputStream();
+        }
+
+        @Override
+        public String getLocation()
+        {
+            return source.getLocation();
+        }
+    }
+
+    private static class MappedBuilderProblem implements BuilderProblem
+    {
+        private final SettingsProblem problem;
+
+        MappedBuilderProblem( SettingsProblem problem )
+        {
+            this.problem = problem;
+        }
+
+        @Override
+        public String getSource()
+        {
+            return problem.getSource();
+        }
+
+        @Override
+        public int getLineNumber()
+        {
+            return problem.getLineNumber();
+        }
+
+        @Override
+        public int getColumnNumber()
+        {
+            return problem.getColumnNumber();
+        }
+
+        @Override
+        public String getLocation()
+        {
+            return problem.getLocation();
+        }
+
+        @Override
+        public Exception getException()
+        {
+            return problem.getException();
+        }
+
+        @Override
+        public String getMessage()
+        {
+            return problem.getMessage();
+        }
+
+        @Override
+        public Severity getSeverity()
+        {
+            return Severity.valueOf( problem.getSeverity().name() );
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java
new file mode 100644
index 000000000..ef75abd4c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java
@@ -0,0 +1,187 @@
+package org.apache.maven.internal.impl;
+
+/*
+ * 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 javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.ToolchainsBuilder;
+import org.apache.maven.api.services.ToolchainsBuilderException;
+import org.apache.maven.api.services.ToolchainsBuilderRequest;
+import org.apache.maven.api.services.ToolchainsBuilderResult;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
+import org.apache.maven.toolchain.building.ToolchainsBuildingException;
+import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+
+@Named
+@Singleton
+public class DefaultToolchainsBuilder implements ToolchainsBuilder
+{
+
+    private final org.apache.maven.toolchain.building.ToolchainsBuilder builder;
+
+    @Inject
+    public DefaultToolchainsBuilder( org.apache.maven.toolchain.building.ToolchainsBuilder builder )
+    {
+        this.builder = builder;
+    }
+
+    @Nonnull
+    @Override
+    public ToolchainsBuilderResult build( ToolchainsBuilderRequest request )
+            throws ToolchainsBuilderException, IllegalArgumentException
+    {
+        DefaultSession session = ( DefaultSession ) request.getSession();
+        try
+        {
+            DefaultToolchainsBuildingRequest req = new DefaultToolchainsBuildingRequest();
+            if ( request.getGlobalToolchainsSource().isPresent() )
+            {
+                req.setGlobalToolchainsSource(
+                        new MappedToolchainsSource( request.getGlobalToolchainsSource().get() ) );
+            }
+            else if ( request.getGlobalToolchainsPath().isPresent() )
+            {
+                req.setGlobalToolchainsSource( new org.apache.maven.building.FileSource(
+                        request.getGlobalToolchainsPath().get().toFile() ) );
+            }
+            if ( request.getUserToolchainsSource().isPresent() )
+            {
+                req.setUserToolchainsSource( new MappedToolchainsSource( request.getUserToolchainsSource().get() ) );
+            }
+            else if ( request.getUserToolchainsPath().isPresent() )
+            {
+                req.setUserToolchainsSource( new org.apache.maven.building.FileSource(
+                        request.getUserToolchainsPath().get().toFile() ) );
+            }
+            ToolchainsBuildingResult result = builder.build( req );
+            return new ToolchainsBuilderResult()
+            {
+                @Override
+                public PersistedToolchains getEffectiveToolchains()
+                {
+                    return result.getEffectiveToolchains().getDelegate();
+                }
+
+                @Override
+                public List<BuilderProblem> getProblems()
+                {
+                    return new MappedList<>( result.getProblems(), MappedBuilderProblem::new );
+                }
+            };
+        }
+        catch ( ToolchainsBuildingException e )
+        {
+            throw new ToolchainsBuilderException( "Unable to build Toolchains", e );
+        }
+    }
+
+    private Properties toProperties( Map<String, String> map )
+    {
+        Properties properties = new Properties();
+        properties.putAll( map );
+        return properties;
+    }
+
+    private static class MappedToolchainsSource implements org.apache.maven.building.Source
+    {
+        private final Source source;
+
+        MappedToolchainsSource( Source source )
+        {
+            this.source = source;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException
+        {
+            return source.getInputStream();
+        }
+
+        @Override
+        public String getLocation()
+        {
+            return source.getLocation();
+        }
+    }
+
+    private static class MappedBuilderProblem implements BuilderProblem
+    {
+        private final org.apache.maven.building.Problem problem;
+
+        MappedBuilderProblem( org.apache.maven.building.Problem problem )
+        {
+            this.problem = problem;
+        }
+
+        @Override
+        public String getSource()
+        {
+            return problem.getSource();
+        }
+
+        @Override
+        public int getLineNumber()
+        {
+            return problem.getLineNumber();
+        }
+
+        @Override
+        public int getColumnNumber()
+        {
+            return problem.getColumnNumber();
+        }
+
+        @Override
+        public String getLocation()
+        {
+            return problem.getLocation();
+        }
+
+        @Override
+        public Exception getException()
+        {
+            return problem.getException();
+        }
+
+        @Override
+        public String getMessage()
+        {
+            return problem.getMessage();
+        }
+
+        @Override
+        public Severity getSeverity()
+        {
+            return Severity.valueOf( problem.getSeverity().name() );
+        }
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java
index 3809ac3b1..1596f5005 100644
--- a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java
+++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java
@@ -32,6 +32,7 @@ import org.apache.maven.api.Project;
 import org.apache.maven.api.Session;
 import org.apache.maven.api.services.ProjectBuilder;
 import org.apache.maven.api.services.ProjectBuilderRequest;
+import org.apache.maven.api.services.SettingsBuilder;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
@@ -87,6 +88,12 @@ public class TestApi
     @Inject
     SessionScope sessionScope;
 
+    @Inject
+    SettingsBuilder settingsBuilder;
+
+    @Inject
+    ToolchainsBuilder toolchainsBuilder;
+
     @BeforeEach
     void setup()
     {