From 003a5bc06daa6e74c98e4d8ab45c6643a6844975 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Mon, 25 Mar 2024 11:50:01 +0100 Subject: [PATCH] [MNG-8084] Make the v4 api usable outside the Maven runtime (#1441) --- .../apache/maven/api/services/PathSource.java | 53 +++ .../maven/api/services/SettingsBuilder.java | 35 ++ .../services/SettingsBuilderException.java | 16 +- .../api/services/SettingsBuilderRequest.java | 113 ++---- .../org/apache/maven/api/services/Source.java | 10 + .../services/ToolchainsBuilderException.java | 16 +- .../services/ToolchainsBuilderRequest.java | 67 +--- .../maven/api/services/xml/Location.java | 58 +++ .../api/services/xml/XmlReaderException.java | 9 +- .../api/services/xml/XmlWriterException.java | 9 +- maven-api-impl/pom.xml | 140 +++++++ .../maven/internal/impl/AbstractNode.java | 0 .../maven/internal/impl/AbstractSession.java | 199 ++++++++-- .../maven/internal/impl/DefaultArtifact.java | 0 .../impl/DefaultArtifactCoordinate.java | 0 .../DefaultArtifactCoordinateFactory.java | 5 +- .../impl/DefaultArtifactDeployer.java | 5 +- .../internal/impl/DefaultArtifactFactory.java | 5 +- .../impl/DefaultArtifactInstaller.java | 7 +- .../impl/DefaultArtifactResolver.java | 5 +- .../internal/impl/DefaultBuilderProblem.java | 111 ++++++ .../impl/DefaultChecksumAlgorithmService.java | 22 +- .../internal/impl/DefaultDependency.java | 0 .../impl/DefaultDependencyCollector.java | 17 +- .../impl/DefaultDependencyCoordinate.java | 6 +- .../DefaultDependencyCoordinateFactory.java | 5 +- .../impl/DefaultDependencyResolverResult.java | 0 .../internal/impl/DefaultLocalRepository.java | 3 - .../impl/DefaultLocalRepositoryManager.java | 5 +- .../internal/impl/DefaultMessageBuilder.java | 0 .../impl/DefaultMessageBuilderFactory.java | 9 +- .../internal/impl/DefaultModelXmlFactory.java | 11 +- .../maven/internal/impl/DefaultNode.java | 0 .../impl/DefaultRemoteRepository.java | 0 .../impl/DefaultRepositoryFactory.java | 14 +- .../internal/impl/DefaultSettingsBuilder.java | 300 +++++++++++++++ .../impl/DefaultSettingsValidator.java | 362 ++++++++++++++++++ .../impl/DefaultSettingsXmlFactory.java | 19 +- .../impl/DefaultToolchainsBuilder.java | 218 +++++++++++ .../impl/DefaultToolchainsXmlFactory.java | 11 +- .../maven/internal/impl/DefaultTransport.java | 5 +- .../impl/DefaultTransportProvider.java | 7 +- .../internal/impl/DefaultVersionParser.java | 7 +- .../impl/DefaultVersionRangeResolver.java | 7 +- .../internal/impl/DefaultVersionResolver.java | 7 +- .../maven/internal/impl/InternalSession.java | 13 - .../maven/internal/impl/MappedCollection.java | 0 .../maven/internal/impl/MappedList.java | 0 .../internal/impl/PathModularization.java | 0 .../impl/PathModularizationCache.java | 0 .../maven/internal/impl/PropertiesAsMap.java | 0 .../maven/internal/impl}/SettingsUtilsV4.java | 13 +- .../maven/internal/impl/StaxLocation.java | 76 ++++ .../org/apache/maven/internal/impl/Utils.java | 0 .../maven/internal/impl/WrapperNode.java | 0 .../DefaultSettingsBuilderFactoryTest.java | 80 ++++ .../impl/DefaultSettingsValidatorTest.java | 234 +++++++++++ .../internal/impl/standalone/ApiRunner.java | 336 ++++++++++++++++ .../impl/standalone/TestApiStandalone.java | 51 +++ .../src/test/resources/settings-simple.xml | 24 ++ maven-core/pom.xml | 4 + .../java/org/apache/maven/DefaultMaven.java | 4 +- .../apache/maven/execution/MavenSession.java | 2 +- .../internal/impl/DefaultArtifactManager.java | 4 +- .../maven/internal/impl/DefaultEvent.java | 4 +- .../internal/impl/DefaultMojoExecution.java | 4 +- .../impl/DefaultPluginXmlFactory.java | 6 +- .../maven/internal/impl/DefaultProject.java | 6 +- .../internal/impl/DefaultProjectBuilder.java | 2 +- .../internal/impl/DefaultProjectManager.java | 6 +- .../maven/internal/impl/DefaultSession.java | 155 ++------ .../internal/impl/DefaultSessionFactory.java | 2 +- .../internal/impl/DefaultSettingsBuilder.java | 162 -------- .../impl/DefaultToolchainManager.java | 8 +- .../impl/DefaultToolchainsBuilder.java | 149 ------- .../maven/internal/impl/EventSpyImpl.java | 2 +- .../internal/impl/InternalMavenSession.java | 46 +++ .../internal/impl/SisuDiBridgeModule.java | 89 +++++ .../plugin/DefaultBuildPluginManager.java | 4 +- .../internal/DefaultMavenPluginManager.java | 8 +- .../maven/project/DefaultProjectBuilder.java | 5 +- .../project/ExtensionDescriptorBuilder.java | 4 +- .../scope/internal/SessionScopeModule.java | 6 +- .../apache/maven/settings/SettingsUtils.java | 2 + .../DefaultBeanConfiguratorPathTest.java | 6 +- .../DefaultBeanConfiguratorTest.java | 6 +- .../apache/maven/internal/impl/TestApi.java | 2 +- ...ginParameterExpressionEvaluatorV4Test.java | 3 +- .../maven/settings/SettingsUtilsTest.java | 1 + .../org/apache/maven/di/impl/Binding.java | 2 +- .../apache/maven/di/impl/InjectorImpl.java | 2 +- .../descriptor/PluginDescriptorBuilder.java | 8 +- maven-settings-builder/pom.xml | 9 + .../building/DefaultSettingsBuilder.java | 296 +++++--------- .../DefaultSettingsBuilderFactory.java | 6 +- .../validation/DefaultSettingsValidator.java | 313 +-------------- .../DefaultSettingsValidatorTest.java | 3 +- maven-toolchain-builder/pom.xml | 9 + .../building/DefaultToolchainsBuilder.java | 223 ++++------- .../DefaultToolchainsBuilderTest.java | 119 +++--- maven-toolchain-model/pom.xml | 3 - .../maven/internal/xml/XmlNodeBuilder.java | 94 ----- .../internal/xml/XmlNodeStaxBuilder.java | 134 +++++++ .../internal/xml/XmlNodeBuilderTest.java | 2 +- .../maven/internal/xml/XmlNodeImplTest.java | 28 +- pom.xml | 6 + src/mdo/reader-stax.vm | 6 +- src/mdo/transformer.vm | 43 +-- 108 files changed, 3100 insertions(+), 1633 deletions(-) create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java create mode 100644 api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/Location.java create mode 100644 maven-api-impl/pom.xml rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/AbstractNode.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/AbstractSession.java (76%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java (97%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java (96%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java (96%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java (95%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java (97%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultBuilderProblem.java rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java (92%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java (88%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java (93%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java (97%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java (97%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java (96%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java (91%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java (92%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultNode.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java (89%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsValidator.java rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java (87%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java (92%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java (98%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java (95%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java (94%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java (97%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java (96%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/InternalSession.java (84%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/MappedCollection.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/MappedList.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/PathModularization.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java (100%) rename {maven-core/src/main/java/org/apache/maven/settings => maven-api-impl/src/main/java/org/apache/maven/internal/impl}/SettingsUtilsV4.java (96%) create mode 100644 maven-api-impl/src/main/java/org/apache/maven/internal/impl/StaxLocation.java rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/Utils.java (100%) rename {maven-core => maven-api-impl}/src/main/java/org/apache/maven/internal/impl/WrapperNode.java (100%) create mode 100644 maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsBuilderFactoryTest.java create mode 100644 maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsValidatorTest.java create mode 100644 maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java create mode 100644 maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java create mode 100644 maven-api-impl/src/test/resources/settings-simple.xml delete mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java delete mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java create mode 100644 maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java create mode 100644 maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeStaxBuilder.java diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java new file mode 100644 index 0000000000..a114594947 --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathSource.java @@ -0,0 +1,53 @@ +/* + * 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. + */ +package org.apache.maven.api.services; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +class PathSource implements Source { + + private final Path path; + + PathSource(Path path) { + this.path = path; + } + + @Override + public Path getPath() { + return path; + } + + @Override + public InputStream openStream() throws IOException { + return Files.newInputStream(path); + } + + @Override + public String getLocation() { + return path.toString(); + } + + @Override + public Source resolve(String relative) { + return new PathSource(path.resolve(relative)); + } +} 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 index 681c96d99e..6561e2d0f2 100644 --- 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 @@ -19,11 +19,13 @@ package org.apache.maven.api.services; import java.nio.file.Path; +import java.util.List; import org.apache.maven.api.Service; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.settings.Settings; /** * Builds the effective settings from a user settings file and/or a global settings file. @@ -97,4 +99,37 @@ public interface SettingsBuilder extends Service { @Nonnull Path userSettingsPath) { return build(SettingsBuilderRequest.build(session, globalSettingsPath, projectSettingsPath, userSettingsPath)); } + + /** + * Validate the specified settings. + * + * @param settings The settings to validate, must not be {@code null}. + * @return The list of problems that were encountered, must not be {@code null}. + */ + @Nonnull + default List validate(@Nonnull Settings settings) { + return validate(settings, false); + } + + /** + * Validate the specified settings. + * + * @param settings The settings to validate, must not be {@code null}. + * @param isProjectSettings Boolean indicating if the validation is for project settings or user / global settings. + * @return The list of problems that were encountered, must not be {@code null}. + */ + @Nonnull + List validate(@Nonnull Settings settings, boolean isProjectSettings); + + /** + * Convert a model profile to a settings profile. + */ + @Nonnull + org.apache.maven.api.settings.Profile convert(@Nonnull org.apache.maven.api.model.Profile profile); + + /** + * Convert a settings profile to a model profile. + */ + @Nonnull + org.apache.maven.api.model.Profile convert(@Nonnull org.apache.maven.api.settings.Profile profile); } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java index c22fed1254..8952810385 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java @@ -18,6 +18,9 @@ */ package org.apache.maven.api.services; +import java.util.List; +import java.util.stream.Collectors; + import org.apache.maven.api.annotations.Experimental; /** @@ -27,13 +30,24 @@ import org.apache.maven.api.annotations.Experimental; */ @Experimental public class SettingsBuilderException extends MavenException { + + private final List problems; + /** * @param message the message to give * @param e the {@link Exception} */ public SettingsBuilderException(String message, Exception e) { super(message, e); + this.problems = List.of(); } - // TODO: add SettingsBuilderResult + public SettingsBuilderException(String message, List problems) { + super(message + ": " + problems.stream().map(BuilderProblem::toString).collect(Collectors.joining(", ")), null); + this.problems = List.copyOf(problems); + } + + public List getProblems() { + return problems; + } } 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 index ee7692d9a9..249e2954fb 100644 --- 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 @@ -18,6 +18,7 @@ */ package org.apache.maven.api.services; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; @@ -40,14 +41,6 @@ public interface SettingsBuilderRequest { @Nonnull Session getSession(); - /** - * Gets the global settings path. - * - * @return the global settings path or {@code null} if none - */ - @Nonnull - Optional getGlobalSettingsPath(); - /** * Gets the global settings source. * @@ -64,22 +57,6 @@ public interface SettingsBuilderRequest { @Nonnull Optional getProjectSettingsSource(); - /** - * Gets the project settings path. - * - * @return the project settings path or {@code null} if none - */ - @Nonnull - Optional getProjectSettingsPath(); - - /** - * Gets the user settings path. - * - * @return the user settings path or {@code null} if none - */ - @Nonnull - Optional getUserSettingsPath(); - /** * Gets the user settings source. * @@ -97,34 +74,43 @@ public interface SettingsBuilderRequest { @Nonnull static SettingsBuilderRequest build( @Nonnull Session session, @Nonnull Path globalSettingsPath, @Nonnull Path userSettingsPath) { - return build(session, globalSettingsPath, null, userSettingsPath); + return build(session, Source.fromPath(globalSettingsPath), null, Source.fromPath(userSettingsPath)); } @Nonnull static SettingsBuilderRequest build( @Nonnull Session session, - @Nonnull Source globalSettingsSource, - @Nonnull Source projectSettingsSource, - @Nonnull Source userSettingsSource) { + @Nullable Source globalSettingsSource, + @Nullable Source projectSettingsSource, + @Nullable Source userSettingsSource) { return builder() .session(nonNull(session, "session cannot be null")) - .globalSettingsSource(nonNull(globalSettingsSource, "globalSettingsSource cannot be null")) - .projectSettingsSource(nonNull(projectSettingsSource, "projectSettingsSource cannot be null")) - .userSettingsSource(nonNull(userSettingsSource, "userSettingsSource cannot be null")) + .globalSettingsSource(globalSettingsSource) + .projectSettingsSource(projectSettingsSource) + .userSettingsSource(userSettingsSource) .build(); } @Nonnull static SettingsBuilderRequest build( @Nonnull Session session, - @Nonnull Path globalSettingsPath, - @Nonnull Path projectSettingsPath, - @Nonnull Path userSettingsPath) { + @Nullable Path globalSettingsPath, + @Nullable Path projectSettingsPath, + @Nullable Path userSettingsPath) { return builder() .session(nonNull(session, "session cannot be null")) - .globalSettingsPath(nonNull(globalSettingsPath, "globalSettingsPath cannot be null")) - .projectSettingsPath(nonNull(projectSettingsPath, "projectSettingsPath cannot be null")) - .userSettingsPath(nonNull(userSettingsPath, "userSettingsPath cannot be null")) + .globalSettingsSource( + globalSettingsPath != null && Files.exists(globalSettingsPath) + ? Source.fromPath(globalSettingsPath) + : null) + .projectSettingsSource( + projectSettingsPath != null && Files.exists(projectSettingsPath) + ? Source.fromPath(projectSettingsPath) + : null) + .userSettingsSource( + userSettingsPath != null && Files.exists(userSettingsPath) + ? Source.fromPath(userSettingsPath) + : null) .build(); } @@ -136,11 +122,8 @@ public interface SettingsBuilderRequest { @NotThreadSafe class SettingsBuilderRequestBuilder { Session session; - Path globalSettingsPath; Source globalSettingsSource; - Path projectSettingsPath; Source projectSettingsSource; - Path userSettingsPath; Source userSettingsSource; public SettingsBuilderRequestBuilder session(Session session) { @@ -148,31 +131,16 @@ public interface SettingsBuilderRequest { return this; } - public SettingsBuilderRequestBuilder globalSettingsPath(Path globalSettingsPath) { - this.globalSettingsPath = globalSettingsPath; - return this; - } - public SettingsBuilderRequestBuilder globalSettingsSource(Source globalSettingsSource) { this.globalSettingsSource = globalSettingsSource; return this; } - public SettingsBuilderRequestBuilder projectSettingsPath(Path projectSettingsPath) { - this.projectSettingsPath = projectSettingsPath; - return this; - } - public SettingsBuilderRequestBuilder projectSettingsSource(Source projectSettingsSource) { this.projectSettingsSource = projectSettingsSource; return this; } - public SettingsBuilderRequestBuilder userSettingsPath(Path userSettingsPath) { - this.userSettingsPath = userSettingsPath; - return this; - } - public SettingsBuilderRequestBuilder userSettingsSource(Source userSettingsSource) { this.userSettingsSource = userSettingsSource; return this; @@ -180,71 +148,38 @@ public interface SettingsBuilderRequest { public SettingsBuilderRequest build() { return new DefaultSettingsBuilderRequest( - session, - globalSettingsPath, - globalSettingsSource, - projectSettingsPath, - projectSettingsSource, - userSettingsPath, - userSettingsSource); + session, globalSettingsSource, projectSettingsSource, userSettingsSource); } private static class DefaultSettingsBuilderRequest extends BaseRequest implements SettingsBuilderRequest { - private final Path globalSettingsPath; private final Source globalSettingsSource; - private final Path projectSettingsPath; private final Source projectSettingsSource; - private final Path userSettingsPath; private final Source userSettingsSource; @SuppressWarnings("checkstyle:ParameterNumber") DefaultSettingsBuilderRequest( @Nonnull Session session, - @Nullable Path globalSettingsPath, @Nullable Source globalSettingsSource, - @Nullable Path projectSettingsPath, @Nullable Source projectSettingsSource, - @Nullable Path userSettingsPath, @Nullable Source userSettingsSource) { super(session); - this.globalSettingsPath = globalSettingsPath; this.globalSettingsSource = globalSettingsSource; - this.projectSettingsPath = projectSettingsPath; this.projectSettingsSource = projectSettingsSource; - this.userSettingsPath = userSettingsPath; this.userSettingsSource = userSettingsSource; } - @Nonnull - @Override - public Optional getGlobalSettingsPath() { - return Optional.ofNullable(globalSettingsPath); - } - @Nonnull @Override public Optional getGlobalSettingsSource() { return Optional.ofNullable(globalSettingsSource); } - @Nonnull - @Override - public Optional getProjectSettingsPath() { - return Optional.ofNullable(projectSettingsPath); - } - @Nonnull @Override public Optional getProjectSettingsSource() { return Optional.ofNullable(projectSettingsSource); } - @Nonnull - @Override - public Optional getUserSettingsPath() { - return Optional.ofNullable(userSettingsPath); - } - @Nonnull @Override public Optional getUserSettingsSource() { diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java index 9b393d668d..201c49e5f0 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java @@ -27,6 +27,8 @@ import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; +import static org.apache.maven.api.services.BaseRequest.nonNull; + /** * Provides access to the contents of a source independently of the * backing store (e.g. file system, database, memory). @@ -86,4 +88,12 @@ public interface Source { * @return related source or null if no such source */ Source resolve(String relative); + + /** + * Creates a Source for the following Path + */ + @Nonnull + static Source fromPath(@Nonnull Path path) { + return new PathSource(nonNull(path, "path cannot be null")); + } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java index c6f5ca8b7b..21c3cda49e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java @@ -18,6 +18,9 @@ */ package org.apache.maven.api.services; +import java.util.List; +import java.util.stream.Collectors; + import org.apache.maven.api.annotations.Experimental; /** @@ -27,13 +30,24 @@ import org.apache.maven.api.annotations.Experimental; */ @Experimental public class ToolchainsBuilderException extends MavenException { + + private final List problems; + /** * @param message the message to give * @param e the {@link Exception} */ public ToolchainsBuilderException(String message, Exception e) { super(message, e); + this.problems = List.of(); } - // TODO: add ToolchainsBuilderResult + public ToolchainsBuilderException(String message, List problems) { + super(message + ": " + problems.stream().map(BuilderProblem::toString).collect(Collectors.joining(", ")), null); + this.problems = List.copyOf(problems); + } + + public List getProblems() { + return problems; + } } 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 index abdb0dcc76..3a1a6d60d9 100644 --- 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 @@ -18,6 +18,7 @@ */ package org.apache.maven.api.services; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; @@ -38,14 +39,6 @@ public interface ToolchainsBuilderRequest { @Nonnull Session getSession(); - /** - * Gets the global Toolchains path. - * - * @return the global Toolchains path or {@code null} if none - */ - @Nonnull - Optional getGlobalToolchainsPath(); - /** * Gets the global Toolchains source. * @@ -54,14 +47,6 @@ public interface ToolchainsBuilderRequest { @Nonnull Optional getGlobalToolchainsSource(); - /** - * Gets the user Toolchains path. - * - * @return the user Toolchains path or {@code null} if none - */ - @Nonnull - Optional getUserToolchainsPath(); - /** * Gets the user Toolchains source. * @@ -72,21 +57,27 @@ public interface ToolchainsBuilderRequest { @Nonnull static ToolchainsBuilderRequest build( - @Nonnull Session session, @Nonnull Source globalToolchainsSource, @Nonnull Source userToolchainsSource) { + @Nonnull Session session, @Nullable Source globalToolchainsSource, @Nullable 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")) + .globalToolchainsSource(globalToolchainsSource) + .userToolchainsSource(userToolchainsSource) .build(); } @Nonnull static ToolchainsBuilderRequest build( - @Nonnull Session session, @Nonnull Path globalToolchainsPath, @Nonnull Path userToolchainsPath) { + @Nonnull Session session, @Nullable Path globalToolchainsPath, @Nullable 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")) + .globalToolchainsSource( + globalToolchainsPath != null && Files.exists(globalToolchainsPath) + ? Source.fromPath(globalToolchainsPath) + : null) + .userToolchainsSource( + userToolchainsPath != null && Files.exists(userToolchainsPath) + ? Source.fromPath(userToolchainsPath) + : null) .build(); } @@ -98,9 +89,7 @@ public interface ToolchainsBuilderRequest { @NotThreadSafe class ToolchainsBuilderRequestBuilder { Session session; - Path globalToolchainsPath; Source globalToolchainsSource; - Path userToolchainsPath; Source userToolchainsSource; public ToolchainsBuilderRequestBuilder session(Session session) { @@ -108,21 +97,11 @@ public interface ToolchainsBuilderRequest { 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; @@ -130,47 +109,29 @@ public interface ToolchainsBuilderRequest { public ToolchainsBuilderRequest build() { return new ToolchainsBuilderRequestBuilder.DefaultToolchainsBuilderRequest( - session, globalToolchainsPath, globalToolchainsSource, userToolchainsPath, userToolchainsSource); + session, globalToolchainsSource, 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 getGlobalToolchainsPath() { - return Optional.ofNullable(globalToolchainsPath); - } - @Nonnull @Override public Optional getGlobalToolchainsSource() { return Optional.ofNullable(globalToolchainsSource); } - @Nonnull - @Override - public Optional getUserToolchainsPath() { - return Optional.ofNullable(userToolchainsPath); - } - @Nonnull @Override public Optional getUserToolchainsSource() { diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/Location.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/Location.java new file mode 100644 index 0000000000..a79d9fcb8d --- /dev/null +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/Location.java @@ -0,0 +1,58 @@ +/* + * 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. + */ +package org.apache.maven.api.services.xml; + +public interface Location { + + /** + * Return the line number where the current event ends, + * returns -1 if none is available. + * @return the current line number + */ + int getLineNumber(); + + /** + * Return the column number where the current event ends, + * returns -1 if none is available. + * @return the current column number + */ + int getColumnNumber(); + + /** + * Return the byte or character offset into the input source this location + * is pointing to. If the input source is a file or a byte stream then + * this is the byte offset into that stream, but if the input source is + * a character media then the offset is the character offset. + * Returns -1 if there is no offset available. + * @return the current offset + */ + int getCharacterOffset(); + + /** + * Returns the public ID of the XML + * @return the public ID, or null if not available + */ + String getPublicId(); + + /** + * Returns the system ID of the XML + * @return the system ID, or null if not available + */ + String getSystemId(); +} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java index a666c7498d..dda58c162e 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java @@ -29,11 +29,18 @@ import org.apache.maven.api.services.MavenException; @Experimental public class XmlReaderException extends MavenException { + private final Location location; + /** * @param message the message for the exception * @param e the exception itself */ - public XmlReaderException(String message, Exception e) { + public XmlReaderException(String message, Location location, Exception e) { super(message, e); + this.location = location; + } + + public Location getLocation() { + return location; } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java index 491a1f06b1..cba0c2df88 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java @@ -29,11 +29,18 @@ import org.apache.maven.api.services.MavenException; @Experimental public class XmlWriterException extends MavenException { + private final Location location; + /** * @param message the message for the exception * @param e the exception itself */ - public XmlWriterException(String message, Exception e) { + public XmlWriterException(String message, Location location, Exception e) { super(message, e); + this.location = location; + } + + public Location getLocation() { + return location; } } diff --git a/maven-api-impl/pom.xml b/maven-api-impl/pom.xml new file mode 100644 index 0000000000..fe6a104bcc --- /dev/null +++ b/maven-api-impl/pom.xml @@ -0,0 +1,140 @@ + + + + 4.0.0 + + org.apache.maven + maven + 4.0.0-alpha-14-SNAPSHOT + + + maven-api-impl + Maven API Implementation + Provides the implementation classes for the Maven API + + + + org.apache.maven + maven-api-core + + + org.apache.maven + maven-di + + + org.apache.maven.resolver + maven-resolver-api + + + org.apache.maven.resolver + maven-resolver-spi + + + org.apache.maven.resolver + maven-resolver-util + + + org.apache.maven.resolver + maven-resolver-supplier + ${resolverVersion} + + + org.apache.maven + maven-resolver-provider + + + + org.mockito + mockito-junit-jupiter + test + + + + + + + org.codehaus.modello + modello-maven-plugin + + + velocity-settings + + velocity + + generate-sources + + 2.0.0 + ${project.basedir}/../api/maven-api-settings + ${project.basedir}/../src/mdo + + src/main/mdo/settings.mdo + + + + + + + + + forcedIOModelVersion=1.2.0 + packageModelV3=org.apache.maven.settings + packageModelV4=org.apache.maven.api.settings + packageToolV4=org.apache.maven.settings.v4 + locationTracking=true + generateLocationClasses=true + + + + + velocity-toolchains + + velocity + + generate-sources + + 1.1.0 + ${project.basedir}/../api/maven-api-toolchain + ${project.basedir}/../src/mdo + + src/main/mdo/toolchains.mdo + + + + + + + + + packageModelV3=org.apache.maven.toolchain.model + packageModelV4=org.apache.maven.api.toolchain + packageToolV4=org.apache.maven.toolchain.v4 + + + + + modello-site-docs + none + + + + + + + diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractNode.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractNode.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/AbstractNode.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractNode.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java similarity index 76% rename from maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index b85b5b816f..8d3068c8a7 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -25,24 +25,55 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.Optional; import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.function.Supplier; import java.util.stream.Collectors; -import org.apache.maven.api.*; +import org.apache.maven.api.Artifact; +import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.Dependency; +import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.DependencyScope; +import org.apache.maven.api.Language; +import org.apache.maven.api.Listener; +import org.apache.maven.api.LocalRepository; +import org.apache.maven.api.Node; +import org.apache.maven.api.Packaging; +import org.apache.maven.api.PathScope; +import org.apache.maven.api.PathType; +import org.apache.maven.api.Project; +import org.apache.maven.api.ProjectScope; +import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.Service; +import org.apache.maven.api.Session; +import org.apache.maven.api.SessionData; +import org.apache.maven.api.Type; +import org.apache.maven.api.Version; +import org.apache.maven.api.VersionConstraint; +import org.apache.maven.api.VersionRange; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.*; -import org.apache.maven.artifact.repository.ArtifactRepository; -import org.apache.maven.project.MavenProject; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; import static org.apache.maven.internal.impl.Utils.map; import static org.apache.maven.internal.impl.Utils.nonNull; public abstract class AbstractSession implements InternalSession { + protected final RepositorySystemSession session; + protected final RepositorySystem repositorySystem; + protected final List repositories; + protected final Lookup lookup; + private final Map, Service> services = new ConcurrentHashMap<>(); private final List listeners = new CopyOnWriteArrayList<>(); private final Map allNodes = Collections.synchronizedMap(new WeakHashMap<>()); @@ -50,10 +81,21 @@ public abstract class AbstractSession implements InternalSession { Collections.synchronizedMap(new WeakHashMap<>()); private final Map allRepositories = Collections.synchronizedMap(new WeakHashMap<>()); - private final Map allProjects = Collections.synchronizedMap(new WeakHashMap<>()); private final Map allDependencies = Collections.synchronizedMap(new WeakHashMap<>()); + public AbstractSession( + RepositorySystemSession session, + RepositorySystem repositorySystem, + List repositories, + List resolverRepositories, + Lookup lookup) { + this.session = session; + this.repositorySystem = repositorySystem; + this.repositories = getRepositories(repositories, resolverRepositories); + this.lookup = lookup; + } + @Override public RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) { return allRepositories.computeIfAbsent(repository, DefaultRemoteRepository::new); @@ -81,16 +123,6 @@ public abstract class AbstractSession implements InternalSession { return allDependencies.computeIfAbsent(dependency, d -> new DefaultDependency(this, d)); } - @Override - public List getProjects(List projects) { - return projects == null ? null : map(projects, this::getProject); - } - - @Override - public Project getProject(MavenProject project) { - return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project)); - } - @Override public List toRepositories(List repositories) { return repositories == null ? null : map(repositories, this::toRepository); @@ -116,22 +148,143 @@ public abstract class AbstractSession implements InternalSession { } } - @Override - public List toArtifactRepositories(List repositories) { - return repositories == null ? null : map(repositories, this::toArtifactRepository); - } - - @Override - public abstract ArtifactRepository toArtifactRepository(RemoteRepository repository); - @Override public List toDependencies( Collection dependencies, boolean managed) { return dependencies == null ? null : map(dependencies, d -> toDependency(d, managed)); } + protected List getRepositories( + List repositories, + List resolverRepositories) { + if (repositories != null) { + return repositories; + } else if (resolverRepositories != null) { + return map(resolverRepositories, this::getRemoteRepository); + } else { + throw new IllegalArgumentException("no remote repositories provided"); + } + } + + @Nonnull @Override - public abstract org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency, boolean managed); + public List getRemoteRepositories() { + return Collections.unmodifiableList(repositories); + } + + @Nonnull + @Override + public SessionData getData() { + org.eclipse.aether.SessionData data = session.getData(); + return new SessionData() { + @Override + public void set(@Nonnull Key key, @Nullable T value) { + data.set(key, value); + } + + @Override + public boolean replace(@Nonnull Key key, @Nullable T oldValue, @Nullable T newValue) { + return data.set(key, oldValue, newValue); + } + + @Nullable + @Override + @SuppressWarnings("unchecked") + public T get(@Nonnull Key key) { + return (T) data.get(key); + } + + @Nullable + @Override + @SuppressWarnings("unchecked") + public T computeIfAbsent(@Nonnull Key key, @Nonnull Supplier supplier) { + return (T) data.computeIfAbsent(key, (Supplier) supplier); + } + }; + } + + @Nonnull + @Override + public LocalRepository getLocalRepository() { + return new DefaultLocalRepository(session.getLocalRepository()); + } + + @Nonnull + @Override + public Session withLocalRepository(@Nonnull LocalRepository localRepository) { + nonNull(localRepository, "localRepository"); + if (session.getLocalRepository() != null + && Objects.equals(session.getLocalRepository().getBasedir().toPath(), localRepository.getPath())) { + return this; + } + org.eclipse.aether.repository.LocalRepository repository = toRepository(localRepository); + org.eclipse.aether.repository.LocalRepositoryManager localRepositoryManager = + repositorySystem.newLocalRepositoryManager(session, repository); + + RepositorySystemSession repoSession = + new DefaultRepositorySystemSession(session).setLocalRepositoryManager(localRepositoryManager); + return newSession(repoSession, repositories); + } + + @Nonnull + @Override + public Session withRemoteRepositories(@Nonnull List repositories) { + return newSession(session, repositories); + } + + protected abstract Session newSession(RepositorySystemSession session, List repositories); + + @Nonnull + @Override + @SuppressWarnings("unchecked") + public T getService(Class clazz) throws NoSuchElementException { + T t = (T) services.computeIfAbsent(clazz, this::lookup); + if (t == null) { + throw new NoSuchElementException(clazz.getName()); + } + return t; + } + + private Service lookup(Class c) { + try { + return lookup.lookup(c); + } catch (LookupException e) { + NoSuchElementException nsee = new NoSuchElementException(c.getName()); + e.initCause(e); + throw nsee; + } + } + + @Nonnull + public RepositorySystemSession getSession() { + return session; + } + + @Nonnull + public RepositorySystem getRepositorySystem() { + return repositorySystem; + } + + public org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency, boolean managed) { + org.eclipse.aether.graph.Dependency dep; + if (dependency instanceof DefaultDependencyCoordinate) { + dep = ((DefaultDependencyCoordinate) dependency).getDependency(); + } else { + dep = new org.eclipse.aether.graph.Dependency( + new org.eclipse.aether.artifact.DefaultArtifact( + dependency.getGroupId(), + dependency.getArtifactId(), + dependency.getClassifier(), + dependency.getType().getExtension(), + dependency.getVersion().toString(), + null), + dependency.getScope().id()); + } + if (!managed && "".equals(dep.getScope())) { + dep = dep.setScope(DependencyScope.COMPILE.id()); + } + return dep; + } @Override public List toArtifacts(Collection artifacts) { diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java index 8ee696bbca..ebc056d9bd 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java @@ -18,11 +18,10 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.ArtifactCoordinate; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.ArtifactCoordinateFactory; import org.apache.maven.api.services.ArtifactCoordinateFactoryRequest; import org.eclipse.aether.artifact.ArtifactType; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java similarity index 96% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java index d9f6dec6e3..e5f7be518d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java @@ -18,14 +18,13 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.util.Collection; import org.apache.maven.api.Artifact; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.ArtifactDeployer; import org.apache.maven.api.services.ArtifactDeployerException; import org.apache.maven.api.services.ArtifactDeployerRequest; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java similarity index 96% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java index e7e4235375..94ed121c4b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java @@ -18,11 +18,10 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.Artifact; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.ArtifactFactory; import org.apache.maven.api.services.ArtifactFactoryRequest; import org.eclipse.aether.artifact.ArtifactType; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java similarity index 95% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java index 65ae1f8978..d8eafe3aba 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java @@ -18,11 +18,10 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.ArtifactInstaller; import org.apache.maven.api.services.ArtifactInstallerException; import org.apache.maven.api.services.ArtifactInstallerRequest; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java index 4eb78b49a9..72ae752e32 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java @@ -18,9 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; @@ -29,6 +26,8 @@ import java.util.Map; import org.apache.maven.api.Artifact; import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.ArtifactManager; import org.apache.maven.api.services.ArtifactResolver; import org.apache.maven.api.services.ArtifactResolverException; diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultBuilderProblem.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultBuilderProblem.java new file mode 100644 index 0000000000..95ffe21cd1 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultBuilderProblem.java @@ -0,0 +1,111 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import org.apache.maven.api.services.BuilderProblem; + +/** + * Describes a problem that was encountered during settings building. A problem can either be an exception that was + * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file + * that exhibits the problem. + */ +class DefaultBuilderProblem implements BuilderProblem { + final String source; + final int lineNumber; + final int columnNumber; + final Exception exception; + final String message; + final Severity severity; + + DefaultBuilderProblem( + String source, int lineNumber, int columnNumber, Exception exception, String message, Severity severity) { + this.source = source; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.exception = exception; + this.message = message; + this.severity = severity; + } + + @Override + public String getSource() { + return source; + } + + @Override + public int getLineNumber() { + return lineNumber; + } + + @Override + public int getColumnNumber() { + return columnNumber; + } + + @Override + public Exception getException() { + return exception; + } + + @Override + public String getMessage() { + return message; + } + + @Override + public Severity getSeverity() { + return severity; + } + + @Override + public String getLocation() { + StringBuilder buffer = new StringBuilder(256); + if (!getSource().isEmpty()) { + buffer.append(getSource()); + } + if (getLineNumber() > 0) { + if (!buffer.isEmpty()) { + buffer.append(", "); + } + buffer.append("line ").append(getLineNumber()); + } + if (getColumnNumber() > 0) { + if (!buffer.isEmpty()) { + buffer.append(", "); + } + buffer.append("column ").append(getColumnNumber()); + } + return buffer.toString(); + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(128); + buffer.append('[').append(severity).append("]"); + String msg = message != null ? message : exception != null ? exception.getMessage() : null; + if (msg != null && !msg.isEmpty()) { + buffer.append(" ").append(msg); + } + String location = getLocation(); + if (!location.isEmpty()) { + buffer.append(" @ ").append(location); + } + return buffer.toString(); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java similarity index 92% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java index 10baef3ccc..d910b77fca 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultChecksumAlgorithmService.java @@ -18,18 +18,26 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import java.io.*; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; -import org.apache.maven.api.services.*; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; +import org.apache.maven.api.services.ChecksumAlgorithmService; +import org.apache.maven.api.services.ChecksumAlgorithmServiceException; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java similarity index 88% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java index 15ec1ba0f0..bd63ca1280 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java @@ -18,15 +18,22 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.util.Collection; import java.util.List; -import org.apache.maven.api.*; +import org.apache.maven.api.Artifact; +import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.Node; +import org.apache.maven.api.Project; +import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.services.*; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; +import org.apache.maven.api.services.DependencyCollector; +import org.apache.maven.api.services.DependencyCollectorException; +import org.apache.maven.api.services.DependencyCollectorRequest; +import org.apache.maven.api.services.DependencyCollectorResult; +import org.apache.maven.api.services.ProjectManager; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.collection.CollectRequest; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java similarity index 93% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java index c0420f5fbb..fd889c961b 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java @@ -20,7 +20,11 @@ package org.apache.maven.internal.impl; import java.util.Collection; -import org.apache.maven.api.*; +import org.apache.maven.api.DependencyCoordinate; +import org.apache.maven.api.DependencyScope; +import org.apache.maven.api.Exclusion; +import org.apache.maven.api.Type; +import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.eclipse.aether.artifact.ArtifactProperties; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java index 6362a8ccde..33c13ea72c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java @@ -18,12 +18,11 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Exclusion; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.DependencyCoordinateFactory; import org.apache.maven.api.services.DependencyCoordinateFactoryRequest; import org.eclipse.aether.artifact.ArtifactType; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java index 85f99a0996..4c6797599e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java @@ -18,8 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; - import java.nio.file.Path; import org.apache.maven.api.LocalRepository; @@ -31,7 +29,6 @@ public class DefaultLocalRepository implements LocalRepository { private final @Nonnull org.eclipse.aether.repository.LocalRepository repository; - @Inject public DefaultLocalRepository(@Nonnull org.eclipse.aether.repository.LocalRepository repository) { this.repository = nonNull(repository, "repository"); } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java similarity index 96% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java index 43ba78660a..da5558fe5e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java @@ -18,15 +18,14 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.nio.file.Path; import org.apache.maven.api.Artifact; import org.apache.maven.api.LocalRepository; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.LocalRepositoryManager; @Named diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java similarity index 91% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java index bb2f6c982e..b8fceef119 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java @@ -18,15 +18,14 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Priority; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.MessageBuilder; import org.apache.maven.api.services.MessageBuilderFactory; -import org.eclipse.sisu.Priority; @Experimental @Named diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java similarity index 92% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java index 7daf44098e..d21f94fe2f 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java @@ -18,9 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; @@ -30,6 +27,8 @@ import java.nio.file.Files; import java.nio.file.Path; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.model.InputSource; import org.apache.maven.api.model.Model; import org.apache.maven.api.services.xml.ModelXmlFactory; @@ -40,6 +39,8 @@ import org.apache.maven.api.services.xml.XmlWriterRequest; import org.apache.maven.model.v4.MavenStaxReader; import org.apache.maven.model.v4.MavenStaxWriter; +import static org.apache.maven.internal.impl.StaxLocation.getLocation; +import static org.apache.maven.internal.impl.StaxLocation.getMessage; import static org.apache.maven.internal.impl.Utils.nonNull; @Named @@ -76,7 +77,7 @@ public class DefaultModelXmlFactory implements ModelXmlFactory { } } } catch (Exception e) { - throw new XmlReaderException("Unable to read model", e); + throw new XmlReaderException("Unable to read model: " + getMessage(e), getLocation(e), e); } } @@ -101,7 +102,7 @@ public class DefaultModelXmlFactory implements ModelXmlFactory { } } } catch (Exception e) { - throw new XmlWriterException("Unable to write model", e); + throw new XmlWriterException("Unable to write model: " + getMessage(e), getLocation(e), e); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultNode.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultNode.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java similarity index 89% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java index 9e6da6300c..2a85389e4e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java @@ -18,30 +18,20 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import java.nio.file.Path; import org.apache.maven.api.LocalRepository; import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.model.Repository; import org.apache.maven.api.services.RepositoryFactory; -import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.repository.RepositoryPolicy; @Named @Singleton public class DefaultRepositoryFactory implements RepositoryFactory { - private final RepositorySystem repositorySystem; - - @Inject - public DefaultRepositoryFactory(RepositorySystem repositorySystem) { - this.repositorySystem = repositorySystem; - } - @Override public LocalRepository createLocal(Path path) { return new DefaultLocalRepository(new org.eclipse.aether.repository.LocalRepository(path.toFile())); diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java new file mode 100644 index 0000000000..4801258d28 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java @@ -0,0 +1,300 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.api.di.Named; +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.services.xml.SettingsXmlFactory; +import org.apache.maven.api.services.xml.XmlReaderException; +import org.apache.maven.api.services.xml.XmlReaderRequest; +import org.apache.maven.api.settings.Profile; +import org.apache.maven.api.settings.Repository; +import org.apache.maven.api.settings.RepositoryPolicy; +import org.apache.maven.api.settings.Server; +import org.apache.maven.api.settings.Settings; +import org.apache.maven.settings.v4.SettingsMerger; +import org.apache.maven.settings.v4.SettingsTransformer; +import org.codehaus.plexus.interpolation.EnvarBasedValueSource; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.RegexBasedInterpolator; + +/** + * Builds the effective settings from a user settings file and/or a global settings file. + * + */ +@Named +public class DefaultSettingsBuilder implements SettingsBuilder { + + private final DefaultSettingsValidator settingsValidator = new DefaultSettingsValidator(); + + private final SettingsMerger settingsMerger = new SettingsMerger(); + + @Override + public SettingsBuilderResult build(SettingsBuilderRequest request) throws SettingsBuilderException { + List problems = new ArrayList<>(); + + Source globalSource = request.getGlobalSettingsSource().orElse(null); + Settings global = readSettings(globalSource, false, request, problems); + + Source projectSource = request.getProjectSettingsSource().orElse(null); + Settings project = readSettings(projectSource, true, request, problems); + + Source userSource = request.getUserSettingsSource().orElse(null); + Settings user = readSettings(userSource, false, request, problems); + + Settings effective = + settingsMerger.merge(user, settingsMerger.merge(project, global, false, null), false, null); + + // If no repository is defined in the user/global settings, + // it means that we have "old" settings (as those are new in 4.0) + // so add central to the computed settings for backward compatibility. + if (effective.getRepositories().isEmpty() + && effective.getPluginRepositories().isEmpty()) { + Repository central = Repository.newBuilder() + .id("central") + .name("Central Repository") + .url("https://repo.maven.apache.org/maven2") + .snapshots(RepositoryPolicy.newBuilder().enabled(false).build()) + .build(); + Repository centralWithNoUpdate = central.withReleases( + RepositoryPolicy.newBuilder().updatePolicy("never").build()); + effective = Settings.newBuilder(effective) + .repositories(List.of(central)) + .pluginRepositories(List.of(centralWithNoUpdate)) + .build(); + } + + // for the special case of a drive-relative Windows path, make sure it's absolute to save plugins from trouble + String localRepository = effective.getLocalRepository(); + if (localRepository != null && !localRepository.isEmpty()) { + Path file = Paths.get(localRepository); + if (!file.isAbsolute() && file.toString().startsWith(File.separator)) { + effective = effective.withLocalRepository(file.toAbsolutePath().toString()); + } + } + + if (hasErrors(problems)) { + throw new SettingsBuilderException("Error building settings", problems); + } + + return new DefaultSettingsBuilderResult(effective, problems); + } + + private boolean hasErrors(List problems) { + if (problems != null) { + for (BuilderProblem problem : problems) { + if (BuilderProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) { + return true; + } + } + } + + return false; + } + + private Settings readSettings( + Source settingsSource, + boolean isProjectSettings, + SettingsBuilderRequest request, + List problems) { + if (settingsSource == null) { + return Settings.newInstance(); + } + + Settings settings; + + try { + try { + InputStream is = settingsSource.openStream(); + if (is == null) { + return Settings.newInstance(); + } + settings = request.getSession() + .getService(SettingsXmlFactory.class) + .read(XmlReaderRequest.builder() + .inputStream(is) + .location(settingsSource.getLocation()) + .strict(true) + .build()); + } catch (XmlReaderException e) { + InputStream is = settingsSource.openStream(); + if (is == null) { + return Settings.newInstance(); + } + settings = request.getSession() + .getService(SettingsXmlFactory.class) + .read(XmlReaderRequest.builder() + .inputStream(is) + .location(settingsSource.getLocation()) + .strict(false) + .build()); + Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null; + problems.add(new DefaultBuilderProblem( + settingsSource.getLocation(), + loc != null ? loc.getLineNumber() : -1, + loc != null ? loc.getColumnNumber() : -1, + e, + e.getMessage(), + BuilderProblem.Severity.WARNING)); + } + } catch (XmlReaderException e) { + Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null; + problems.add(new DefaultBuilderProblem( + settingsSource.getLocation(), + loc != null ? loc.getLineNumber() : -1, + loc != null ? loc.getColumnNumber() : -1, + e, + "Non-parseable settings " + settingsSource.getLocation() + ": " + e.getMessage(), + BuilderProblem.Severity.FATAL)); + return Settings.newInstance(); + } catch (IOException e) { + problems.add(new DefaultBuilderProblem( + settingsSource.getLocation(), + -1, + -1, + e, + "Non-readable settings " + settingsSource.getLocation() + ": " + e.getMessage(), + BuilderProblem.Severity.FATAL)); + return Settings.newInstance(); + } + + settings = interpolate(settings, request, problems); + + settingsValidator.validate(settings, isProjectSettings, problems); + + if (isProjectSettings) { + settings = Settings.newBuilder(settings, true) + .localRepository(null) + .interactiveMode(false) + .offline(false) + .proxies(List.of()) + .usePluginRegistry(false) + .servers(settings.getServers().stream() + .map(s -> Server.newBuilder(s, true) + .username(null) + .passphrase(null) + .privateKey(null) + .password(null) + .filePermissions(null) + .directoryPermissions(null) + .build()) + .toList()) + .build(); + } + + return settings; + } + + private Settings interpolate(Settings settings, SettingsBuilderRequest request, List problems) { + + RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); + + interpolator.addValueSource(new MapBasedValueSource(request.getSession().getUserProperties())); + + interpolator.addValueSource(new MapBasedValueSource(request.getSession().getSystemProperties())); + + try { + interpolator.addValueSource(new EnvarBasedValueSource()); + } catch (IOException e) { + problems.add(new DefaultBuilderProblem( + null, + -1, + -1, + e, + "Failed to use environment variables for interpolation: " + e.getMessage(), + BuilderProblem.Severity.WARNING)); + } + + return new SettingsTransformer(value -> { + try { + return value != null ? interpolator.interpolate(value) : null; + } catch (InterpolationException e) { + problems.add(new DefaultBuilderProblem( + null, + -1, + -1, + e, + "Failed to interpolate settings: " + e.getMessage(), + BuilderProblem.Severity.WARNING)); + return value; + } + }) + .visit(settings); + } + + @Override + public List validate(Settings settings, boolean isProjectSettings) { + ArrayList problems = new ArrayList<>(); + settingsValidator.validate(settings, isProjectSettings, problems); + return problems; + } + + @Override + public Profile convert(org.apache.maven.api.model.Profile profile) { + return SettingsUtilsV4.convertToSettingsProfile(profile); + } + + @Override + public org.apache.maven.api.model.Profile convert(Profile profile) { + return SettingsUtilsV4.convertFromSettingsProfile(profile); + } + + /** + * Collects the output of the settings builder. + * + */ + static class DefaultSettingsBuilderResult implements SettingsBuilderResult { + + private final Settings effectiveSettings; + + private final List problems; + + DefaultSettingsBuilderResult(Settings effectiveSettings, List problems) { + this.effectiveSettings = effectiveSettings; + this.problems = (problems != null) ? problems : new ArrayList<>(); + } + + @Override + public Settings getEffectiveSettings() { + return effectiveSettings; + } + + @Override + public List getProblems() { + return problems; + } + } +} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsValidator.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsValidator.java new file mode 100644 index 0000000000..904b62d032 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsValidator.java @@ -0,0 +1,362 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; + +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.settings.Mirror; +import org.apache.maven.api.settings.Profile; +import org.apache.maven.api.settings.Proxy; +import org.apache.maven.api.settings.Repository; +import org.apache.maven.api.settings.Server; +import org.apache.maven.api.settings.Settings; + +/** + */ +public class DefaultSettingsValidator { + + private static final String ID = "[\\w.-]+"; + private static final Pattern ID_REGEX = Pattern.compile(ID); + + private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS + + public void validate(Settings settings, boolean isProjectSettings, List problems) { + if (isProjectSettings) { + String msgS = "is not supported on project settings."; + String msgP = "are not supported on project settings."; + if (settings.getLocalRepository() != null + && !settings.getLocalRepository().isEmpty()) { + addViolation(problems, BuilderProblem.Severity.WARNING, "localRepository", null, msgS); + } + if (!settings.isInteractiveMode()) { + addViolation(problems, BuilderProblem.Severity.WARNING, "interactiveMode", null, msgS); + } + if (settings.isOffline()) { + addViolation(problems, BuilderProblem.Severity.WARNING, "offline", null, msgS); + } + if (!settings.getProxies().isEmpty()) { + addViolation(problems, BuilderProblem.Severity.WARNING, "proxies", null, msgP); + } + if (settings.isUsePluginRegistry()) { + addViolation(problems, BuilderProblem.Severity.WARNING, "usePluginRegistry", null, msgS); + } + List servers = settings.getServers(); + for (int i = 0; i < servers.size(); i++) { + Server server = servers.get(i); + String serverField = "servers.server[" + i + "]"; + validateStringEmpty(problems, serverField + ".username", server.getUsername(), msgS); + validateStringEmpty(problems, serverField + ".password", server.getPassword(), msgS); + validateStringEmpty(problems, serverField + ".privateKey", server.getPrivateKey(), msgS); + validateStringEmpty(problems, serverField + ".passphrase", server.getPassphrase(), msgS); + validateStringEmpty(problems, serverField + ".filePermissions", server.getFilePermissions(), msgS); + validateStringEmpty( + problems, serverField + ".directoryPermissions", server.getDirectoryPermissions(), msgS); + } + } + + if (settings.isUsePluginRegistry()) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + "usePluginRegistry", + null, + "is deprecated and has no effect."); + } + + List pluginGroups = settings.getPluginGroups(); + + if (pluginGroups != null) { + for (int i = 0; i < pluginGroups.size(); i++) { + String pluginGroup = pluginGroups.get(i); + + validateStringNotEmpty(problems, "pluginGroups.pluginGroup[" + i + "]", pluginGroup, null); + + if (!ID_REGEX.matcher(pluginGroup).matches()) { + addViolation( + problems, + BuilderProblem.Severity.ERROR, + "pluginGroups.pluginGroup[" + i + "]", + null, + "must denote a valid group id and match the pattern " + ID); + } + } + } + + List servers = settings.getServers(); + + if (servers != null) { + Set serverIds = new HashSet<>(); + + for (int i = 0; i < servers.size(); i++) { + Server server = servers.get(i); + + validateStringNotEmpty(problems, "servers.server[" + i + "].id", server.getId(), null); + + if (!serverIds.add(server.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + "servers.server.id", + null, + "must be unique but found duplicate server with id " + server.getId()); + } + } + } + + List mirrors = settings.getMirrors(); + + if (mirrors != null) { + for (Mirror mirror : mirrors) { + validateStringNotEmpty(problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl()); + + validateBannedCharacters( + problems, + "mirrors.mirror.id", + BuilderProblem.Severity.WARNING, + mirror.getId(), + null, + ILLEGAL_REPO_ID_CHARS); + + if ("local".equals(mirror.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + "mirrors.mirror.id", + null, + "must not be 'local'" + + ", this identifier is reserved for the local repository" + + ", using it for other repositories will corrupt your repository metadata."); + } + + validateStringNotEmpty(problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId()); + + validateStringNotEmpty(problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId()); + } + } + + List profiles = settings.getProfiles(); + + if (profiles != null) { + Set profileIds = new HashSet<>(); + + for (Profile profile : profiles) { + if (!profileIds.add(profile.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + "profiles.profile.id", + null, + "must be unique but found duplicate profile with id " + profile.getId()); + } + + String prefix = "profiles.profile[" + profile.getId() + "]."; + + validateRepositories(problems, profile.getRepositories(), prefix + "repositories.repository"); + validateRepositories( + problems, profile.getPluginRepositories(), prefix + "pluginRepositories.pluginRepository"); + } + } + + List proxies = settings.getProxies(); + + if (proxies != null) { + Set proxyIds = new HashSet<>(); + + for (Proxy proxy : proxies) { + if (!proxyIds.add(proxy.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + "proxies.proxy.id", + null, + "must be unique but found duplicate proxy with id " + proxy.getId()); + } + validateStringNotEmpty(problems, "proxies.proxy.host", proxy.getHost(), proxy.getId()); + + try { + Integer.parseInt(proxy.getPortString()); + } catch (NumberFormatException e) { + addViolation( + problems, + BuilderProblem.Severity.ERROR, + "proxies.proxy[" + proxy.getId() + "].port", + null, + "must be a valid integer but found '" + proxy.getPortString() + "'"); + } + } + } + } + + private void validateRepositories(List problems, List repositories, String prefix) { + Set repoIds = new HashSet<>(); + + for (Repository repository : repositories) { + validateStringNotEmpty(problems, prefix + ".id", repository.getId(), repository.getUrl()); + + validateBannedCharacters( + problems, + prefix + ".id", + BuilderProblem.Severity.WARNING, + repository.getId(), + null, + ILLEGAL_REPO_ID_CHARS); + + if ("local".equals(repository.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + prefix + ".id", + null, + "must not be 'local'" + + ", this identifier is reserved for the local repository" + + ", using it for other repositories will corrupt your repository metadata."); + } + + if (!repoIds.add(repository.getId())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + prefix + ".id", + null, + "must be unique but found duplicate repository with id " + repository.getId()); + } + + validateStringNotEmpty(problems, prefix + ".url", repository.getUrl(), repository.getId()); + + if ("legacy".equals(repository.getLayout())) { + addViolation( + problems, + BuilderProblem.Severity.WARNING, + prefix + ".layout", + repository.getId(), + "uses the unsupported value 'legacy', artifact resolution might fail."); + } + } + } + + // ---------------------------------------------------------------------- + // Field validation + // ---------------------------------------------------------------------- + + /** + * Asserts: + *

+ *

    + *
  • string.length == null + *
  • string.length == 0 + *
+ */ + private static boolean validateStringEmpty( + List problems, String fieldName, String string, String message) { + if (string == null || string.length() == 0) { + return true; + } + + addViolation(problems, BuilderProblem.Severity.WARNING, fieldName, null, message); + + return false; + } + + /** + * Asserts: + *

+ *

    + *
  • string.length != null + *
  • string.length > 0 + *
+ */ + private static boolean validateStringNotEmpty( + List problems, String fieldName, String string, String sourceHint) { + if (!validateNotNull(problems, fieldName, string, sourceHint)) { + return false; + } + + if (!string.isEmpty()) { + return true; + } + + addViolation(problems, BuilderProblem.Severity.ERROR, fieldName, sourceHint, "is missing"); + + return false; + } + + /** + * Asserts: + *

+ *

    + *
  • string != null + *
+ */ + private static boolean validateNotNull( + List problems, String fieldName, Object object, String sourceHint) { + if (object != null) { + return true; + } + + addViolation(problems, BuilderProblem.Severity.ERROR, fieldName, sourceHint, "is missing"); + + return false; + } + + private static boolean validateBannedCharacters( + List problems, + String fieldName, + BuilderProblem.Severity severity, + String string, + String sourceHint, + String banned) { + if (string != null) { + for (int i = string.length() - 1; i >= 0; i--) { + if (banned.indexOf(string.charAt(i)) >= 0) { + addViolation( + problems, + severity, + fieldName, + sourceHint, + "must not contain any of these characters " + banned + " but found " + string.charAt(i)); + return false; + } + } + } + + return true; + } + + private static void addViolation( + List problems, + BuilderProblem.Severity severity, + String fieldName, + String sourceHint, + String message) { + StringBuilder buffer = new StringBuilder(256); + buffer.append('\'').append(fieldName).append('\''); + + if (sourceHint != null) { + buffer.append(" for ").append(sourceHint); + } + + buffer.append(' ').append(message); + + problems.add(new DefaultBuilderProblem(null, -1, -1, null, buffer.toString(), severity)); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java similarity index 87% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java index d5223a0fa0..cb58c4ad07 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java @@ -18,15 +18,14 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.xml.SettingsXmlFactory; import org.apache.maven.api.services.xml.XmlReaderException; import org.apache.maven.api.services.xml.XmlReaderRequest; @@ -37,7 +36,8 @@ import org.apache.maven.api.settings.Settings; import org.apache.maven.settings.v4.SettingsStaxReader; import org.apache.maven.settings.v4.SettingsStaxWriter; -import static org.apache.maven.internal.impl.Utils.nonNull; +import static org.apache.maven.internal.impl.StaxLocation.getLocation; +import static org.apache.maven.internal.impl.StaxLocation.getMessage; @Named @Singleton @@ -63,7 +63,7 @@ public class DefaultSettingsXmlFactory implements SettingsXmlFactory { return xml.read(inputStream, request.isStrict(), source); } } catch (Exception e) { - throw new XmlReaderException("Unable to read settings", e); + throw new XmlReaderException("Unable to read settings: " + getMessage(e), getLocation(e), e); } } @@ -83,7 +83,14 @@ public class DefaultSettingsXmlFactory implements SettingsXmlFactory { new SettingsStaxWriter().write(outputStream, content); } } catch (Exception e) { - throw new XmlWriterException("Unable to write settings", e); + throw new XmlWriterException("Unable to write settings: " + getMessage(e), getLocation(e), e); } } + + static T nonNull(T t, String name) { + if (t == null) { + throw new IllegalArgumentException(name + " cannot be null"); + } + return t; + } } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java new file mode 100644 index 0000000000..08b3f509e8 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java @@ -0,0 +1,218 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.maven.api.di.Named; +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.Source; +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.xml.ToolchainsXmlFactory; +import org.apache.maven.api.services.xml.XmlReaderException; +import org.apache.maven.api.services.xml.XmlReaderRequest; +import org.apache.maven.api.toolchain.PersistedToolchains; +import org.apache.maven.toolchain.v4.MavenToolchainsMerger; +import org.apache.maven.toolchain.v4.MavenToolchainsTransformer; +import org.codehaus.plexus.interpolation.EnvarBasedValueSource; +import org.codehaus.plexus.interpolation.InterpolationException; +import org.codehaus.plexus.interpolation.MapBasedValueSource; +import org.codehaus.plexus.interpolation.RegexBasedInterpolator; + +/** + * Builds the effective toolchains from a user toolchains file and/or a global toolchains file. + * + */ +@Named +public class DefaultToolchainsBuilder implements ToolchainsBuilder { + + private final MavenToolchainsMerger toolchainsMerger = new MavenToolchainsMerger(); + + @Override + public ToolchainsBuilderResult build(ToolchainsBuilderRequest request) throws ToolchainsBuilderException { + List problems = new ArrayList<>(); + + Source globalSource = request.getGlobalToolchainsSource().orElse(null); + PersistedToolchains global = readToolchains(globalSource, request, problems); + + Source userSource = request.getUserToolchainsSource().orElse(null); + PersistedToolchains user = readToolchains(userSource, request, problems); + + PersistedToolchains effective = toolchainsMerger.merge(user, global, false, null); + + if (hasErrors(problems)) { + throw new ToolchainsBuilderException("Error building toolchains", problems); + } + + return new DefaultToolchainsBuilderResult(effective, problems); + } + + private boolean hasErrors(List problems) { + if (problems != null) { + for (BuilderProblem problem : problems) { + if (BuilderProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) { + return true; + } + } + } + + return false; + } + + private PersistedToolchains readToolchains( + Source toolchainsSource, ToolchainsBuilderRequest request, List problems) { + if (toolchainsSource == null) { + return PersistedToolchains.newInstance(); + } + + PersistedToolchains toolchains; + + try { + try { + InputStream is = toolchainsSource.openStream(); + if (is == null) { + return PersistedToolchains.newInstance(); + } + toolchains = request.getSession() + .getService(ToolchainsXmlFactory.class) + .read(XmlReaderRequest.builder() + .inputStream(is) + .location(toolchainsSource.getLocation()) + .strict(true) + .build()); + } catch (XmlReaderException e) { + InputStream is = toolchainsSource.openStream(); + if (is == null) { + return PersistedToolchains.newInstance(); + } + toolchains = request.getSession() + .getService(ToolchainsXmlFactory.class) + .read(XmlReaderRequest.builder() + .inputStream(is) + .location(toolchainsSource.getLocation()) + .strict(false) + .build()); + Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null; + problems.add(new DefaultBuilderProblem( + toolchainsSource.getLocation(), + loc != null ? loc.getLineNumber() : -1, + loc != null ? loc.getColumnNumber() : -1, + e, + e.getMessage(), + BuilderProblem.Severity.WARNING)); + } + } catch (XmlReaderException e) { + Location loc = e.getCause() instanceof XMLStreamException xe ? xe.getLocation() : null; + problems.add(new DefaultBuilderProblem( + toolchainsSource.getLocation(), + loc != null ? loc.getLineNumber() : -1, + loc != null ? loc.getColumnNumber() : -1, + e, + "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(), + BuilderProblem.Severity.FATAL)); + return PersistedToolchains.newInstance(); + } catch (IOException e) { + problems.add(new DefaultBuilderProblem( + toolchainsSource.getLocation(), + -1, + -1, + e, + "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(), + BuilderProblem.Severity.FATAL)); + return PersistedToolchains.newInstance(); + } + + toolchains = interpolate(toolchains, request, problems); + + return toolchains; + } + + private PersistedToolchains interpolate( + PersistedToolchains toolchains, ToolchainsBuilderRequest request, List problems) { + + RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); + + interpolator.addValueSource(new MapBasedValueSource(request.getSession().getUserProperties())); + + interpolator.addValueSource(new MapBasedValueSource(request.getSession().getSystemProperties())); + + try { + interpolator.addValueSource(new EnvarBasedValueSource()); + } catch (IOException e) { + problems.add(new DefaultBuilderProblem( + null, + -1, + -1, + e, + "Failed to use environment variables for interpolation: " + e.getMessage(), + BuilderProblem.Severity.WARNING)); + } + + return new MavenToolchainsTransformer(value -> { + try { + return value != null ? interpolator.interpolate(value) : null; + } catch (InterpolationException e) { + problems.add(new DefaultBuilderProblem( + null, + -1, + -1, + e, + "Failed to interpolate toolchains: " + e.getMessage(), + BuilderProblem.Severity.WARNING)); + return value; + } + }) + .visit(toolchains); + } + + /** + * Collects the output of the toolchains builder. + * + */ + static class DefaultToolchainsBuilderResult implements ToolchainsBuilderResult { + + private final PersistedToolchains effectiveToolchains; + + private final List problems; + + DefaultToolchainsBuilderResult(PersistedToolchains effectiveToolchains, List problems) { + this.effectiveToolchains = effectiveToolchains; + this.problems = (problems != null) ? problems : new ArrayList<>(); + } + + @Override + public PersistedToolchains getEffectiveToolchains() { + return effectiveToolchains; + } + + @Override + public List getProblems() { + return problems; + } + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java similarity index 92% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java index 42baff9efb..85d626dd0d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java @@ -18,9 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; @@ -28,6 +25,8 @@ import java.io.Writer; import java.util.Objects; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.model.InputSource; import org.apache.maven.api.services.xml.ToolchainsXmlFactory; import org.apache.maven.api.services.xml.XmlReaderException; @@ -38,6 +37,8 @@ import org.apache.maven.api.toolchain.PersistedToolchains; import org.apache.maven.toolchain.v4.MavenToolchainsStaxReader; import org.apache.maven.toolchain.v4.MavenToolchainsStaxWriter; +import static org.apache.maven.internal.impl.StaxLocation.getLocation; +import static org.apache.maven.internal.impl.StaxLocation.getMessage; import static org.apache.maven.internal.impl.Utils.nonNull; @Named @@ -64,7 +65,7 @@ public class DefaultToolchainsXmlFactory implements ToolchainsXmlFactory { return xml.read(inputStream, request.isStrict()); } } catch (Exception e) { - throw new XmlReaderException("Unable to read toolchains", e); + throw new XmlReaderException("Unable to read toolchains: " + getMessage(e), getLocation(e), e); } } @@ -84,7 +85,7 @@ public class DefaultToolchainsXmlFactory implements ToolchainsXmlFactory { new MavenToolchainsStaxWriter().write(outputStream, content); } } catch (Exception e) { - throw new XmlWriterException("Unable to write toolchains", e); + throw new XmlWriterException("Unable to write toolchains: " + getMessage(e), getLocation(e), e); } } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java similarity index 98% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java index c8e692ce44..8e11ecae1c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java @@ -18,9 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Named; -import javax.inject.Singleton; - import java.io.IOException; import java.io.UncheckedIOException; import java.net.URI; @@ -29,6 +26,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.Transport; import org.eclipse.aether.spi.connector.transport.GetTask; import org.eclipse.aether.spi.connector.transport.PutTask; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java similarity index 95% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java index e3ba885c16..1ffab51882 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java @@ -18,15 +18,14 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import java.net.URI; import java.net.URISyntaxException; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.Transport; import org.apache.maven.api.services.TransportProvider; import org.apache.maven.api.services.TransportProviderException; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java similarity index 94% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java index cee860f787..7e8ae11cbc 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java @@ -18,13 +18,12 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import org.apache.maven.api.Version; import org.apache.maven.api.VersionConstraint; import org.apache.maven.api.VersionRange; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.VersionParser; import org.apache.maven.model.version.ModelVersionParser; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java similarity index 97% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java index a8ef08cfa9..41e107698e 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionRangeResolver.java @@ -18,10 +18,6 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import java.util.List; import java.util.Map; import java.util.Optional; @@ -29,6 +25,9 @@ import java.util.stream.Collectors; import org.apache.maven.api.Repository; import org.apache.maven.api.Version; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.VersionRangeResolver; import org.apache.maven.api.services.VersionRangeResolverException; import org.apache.maven.api.services.VersionRangeResolverRequest; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java similarity index 96% rename from maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java index 915d2480e0..b43e9bce9d 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultVersionResolver.java @@ -18,15 +18,14 @@ */ package org.apache.maven.internal.impl; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - import java.util.List; import java.util.Optional; import org.apache.maven.api.Repository; import org.apache.maven.api.Version; +import org.apache.maven.api.di.Inject; +import org.apache.maven.api.di.Named; +import org.apache.maven.api.di.Singleton; import org.apache.maven.api.services.VersionResolver; import org.apache.maven.api.services.VersionResolverException; import org.apache.maven.api.services.VersionResolverRequest; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/InternalSession.java similarity index 84% rename from maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/InternalSession.java index a41c087a62..0b5bf1874c 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/InternalSession.java @@ -27,11 +27,9 @@ import org.apache.maven.api.Dependency; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.LocalRepository; import org.apache.maven.api.Node; -import org.apache.maven.api.Project; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.execution.MavenSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; @@ -55,21 +53,12 @@ public interface InternalSession extends Session { @Nonnull Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency); - List getProjects(List projects); - - Project getProject(org.apache.maven.project.MavenProject project); - List toRepositories(List repositories); org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository); org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository); - List toArtifactRepositories( - List repositories); - - org.apache.maven.artifact.repository.ArtifactRepository toArtifactRepository(RemoteRepository repository); - List toDependencies( Collection dependencies, boolean managed); @@ -81,8 +70,6 @@ public interface InternalSession extends Session { org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinate coord); - MavenSession getMavenSession(); - RepositorySystemSession getSession(); RepositorySystem getRepositorySystem(); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/MappedCollection.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/MappedCollection.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/MappedCollection.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/MappedCollection.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/MappedList.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/MappedList.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/MappedList.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/MappedList.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/PathModularization.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularization.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/PathModularizationCache.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/SettingsUtilsV4.java similarity index 96% rename from maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/SettingsUtilsV4.java index 656219802d..83786692f6 100644 --- a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/SettingsUtilsV4.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.maven.settings; +package org.apache.maven.internal.impl; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -311,17 +311,6 @@ public final class SettingsUtilsV4 { return policy; } - /** - * @param settings could be null - * @return a new instance of settings or null if settings was null. - */ - public static org.apache.maven.settings.Settings copySettings(org.apache.maven.settings.Settings settings) { - if (settings == null) { - return null; - } - return new org.apache.maven.settings.Settings(settings.getDelegate()); - } - private static org.apache.maven.api.model.InputLocation toLocation( org.apache.maven.api.settings.InputLocation location) { if (location != null) { diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/StaxLocation.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/StaxLocation.java new file mode 100644 index 0000000000..2e0c19ad00 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/StaxLocation.java @@ -0,0 +1,76 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import javax.xml.stream.XMLStreamException; + +import org.apache.maven.api.services.xml.Location; + +public class StaxLocation implements Location { + + private final javax.xml.stream.Location location; + + public static Location getLocation(Exception e) { + return toLocation(e instanceof XMLStreamException xe ? xe.getLocation() : null); + } + + public static Location toLocation(javax.xml.stream.Location location) { + return location != null ? new StaxLocation(location) : null; + } + + public static String getMessage(Exception e) { + String message = e.getMessage(); + if (e instanceof XMLStreamException xe && xe.getLocation() != null) { + int idx = message.indexOf("\nMessage: "); + if (idx >= 0) { + return message.substring(idx + "\nMessage: ".length()); + } + } + return message; + } + + public StaxLocation(javax.xml.stream.Location location) { + this.location = location; + } + + @Override + public int getLineNumber() { + return location.getLineNumber(); + } + + @Override + public int getColumnNumber() { + return location.getColumnNumber(); + } + + @Override + public int getCharacterOffset() { + return location.getCharacterOffset(); + } + + @Override + public String getPublicId() { + return location.getPublicId(); + } + + @Override + public String getSystemId() { + return location.getSystemId(); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/Utils.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/Utils.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/Utils.java diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/WrapperNode.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/WrapperNode.java similarity index 100% rename from maven-core/src/main/java/org/apache/maven/internal/impl/WrapperNode.java rename to maven-api-impl/src/main/java/org/apache/maven/internal/impl/WrapperNode.java diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsBuilderFactoryTest.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsBuilderFactoryTest.java new file mode 100644 index 0000000000..db4ea2cc55 --- /dev/null +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsBuilderFactoryTest.java @@ -0,0 +1,80 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.maven.api.Session; +import org.apache.maven.api.services.SettingsBuilder; +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.services.xml.SettingsXmlFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + */ +@ExtendWith(MockitoExtension.class) +class DefaultSettingsBuilderFactoryTest { + + @Mock + Session session; + + @BeforeEach + void setup() { + Map map = System.getProperties().entrySet().stream() + .collect(Collectors.toMap( + e -> e.getKey().toString(), e -> e.getValue().toString())); + // lenient().when(session.getSystemProperties()).thenReturn(map); + // lenient().when(session.getUserProperties()).thenReturn(Collections.emptyMap()); + + Mockito.lenient() + .when(session.getService(SettingsXmlFactory.class)) + .thenReturn(new DefaultSettingsXmlFactory()); + } + + @Test + void testCompleteWiring() { + SettingsBuilder builder = new DefaultSettingsBuilder(); + assertNotNull(builder); + + SettingsBuilderRequest request = SettingsBuilderRequest.builder() + .session(session) + .userSettingsSource(Source.fromPath(getSettings("settings-simple"))) + .build(); + + SettingsBuilderResult result = builder.build(request); + assertNotNull(result); + assertNotNull(result.getEffectiveSettings()); + } + + private Path getSettings(String name) { + return Paths.get("src/test/resources/" + name + ".xml").toAbsolutePath(); + } +} diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsValidatorTest.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsValidatorTest.java new file mode 100644 index 0000000000..7efbe7e618 --- /dev/null +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/DefaultSettingsValidatorTest.java @@ -0,0 +1,234 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import java.util.List; + +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.SettingsBuilder; +import org.apache.maven.api.settings.Profile; +import org.apache.maven.api.settings.Repository; +import org.apache.maven.api.settings.Settings; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + */ +class DefaultSettingsValidatorTest { + + private SettingsBuilder validator; + + @BeforeEach + void setUp() throws Exception { + validator = new DefaultSettingsBuilder(); + } + + @AfterEach + void tearDown() throws Exception { + validator = null; + } + + private void assertContains(String msg, String substring) { + assertTrue(msg.contains(substring), "\"" + substring + "\" was not found in: " + msg); + } + + @Test + void testValidate() { + Profile prof = Profile.newBuilder().id("xxx").build(); + Settings model = Settings.newBuilder().profiles(List.of(prof)).build(); + List problems = validator.validate(model); + assertEquals(0, problems.size()); + + Repository repo = org.apache.maven.api.settings.Repository.newInstance(false); + Settings model2 = Settings.newBuilder() + .profiles(List.of(prof.withRepositories(List.of(repo)))) + .build(); + problems.clear(); + problems = validator.validate(model2); + assertEquals(2, problems.size()); + + repo = repo.withUrl("http://xxx.xxx.com"); + model2 = Settings.newBuilder() + .profiles(List.of(prof.withRepositories(List.of(repo)))) + .build(); + problems.clear(); + problems = validator.validate(model2); + assertEquals(1, problems.size()); + + repo = repo.withId("xxx"); + model2 = Settings.newBuilder() + .profiles(List.of(prof.withRepositories(List.of(repo)))) + .build(); + problems.clear(); + problems = validator.validate(model2); + assertEquals(0, problems.size()); + } + + /* + @Test + void testValidateMirror() throws Exception { + Settings settings = new Settings(); + Mirror mirror = new Mirror(); + mirror.setId("local"); + settings.addMirror(mirror); + mirror = new Mirror(); + mirror.setId("illegal\\:/chars"); + mirror.setUrl("http://void"); + mirror.setMirrorOf("void"); + settings.addMirror(mirror); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(4, problems.messages.size()); + assertContains(problems.messages.get(0), "'mirrors.mirror.id' must not be 'local'"); + assertContains(problems.messages.get(1), "'mirrors.mirror.url' for local is missing"); + assertContains(problems.messages.get(2), "'mirrors.mirror.mirrorOf' for local is missing"); + assertContains(problems.messages.get(3), "'mirrors.mirror.id' must not contain any of these characters"); + } + + @Test + void testValidateRepository() throws Exception { + Profile profile = new Profile(); + Repository repo = new Repository(); + repo.setId("local"); + profile.addRepository(repo); + repo = new Repository(); + repo.setId("illegal\\:/chars"); + repo.setUrl("http://void"); + profile.addRepository(repo); + Settings settings = new Settings(); + settings.addProfile(profile); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(3, problems.messages.size()); + assertContains( + problems.messages.get(0), "'profiles.profile[default].repositories.repository.id' must not be 'local'"); + assertContains( + problems.messages.get(1), + "'profiles.profile[default].repositories.repository.url' for local is missing"); + assertContains( + problems.messages.get(2), + "'profiles.profile[default].repositories.repository.id' must not contain any of these characters"); + } + + @Test + void testValidateUniqueServerId() throws Exception { + Settings settings = new Settings(); + Server server1 = new Server(); + server1.setId("test"); + settings.addServer(server1); + Server server2 = new Server(); + server2.setId("test"); + settings.addServer(server2); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(1, problems.messages.size()); + assertContains( + problems.messages.get(0), "'servers.server.id' must be unique but found duplicate server with id test"); + } + + @Test + void testValidateUniqueProfileId() throws Exception { + Settings settings = new Settings(); + Profile profile1 = new Profile(); + profile1.setId("test"); + settings.addProfile(profile1); + Profile profile2 = new Profile(); + profile2.setId("test"); + settings.addProfile(profile2); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(1, problems.messages.size()); + assertContains( + problems.messages.get(0), + "'profiles.profile.id' must be unique but found duplicate profile with id test"); + } + + @Test + void testValidateUniqueRepositoryId() throws Exception { + Settings settings = new Settings(); + Profile profile = new Profile(); + profile.setId("pro"); + settings.addProfile(profile); + Repository repo1 = new Repository(); + repo1.setUrl("http://apache.org/"); + repo1.setId("test"); + profile.addRepository(repo1); + Repository repo2 = new Repository(); + repo2.setUrl("http://apache.org/"); + repo2.setId("test"); + profile.addRepository(repo2); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(1, problems.messages.size()); + assertContains( + problems.messages.get(0), + "'profiles.profile[pro].repositories.repository.id' must be unique" + + " but found duplicate repository with id test"); + } + + @Test + void testValidateUniqueProxyId() throws Exception { + Settings settings = new Settings(); + Proxy proxy = new Proxy(); + String id = "foo"; + proxy.setId(id); + proxy.setHost("www.example.com"); + settings.addProxy(proxy); + settings.addProxy(proxy); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(1, problems.messages.size()); + assertContains( + problems.messages.get(0), + "'proxies.proxy.id' must be unique" + " but found duplicate proxy with id " + id); + } + + @Test + void testValidateProxy() throws Exception { + Settings settings = new Settings(); + Proxy proxy1 = new Proxy(); + settings.addProxy(proxy1); + + SimpleProblemCollector problems = new SimpleProblemCollector(); + validator.validate(settings, problems); + assertEquals(1, problems.messages.size()); + assertContains(problems.messages.get(0), "'proxies.proxy.host' for default is missing"); + } + + private static class SimpleProblemCollector implements SettingsProblemCollector { + + public List messages = new ArrayList<>(); + + public void add(Severity severity, String message, int line, int column, Exception cause) { + messages.add(message); + } + } + + */ +} diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java new file mode 100644 index 0000000000..e04efa6140 --- /dev/null +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/ApiRunner.java @@ -0,0 +1,336 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl.standalone; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.maven.api.Artifact; +import org.apache.maven.api.Project; +import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.Session; +import org.apache.maven.api.Version; +import org.apache.maven.api.di.Provides; +import org.apache.maven.api.services.ArtifactManager; +import org.apache.maven.api.services.Lookup; +import org.apache.maven.api.services.MavenException; +import org.apache.maven.api.services.RepositoryFactory; +import org.apache.maven.api.services.SettingsBuilder; +import org.apache.maven.api.settings.Settings; +import org.apache.maven.di.Injector; +import org.apache.maven.di.Key; +import org.apache.maven.di.impl.DIException; +import org.apache.maven.internal.impl.AbstractSession; +import org.apache.maven.internal.impl.DefaultArtifactCoordinateFactory; +import org.apache.maven.internal.impl.DefaultArtifactDeployer; +import org.apache.maven.internal.impl.DefaultArtifactFactory; +import org.apache.maven.internal.impl.DefaultArtifactInstaller; +import org.apache.maven.internal.impl.DefaultArtifactResolver; +import org.apache.maven.internal.impl.DefaultChecksumAlgorithmService; +import org.apache.maven.internal.impl.DefaultDependencyCollector; +import org.apache.maven.internal.impl.DefaultDependencyCoordinateFactory; +import org.apache.maven.internal.impl.DefaultLocalRepositoryManager; +import org.apache.maven.internal.impl.DefaultMessageBuilderFactory; +import org.apache.maven.internal.impl.DefaultModelXmlFactory; +import org.apache.maven.internal.impl.DefaultRepositoryFactory; +import org.apache.maven.internal.impl.DefaultSettingsBuilder; +import org.apache.maven.internal.impl.DefaultSettingsXmlFactory; +import org.apache.maven.internal.impl.DefaultToolchainsBuilder; +import org.apache.maven.internal.impl.DefaultToolchainsXmlFactory; +import org.apache.maven.internal.impl.DefaultTransportProvider; +import org.apache.maven.internal.impl.DefaultVersionParser; +import org.apache.maven.internal.impl.DefaultVersionRangeResolver; +import org.apache.maven.internal.impl.DefaultVersionResolver; +import org.apache.maven.model.path.DefaultPathTranslator; +import org.apache.maven.model.path.ProfileActivationFilePathInterpolator; +import org.apache.maven.model.profile.DefaultProfileSelector; +import org.apache.maven.model.profile.activation.FileProfileActivator; +import org.apache.maven.model.profile.activation.JdkVersionProfileActivator; +import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator; +import org.apache.maven.model.profile.activation.PropertyProfileActivator; +import org.apache.maven.model.root.DefaultRootLocator; +import org.apache.maven.repository.internal.DefaultModelVersionParser; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.supplier.RepositorySystemSupplier; +import org.eclipse.aether.util.version.GenericVersionScheme; + +public class ApiRunner { + + /** + * Create a new session. + */ + public static Session createSession() { + Injector injector = Injector.create(); + injector.bindInstance(Injector.class, injector); + injector.bindImplicit(ApiRunner.class); + injector.bindImplicit(DefaultArtifactCoordinateFactory.class); + injector.bindImplicit(DefaultArtifactDeployer.class); + injector.bindImplicit(DefaultArtifactFactory.class); + injector.bindImplicit(DefaultArtifactInstaller.class); + injector.bindImplicit(DefaultArtifactResolver.class); + injector.bindImplicit(DefaultChecksumAlgorithmService.class); + injector.bindImplicit(DefaultDependencyCollector.class); + injector.bindImplicit(DefaultDependencyCoordinateFactory.class); + injector.bindImplicit(DefaultLocalRepositoryManager.class); + injector.bindImplicit(DefaultMessageBuilderFactory.class); + injector.bindImplicit(DefaultModelXmlFactory.class); + injector.bindImplicit(DefaultRepositoryFactory.class); + injector.bindImplicit(DefaultSettingsBuilder.class); + injector.bindImplicit(DefaultSettingsXmlFactory.class); + injector.bindImplicit(DefaultToolchainsBuilder.class); + injector.bindImplicit(DefaultToolchainsXmlFactory.class); + injector.bindImplicit(DefaultTransportProvider.class); + injector.bindImplicit(DefaultVersionParser.class); + injector.bindImplicit(DefaultVersionRangeResolver.class); + injector.bindImplicit(DefaultVersionResolver.class); + + return injector.getInstance(Session.class); + } + + static class DefaultSession extends AbstractSession { + + DefaultSession(RepositorySystemSession session, RepositorySystem repositorySystem, Lookup lookup) { + this(session, repositorySystem, Collections.emptyList(), null, lookup); + } + + protected DefaultSession( + RepositorySystemSession session, + RepositorySystem repositorySystem, + List repositories, + List resolverRepositories, + Lookup lookup) { + super(session, repositorySystem, repositories, resolverRepositories, lookup); + } + + @Override + protected Session newSession(RepositorySystemSession session, List repositories) { + return new DefaultSession(session, repositorySystem, repositories, null, lookup); + } + + @Override + public Settings getSettings() { + return null; + } + + @Override + public Map getUserProperties() { + return null; + } + + @Override + public Map getSystemProperties() { + return null; + } + + @Override + public Map getEffectiveProperties(Project project) { + return null; + } + + @Override + public Version getMavenVersion() { + return null; + } + + @Override + public int getDegreeOfConcurrency() { + return 0; + } + + @Override + public Instant getStartTime() { + return null; + } + + @Override + public Path getTopDirectory() { + return null; + } + + @Override + public Path getRootDirectory() { + return null; + } + + @Override + public List getProjects() { + return List.of(); + } + + @Override + public Map getPluginContext(Project project) { + throw new UnsupportedInStandaloneModeException(); + } + } + + @Provides + static Lookup newLookup(Injector injector) { + return new Lookup() { + @Override + public T lookup(Class type) { + try { + return injector.getInstance(type); + } catch (DIException e) { + throw new MavenException("Unable to locate instance of type " + type, e); + } + } + + @Override + public T lookup(Class type, String name) { + try { + return injector.getInstance(Key.of(type, name)); + } catch (DIException e) { + throw new MavenException("Unable to locate instance of type " + type, e); + } + } + + @Override + public Optional lookupOptional(Class type) { + try { + return Optional.of(injector.getInstance(type)); + } catch (DIException e) { + return Optional.empty(); + } + } + + @Override + public Optional lookupOptional(Class type, String name) { + try { + return Optional.of(injector.getInstance(Key.of(type, name))); + } catch (DIException e) { + return Optional.empty(); + } + } + + @Override + public List lookupList(Class type) { + return injector.getInstance(new Key>() {}); + } + + @Override + public Map lookupMap(Class type) { + return injector.getInstance(new Key>() {}); + } + }; + } + + @Provides + static ArtifactManager newArtifactManager() { + return new ArtifactManager() { + private final Map paths = new ConcurrentHashMap<>(); + + @Override + public Optional getPath(Artifact artifact) { + return Optional.ofNullable(paths.get(artifact)); + } + + @Override + public void setPath(Artifact artifact, Path path) { + paths.put(artifact, path); + } + }; + } + + @Provides + static DefaultModelVersionParser newModelVersionParser() { + return new DefaultModelVersionParser(new GenericVersionScheme()); + } + + @Provides + static Session newSession(Lookup lookup) { + Map properties = new HashMap<>(); + // Env variables prefixed with "env." + System.getenv().forEach((k, v) -> properties.put("env." + k, v)); + // Java System properties + System.getProperties().forEach((k, v) -> properties.put(k.toString(), v.toString())); + + RepositorySystem system = new RepositorySystemSupplier().get(); + + // SettingsDecrypter settingsDecrypter = + // (SettingsDecrypter)Objects.requireNonNull(this.createSettingsDecrypter(preBoot)); + new DefaultProfileSelector(List.of( + new JdkVersionProfileActivator(), + new PropertyProfileActivator(), + new OperatingSystemProfileActivator(), + new FileProfileActivator(new ProfileActivationFilePathInterpolator( + new DefaultPathTranslator(), new DefaultRootLocator())))); + + Path userHome = Paths.get(properties.get("user.home")); + Path mavenUserHome = userHome.resolve(".m2"); + Path mavenSystemHome = properties.containsKey("maven.home") + ? Paths.get(properties.get("maven.home")) + : properties.containsKey("env.MAVEN_HOME") ? Paths.get(properties.get("env.MAVEN_HOME")) : null; + + DefaultRepositorySystemSession rsession = new DefaultRepositorySystemSession(h -> false); + rsession.setSystemProperties(properties); + rsession.setConfigProperties(properties); + + DefaultSession session = new DefaultSession( + rsession, + system, + List.of(lookup.lookup(RepositoryFactory.class) + .createRemote("central", "https://repo.maven.apache.org/maven2")), + null, + lookup); + + Settings settings = session.getService(SettingsBuilder.class) + .build( + session, + mavenSystemHome != null ? mavenSystemHome.resolve("settings.xml") : null, + mavenUserHome.resolve("settings.xml")) + .getEffectiveSettings(); + + settings.getProfiles(); + + // local repository + String localRepository = settings.getLocalRepository() != null + ? settings.getLocalRepository() + : mavenUserHome.resolve("repository").toString(); + LocalRepositoryManager llm = system.newLocalRepositoryManager(rsession, new LocalRepository(localRepository)); + rsession.setLocalRepositoryManager(llm); + // active proxies + // TODO + // active profiles + + DefaultSession defaultSession = new DefaultSession( + rsession, + system, + List.of(lookup.lookup(RepositoryFactory.class) + .createRemote("central", "https://repo.maven.apache.org/maven2")), + null, + lookup); + // settings.getDelegate().getRepositories().stream() + // .map(r -> SettingsUtilsV4.) + // defaultSession.getService(RepositoryFactory.class).createRemote() + return defaultSession; + } + + static class UnsupportedInStandaloneModeException extends MavenException {} +} diff --git a/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java new file mode 100644 index 0000000000..d56a3ecd6d --- /dev/null +++ b/maven-api-impl/src/test/java/org/apache/maven/internal/impl/standalone/TestApiStandalone.java @@ -0,0 +1,51 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl.standalone; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import org.apache.maven.api.Artifact; +import org.apache.maven.api.ArtifactCoordinate; +import org.apache.maven.api.Node; +import org.apache.maven.api.Session; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class TestApiStandalone { + + @Test + void testStandalone() { + Session session = ApiRunner.createSession(); + + ArtifactCoordinate coord = session.createArtifactCoordinate("org.apache.maven:maven-api-core:4.0.0-alpha-13"); + Map.Entry res = session.resolveArtifact(coord); + assertNotNull(res); + assertNotNull(res.getValue()); + assertTrue(Files.exists(res.getValue())); + + Node node = session.collectDependencies(session.createDependencyCoordinate(coord)); + assertNotNull(node); + assertEquals(8, node.getChildren().size()); + } +} diff --git a/maven-api-impl/src/test/resources/settings-simple.xml b/maven-api-impl/src/test/resources/settings-simple.xml new file mode 100644 index 0000000000..ea664bacdf --- /dev/null +++ b/maven-api-impl/src/test/resources/settings-simple.xml @@ -0,0 +1,24 @@ + + + + + + ${user.home}/.m2/repository + diff --git a/maven-core/pom.xml b/maven-core/pom.xml index 75e62a68d2..86f84af70c 100644 --- a/maven-core/pom.xml +++ b/maven-core/pom.xml @@ -87,6 +87,10 @@ under the License. org.apache.maven maven-api-spi + + org.apache.maven + maven-api-impl + org.apache.maven.resolver maven-resolver-api diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java index c44a039342..eb5904a9b7 100644 --- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java +++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java @@ -60,7 +60,7 @@ import org.apache.maven.execution.ProjectDependencyGraph; import org.apache.maven.graph.GraphBuilder; import org.apache.maven.graph.ProjectSelector; import org.apache.maven.internal.impl.DefaultSessionFactory; -import org.apache.maven.internal.impl.InternalSession; +import org.apache.maven.internal.impl.InternalMavenSession; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.lifecycle.internal.ExecutionEventCatapult; import org.apache.maven.lifecycle.internal.LifecycleStarter; @@ -218,7 +218,7 @@ public class DefaultMaven implements Maven { sessionScope.seed(MavenSession.class, session); sessionScope.seed(Session.class, session.getSession()); - sessionScope.seed(InternalSession.class, InternalSession.from(session.getSession())); + sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(session.getSession())); legacySupport.setSession(session); diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java index ac6c1eddbc..a10b03bde1 100644 --- a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java +++ b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java @@ -32,6 +32,7 @@ import java.util.stream.Collectors; import org.apache.maven.api.Session; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.RepositoryCache; +import org.apache.maven.internal.impl.SettingsUtilsV4; import org.apache.maven.model.Profile; import org.apache.maven.monitor.event.EventDispatcher; import org.apache.maven.plugin.descriptor.PluginDescriptor; @@ -41,7 +42,6 @@ import org.apache.maven.settings.Mirror; import org.apache.maven.settings.Proxy; import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; -import org.apache.maven.settings.SettingsUtilsV4; import org.codehaus.plexus.PlexusContainer; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.eclipse.aether.RepositorySystemSession; diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java index 1ac100076d..3835e81250 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java @@ -44,12 +44,12 @@ import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultArtifactManager implements ArtifactManager { @Nonnull - private final InternalSession session; + private final InternalMavenSession session; private final Map paths = new ConcurrentHashMap<>(); @Inject - public DefaultArtifactManager(@Nonnull InternalSession session) { + public DefaultArtifactManager(@Nonnull InternalMavenSession session) { this.session = session; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java index 86ec498dfb..2f4cf648c8 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java @@ -28,10 +28,10 @@ import org.apache.maven.api.Session; import org.apache.maven.execution.ExecutionEvent; public class DefaultEvent implements Event { - private final InternalSession session; + private final InternalMavenSession session; private final ExecutionEvent delegate; - public DefaultEvent(InternalSession session, ExecutionEvent delegate) { + public DefaultEvent(InternalMavenSession session, ExecutionEvent delegate) { this.session = session; this.delegate = delegate; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java index 406f45ea32..4e49e48693 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java @@ -41,10 +41,10 @@ import org.codehaus.plexus.util.xml.Xpp3Dom; import org.eclipse.aether.graph.DependencyNode; public class DefaultMojoExecution implements MojoExecution { - private final InternalSession session; + private final InternalMavenSession session; private final org.apache.maven.plugin.MojoExecution delegate; - public DefaultMojoExecution(InternalSession session, org.apache.maven.plugin.MojoExecution delegate) { + public DefaultMojoExecution(InternalMavenSession session, org.apache.maven.plugin.MojoExecution delegate) { this.session = session; this.delegate = delegate; } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPluginXmlFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPluginXmlFactory.java index dc919b9d2a..71c59cc3a1 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPluginXmlFactory.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPluginXmlFactory.java @@ -35,6 +35,8 @@ import org.apache.maven.api.services.xml.*; import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxReader; import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxWriter; +import static org.apache.maven.internal.impl.StaxLocation.getLocation; +import static org.apache.maven.internal.impl.StaxLocation.getMessage; import static org.apache.maven.internal.impl.Utils.nonNull; @Named @@ -67,7 +69,7 @@ public class DefaultPluginXmlFactory implements PluginXmlFactory { } } } catch (Exception e) { - throw new XmlReaderException("Unable to read model", e); + throw new XmlReaderException("Unable to read plugin: " + getMessage(e), getLocation(e), e); } } @@ -92,7 +94,7 @@ public class DefaultPluginXmlFactory implements PluginXmlFactory { } } } catch (Exception e) { - throw new XmlWriterException("Unable to write model", e); + throw new XmlWriterException("Unable to write plugin: " + getMessage(e), getLocation(e), e); } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java index 35162d8471..103d5a8b86 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java @@ -35,17 +35,17 @@ import static org.apache.maven.internal.impl.Utils.nonNull; public class DefaultProject implements Project { - private final InternalSession session; + private final InternalMavenSession session; private final MavenProject project; private final Packaging packaging; - public DefaultProject(InternalSession session, MavenProject project) { + public DefaultProject(InternalMavenSession session, MavenProject project) { this.session = session; this.project = project; this.packaging = session.requirePackaging(project.getPackaging()); } - public InternalSession getSession() { + public InternalMavenSession getSession() { return session; } 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 356dbc63e2..d785dad9f8 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 @@ -65,7 +65,7 @@ public class DefaultProjectBuilder implements ProjectBuilder { @Override public ProjectBuilderResult build(ProjectBuilderRequest request) throws ProjectBuilderException, IllegalArgumentException { - InternalSession session = InternalSession.from(request.getSession()); + InternalMavenSession session = InternalMavenSession.from(request.getSession()); try { List repositories = session.toArtifactRepositories(session.getRemoteRepositories()); ProjectBuildingRequest req = new DefaultProjectBuildingRequest() diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java index 892e7f1e33..79b1fbceea 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java @@ -44,11 +44,11 @@ import static org.apache.maven.internal.impl.Utils.nonNull; @SessionScoped public class DefaultProjectManager implements ProjectManager { - private final InternalSession session; + private final InternalMavenSession session; private final ArtifactManager artifactManager; @Inject - public DefaultProjectManager(InternalSession session, ArtifactManager artifactManager) { + public DefaultProjectManager(InternalMavenSession session, ArtifactManager artifactManager) { this.session = session; this.artifactManager = artifactManager; } @@ -66,7 +66,7 @@ public class DefaultProjectManager implements ProjectManager { @Nonnull @Override public Collection getAttachedArtifacts(Project project) { - InternalSession session = ((DefaultProject) project).getSession(); + InternalMavenSession session = ((DefaultProject) project).getSession(); Collection attached = map( getMavenProject(project).getAttachedArtifacts(), a -> session.getArtifact(RepositoryUtils.toArtifact(a))); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java index 598ddbe6c4..f2a71b2352 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java @@ -21,8 +21,6 @@ package org.apache.maven.internal.impl; import java.nio.file.Path; import java.time.Instant; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import org.apache.maven.RepositoryUtils; import org.apache.maven.api.*; @@ -38,43 +36,39 @@ import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; +import org.apache.maven.project.MavenProject; import org.apache.maven.rtinfo.RuntimeInformation; -import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import static org.apache.maven.internal.impl.Utils.map; import static org.apache.maven.internal.impl.Utils.nonNull; -public class DefaultSession extends AbstractSession { +public class DefaultSession extends AbstractSession implements InternalMavenSession { private final MavenSession mavenSession; - private final RepositorySystemSession session; - private final RepositorySystem repositorySystem; - private final List repositories; private final MavenRepositorySystem mavenRepositorySystem; - private final Lookup lookup; private final RuntimeInformation runtimeInformation; - private final Map, Service> services = new ConcurrentHashMap<>(); + private final Map allProjects = Collections.synchronizedMap(new WeakHashMap<>()); @SuppressWarnings("checkstyle:ParameterNumber") public DefaultSession( @Nonnull MavenSession session, @Nonnull RepositorySystem repositorySystem, - @Nullable List repositories, + @Nullable List remoteRepositories, @Nonnull MavenRepositorySystem mavenRepositorySystem, @Nonnull Lookup lookup, @Nonnull RuntimeInformation runtimeInformation) { + super( + session.getRepositorySession(), + repositorySystem, + remoteRepositories, + remoteRepositories == null + ? map(session.getRequest().getRemoteRepositories(), RepositoryUtils::toRepo) + : null, + lookup); this.mavenSession = nonNull(session); - this.session = mavenSession.getRepositorySession(); - this.repositorySystem = nonNull(repositorySystem); - this.repositories = repositories != null - ? repositories - : map( - mavenSession.getRequest().getRemoteRepositories(), - r -> getRemoteRepository(RepositoryUtils.toRepo(r))); this.mavenRepositorySystem = mavenRepositorySystem; - this.lookup = lookup; this.runtimeInformation = runtimeInformation; } @@ -82,16 +76,19 @@ public class DefaultSession extends AbstractSession { return mavenSession; } - @Nonnull @Override - public LocalRepository getLocalRepository() { - return new DefaultLocalRepository(session.getLocalRepository()); + public List getProjects(List projects) { + return projects == null ? null : map(projects, this::getProject); } - @Nonnull @Override - public List getRemoteRepositories() { - return Collections.unmodifiableList(repositories); + public Project getProject(MavenProject project) { + return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project)); + } + + @Override + public List toArtifactRepositories(List repositories) { + return repositories == null ? null : map(repositories, this::toArtifactRepository); } @Nonnull @@ -171,92 +168,13 @@ public class DefaultSession extends AbstractSession { } } - @Nonnull - @Override - public SessionData getData() { - org.eclipse.aether.SessionData data = session.getData(); - return new SessionData() { - @Override - public void set(@Nonnull Key key, @Nullable T value) { - data.set(key, value); - } - - @Override - public boolean replace(@Nonnull Key key, @Nullable T oldValue, @Nullable T newValue) { - return data.set(key, oldValue, newValue); - } - - @Nullable - @Override - @SuppressWarnings("unchecked") - public T get(@Nonnull Key key) { - return (T) data.get(key); - } - - @Nullable - @Override - @SuppressWarnings("unchecked") - public T computeIfAbsent(@Nonnull Key key, @Nonnull Supplier supplier) { - return (T) data.computeIfAbsent(key, (Supplier) supplier); - } - }; - } - - @Nonnull - @Override - public Session withLocalRepository(@Nonnull LocalRepository localRepository) { - nonNull(localRepository, "localRepository"); - if (session.getLocalRepository() != null - && Objects.equals(session.getLocalRepository().getBasedir().toPath(), localRepository.getPath())) { - return this; + protected Session newSession(RepositorySystemSession repoSession, List repositories) { + MavenSession ms = this.mavenSession; + if (repoSession != this.getSession()) { + ms = new MavenSession(repoSession, ms.getRequest(), ms.getResult()); } - org.eclipse.aether.repository.LocalRepository repository = toRepository(localRepository); - org.eclipse.aether.repository.LocalRepositoryManager localRepositoryManager = - repositorySystem.newLocalRepositoryManager(session, repository); - - RepositorySystemSession repoSession = - new DefaultRepositorySystemSession(session).setLocalRepositoryManager(localRepositoryManager); - MavenSession newSession = new MavenSession(repoSession, mavenSession.getRequest(), mavenSession.getResult()); return new DefaultSession( - newSession, repositorySystem, repositories, mavenRepositorySystem, lookup, runtimeInformation); - } - - @Nonnull - @Override - public Session withRemoteRepositories(@Nonnull List repositories) { - return new DefaultSession( - mavenSession, repositorySystem, repositories, mavenRepositorySystem, lookup, runtimeInformation); - } - - @Nonnull - @Override - @SuppressWarnings("unchecked") - public T getService(Class clazz) throws NoSuchElementException { - T t = (T) services.computeIfAbsent(clazz, this::lookup); - if (t == null) { - throw new NoSuchElementException(clazz.getName()); - } - return t; - } - - private Service lookup(Class c) { - try { - return lookup.lookup(c); - } catch (LookupException e) { - NoSuchElementException nsee = new NoSuchElementException(c.getName()); - e.initCause(e); - throw nsee; - } - } - - @Nonnull - public RepositorySystemSession getSession() { - return session; - } - - @Nonnull - public RepositorySystem getRepositorySystem() { - return repositorySystem; + ms, getRepositorySystem(), repositories, mavenRepositorySystem, lookup, runtimeInformation); } public ArtifactRepository toArtifactRepository(RemoteRepository repository) { @@ -281,25 +199,4 @@ public class DefaultSession extends AbstractSession { throw new UnsupportedOperationException("Not yet implemented"); } } - - public org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency, boolean managed) { - org.eclipse.aether.graph.Dependency dep; - if (dependency instanceof DefaultDependencyCoordinate) { - dep = ((DefaultDependencyCoordinate) dependency).getDependency(); - } else { - dep = new org.eclipse.aether.graph.Dependency( - new org.eclipse.aether.artifact.DefaultArtifact( - dependency.getGroupId(), - dependency.getArtifactId(), - dependency.getClassifier(), - dependency.getType().getExtension(), - dependency.getVersion().toString(), - null), - dependency.getScope().id()); - } - if (!managed && "".equals(dep.getScope())) { - dep = dep.setScope(DependencyScope.COMPILE.id()); - } - return dep; - } } diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java index db81236abd..87e20a34d3 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java @@ -53,7 +53,7 @@ public class DefaultSessionFactory { public Session getSession(MavenSession mavenSession) { SessionData data = mavenSession.getRepositorySession().getData(); - return (Session) data.computeIfAbsent(InternalSession.class, () -> newSession(mavenSession)); + return (Session) data.computeIfAbsent(InternalMavenSession.class, () -> newSession(mavenSession)); } private Session newSession(MavenSession mavenSession) { 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 deleted file mode 100644 index 39d1961885..0000000000 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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. - */ -package org.apache.maven.internal.impl; - -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 { - InternalSession session = InternalSession.from(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 getProblems() { - return new MappedList<>(result.getProblems(), MappedBuilderProblem::new); - } - }; - } catch (SettingsBuildingException e) { - throw new SettingsBuilderException("Unable to build settings", e); - } - } - - private Properties toProperties(Map 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.openStream(); - } - - @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/DefaultToolchainManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java index b22f813299..ea353e0bcb 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java @@ -49,7 +49,7 @@ public class DefaultToolchainManager implements ToolchainManager { @Override public List getToolchains(Session session, String type, Map requirements) throws ToolchainManagerException { - MavenSession s = InternalSession.from(session).getMavenSession(); + MavenSession s = InternalMavenSession.from(session).getMavenSession(); List toolchains = toolchainManagerPrivate.getToolchains(s, type, requirements); return new MappedList<>(toolchains, this::toToolchain); @@ -58,7 +58,7 @@ public class DefaultToolchainManager implements ToolchainManager { @Override public Optional getToolchainFromBuildContext(Session session, String type) throws ToolchainManagerException { - MavenSession s = InternalSession.from(session).getMavenSession(); + MavenSession s = InternalMavenSession.from(session).getMavenSession(); return Optional.ofNullable(toolchainManagerPrivate.getToolchainFromBuildContext(type, s)) .map(this::toToolchain); } @@ -66,7 +66,7 @@ public class DefaultToolchainManager implements ToolchainManager { @Override public List getToolchainsForType(Session session, String type) throws ToolchainManagerException { try { - MavenSession s = InternalSession.from(session).getMavenSession(); + MavenSession s = InternalMavenSession.from(session).getMavenSession(); ToolchainPrivate[] toolchains = toolchainManagerPrivate.getToolchainsForType(type, s); return new MappedList<>(Arrays.asList(toolchains), this::toToolchain); } catch (MisconfiguredToolchainException e) { @@ -76,7 +76,7 @@ public class DefaultToolchainManager implements ToolchainManager { @Override public void storeToolchainToBuildContext(Session session, Toolchain toolchain) throws ToolchainManagerException { - MavenSession s = InternalSession.from(session).getMavenSession(); + MavenSession s = InternalMavenSession.from(session).getMavenSession(); org.apache.maven.toolchain.ToolchainPrivate tc = (org.apache.maven.toolchain.ToolchainPrivate) ((ToolchainWrapper) toolchain).toolchain; toolchainManagerPrivate.storeToolchainToBuildContext(tc, s); 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 deleted file mode 100644 index cff334d788..0000000000 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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. - */ -package org.apache.maven.internal.impl; - -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 org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.services.BuilderProblem; -import org.apache.maven.api.services.Source; -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.toolchain.PersistedToolchains; -import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest; -import org.apache.maven.toolchain.building.ToolchainsBuildingException; -import org.apache.maven.toolchain.building.ToolchainsBuildingResult; - -@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 { - 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 getProblems() { - return new MappedList<>(result.getProblems(), MappedBuilderProblem::new); - } - }; - } catch (ToolchainsBuildingException e) { - throw new ToolchainsBuilderException("Unable to build Toolchains", e); - } - } - - 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.openStream(); - } - - @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/main/java/org/apache/maven/internal/impl/EventSpyImpl.java b/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java index 6d1dd78ce5..ebb86e8368 100644 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java @@ -47,7 +47,7 @@ public class EventSpyImpl implements EventSpy { public void onEvent(Object arg) throws Exception { if (arg instanceof ExecutionEvent) { ExecutionEvent ee = (ExecutionEvent) arg; - InternalSession session = InternalSession.from(sessionFactory.getSession(ee.getSession())); + InternalMavenSession session = InternalMavenSession.from(sessionFactory.getSession(ee.getSession())); Collection listeners = session.getListeners(); if (!listeners.isEmpty()) { Event event = new DefaultEvent(session, ee); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java new file mode 100644 index 0000000000..1ee399c6c0 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalMavenSession.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import java.util.List; + +import org.apache.maven.api.Project; +import org.apache.maven.api.RemoteRepository; +import org.apache.maven.api.Session; +import org.apache.maven.execution.MavenSession; + +import static org.apache.maven.internal.impl.Utils.cast; + +public interface InternalMavenSession extends InternalSession { + + static InternalMavenSession from(Session session) { + return cast(InternalMavenSession.class, session, "session should be an " + InternalMavenSession.class); + } + + List getProjects(List projects); + + Project getProject(org.apache.maven.project.MavenProject project); + + List toArtifactRepositories( + List repositories); + + org.apache.maven.artifact.repository.ArtifactRepository toArtifactRepository(RemoteRepository repository); + + MavenSession getMavenSession(); +} diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java b/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java new file mode 100644 index 0000000000..fd35c4c3f7 --- /dev/null +++ b/maven-core/src/main/java/org/apache/maven/internal/impl/SisuDiBridgeModule.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.maven.internal.impl; + +import javax.inject.Named; +import javax.inject.Provider; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + +import com.google.inject.AbstractModule; +import org.apache.maven.di.Injector; +import org.apache.maven.di.Key; +import org.apache.maven.di.impl.Binding; +import org.apache.maven.di.impl.InjectorImpl; +import org.codehaus.plexus.PlexusContainer; + +@Named +class SisuDiBridgeModule extends AbstractModule { + + @Override + protected void configure() { + Provider containerProvider = getProvider(PlexusContainer.class); + + Injector injector = new InjectorImpl() { + @Override + protected Set> getBindings(Key key) { + Set> bindings = super.getBindings(key); + if (bindings == null && key.getRawType() != List.class && key.getRawType() != Map.class) { + try { + T t = containerProvider.get().lookup(key.getRawType()); + bindings = Set.of(new Binding.BindingToInstance<>(t)); + } catch (Throwable e) { + // ignore + e.printStackTrace(); + } + } + return bindings; + } + }; + injector.bindInstance(Injector.class, injector); + bind(Injector.class).toInstance(injector); + + Stream.of( + DefaultArtifactCoordinateFactory.class, + DefaultArtifactDeployer.class, + DefaultArtifactFactory.class, + DefaultArtifactInstaller.class, + DefaultArtifactResolver.class, + DefaultChecksumAlgorithmService.class, + DefaultDependencyCollector.class, + DefaultDependencyCoordinateFactory.class, + DefaultLocalRepositoryManager.class, + DefaultMessageBuilderFactory.class, + DefaultModelXmlFactory.class, + DefaultRepositoryFactory.class, + DefaultSettingsBuilder.class, + DefaultSettingsXmlFactory.class, + DefaultToolchainsBuilder.class, + DefaultToolchainsXmlFactory.class, + DefaultTransportProvider.class, + DefaultVersionParser.class, + DefaultVersionRangeResolver.class, + DefaultVersionResolver.class) + .forEach((Class clazz) -> { + injector.bindImplicit(clazz); + Class itf = (Class) clazz.getInterfaces()[0]; + bind(itf).toProvider(() -> injector.getInstance(clazz)); + }); + } +} diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java index 3c812348bc..84774deebc 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java @@ -34,7 +34,7 @@ import org.apache.maven.execution.MojoExecutionListener; import org.apache.maven.execution.scope.internal.MojoExecutionScope; import org.apache.maven.internal.impl.DefaultLog; import org.apache.maven.internal.impl.DefaultMojoExecution; -import org.apache.maven.internal.impl.InternalSession; +import org.apache.maven.internal.impl.InternalMavenSession; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.descriptor.MojoDescriptor; import org.apache.maven.plugin.descriptor.PluginDescriptor; @@ -121,7 +121,7 @@ public class DefaultBuildPluginManager implements BuildPluginManager { org.apache.maven.api.plugin.Log.class, new DefaultLog(LoggerFactory.getLogger( mojoExecution.getMojoDescriptor().getFullGoalName()))); - InternalSession sessionV4 = InternalSession.from(session.getSession()); + InternalMavenSession sessionV4 = InternalMavenSession.from(session.getSession()); scope.seed(Project.class, sessionV4.getProject(project)); scope.seed(org.apache.maven.api.MojoExecution.class, new DefaultMojoExecution(sessionV4, mojoExecution)); diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java index a10a356c23..ec476eb8f8 100644 --- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java +++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java @@ -44,7 +44,7 @@ import org.apache.maven.execution.scope.internal.MojoExecutionScope; import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule; import org.apache.maven.internal.impl.DefaultLog; import org.apache.maven.internal.impl.DefaultMojoExecution; -import org.apache.maven.internal.impl.InternalSession; +import org.apache.maven.internal.impl.InternalMavenSession; import org.apache.maven.internal.xml.XmlPlexusConfiguration; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.ContextEnabled; @@ -522,12 +522,12 @@ public class DefaultMavenPluginManager implements MavenPluginManager { throws PluginContainerException, PluginConfigurationException { T mojo; - InternalSession sessionV4 = InternalSession.from(session.getSession()); + InternalMavenSession sessionV4 = InternalMavenSession.from(session.getSession()); Project project = sessionV4.getProject(session.getCurrentProject()); List repos = sessionV4.getService(ProjectManager.class).getRemoteProjectRepositories(project); - sessionV4 = InternalSession.from(sessionV4.withRemoteRepositories(repos)); + sessionV4 = InternalMavenSession.from(sessionV4.withRemoteRepositories(repos)); org.apache.maven.api.MojoExecution execution = new DefaultMojoExecution(sessionV4, mojoExecution); org.apache.maven.api.plugin.Log log = new DefaultLog( @@ -665,7 +665,7 @@ public class DefaultMavenPluginManager implements MavenPluginManager { pomConfiguration = XmlPlexusConfiguration.toPlexusConfiguration(dom); } - InternalSession sessionV4 = InternalSession.from(session.getSession()); + InternalMavenSession sessionV4 = InternalMavenSession.from(session.getSession()); ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution); for (MavenPluginConfigurationValidator validator : configurationValidators) { diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java index 1c94df3da4..be2d16a94f 100644 --- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java @@ -38,7 +38,7 @@ import org.apache.maven.artifact.InvalidArtifactRTException; import org.apache.maven.artifact.InvalidRepositoryException; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.bridge.MavenRepositorySystem; -import org.apache.maven.internal.impl.InternalSession; +import org.apache.maven.internal.impl.InternalMavenSession; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.DependencyManagement; @@ -909,7 +909,8 @@ public class DefaultProjectBuilder implements ProjectBuilder { modelBuildingRequest.setModelCache(modelCacheFactory.createCache(session)); } modelBuildingRequest.setTransformerContextBuilder(transformerContextBuilder); - InternalSession session = (InternalSession) this.session.getData().get(InternalSession.class); + InternalMavenSession session = + (InternalMavenSession) this.session.getData().get(InternalMavenSession.class); if (session != null) { try { modelBuildingRequest.setRootDirectory(session.getRootDirectory()); diff --git a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java index cd84aa832e..8ac42aa6e2 100644 --- a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java +++ b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java @@ -32,7 +32,7 @@ import java.util.zip.ZipEntry; import com.ctc.wstx.stax.WstxInputFactory; import org.apache.maven.api.xml.XmlNode; -import org.apache.maven.internal.xml.XmlNodeBuilder; +import org.apache.maven.internal.xml.XmlNodeStaxBuilder; /** * Creates an extension descriptor from some XML stream. @@ -89,7 +89,7 @@ public class ExtensionDescriptorBuilder { XmlNode dom; try { XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(is); - dom = XmlNodeBuilder.build(reader); + dom = XmlNodeStaxBuilder.build(reader); } catch (XMLStreamException e) { throw new IOException(e.getMessage(), e); } diff --git a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java index f873344399..a9e812df57 100644 --- a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java +++ b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java @@ -25,7 +25,7 @@ import com.google.inject.AbstractModule; import org.apache.maven.SessionScoped; import org.apache.maven.api.Session; import org.apache.maven.execution.MavenSession; -import org.apache.maven.internal.impl.InternalSession; +import org.apache.maven.internal.impl.InternalMavenSession; /** * SessionScopeModule @@ -55,8 +55,8 @@ public class SessionScopeModule extends AbstractModule { bind(Session.class) .toProvider(SessionScope.seededKeyProvider(Session.class)) .in(scope); - bind(InternalSession.class) - .toProvider(SessionScope.seededKeyProvider(InternalSession.class)) + bind(InternalMavenSession.class) + .toProvider(SessionScope.seededKeyProvider(InternalMavenSession.class)) .in(scope); } } diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java index 03f22c8ae6..c6e2ea8b98 100644 --- a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java +++ b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java @@ -18,6 +18,8 @@ */ package org.apache.maven.settings; +import org.apache.maven.internal.impl.SettingsUtilsV4; + /** * Several convenience methods to handle settings * diff --git a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java index 165473fef0..aa09b32608 100644 --- a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java +++ b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java @@ -26,7 +26,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import org.apache.maven.configuration.internal.DefaultBeanConfigurator; -import org.apache.maven.internal.xml.XmlNodeBuilder; +import org.apache.maven.internal.xml.XmlNodeStaxBuilder; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -52,9 +52,9 @@ class DefaultBeanConfiguratorPathTest { private Xpp3Dom toConfig(String xml) { try { - return new Xpp3Dom(XmlNodeBuilder.build( + return new Xpp3Dom(XmlNodeStaxBuilder.build( new StringReader("" + xml + ""), - (XmlNodeBuilder.InputLocationBuilderStax) null)); + (XmlNodeStaxBuilder.InputLocationBuilderStax) null)); } catch (XMLStreamException e) { throw new IllegalArgumentException(e); } diff --git a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java index ea9b8a8197..94ac507793 100644 --- a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java +++ b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java @@ -24,7 +24,7 @@ import java.io.File; import java.io.StringReader; import org.apache.maven.configuration.internal.DefaultBeanConfigurator; -import org.apache.maven.internal.xml.XmlNodeBuilder; +import org.apache.maven.internal.xml.XmlNodeStaxBuilder; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -50,9 +50,9 @@ class DefaultBeanConfiguratorTest { private Xpp3Dom toConfig(String xml) { try { - return new Xpp3Dom(XmlNodeBuilder.build( + return new Xpp3Dom(XmlNodeStaxBuilder.build( new StringReader("" + xml + ""), - (XmlNodeBuilder.InputLocationBuilderStax) null)); + (XmlNodeStaxBuilder.InputLocationBuilderStax) null)); } catch (XMLStreamException e) { throw new IllegalArgumentException(e); } 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 e4b74c9c57..441c89e699 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 @@ -125,7 +125,7 @@ class TestApi { .withRemoteRepositories(Collections.singletonList(remoteRepository)); sessionScope.enter(); - sessionScope.seed(InternalSession.class, InternalSession.from(this.session)); + sessionScope.seed(InternalMavenSession.class, InternalMavenSession.from(this.session)); } private Project project(Artifact artifact) { diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java index d90d9052e6..d1d62161e1 100644 --- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java +++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java @@ -413,7 +413,8 @@ public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenC pd.addComponentDescriptor(md); - return new DefaultMojoExecution((AbstractSession) session, new org.apache.maven.plugin.MojoExecution(md)); + return new DefaultMojoExecution( + InternalMavenSession.from(session), new org.apache.maven.plugin.MojoExecution(md)); } private DefaultSession newSession() throws Exception { diff --git a/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java b/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java index 4e378eec04..8c65f68ce5 100644 --- a/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java +++ b/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java @@ -32,6 +32,7 @@ import org.apache.maven.api.settings.ActivationProperty; import org.apache.maven.api.settings.Profile; import org.apache.maven.api.settings.Repository; import org.apache.maven.api.settings.Settings; +import org.apache.maven.internal.impl.SettingsUtilsV4; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/maven-di/src/main/java/org/apache/maven/di/impl/Binding.java b/maven-di/src/main/java/org/apache/maven/di/impl/Binding.java index 1f74a6721a..1e18932cfe 100644 --- a/maven-di/src/main/java/org/apache/maven/di/impl/Binding.java +++ b/maven-di/src/main/java/org/apache/maven/di/impl/Binding.java @@ -143,7 +143,7 @@ public abstract class Binding { public static class BindingToInstance extends Binding { final T instance; - BindingToInstance(T instance) { + public BindingToInstance(T instance) { super(null, Collections.emptySet()); this.instance = instance; } diff --git a/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java b/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java index a2ad2ca6f1..6230c3dc51 100644 --- a/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java +++ b/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java @@ -130,7 +130,7 @@ public class InjectorImpl implements Injector { } @SuppressWarnings({"unchecked", "rawtypes"}) - private Set> getBindings(Key key) { + protected Set> getBindings(Key key) { return (Set) bindings.get(key); } diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java index 89d31b7df4..0787dec8d2 100644 --- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java +++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java @@ -32,7 +32,7 @@ import java.util.Optional; import com.ctc.wstx.stax.WstxInputFactory; import org.apache.maven.api.xml.XmlNode; -import org.apache.maven.internal.xml.XmlNodeBuilder; +import org.apache.maven.internal.xml.XmlNodeStaxBuilder; import org.apache.maven.internal.xml.XmlPlexusConfiguration; import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxReader; import org.codehaus.plexus.component.repository.ComponentDependency; @@ -142,7 +142,7 @@ public class PluginDescriptorBuilder { new PluginDescriptorStaxReader().read(xsr, true); return new PluginDescriptor(pd); } else { - XmlNode node = XmlNodeBuilder.build(xsr, true, null); + XmlNode node = XmlNodeStaxBuilder.build(xsr, true, null); PlexusConfiguration cfg = XmlPlexusConfiguration.toPlexusConfiguration(node); return build(source, cfg); } @@ -474,7 +474,7 @@ public class PluginDescriptorBuilder { public PlexusConfiguration buildConfiguration(Reader configuration) throws PlexusConfigurationException { try { XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration); - return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeBuilder.build(reader, true, null)); + return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeStaxBuilder.build(reader, true, null)); } catch (XMLStreamException e) { throw new PlexusConfigurationException(e.getMessage(), e); } @@ -483,7 +483,7 @@ public class PluginDescriptorBuilder { public PlexusConfiguration buildConfiguration(InputStream configuration) throws PlexusConfigurationException { try { XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration); - return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeBuilder.build(reader, true, null)); + return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeStaxBuilder.build(reader, true, null)); } catch (XMLStreamException e) { throw new PlexusConfigurationException(e.getMessage(), e); } diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml index a8eda9612b..ec37752a28 100644 --- a/maven-settings-builder/pom.xml +++ b/maven-settings-builder/pom.xml @@ -38,6 +38,10 @@ under the License. + + org.apache.maven + maven-api-impl + org.apache.maven maven-builder-support @@ -79,6 +83,11 @@ under the License. org.apache.maven.settings.validation.SettingsValidator#validate(org.apache.maven.settings.Settings,boolean,org.apache.maven.settings.building.SettingsProblemCollector):METHOD_NEW_DEFAULT + org.apache.maven.settings.building.DefaultSettingsBuilder#setSettingsReader(org.apache.maven.settings.io.SettingsReader):METHOD_REMOVED + org.apache.maven.settings.building.DefaultSettingsBuilder#setSettingsValidator(org.apache.maven.settings.validation.SettingsValidator):METHOD_REMOVED + org.apache.maven.settings.building.DefaultSettingsBuilder#setSettingsWriter(org.apache.maven.settings.io.SettingsWriter):METHOD_REMOVED + org.apache.maven.settings.building.DefaultSettingsBuilder#DefaultSettingsBuilder(org.apache.maven.settings.io.SettingsReader,org.apache.maven.settings.io.SettingsWriter,org.apache.maven.settings.validation.SettingsValidator):CONSTRUCTOR_REMOVED + org.apache.maven.settings.validation.DefaultSettingsValidator#DefaultSettingsValidator():CONSTRUCTOR_REMOVED diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java index 23d5ba3d7c..6027acd211 100644 --- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java +++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java @@ -24,29 +24,21 @@ import javax.inject.Singleton; import java.io.File; import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.List; -import java.util.Map; +import java.util.stream.Collectors; -import org.apache.maven.api.settings.InputSource; +import org.apache.maven.api.Session; +import org.apache.maven.api.services.BuilderProblem; +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.xml.SettingsXmlFactory; import org.apache.maven.building.FileSource; import org.apache.maven.building.Source; -import org.apache.maven.settings.Repository; -import org.apache.maven.settings.RepositoryPolicy; -import org.apache.maven.settings.Server; import org.apache.maven.settings.Settings; -import org.apache.maven.settings.TrackableBase; -import org.apache.maven.settings.io.SettingsParseException; -import org.apache.maven.settings.io.SettingsReader; -import org.apache.maven.settings.io.SettingsWriter; -import org.apache.maven.settings.merge.MavenSettingsMerger; -import org.apache.maven.settings.v4.SettingsTransformer; -import org.apache.maven.settings.validation.SettingsValidator; -import org.codehaus.plexus.interpolation.EnvarBasedValueSource; -import org.codehaus.plexus.interpolation.InterpolationException; -import org.codehaus.plexus.interpolation.PropertiesBasedValueSource; -import org.codehaus.plexus.interpolation.RegexBasedInterpolator; /** * Builds the effective settings from a user settings file and/or a global settings file. @@ -56,215 +48,99 @@ import org.codehaus.plexus.interpolation.RegexBasedInterpolator; @Singleton public class DefaultSettingsBuilder implements SettingsBuilder { - private SettingsReader settingsReader; - - private SettingsWriter settingsWriter; - - private SettingsValidator settingsValidator; - - private final MavenSettingsMerger settingsMerger = new MavenSettingsMerger(); + private final org.apache.maven.internal.impl.DefaultSettingsBuilder builder; + private final org.apache.maven.internal.impl.DefaultSettingsXmlFactory settingsXmlFactory; @Inject public DefaultSettingsBuilder( - SettingsReader settingsReader, SettingsWriter settingsWriter, SettingsValidator settingsValidator) { - this.settingsReader = settingsReader; - this.settingsWriter = settingsWriter; - this.settingsValidator = settingsValidator; - } - - public DefaultSettingsBuilder setSettingsReader(SettingsReader settingsReader) { - this.settingsReader = settingsReader; - return this; - } - - public DefaultSettingsBuilder setSettingsWriter(SettingsWriter settingsWriter) { - this.settingsWriter = settingsWriter; - return this; - } - - public DefaultSettingsBuilder setSettingsValidator(SettingsValidator settingsValidator) { - this.settingsValidator = settingsValidator; - return this; + org.apache.maven.internal.impl.DefaultSettingsBuilder builder, + org.apache.maven.internal.impl.DefaultSettingsXmlFactory settingsXmlFactory) { + this.builder = builder; + this.settingsXmlFactory = settingsXmlFactory; } @Override public SettingsBuildingResult build(SettingsBuildingRequest request) throws SettingsBuildingException { - DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector(null); - Source globalSettingsSource = - getSettingsSource(request.getGlobalSettingsFile(), request.getGlobalSettingsSource()); - Settings globalSettings = readSettings(globalSettingsSource, false, request, problems); + try { + SettingsBuilderResult result = builder.build(SettingsBuilderRequest.builder() + .session((Session) java.lang.reflect.Proxy.newProxyInstance( + Session.class.getClassLoader(), + new Class[] {Session.class}, + (Object proxy, Method method, Object[] args) -> { + if ("getSystemProperties".equals(method.getName())) { + return request.getSystemProperties().entrySet().stream() + .collect(Collectors.toMap( + e -> e.getKey().toString(), + e -> e.getValue().toString())); + } else if ("getUserProperties".equals(method.getName())) { + return request.getUserProperties().entrySet().stream() + .collect(Collectors.toMap( + e -> e.getKey().toString(), + e -> e.getValue().toString())); + } else if ("getService".equals(method.getName())) { + if (args[0] == SettingsXmlFactory.class) { + return settingsXmlFactory; + } + } + return null; + })) + .globalSettingsSource(toSource(request.getGlobalSettingsFile(), request.getGlobalSettingsSource())) + .projectSettingsSource( + toSource(request.getProjectSettingsFile(), request.getProjectSettingsSource())) + .userSettingsSource(toSource(request.getUserSettingsFile(), request.getUserSettingsSource())) + .build()); - Source projectSettingsSource = - getSettingsSource(request.getProjectSettingsFile(), request.getProjectSettingsSource()); - Settings projectSettings = readSettings(projectSettingsSource, true, request, problems); - - Source userSettingsSource = getSettingsSource(request.getUserSettingsFile(), request.getUserSettingsSource()); - Settings userSettings = readSettings(userSettingsSource, false, request, problems); - - settingsMerger.merge(projectSettings, globalSettings, TrackableBase.GLOBAL_LEVEL); - settingsMerger.merge(userSettings, projectSettings, TrackableBase.PROJECT_LEVEL); - - // If no repository is defined in the user/global settings, - // it means that we have "old" settings (as those are new in 4.0) - // so add central to the computed settings for backward compatibility. - if (userSettings.getRepositories().isEmpty() - && userSettings.getPluginRepositories().isEmpty()) { - Repository central = new Repository(); - central.setId("central"); - central.setName("Central Repository"); - central.setUrl("https://repo.maven.apache.org/maven2"); - RepositoryPolicy disabledPolicy = new RepositoryPolicy(); - disabledPolicy.setEnabled(false); - central.setSnapshots(disabledPolicy); - userSettings.getRepositories().add(central); - central = central.clone(); - RepositoryPolicy updateNeverPolicy = new RepositoryPolicy(); - disabledPolicy.setUpdatePolicy("never"); - central.setReleases(updateNeverPolicy); - userSettings.getPluginRepositories().add(central); + return new DefaultSettingsBuildingResult( + new Settings(result.getEffectiveSettings()), convert(result.getProblems())); + } catch (SettingsBuilderException e) { + throw new SettingsBuildingException(convert(e.getProblems())); } - - problems.setSource(""); - - // for the special case of a drive-relative Windows path, make sure it's absolute to save plugins from trouble - String localRepository = userSettings.getLocalRepository(); - if (localRepository != null && !localRepository.isEmpty()) { - File file = new File(localRepository); - if (!file.isAbsolute() && file.getPath().startsWith(File.separator)) { - userSettings.setLocalRepository(file.getAbsolutePath()); - } - } - - if (hasErrors(problems.getProblems())) { - throw new SettingsBuildingException(problems.getProblems()); - } - - return new DefaultSettingsBuildingResult(userSettings, problems.getProblems()); } - private boolean hasErrors(List problems) { - if (problems != null) { - for (SettingsProblem problem : problems) { - if (SettingsProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) { - return true; + private org.apache.maven.api.services.Source toSource(File file, Source source) { + if (file != null && file.exists()) { + return org.apache.maven.api.services.Source.fromPath(file.toPath()); + } else if (source instanceof FileSource fs) { + return org.apache.maven.api.services.Source.fromPath(fs.getPath()); + } else if (source != null) { + return new org.apache.maven.api.services.Source() { + @Override + public Path getPath() { + return null; } - } - } - return false; + @Override + public InputStream openStream() throws IOException { + return source.getInputStream(); + } + + @Override + public String getLocation() { + return source.getLocation(); + } + + @Override + public org.apache.maven.api.services.Source resolve(String relative) { + return null; + } + }; + } else { + return null; + } } - private Source getSettingsSource(File settingsFile, Source settingsSource) { - if (settingsSource != null) { - return settingsSource; - } else if (settingsFile != null && settingsFile.exists()) { - return new FileSource(settingsFile); - } - return null; + private List convert(List problems) { + return problems.stream().map(this::convert).toList(); } - private Settings readSettings( - Source settingsSource, - boolean isProjectSettings, - SettingsBuildingRequest request, - DefaultSettingsProblemCollector problems) { - if (settingsSource == null) { - return new Settings(); - } - - problems.setSource(settingsSource.getLocation()); - - Settings settings; - - try { - Map options = new HashMap<>(); - options.put(SettingsReader.IS_STRICT, Boolean.TRUE); - options.put(InputSource.class.getName(), new InputSource(settingsSource.getLocation())); - try { - settings = settingsReader.read(settingsSource.getInputStream(), options); - } catch (SettingsParseException e) { - options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE); - - settings = settingsReader.read(settingsSource.getInputStream(), options); - - problems.add( - SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e); - } - } catch (SettingsParseException e) { - problems.add( - SettingsProblem.Severity.FATAL, - "Non-parseable settings " + settingsSource.getLocation() + ": " + e.getMessage(), - e.getLineNumber(), - e.getColumnNumber(), - e); - return new Settings(); - } catch (IOException e) { - problems.add( - SettingsProblem.Severity.FATAL, - "Non-readable settings " + settingsSource.getLocation() + ": " + e.getMessage(), - -1, - -1, - e); - return new Settings(); - } - - settings = interpolate(settings, request, problems); - - settingsValidator.validate(settings, isProjectSettings, problems); - - if (isProjectSettings) { - settings.setLocalRepository(null); - settings.setInteractiveMode(true); - settings.setOffline(false); - settings.setProxies(Collections.emptyList()); - settings.setUsePluginRegistry(false); - for (Server server : settings.getServers()) { - server.setUsername(null); - server.setPassword(null); - server.setPrivateKey(null); - server.setPassword(null); - server.setFilePermissions(null); - server.setDirectoryPermissions(null); - } - } - - return settings; - } - - private Settings interpolate( - Settings settings, SettingsBuildingRequest request, SettingsProblemCollector problems) { - - RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); - - interpolator.addValueSource(new PropertiesBasedValueSource(request.getUserProperties())); - - interpolator.addValueSource(new PropertiesBasedValueSource(request.getSystemProperties())); - - try { - interpolator.addValueSource(new EnvarBasedValueSource()); - } catch (IOException e) { - problems.add( - SettingsProblem.Severity.WARNING, - "Failed to use environment variables for interpolation: " + e.getMessage(), - -1, - -1, - e); - } - - return new Settings(new SettingsTransformer(value -> { - try { - return value != null ? interpolator.interpolate(value) : null; - } catch (InterpolationException e) { - problems.add( - SettingsProblem.Severity.WARNING, - "Failed to interpolate settings: " + e.getMessage(), - -1, - -1, - e); - return value; - } - }) - .visit(settings.getDelegate())); + private SettingsProblem convert(BuilderProblem problem) { + return new DefaultSettingsProblem( + problem.getMessage(), + SettingsProblem.Severity.valueOf(problem.getSeverity().name()), + problem.getSource(), + problem.getLineNumber(), + problem.getColumnNumber(), + problem.getException()); } } diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java index c94cd903f8..455521a1dc 100644 --- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java +++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java @@ -43,7 +43,7 @@ public class DefaultSettingsBuilderFactory { } protected SettingsValidator newSettingsValidator() { - return new DefaultSettingsValidator(); + return new DefaultSettingsValidator(new org.apache.maven.internal.impl.DefaultSettingsBuilder()); } /** @@ -52,6 +52,8 @@ public class DefaultSettingsBuilderFactory { * @return The new settings builder instance, never {@code null}. */ public DefaultSettingsBuilder newInstance() { - return new DefaultSettingsBuilder(newSettingsReader(), newSettingsWriter(), newSettingsValidator()); + return new DefaultSettingsBuilder( + new org.apache.maven.internal.impl.DefaultSettingsBuilder(), + new org.apache.maven.internal.impl.DefaultSettingsXmlFactory()); } } diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java index 1894c840b8..ccbd0e42b2 100644 --- a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java +++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java @@ -18,19 +18,15 @@ */ package org.apache.maven.settings.validation; +import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.regex.Pattern; -import org.apache.maven.settings.Mirror; -import org.apache.maven.settings.Profile; -import org.apache.maven.settings.Proxy; -import org.apache.maven.settings.Repository; -import org.apache.maven.settings.Server; +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.SettingsBuilder; import org.apache.maven.settings.Settings; import org.apache.maven.settings.building.SettingsProblem.Severity; import org.apache.maven.settings.building.SettingsProblemCollector; @@ -44,7 +40,12 @@ public class DefaultSettingsValidator implements SettingsValidator { private static final String ID = "[\\w.-]+"; private static final Pattern ID_REGEX = Pattern.compile(ID); - private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS + private final SettingsBuilder settingsBuilder; + + @Inject + public DefaultSettingsValidator(SettingsBuilder settingsBuilder) { + this.settingsBuilder = settingsBuilder; + } @Override public void validate(Settings settings, SettingsProblemCollector problems) { @@ -53,201 +54,9 @@ public class DefaultSettingsValidator implements SettingsValidator { @Override public void validate(Settings settings, boolean isProjectSettings, SettingsProblemCollector problems) { - if (isProjectSettings) { - String msgS = "is not supported on project settings."; - String msgP = "are not supported on project settings."; - if (settings.getLocalRepository() != null - && !settings.getLocalRepository().isEmpty()) { - addViolation(problems, Severity.WARNING, "localRepository", null, msgS); - } - if (settings.getInteractiveMode() != null && !settings.getInteractiveMode()) { - addViolation(problems, Severity.WARNING, "interactiveMode", null, msgS); - } - if (settings.isOffline()) { - addViolation(problems, Severity.WARNING, "offline", null, msgS); - } - if (!settings.getProxies().isEmpty()) { - addViolation(problems, Severity.WARNING, "proxies", null, msgP); - } - if (settings.isUsePluginRegistry()) { - addViolation(problems, Severity.WARNING, "usePluginRegistry", null, msgS); - } - List servers = settings.getServers(); - for (int i = 0; i < servers.size(); i++) { - Server server = servers.get(i); - String serverField = "servers.server[" + i + "]"; - validateStringEmpty(problems, serverField + ".username", server.getUsername(), msgS); - validateStringEmpty(problems, serverField + ".password", server.getPassword(), msgS); - validateStringEmpty(problems, serverField + ".privateKey", server.getPrivateKey(), msgS); - validateStringEmpty(problems, serverField + ".passphrase", server.getPassphrase(), msgS); - validateStringEmpty(problems, serverField + ".filePermissions", server.getFilePermissions(), msgS); - validateStringEmpty( - problems, serverField + ".directoryPermissions", server.getDirectoryPermissions(), msgS); - } - } - - if (settings.isUsePluginRegistry()) { - addViolation(problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect."); - } - - List pluginGroups = settings.getPluginGroups(); - - if (pluginGroups != null) { - for (int i = 0; i < pluginGroups.size(); i++) { - String pluginGroup = pluginGroups.get(i); - - validateStringNotEmpty(problems, "pluginGroups.pluginGroup[" + i + "]", pluginGroup, null); - - if (!ID_REGEX.matcher(pluginGroup).matches()) { - addViolation( - problems, - Severity.ERROR, - "pluginGroups.pluginGroup[" + i + "]", - null, - "must denote a valid group id and match the pattern " + ID); - } - } - } - - List servers = settings.getServers(); - - if (servers != null) { - Set serverIds = new HashSet<>(); - - for (int i = 0; i < servers.size(); i++) { - Server server = servers.get(i); - - validateStringNotEmpty(problems, "servers.server[" + i + "].id", server.getId(), null); - - if (!serverIds.add(server.getId())) { - addViolation( - problems, - Severity.WARNING, - "servers.server.id", - null, - "must be unique but found duplicate server with id " + server.getId()); - } - } - } - - List mirrors = settings.getMirrors(); - - if (mirrors != null) { - for (Mirror mirror : mirrors) { - validateStringNotEmpty(problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl()); - - validateBannedCharacters( - problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null, ILLEGAL_REPO_ID_CHARS); - - if ("local".equals(mirror.getId())) { - addViolation( - problems, - Severity.WARNING, - "mirrors.mirror.id", - null, - "must not be 'local'" - + ", this identifier is reserved for the local repository" - + ", using it for other repositories will corrupt your repository metadata."); - } - - validateStringNotEmpty(problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId()); - - validateStringNotEmpty(problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId()); - } - } - - List profiles = settings.getProfiles(); - - if (profiles != null) { - Set profileIds = new HashSet<>(); - - for (Profile profile : profiles) { - if (!profileIds.add(profile.getId())) { - addViolation( - problems, - Severity.WARNING, - "profiles.profile.id", - null, - "must be unique but found duplicate profile with id " + profile.getId()); - } - - String prefix = "profiles.profile[" + profile.getId() + "]."; - - validateRepositories(problems, profile.getRepositories(), prefix + "repositories.repository"); - validateRepositories( - problems, profile.getPluginRepositories(), prefix + "pluginRepositories.pluginRepository"); - } - } - - List proxies = settings.getProxies(); - - if (proxies != null) { - Set proxyIds = new HashSet<>(); - - for (Proxy proxy : proxies) { - if (!proxyIds.add(proxy.getId())) { - addViolation( - problems, - Severity.WARNING, - "proxies.proxy.id", - null, - "must be unique but found duplicate proxy with id " + proxy.getId()); - } - validateStringNotEmpty(problems, "proxies.proxy.host", proxy.getHost(), proxy.getId()); - - try { - Integer.parseInt(proxy.getPortString()); - } catch (NumberFormatException e) { - addViolation( - problems, - Severity.ERROR, - "proxies.proxy[" + proxy.getId() + "].port", - null, - "must be a valid integer but found '" + proxy.getPortString() + "'"); - } - } - } - } - - private void validateRepositories(SettingsProblemCollector problems, List repositories, String prefix) { - Set repoIds = new HashSet<>(); - - for (Repository repository : repositories) { - validateStringNotEmpty(problems, prefix + ".id", repository.getId(), repository.getUrl()); - - validateBannedCharacters( - problems, prefix + ".id", Severity.WARNING, repository.getId(), null, ILLEGAL_REPO_ID_CHARS); - - if ("local".equals(repository.getId())) { - addViolation( - problems, - Severity.WARNING, - prefix + ".id", - null, - "must not be 'local'" - + ", this identifier is reserved for the local repository" - + ", using it for other repositories will corrupt your repository metadata."); - } - - if (!repoIds.add(repository.getId())) { - addViolation( - problems, - Severity.WARNING, - prefix + ".id", - null, - "must be unique but found duplicate repository with id " + repository.getId()); - } - - validateStringNotEmpty(problems, prefix + ".url", repository.getUrl(), repository.getId()); - - if ("legacy".equals(repository.getLayout())) { - addViolation( - problems, - Severity.WARNING, - prefix + ".layout", - repository.getId(), - "uses the unsupported value 'legacy', artifact resolution might fail."); - } + List list = settingsBuilder.validate(settings.getDelegate(), isProjectSettings); + for (BuilderProblem problem : list) { + addViolation(problems, Severity.valueOf(problem.getSeverity().name()), problem.getMessage()); } } @@ -255,101 +64,7 @@ public class DefaultSettingsValidator implements SettingsValidator { // Field validation // ---------------------------------------------------------------------- - /** - * Asserts: - *

- *

    - *
  • string.length == null - *
  • string.length == 0 - *
- */ - private static boolean validateStringEmpty( - SettingsProblemCollector problems, String fieldName, String string, String message) { - if (string == null || string.length() == 0) { - return true; - } - - addViolation(problems, Severity.WARNING, fieldName, null, message); - - return false; - } - - /** - * Asserts: - *

- *

    - *
  • string.length != null - *
  • string.length > 0 - *
- */ - private static boolean validateStringNotEmpty( - SettingsProblemCollector problems, String fieldName, String string, String sourceHint) { - if (!validateNotNull(problems, fieldName, string, sourceHint)) { - return false; - } - - if (!string.isEmpty()) { - return true; - } - - addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing"); - - return false; - } - - /** - * Asserts: - *

- *

    - *
  • string != null - *
- */ - private static boolean validateNotNull( - SettingsProblemCollector problems, String fieldName, Object object, String sourceHint) { - if (object != null) { - return true; - } - - addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing"); - - return false; - } - - private static boolean validateBannedCharacters( - SettingsProblemCollector problems, - String fieldName, - Severity severity, - String string, - String sourceHint, - String banned) { - if (string != null) { - for (int i = string.length() - 1; i >= 0; i--) { - if (banned.indexOf(string.charAt(i)) >= 0) { - addViolation( - problems, - severity, - fieldName, - sourceHint, - "must not contain any of these characters " + banned + " but found " + string.charAt(i)); - return false; - } - } - } - - return true; - } - - private static void addViolation( - SettingsProblemCollector problems, Severity severity, String fieldName, String sourceHint, String message) { - StringBuilder buffer = new StringBuilder(256); - buffer.append('\'').append(fieldName).append('\''); - - if (sourceHint != null) { - buffer.append(" for ").append(sourceHint); - } - - buffer.append(' ').append(message); - - problems.add(severity, buffer.toString(), -1, -1, null); + private static void addViolation(SettingsProblemCollector problems, Severity severity, String message) { + problems.add(severity, message, -1, -1, null); } } diff --git a/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java b/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java index c92b4afecb..69cb2ca8e9 100644 --- a/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java +++ b/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java @@ -21,6 +21,7 @@ package org.apache.maven.settings.validation; import java.util.ArrayList; import java.util.List; +import org.apache.maven.internal.impl.DefaultSettingsBuilder; import org.apache.maven.settings.Mirror; import org.apache.maven.settings.Profile; import org.apache.maven.settings.Proxy; @@ -44,7 +45,7 @@ class DefaultSettingsValidatorTest { @BeforeEach void setUp() throws Exception { - validator = new DefaultSettingsValidator(); + validator = new DefaultSettingsValidator(new DefaultSettingsBuilder()); } @AfterEach diff --git a/maven-toolchain-builder/pom.xml b/maven-toolchain-builder/pom.xml index e50f32b31d..6554336035 100644 --- a/maven-toolchain-builder/pom.xml +++ b/maven-toolchain-builder/pom.xml @@ -31,6 +31,10 @@ under the License. The effective toolchain builder. + + org.apache.maven + maven-api-impl + org.apache.maven maven-toolchain-model @@ -53,6 +57,11 @@ under the License. mockito-core test + + org.mockito + mockito-junit-jupiter + test + diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java index ebd8303b81..44a6044c97 100644 --- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java +++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java @@ -23,25 +23,27 @@ import javax.inject.Named; import javax.inject.Singleton; import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.Collections; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; +import org.apache.maven.api.Session; +import org.apache.maven.api.services.BuilderProblem; +import org.apache.maven.api.services.Source; +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.xml.ToolchainsXmlFactory; +import org.apache.maven.building.FileSource; import org.apache.maven.building.Problem; import org.apache.maven.building.ProblemCollector; import org.apache.maven.building.ProblemCollectorFactory; -import org.apache.maven.building.Source; -import org.apache.maven.toolchain.io.ToolchainsParseException; -import org.apache.maven.toolchain.io.ToolchainsReader; -import org.apache.maven.toolchain.io.ToolchainsWriter; -import org.apache.maven.toolchain.merge.MavenToolchainMerger; import org.apache.maven.toolchain.model.PersistedToolchains; -import org.apache.maven.toolchain.model.TrackableBase; -import org.codehaus.plexus.interpolation.EnvarBasedValueSource; -import org.codehaus.plexus.interpolation.InterpolationException; -import org.codehaus.plexus.interpolation.RegexBasedInterpolator; +import org.codehaus.plexus.interpolation.os.OperatingSystemUtils; /** * @@ -50,143 +52,88 @@ import org.codehaus.plexus.interpolation.RegexBasedInterpolator; @Named @Singleton public class DefaultToolchainsBuilder implements ToolchainsBuilder { - private final MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger(); - private final ToolchainsWriter toolchainsWriter; - private final ToolchainsReader toolchainsReader; + private final org.apache.maven.api.services.ToolchainsBuilder builder; + private final ToolchainsXmlFactory toolchainsXmlFactory; @Inject - public DefaultToolchainsBuilder(ToolchainsWriter toolchainsWriter, ToolchainsReader toolchainsReader) { - this.toolchainsWriter = toolchainsWriter; - this.toolchainsReader = toolchainsReader; + public DefaultToolchainsBuilder( + org.apache.maven.api.services.ToolchainsBuilder builder, ToolchainsXmlFactory toolchainsXmlFactory) { + this.builder = builder; + this.toolchainsXmlFactory = toolchainsXmlFactory; } @Override public ToolchainsBuildingResult build(ToolchainsBuildingRequest request) throws ToolchainsBuildingException { - ProblemCollector problems = ProblemCollectorFactory.newInstance(null); + try { + ToolchainsBuilderResult result = builder.build(ToolchainsBuilderRequest.builder() + .session((Session) java.lang.reflect.Proxy.newProxyInstance( + Session.class.getClassLoader(), + new Class[] {Session.class}, + (Object proxy, Method method, Object[] args) -> { + if ("getSystemProperties".equals(method.getName())) { + Map properties = new HashMap<>(); + Properties env = OperatingSystemUtils.getSystemEnvVars(); + env.stringPropertyNames() + .forEach(k -> properties.put("env." + k, env.getProperty(k))); + return properties; + } else if ("getUserProperties".equals(method.getName())) { + return Map.of(); + } else if ("getService".equals(method.getName())) { + if (args[0] == ToolchainsXmlFactory.class) { + return toolchainsXmlFactory; + } + } + return null; + })) + .globalToolchainsSource(convert(request.getGlobalToolchainsSource())) + .userToolchainsSource(convert(request.getUserToolchainsSource())) + .build()); - PersistedToolchains globalToolchains = readToolchains(request.getGlobalToolchainsSource(), request, problems); - - PersistedToolchains userToolchains = readToolchains(request.getUserToolchainsSource(), request, problems); - - toolchainsMerger.merge(userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL); - - problems.setSource(""); - - userToolchains = interpolate(userToolchains, problems); - - if (hasErrors(problems.getProblems())) { - throw new ToolchainsBuildingException(problems.getProblems()); + return new DefaultToolchainsBuildingResult( + new PersistedToolchains(result.getEffectiveToolchains()), convert(result.getProblems())); + } catch (ToolchainsBuilderException e) { + throw new ToolchainsBuildingException(convert(e.getProblems())); } - - return new DefaultToolchainsBuildingResult(userToolchains, problems.getProblems()); } - private PersistedToolchains interpolate(PersistedToolchains toolchains, ProblemCollector problems) { - - StringWriter stringWriter = new StringWriter(1024 * 4); - try { - toolchainsWriter.write(stringWriter, null, toolchains); - } catch (IOException e) { - throw new IllegalStateException("Failed to serialize toolchains to memory", e); - } - - String serializedToolchains = stringWriter.toString(); - - RegexBasedInterpolator interpolator = new RegexBasedInterpolator(); - - try { - interpolator.addValueSource(new EnvarBasedValueSource()); - } catch (IOException e) { - problems.add( - Problem.Severity.WARNING, - "Failed to use environment variables for interpolation: " + e.getMessage(), - -1, - -1, - e); - } - - interpolator.addPostProcessor((expression, value) -> { - if (value != null) { - // we're going to parse this back in as XML so we need to escape XML markup - value = value.toString() - .replace("&", "&") - .replace("<", "<") - .replace(">", ">"); - return value; - } - return null; - }); - - try { - serializedToolchains = interpolator.interpolate(serializedToolchains); - } catch (InterpolationException e) { - problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e); - return toolchains; - } - - PersistedToolchains result; - try { - Map options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE); - - result = toolchainsReader.read(new StringReader(serializedToolchains), options); - } catch (IOException e) { - problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e); - return toolchains; - } - - return result; - } - - private PersistedToolchains readToolchains( - Source toolchainsSource, ToolchainsBuildingRequest request, ProblemCollector problems) { - if (toolchainsSource == null) { - return new PersistedToolchains(); - } - - PersistedToolchains toolchains; - - try { - Map options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.TRUE); - - try { - toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options); - } catch (ToolchainsParseException e) { - options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE); - - toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options); - - problems.add(Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e); - } - } catch (ToolchainsParseException e) { - problems.add( - Problem.Severity.FATAL, - "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(), - e.getLineNumber(), - e.getColumnNumber(), - e); - return new PersistedToolchains(); - } catch (IOException e) { - problems.add( - Problem.Severity.FATAL, - "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(), - -1, - -1, - e); - return new PersistedToolchains(); - } - - return toolchains; - } - - private boolean hasErrors(List problems) { - if (problems != null) { - for (Problem problem : problems) { - if (Problem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) { - return true; + private Source convert(org.apache.maven.building.Source source) { + if (source instanceof FileSource fs) { + return Source.fromPath(fs.getPath()); + } else if (source != null) { + return new Source() { + @Override + public Path getPath() { + return null; } - } - } - return false; + @Override + public InputStream openStream() throws IOException { + return source.getInputStream(); + } + + @Override + public String getLocation() { + return source.getLocation(); + } + + @Override + public Source resolve(String relative) { + return null; + } + }; + } else { + return null; + } + } + + private List convert(List problems) { + ProblemCollector collector = ProblemCollectorFactory.newInstance(null); + problems.forEach(p -> collector.add( + Problem.Severity.valueOf(p.getSeverity().name()), + p.getMessage(), + p.getLineNumber(), + p.getColumnNumber(), + p.getException())); + return collector.getProblems(); } } 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 index 80e44ec6c8..6ae5d2cd3a 100644 --- 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 @@ -18,54 +18,61 @@ */ package org.apache.maven.toolchain.building; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + import java.io.IOException; -import java.io.InputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import org.apache.maven.api.services.xml.XmlReaderException; +import org.apache.maven.api.services.xml.XmlReaderRequest; +import org.apache.maven.building.Source; 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.internal.impl.DefaultToolchainsXmlFactory; 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.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; -import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import static org.apache.maven.internal.impl.StaxLocation.getLocation; 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; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) class DefaultToolchainsBuilderTest { private static final String LS = System.lineSeparator(); @Spy - private DefaultToolchainsReader toolchainsReader; - - @Spy - private DefaultToolchainsWriter toolchainsWriter; + private DefaultToolchainsXmlFactory toolchainsXmlFactory; @InjectMocks private DefaultToolchainsBuilder toolchainBuilder; @BeforeEach void onSetup() { - MockitoAnnotations.initMocks(this); + // MockitoAnnotations.openMocks(this); Map envVarMap = new HashMap<>(); envVarMap.put("testKey", "testValue"); envVarMap.put("testSpecialCharactersKey", ""); OperatingSystemUtils.setEnvVarSource(new TestEnvVarSource(envVarMap)); + + toolchainBuilder = new DefaultToolchainsBuilder( + new org.apache.maven.internal.impl.DefaultToolchainsBuilder(), toolchainsXmlFactory); } @Test @@ -79,19 +86,17 @@ class DefaultToolchainsBuilderTest { @Test void testBuildRequestWithUserToolchains() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setUserToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "user_value"); ToolchainModel toolchain = new ToolchainModel(); toolchain.setType("TYPE"); toolchain.setProvides(props); - PersistedToolchains userResult = new PersistedToolchains(); - userResult.setToolchains(Collections.singletonList(toolchain)); - doReturn(userResult) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + PersistedToolchains persistedToolchains = new PersistedToolchains(); + persistedToolchains.setToolchains(Collections.singletonList(toolchain)); + + String xml = new DefaultToolchainsXmlFactory().toXmlString(persistedToolchains.getDelegate()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setUserToolchainsSource(new StringSource(xml)); ToolchainsBuildingResult result = toolchainBuilder.build(request); assertNotNull(result.getEffectiveToolchains()); @@ -111,19 +116,17 @@ class DefaultToolchainsBuilderTest { @Test void testBuildRequestWithGlobalToolchains() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setGlobalToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "global_value"); ToolchainModel toolchain = new ToolchainModel(); toolchain.setType("TYPE"); toolchain.setProvides(props); - PersistedToolchains globalResult = new PersistedToolchains(); - globalResult.setToolchains(Collections.singletonList(toolchain)); - doReturn(globalResult) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + PersistedToolchains persistedToolchains = new PersistedToolchains(); + persistedToolchains.setToolchains(Collections.singletonList(toolchain)); + + String xml = new DefaultToolchainsXmlFactory().toXmlString(persistedToolchains.getDelegate()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setGlobalToolchainsSource(new StringSource(xml)); ToolchainsBuildingResult result = toolchainBuilder.build(request); assertNotNull(result.getEffectiveToolchains()); @@ -143,10 +146,6 @@ class DefaultToolchainsBuilderTest { @Test void testBuildRequestWithBothToolchains() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setGlobalToolchainsSource(new StringSource("")); - request.setUserToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "user_value"); ToolchainModel toolchain = new ToolchainModel(); @@ -163,10 +162,11 @@ class DefaultToolchainsBuilderTest { PersistedToolchains globalResult = new PersistedToolchains(); globalResult.setToolchains(Collections.singletonList(toolchain)); - doReturn(globalResult) - .doReturn(userResult) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setUserToolchainsSource( + new StringSource(new DefaultToolchainsXmlFactory().toXmlString(userResult.getDelegate()))); + request.setGlobalToolchainsSource( + new StringSource(new DefaultToolchainsXmlFactory().toXmlString(globalResult.getDelegate()))); ToolchainsBuildingResult result = toolchainBuilder.build(request); assertNotNull(result.getEffectiveToolchains()); @@ -195,12 +195,15 @@ class DefaultToolchainsBuilderTest { @Test void testStrictToolchainsParseException() throws Exception { + Location loc = mock(Location.class); + when(loc.getLineNumber()).thenReturn(4); + when(loc.getColumnNumber()).thenReturn(2); + XMLStreamException parseException = new XMLStreamException("MESSAGE", loc); + doThrow(new XmlReaderException("MESSAGE", getLocation(parseException), parseException)) + .when(toolchainsXmlFactory) + .read(any(XmlReaderRequest.class)); ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); request.setGlobalToolchainsSource(new StringSource("")); - ToolchainsParseException parseException = new ToolchainsParseException("MESSAGE", 4, 2); - doThrow(parseException) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); try { toolchainBuilder.build(request); @@ -214,12 +217,13 @@ class DefaultToolchainsBuilderTest { @Test void testIOException() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setGlobalToolchainsSource(new StringSource("", "LOCATION")); + Source src = mock(Source.class); IOException ioException = new IOException("MESSAGE"); - doThrow(ioException) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + doThrow(ioException).when(src).getInputStream(); + doReturn("LOCATION").when(src).getLocation(); + + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setGlobalToolchainsSource(src); try { toolchainBuilder.build(request); @@ -233,9 +237,6 @@ class DefaultToolchainsBuilderTest { @Test void testEnvironmentVariablesAreInterpolated() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setUserToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "${env.testKey}"); Xpp3Dom configurationChild = new Xpp3Dom("jdkHome"); @@ -249,9 +250,9 @@ class DefaultToolchainsBuilderTest { PersistedToolchains persistedToolchains = new PersistedToolchains(); persistedToolchains.setToolchains(Collections.singletonList(toolchain)); - doReturn(persistedToolchains) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + String xml = new DefaultToolchainsXmlFactory().toXmlString(persistedToolchains.getDelegate()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setUserToolchainsSource(new StringSource(xml)); ToolchainsBuildingResult result = toolchainBuilder.build(request); String interpolatedValue = "testValue"; @@ -272,9 +273,6 @@ class DefaultToolchainsBuilderTest { @Test void testNonExistingEnvironmentVariablesAreNotInterpolated() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setUserToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "${env.testNonExistingKey}"); ToolchainModel toolchain = new ToolchainModel(); @@ -283,9 +281,9 @@ class DefaultToolchainsBuilderTest { PersistedToolchains persistedToolchains = new PersistedToolchains(); persistedToolchains.setToolchains(Collections.singletonList(toolchain)); - doReturn(persistedToolchains) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + String xml = new DefaultToolchainsXmlFactory().toXmlString(persistedToolchains.getDelegate()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setUserToolchainsSource(new StringSource(xml)); ToolchainsBuildingResult result = toolchainBuilder.build(request); assertEquals( @@ -301,9 +299,6 @@ class DefaultToolchainsBuilderTest { @Test void testEnvironmentVariablesWithSpecialCharactersAreInterpolated() throws Exception { - ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); - request.setUserToolchainsSource(new StringSource("")); - Properties props = new Properties(); props.put("key", "${env.testSpecialCharactersKey}"); ToolchainModel toolchain = new ToolchainModel(); @@ -312,9 +307,9 @@ class DefaultToolchainsBuilderTest { PersistedToolchains persistedToolchains = new PersistedToolchains(); persistedToolchains.setToolchains(Collections.singletonList(toolchain)); - doReturn(persistedToolchains) - .when(toolchainsReader) - .read(any(InputStream.class), ArgumentMatchers.anyMap()); + String xml = new DefaultToolchainsXmlFactory().toXmlString(persistedToolchains.getDelegate()); + ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest(); + request.setUserToolchainsSource(new StringSource(xml)); ToolchainsBuildingResult result = toolchainBuilder.build(request); String interpolatedValue = ""; diff --git a/maven-toolchain-model/pom.xml b/maven-toolchain-model/pom.xml index b452af6982..93016abeac 100644 --- a/maven-toolchain-model/pom.xml +++ b/maven-toolchain-model/pom.xml @@ -68,9 +68,6 @@ under the License. - - - packageModelV3=org.apache.maven.toolchain.model diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java index 91b199ee96..69cc175719 100644 --- a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java +++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java @@ -18,9 +18,6 @@ */ package org.apache.maven.internal.xml; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; - import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -29,7 +26,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import com.ctc.wstx.stax.WstxInputFactory; import org.apache.maven.api.xml.XmlNode; import org.codehaus.plexus.util.xml.pull.MXParser; import org.codehaus.plexus.util.xml.pull.XmlPullParser; @@ -159,92 +155,6 @@ public class XmlNodeBuilder { throw new IllegalStateException("End of document found before returning to 0 depth"); } - public static XmlNodeImpl build(Reader reader, InputLocationBuilderStax locationBuilder) throws XMLStreamException { - XMLStreamReader parser = WstxInputFactory.newFactory().createXMLStreamReader(reader); - return build(parser, DEFAULT_TRIM, locationBuilder); - } - - public static XmlNodeImpl build(XMLStreamReader parser) throws XMLStreamException { - return build(parser, DEFAULT_TRIM, null); - } - - public static XmlNodeImpl build(XMLStreamReader parser, InputLocationBuilderStax locationBuilder) - throws XMLStreamException { - return build(parser, DEFAULT_TRIM, locationBuilder); - } - - public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder) - throws XMLStreamException { - boolean spacePreserve = false; - String lPrefix = null; - String lNamespaceUri = null; - String lName = null; - String lValue = null; - Object location = null; - Map attrs = null; - List children = null; - int eventType = parser.getEventType(); - int lastStartTag = -1; - while (eventType != XMLStreamReader.END_DOCUMENT) { - if (eventType == XMLStreamReader.START_ELEMENT) { - lastStartTag = parser.getLocation().getLineNumber() * 1000 - + parser.getLocation().getColumnNumber(); - if (lName == null) { - int namespacesSize = parser.getNamespaceCount(); - lPrefix = parser.getPrefix(); - lNamespaceUri = parser.getNamespaceURI(); - lName = parser.getLocalName(); - location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null; - int attributesSize = parser.getAttributeCount(); - if (attributesSize > 0 || namespacesSize > 0) { - attrs = new HashMap<>(); - for (int i = 0; i < namespacesSize; i++) { - String nsPrefix = parser.getNamespacePrefix(i); - String nsUri = parser.getNamespaceURI(i); - attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri); - } - for (int i = 0; i < attributesSize; i++) { - String aName = parser.getAttributeLocalName(i); - String aValue = parser.getAttributeValue(i); - String aPrefix = parser.getAttributePrefix(i); - if (aPrefix != null && !aPrefix.isEmpty()) { - aName = aPrefix + ":" + aName; - } - attrs.put(aName, aValue); - spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue)); - } - } - } else { - if (children == null) { - children = new ArrayList<>(); - } - XmlNode child = build(parser, trim, locationBuilder); - children.add(child); - } - } else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) { - String text = parser.getText(); - lValue = lValue != null ? lValue + text : text; - } else if (eventType == XMLStreamReader.END_ELEMENT) { - boolean emptyTag = lastStartTag - == parser.getLocation().getLineNumber() * 1000 - + parser.getLocation().getColumnNumber(); - if (lValue != null && trim && !spacePreserve) { - lValue = lValue.trim(); - } - return new XmlNodeImpl( - lPrefix, - lNamespaceUri, - lName, - children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null, - attrs, - children, - location); - } - eventType = parser.next(); - } - throw new IllegalStateException("End of document found before returning to 0 depth"); - } - /** * Input location builder interface, to be implemented to choose how to store data. * @@ -253,8 +163,4 @@ public class XmlNodeBuilder { public interface InputLocationBuilder { Object toInputLocation(XmlPullParser parser); } - - public interface InputLocationBuilderStax { - Object toInputLocation(XMLStreamReader parser); - } } diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeStaxBuilder.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeStaxBuilder.java new file mode 100644 index 0000000000..a2fe19a428 --- /dev/null +++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeStaxBuilder.java @@ -0,0 +1,134 @@ +/* + * 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. + */ +package org.apache.maven.internal.xml; + +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.ctc.wstx.stax.WstxInputFactory; +import org.apache.maven.api.xml.XmlNode; + +/** + * All methods in this class attempt to fully parse the XML. + * The caller is responsible for closing {@code InputStream} and {@code Reader} arguments. + */ +public class XmlNodeStaxBuilder { + private static final boolean DEFAULT_TRIM = true; + + public static XmlNodeImpl build(Reader reader, InputLocationBuilderStax locationBuilder) throws XMLStreamException { + XMLStreamReader parser = WstxInputFactory.newFactory().createXMLStreamReader(reader); + return build(parser, DEFAULT_TRIM, locationBuilder); + } + + public static XmlNodeImpl build(XMLStreamReader parser) throws XMLStreamException { + return build(parser, DEFAULT_TRIM, null); + } + + public static XmlNodeImpl build(XMLStreamReader parser, InputLocationBuilderStax locationBuilder) + throws XMLStreamException { + return build(parser, DEFAULT_TRIM, locationBuilder); + } + + public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder) + throws XMLStreamException { + boolean spacePreserve = false; + String lPrefix = null; + String lNamespaceUri = null; + String lName = null; + String lValue = null; + Object location = null; + Map attrs = null; + List children = null; + int eventType = parser.getEventType(); + int lastStartTag = -1; + while (eventType != XMLStreamReader.END_DOCUMENT) { + if (eventType == XMLStreamReader.START_ELEMENT) { + lastStartTag = parser.getLocation().getLineNumber() * 1000 + + parser.getLocation().getColumnNumber(); + if (lName == null) { + int namespacesSize = parser.getNamespaceCount(); + lPrefix = parser.getPrefix(); + lNamespaceUri = parser.getNamespaceURI(); + lName = parser.getLocalName(); + location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null; + int attributesSize = parser.getAttributeCount(); + if (attributesSize > 0 || namespacesSize > 0) { + attrs = new HashMap<>(); + for (int i = 0; i < namespacesSize; i++) { + String nsPrefix = parser.getNamespacePrefix(i); + String nsUri = parser.getNamespaceURI(i); + attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri); + } + for (int i = 0; i < attributesSize; i++) { + String aName = parser.getAttributeLocalName(i); + String aValue = parser.getAttributeValue(i); + String aPrefix = parser.getAttributePrefix(i); + if (aPrefix != null && !aPrefix.isEmpty()) { + aName = aPrefix + ":" + aName; + } + attrs.put(aName, aValue); + spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue)); + } + } + } else { + if (children == null) { + children = new ArrayList<>(); + } + XmlNode child = build(parser, trim, locationBuilder); + children.add(child); + } + } else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) { + String text = parser.getText(); + lValue = lValue != null ? lValue + text : text; + } else if (eventType == XMLStreamReader.END_ELEMENT) { + boolean emptyTag = lastStartTag + == parser.getLocation().getLineNumber() * 1000 + + parser.getLocation().getColumnNumber(); + if (lValue != null && trim && !spacePreserve) { + lValue = lValue.trim(); + } + return new XmlNodeImpl( + lPrefix, + lNamespaceUri, + lName, + children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null, + attrs, + children, + location); + } + eventType = parser.next(); + } + throw new IllegalStateException("End of document found before returning to 0 depth"); + } + + /** + * Input location builder interface, to be implemented to choose how to store data. + * + * @since 3.2.0 + */ + public interface InputLocationBuilderStax { + Object toInputLocation(XMLStreamReader parser); + } +} diff --git a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java index abcc2f3125..5d3f3a0577 100644 --- a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java +++ b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java @@ -50,7 +50,7 @@ class XmlNodeBuilderTest { String doc = ""; StringReader r = new StringReader(doc); XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(r); - XmlNode node = XmlNodeBuilder.build(xsr); + XmlNode node = XmlNodeStaxBuilder.build(xsr); assertEquals("doc", node.getName()); assertEquals(1, node.getAttributes().size()); assertEquals("foo:bar", node.getAttribute("xmlns")); diff --git a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java index 973f990df2..b4be85d573 100644 --- a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java +++ b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java @@ -165,8 +165,8 @@ class XmlNodeImplTest { + "TOOVERWRITERHS" + ""; - XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); - XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); + XmlNodeImpl leftDom = XmlNodeStaxBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); + XmlNodeImpl rightDom = XmlNodeStaxBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true); assertEquals(3, getChildren(mergeResult, "property").size()); @@ -211,8 +211,8 @@ class XmlNodeImplTest { + "RHS-ONLYRHS" + "TOOVERWRITERHS" + ""; - XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); - XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); + XmlNodeImpl leftDom = XmlNodeStaxBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); + XmlNodeImpl rightDom = XmlNodeStaxBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true); assertEquals(3, getChildren(mergeResult, "property").size()); @@ -248,8 +248,8 @@ class XmlNodeImplTest { String rhs = "recessive"; - XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); - XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); + XmlNodeImpl leftDom = XmlNodeStaxBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); + XmlNodeImpl rightDom = XmlNodeStaxBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true); assertEquals(" ", mergeResult.getValue()); @@ -261,8 +261,8 @@ class XmlNodeImplTest { String rhs = "recessive"; - XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); - XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); + XmlNodeImpl leftDom = XmlNodeStaxBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); + XmlNodeImpl rightDom = XmlNodeStaxBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true); assertEquals("", mergeResult.getValue()); @@ -274,8 +274,8 @@ class XmlNodeImplTest { String rhs = "recessive"; - XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); - XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); + XmlNodeImpl leftDom = XmlNodeStaxBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left")); + XmlNodeImpl rightDom = XmlNodeStaxBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right")); XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true); assertNull(mergeResult.getValue()); @@ -642,7 +642,7 @@ class XmlNodeImplTest { return toXmlNode(xml, null); } - private static XmlNode toXmlNode(String xml, XmlNodeBuilder.InputLocationBuilderStax locationBuilder) + private static XmlNode toXmlNode(String xml, XmlNodeStaxBuilder.InputLocationBuilderStax locationBuilder) throws XMLStreamException, IOException { return toXmlNode(new StringReader(xml), locationBuilder); } @@ -651,12 +651,12 @@ class XmlNodeImplTest { return toXmlNode(reader, null); } - private static XmlNode toXmlNode(Reader reader, XmlNodeBuilder.InputLocationBuilderStax locationBuilder) + private static XmlNode toXmlNode(Reader reader, XmlNodeStaxBuilder.InputLocationBuilderStax locationBuilder) throws XMLStreamException, IOException { - return XmlNodeBuilder.build(reader, locationBuilder); + return XmlNodeStaxBuilder.build(reader, locationBuilder); } - private static class FixedInputLocationBuilder implements XmlNodeBuilder.InputLocationBuilderStax { + private static class FixedInputLocationBuilder implements XmlNodeStaxBuilder.InputLocationBuilderStax { private final Object location; public FixedInputLocationBuilder(Object location) { diff --git a/pom.xml b/pom.xml index 7a955519c9..9dd8c868b2 100644 --- a/pom.xml +++ b/pom.xml @@ -101,6 +101,7 @@ under the License. api + maven-api-impl maven-plugin-api maven-builder-support maven-model @@ -217,6 +218,11 @@ under the License. maven-core ${project.version}
+ + org.apache.maven + maven-api-impl + ${project.version} + org.apache.maven maven-embedder diff --git a/src/mdo/reader-stax.vm b/src/mdo/reader-stax.vm index f53ca01396..d253537c5b 100644 --- a/src/mdo/reader-stax.vm +++ b/src/mdo/reader-stax.vm @@ -71,7 +71,7 @@ import ${packageModelV4}.InputLocation; #foreach ( $class in $model.allClasses ) import ${packageModelV4}.${class.name}; #end -import org.apache.maven.internal.xml.XmlNodeBuilder; +import org.apache.maven.internal.xml.XmlNodeStaxBuilder; import org.apache.maven.api.xml.XmlNode; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; @@ -897,14 +897,14 @@ public class ${className} { #if ( $locationTracking ) private XmlNode buildXmlNode(XMLStreamReader parser, InputSource source) throws XMLStreamException { - return XmlNodeBuilder.build(parser, + return XmlNodeStaxBuilder.build(parser, addLocationInformation ? p -> new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source) : null); } #else private XmlNode buildXmlNode(XMLStreamReader parser) throws XMLStreamException { - return XmlNodeBuilder.build(parser); + return XmlNodeStaxBuilder.build(parser); } #end diff --git a/src/mdo/transformer.vm b/src/mdo/transformer.vm index 8eaac496fb..ac6cd05f0b 100644 --- a/src/mdo/transformer.vm +++ b/src/mdo/transformer.vm @@ -48,7 +48,7 @@ import org.apache.maven.api.xml.XmlNode; #foreach ( $class in $model.allClasses ) import ${packageModelV4}.${class.name}; #end -import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.apache.maven.internal.xml.XmlNodeImpl; @Generated public class ${className} { @@ -144,35 +144,16 @@ public class ${className} { } protected XmlNode transform(XmlNode node) { - if (node != null) { - Xpp3Dom xpp = new Xpp3Dom(node); - transform(xpp); - return xpp.getDom(); - } - return node; - } - - protected void transform(Xpp3Dom dom) { - if (dom != null) { - String org, val; - // Content - org = dom.getValue(); - val = transform(org); - if (org != val) { - dom.setValue(val); - } - // Attributes - for (String attr : dom.getAttributeNames()) { - org = dom.getAttribute(attr); - val = transform(org); - if (org != val) { - dom.setAttribute(attr, val); - } - } - // Children - for (int i = 0, l = dom.getChildCount(); i < l; i++) { - transform(dom.getChild(i)); - } - } + return node != null ? new XmlNodeImpl( + node.getPrefix(), + node.getNamespaceUri(), + node.getName(), + transform(node.getValue()), + node.getAttributes().entrySet() + .stream().collect(Collectors.toMap(e -> e.getKey(), e -> transform(e.getValue()))), + node.getChildren().stream() + .map(this::transform).collect(Collectors.toList()), + node.getInputLocation() + ) : null; } }