diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java index 4d41444109ab..247cc4798390 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java @@ -33,7 +33,7 @@ * Represents a dependency node within a Maven project's dependency collector. * * @since 4.0.0 - * @see org.apache.maven.api.services.DependencyCollectorResult#getRoot() + * @see org.apache.maven.api.services.DependencyResolverResult#getRoot() */ @Experimental @Immutable diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java index 31aeb06b7b8c..720bb85e475d 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java @@ -496,25 +496,25 @@ Artifact createArtifact( boolean isVersionSnapshot(@Nonnull String version); /** - * Shortcut for {@code getService(DependencyCollector.class).collect(...)} + * Shortcut for {@code getService(DependencyResolver.class).collect(...)} * * @param artifact artifact for which to get the dependencies, including transitive ones * @return root node of the dependency graph for the given artifact * - * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact) - * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed + * @see org.apache.maven.api.services.DependencyResolver#collect(Session, Artifact) + * @throws org.apache.maven.api.services.DependencyResolverException if the dependency collection failed */ @Nonnull Node collectDependencies(@Nonnull Artifact artifact); /** - * Shortcut for {@code getService(DependencyCollector.class).collect(...)} + * Shortcut for {@code getService(DependencyResolver.class).collect(...)} * * @param project project for which to get the dependencies, including transitive ones * @return root node of the dependency graph for the given project * - * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project) - * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed + * @see org.apache.maven.api.services.DependencyResolver#collect(Session, Project) + * @throws org.apache.maven.api.services.DependencyResolverException if the dependency collection failed */ @Nonnull Node collectDependencies(@Nonnull Project project); @@ -524,13 +524,13 @@ Artifact createArtifact( * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the * artifact files. *

- * Shortcut for {@code getService(DependencyCollector.class).resolve(...)} + * Shortcut for {@code getService(DependencyResolver.class).resolve(...)} * * @param dependency dependency for which to get transitive dependencies * @return root node of the dependency graph for the given artifact * - * @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate) - * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed + * @see org.apache.maven.api.services.DependencyResolver#collect(Session, DependencyCoordinate) + * @throws org.apache.maven.api.services.DependencyResolverException if the dependency collection failed */ @Nonnull Node collectDependencies(@Nonnull DependencyCoordinate dependency); diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java deleted file mode 100644 index 788fd67c8ce8..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java +++ /dev/null @@ -1,107 +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.api.services; - -import org.apache.maven.api.Artifact; -import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.Project; -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; - -/** - * The DependencyCollector service can be used to collect dependencies - * for a given artifact and builds a graph of them. - * The dependencies collection mechanism will not download any artifacts, - * and only the pom files will be downloaded. - * - * @since 4.0.0 - */ -@Experimental -public interface DependencyCollector extends Service { - - /** - * Collects the transitive dependencies and builds a dependency graph. - * Note that this operation is only concerned about determining the coordinates of the - * transitive dependencies and does not actually resolve the artifact files. - * - * @param request the dependency collection request, must not be {@code null} - * @return the collection result, never {@code null} - * @throws DependencyCollectorException if the dependency tree could not be built - * @throws IllegalArgumentException if an argument is null or invalid - * - * @see DependencyCollector#collect(Session, Project) - * @see DependencyCollector#collect(Session, DependencyCoordinate) - * @see DependencyCollector#collect(Session, Artifact) - */ - @Nonnull - DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest request); - - /** - * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is - * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the - * artifact files. - * - * @param session the {@link Session}, must not be {@code null} - * @param root the Maven Dependency, must not be {@code null} - * @return the collection result, never {@code null} - * @throws DependencyCollectorException if the dependency tree could not be built - * @throws IllegalArgumentException if an argument is null or invalid - * @see #collect(DependencyCollectorRequest) - */ - @Nonnull - default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull DependencyCoordinate root) { - return collect(DependencyCollectorRequest.build(session, root)); - } - - /** - * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is - * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the - * artifact files. - * - * @param session the {@link Session}, must not be {@code null} - * @param project the {@link Project}, must not be {@code null} - * @return the collection result, never {@code null} - * @throws DependencyCollectorException if the dependency tree could not be built - * @throws IllegalArgumentException if an argument is null or invalid - * @see #collect(DependencyCollectorRequest) - */ - @Nonnull - default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull Project project) { - return collect(DependencyCollectorRequest.build(session, project)); - } - - /** - * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is - * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the - * artifact files. - * - * @param session the {@link Session}, must not be {@code null} - * @param artifact the {@link Artifact}, must not be {@code null} - * @return the collection result, never {@code null} - * @throws DependencyCollectorException if the dependency tree could not be built - * @throws IllegalArgumentException if an argument is null or invalid - * @see #collect(DependencyCollectorRequest) - */ - @Nonnull - default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull Artifact artifact) { - return collect(DependencyCollectorRequest.build(session, artifact)); - } -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java deleted file mode 100644 index 466c40ec9b39..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java +++ /dev/null @@ -1,43 +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.api.services; - -import org.apache.maven.api.annotations.Experimental; - -/** - * Thrown in case of bad artifact descriptors, version ranges or other - * issues encountered during calculation of the dependency graph. - * - * @since 4.0.0 - */ -@Experimental -public class DependencyCollectorException extends MavenException { - /** - * - */ - private static final long serialVersionUID = -3134726259840210686L; - - /** - * @param message the message you would give for the exception - * @param cause the cause which is related to the message - */ - public DependencyCollectorException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java deleted file mode 100644 index ebaa10b09eb4..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java +++ /dev/null @@ -1,310 +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.api.services; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import org.apache.maven.api.Artifact; -import org.apache.maven.api.DependencyCoordinate; -import org.apache.maven.api.Project; -import org.apache.maven.api.Session; -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Immutable; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.annotations.NotThreadSafe; -import org.apache.maven.api.annotations.Nullable; - -import static org.apache.maven.api.services.BaseRequest.nonNull; - -/** - * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to - * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct - * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies - * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in - * which case the root node of the resulting graph has no associated dependency. - * - * @since 4.0.0 - * @see DependencyCollector#collect(DependencyCollectorRequest) - */ -@Experimental -@Immutable -public interface DependencyCollectorRequest { - - @Nonnull - Session getSession(); - - Optional getProject(); - - @Nonnull - Optional getRootArtifact(); - - @Nonnull - Optional getRoot(); - - @Nonnull - Collection getDependencies(); - - @Nonnull - Collection getManagedDependencies(); - - boolean getVerbose(); - - @Nonnull - static DependencyCollectorRequest build(@Nonnull Session session, Artifact root) { - return builder() - .session(nonNull(session, "session cannot be null")) - .rootArtifact(nonNull(root, "root cannot be null")) - .build(); - } - - @Nonnull - static DependencyCollectorRequest build(@Nonnull Session session, @Nonnull DependencyCoordinate root) { - return builder() - .session(nonNull(session, "session cannot be null")) - .root(nonNull(root, "root cannot be null")) - .build(); - } - - @Nonnull - static DependencyCollectorRequest build(@Nonnull Session session, @Nonnull Project project) { - return builder() - .session(nonNull(session, "session cannot be null")) - .project(nonNull(project, "project cannot be null")) - .build(); - } - - @Nonnull - static DependencyCollectorRequestBuilder builder() { - return new DependencyCollectorRequestBuilder(); - } - - @NotThreadSafe - class DependencyCollectorRequestBuilder { - - Session session; - Project project; - Artifact rootArtifact; - DependencyCoordinate root; - List dependencies = Collections.emptyList(); - List managedDependencies = Collections.emptyList(); - boolean verbose; - - DependencyCollectorRequestBuilder() {} - - @Nonnull - public DependencyCollectorRequestBuilder session(@Nonnull Session session) { - this.session = session; - return this; - } - - @Nonnull - public DependencyCollectorRequestBuilder project(@Nullable Project project) { - this.project = project; - return this; - } - - /** - * Sets the root artifact for the dependency graph. - * This must not be confused with {@link #root(DependencyCoordinate)}: The root dependency, like any - * other specified dependency, will be subject to dependency collection/resolution, i.e. should have an artifact - * descriptor and a corresponding artifact file. The root artifact on the other hand is only used - * as a label for the root node of the graph in case no root dependency was specified. As such, the configured - * root artifact is ignored if {@link #root(DependencyCoordinate)} has been set. - * - * @param rootArtifact the root artifact for the dependency graph, may be {@code null} - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder rootArtifact(@Nullable Artifact rootArtifact) { - this.rootArtifact = rootArtifact; - return this; - } - - /** - * @param root The root dependency - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder root(@Nonnull DependencyCoordinate root) { - this.root = root; - return this; - } - - /** - * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the - * direct dependencies from the request will be merged with the direct dependencies from the root dependency's - * artifact descriptor, giving higher priority to the dependencies from the request. - * - * @param dependencies the direct dependencies, may be {@code null} - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder dependencies(@Nullable List dependencies) { - this.dependencies = (dependencies != null) ? dependencies : Collections.emptyList(); - return this; - } - - /** - * Adds the specified direct dependency. - * - * @param dependency the dependency to add, may be {@code null} - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder dependency(@Nullable DependencyCoordinate dependency) { - if (dependency != null) { - if (this.dependencies.isEmpty()) { - this.dependencies = new ArrayList<>(); - } - this.dependencies.add(dependency); - } - return this; - } - - /** - * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not - * apply to - * the direct dependencies of the root node. - * - * @param managedDependencies the dependency management, may be {@code null} - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder managedDependencies( - @Nullable List managedDependencies) { - this.managedDependencies = (managedDependencies != null) ? managedDependencies : Collections.emptyList(); - return this; - } - - /** - * Adds the specified managed dependency. - * - * @param managedDependency The managed dependency to add, may be {@code null} in which case the call - * will have no effect. - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder managedDependency(@Nullable DependencyCoordinate managedDependency) { - if (managedDependency != null) { - if (this.managedDependencies.isEmpty()) { - this.managedDependencies = new ArrayList<>(); - } - this.managedDependencies.add(managedDependency); - } - return this; - } - - /** - * Specifies that the collection should be verbose. - * - * @param verbose whether the collection should be verbose or not - * @return this request for chaining, never {@code null} - */ - @Nonnull - public DependencyCollectorRequestBuilder verbose(boolean verbose) { - this.verbose = verbose; - return this; - } - - @Nonnull - public DependencyCollectorRequest build() { - return new DefaultDependencyCollectorRequest( - session, project, rootArtifact, root, dependencies, managedDependencies, verbose); - } - - static class DefaultDependencyCollectorRequest extends BaseRequest implements DependencyCollectorRequest { - private final Project project; - private final Artifact rootArtifact; - private final DependencyCoordinate root; - private final Collection dependencies; - private final Collection managedDependencies; - private final boolean verbose; - - /** - * Creates a request with the specified properties. - * - * @param session {@link Session} - * @param rootArtifact The root dependency whose transitive dependencies should be collected, may be {@code - * null}. - */ - DefaultDependencyCollectorRequest( - @Nonnull Session session, - @Nullable Project project, - @Nullable Artifact rootArtifact, - @Nullable DependencyCoordinate root, - @Nonnull Collection dependencies, - @Nonnull Collection managedDependencies, - boolean verbose) { - super(session); - this.project = project; - this.rootArtifact = rootArtifact; - this.root = root; - this.dependencies = unmodifiable(nonNull(dependencies, "dependencies cannot be null")); - this.managedDependencies = - unmodifiable(nonNull(managedDependencies, "managedDependencies cannot be null")); - this.verbose = verbose; - } - - @Nonnull - @Override - public Optional getProject() { - return Optional.ofNullable(project); - } - - @Nonnull - @Override - public Optional getRootArtifact() { - return Optional.ofNullable(rootArtifact); - } - - @Nonnull - @Override - public Optional getRoot() { - return Optional.ofNullable(root); - } - - @Nonnull - @Override - public Collection getDependencies() { - return dependencies; - } - - @Nonnull - @Override - public Collection getManagedDependencies() { - return managedDependencies; - } - - @Override - public boolean getVerbose() { - return verbose; - } - - @Nonnull - @Override - public String toString() { - return getRoot() + " -> " + getDependencies(); - } - } - } -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java deleted file mode 100644 index 77b6350390ae..000000000000 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java +++ /dev/null @@ -1,51 +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.api.services; - -import java.util.List; - -import org.apache.maven.api.Node; -import org.apache.maven.api.annotations.Experimental; -import org.apache.maven.api.annotations.Nonnull; -import org.apache.maven.api.annotations.Nullable; - -/** - * The result of a dependency collection request. - * - * @since 4.0.0 - * @see DependencyCollector#collect(DependencyCollectorRequest) - */ -@Experimental -public interface DependencyCollectorResult { - /** - * Gets the exceptions that occurred while building the dependency graph. - * - * @return the exceptions that occurred, never {@code null} - */ - @Nonnull - List getExceptions(); - - /** - * Gets the root node of the dependency graph. - * - * @return the root node of the dependency graph or {@code null} if none - */ - @Nullable - Node getRoot(); -} diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java index 9fefbc4cda7c..95feaa1925f2 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolver.java @@ -20,6 +20,7 @@ import java.util.List; +import org.apache.maven.api.Artifact; import org.apache.maven.api.DependencyCoordinate; import org.apache.maven.api.Node; import org.apache.maven.api.PathScope; @@ -35,55 +36,165 @@ @Experimental public interface DependencyResolver extends Service { - List flatten(Session session, Node node, PathScope scope) throws DependencyResolverException; + /** + * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is + * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the + * artifact files. + * + * @param session the {@link Session}, must not be {@code null} + * @param root the Maven Dependency, must not be {@code null} + * @return the collection result, never {@code null} + * @throws DependencyResolverException if the dependency tree could not be built + * @throws IllegalArgumentException if an argument is null or invalid + * @see #collect(DependencyResolverRequest) + */ + @Nonnull + default DependencyResolverResult collect(@Nonnull Session session, @Nonnull DependencyCoordinate root) { + return collect(DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.COLLECT, root)); + } /** - * This method collects, flattens and resolves the dependencies. + * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is + * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the + * artifact files. * - * @param request the request to resolve - * @return the result of the resolution - * @throws DependencyCollectorException - * @throws DependencyResolverException - * @throws ArtifactResolverException + * @param session the {@link Session}, must not be {@code null} + * @param project the {@link Project}, must not be {@code null} + * @return the collection result, never {@code null} + * @throws DependencyResolverException if the dependency tree could not be built + * @throws IllegalArgumentException if an argument is null or invalid + * @see #collect(DependencyResolverRequest) + */ + @Nonnull + default DependencyResolverResult collect(@Nonnull Session session, @Nonnull Project project) { + return collect( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.COLLECT, project)); + } + + /** + * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is + * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the + * artifact files. * - * @see DependencyCollector#collect(DependencyCollectorRequest) - * @see #flatten(Session, Node, PathScope) - * @see ArtifactResolver#resolve(ArtifactResolverRequest) + * @param session the {@link Session}, must not be {@code null} + * @param artifact the {@link Artifact}, must not be {@code null} + * @return the collection result, never {@code null} + * @throws DependencyResolverException if the dependency tree could not be built + * @throws IllegalArgumentException if an argument is null or invalid + * @see #collect(DependencyResolverRequest) */ - DependencyResolverResult resolve(DependencyResolverRequest request) - throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException; + @Nonnull + default DependencyResolverResult collect(@Nonnull Session session, @Nonnull Artifact artifact) { + return collect( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.COLLECT, artifact)); + } + + /** + * Collects the transitive dependencies and builds a dependency graph. + * Note that this operation is only concerned about determining the coordinates of the + * transitive dependencies and does not actually resolve the artifact files. + * + * @param request the dependency collection request, must not be {@code null} + * @return the collection result, never {@code null} + * @throws DependencyResolverException if the dependency tree could not be built + * @throws IllegalArgumentException if an argument is null or invalid + * + * @see DependencyResolver#collect(Session, Project) + * @see DependencyResolver#collect(Session, DependencyCoordinate) + * @see DependencyResolver#collect(Session, Artifact) + */ + @Nonnull + default DependencyResolverResult collect(@Nonnull DependencyResolverRequest request) { + if (request.getRequestType() != DependencyResolverRequest.RequestType.COLLECT) { + throw new IllegalArgumentException("requestType should be COLLECT when calling collect()"); + } + return resolve(request); + } + + /** + * Flattens a list of nodes. + * + * @param session + * @param node + * @param scope + * @return + * @throws DependencyResolverException + */ + List flatten(Session session, Node node, PathScope scope) throws DependencyResolverException; + + @Nonnull + default DependencyResolverResult flatten(@Nonnull Session session, @Nonnull Project project) { + return flatten( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.FLATTEN, project)); + } + + @Nonnull + default DependencyResolverResult flatten( + @Nonnull Session session, @Nonnull Project project, @Nonnull PathScope scope) { + return flatten(DependencyResolverRequest.build( + session, DependencyResolverRequest.RequestType.FLATTEN, project, scope)); + } + + @Nonnull + default DependencyResolverResult flatten(@Nonnull DependencyResolverRequest request) { + if (request.getRequestType() != DependencyResolverRequest.RequestType.FLATTEN) { + throw new IllegalArgumentException("requestType should be FLATTEN when calling flatten()"); + } + return resolve(request); + } @Nonnull default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull Project project) { - return resolve(DependencyResolverRequest.build(session, project)); + return resolve( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.RESOLVE, project)); } @Nonnull default DependencyResolverResult resolve( @Nonnull Session session, @Nonnull Project project, @Nonnull PathScope scope) { - return resolve(DependencyResolverRequest.build(session, project, scope)); + return resolve(DependencyResolverRequest.build( + session, DependencyResolverRequest.RequestType.RESOLVE, project, scope)); } @Nonnull default DependencyResolverResult resolve(@Nonnull Session session, @Nonnull DependencyCoordinate dependency) { - return resolve(DependencyResolverRequest.build(session, dependency)); + return resolve( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.RESOLVE, dependency)); } @Nonnull default DependencyResolverResult resolve( @Nonnull Session session, @Nonnull DependencyCoordinate dependency, @Nonnull PathScope scope) { - return resolve(DependencyResolverRequest.build(session, dependency, scope)); + return resolve(DependencyResolverRequest.build( + session, DependencyResolverRequest.RequestType.RESOLVE, dependency, scope)); } @Nonnull default DependencyResolverResult resolve( @Nonnull Session session, @Nonnull List dependencies) { - return resolve(DependencyResolverRequest.build(session, dependencies)); + return resolve( + DependencyResolverRequest.build(session, DependencyResolverRequest.RequestType.RESOLVE, dependencies)); } @Nonnull default DependencyResolverResult resolve( @Nonnull Session session, @Nonnull List dependencies, @Nonnull PathScope scope) { - return resolve(DependencyResolverRequest.build(session, dependencies, scope)); + return resolve(DependencyResolverRequest.build( + session, DependencyResolverRequest.RequestType.RESOLVE, dependencies, scope)); } + + /** + * This method collects, flattens and resolves the dependencies. + * + * @param request the request to resolve + * @return the result of the resolution + * @throws DependencyResolverException + * @throws ArtifactResolverException + * + * @see DependencyResolver#collect(DependencyResolverRequest) + * @see #flatten(Session, Node, PathScope) + * @see ArtifactResolver#resolve(ArtifactResolverRequest) + */ + DependencyResolverResult resolve(DependencyResolverRequest request) + throws DependencyResolverException, ArtifactResolverException; } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java index 2f410a8a303f..dfc7760fc7cc 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java @@ -18,8 +18,11 @@ */ package org.apache.maven.api.services; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.function.Predicate; import org.apache.maven.api.Artifact; @@ -30,14 +33,54 @@ import org.apache.maven.api.Project; import org.apache.maven.api.Session; import org.apache.maven.api.annotations.Experimental; +import org.apache.maven.api.annotations.Immutable; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.NotThreadSafe; import org.apache.maven.api.annotations.Nullable; +/** + * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to + * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct + * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies + * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in + * which case the root node of the resulting graph has no associated dependency. + * + * @since 4.0.0 + */ @Experimental -public interface DependencyResolverRequest extends DependencyCollectorRequest { +@Immutable +public interface DependencyResolverRequest { + + enum RequestType { + COLLECT, + FLATTEN, + RESOLVE + } + + @Nonnull + Session getSession(); + + @Nonnull + RequestType getRequestType(); + + @Nonnull + Optional getProject(); + + @Nonnull + Optional getRootArtifact(); + + @Nonnull + Optional getRoot(); @Nonnull + Collection getDependencies(); + + @Nonnull + Collection getManagedDependencies(); + + boolean getVerbose(); + + @Nullable PathScope getPathScope(); /** @@ -48,6 +91,7 @@ public interface DependencyResolverRequest extends DependencyCollectorRequest { * * @return a filter for the types of path (class-path, module-path, …) accepted by the tool */ + @Nullable Predicate getPathTypeFilter(); @Nonnull @@ -56,119 +100,202 @@ static DependencyResolverRequestBuilder builder() { } @Nonnull - static DependencyResolverRequest build(Session session, Project project) { - return build(session, project, PathScope.MAIN_RUNTIME); + static DependencyResolverRequest build(Session session, RequestType requestType, Artifact rootArtifact) { + return new DependencyResolverRequestBuilder() + .session(session) + .requestType(requestType) + .rootArtifact(rootArtifact) + .pathScope(PathScope.MAIN_RUNTIME) + .build(); } @Nonnull - static DependencyResolverRequest build(Session session, Project project, PathScope scope) { + static DependencyResolverRequest build(Session session, RequestType requestType, Project project) { + return build(session, requestType, project, PathScope.MAIN_RUNTIME); + } + + @Nonnull + static DependencyResolverRequest build(Session session, RequestType requestType, Project project, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) + .requestType(requestType) .project(project) .pathScope(scope) .build(); } @Nonnull - static DependencyResolverRequest build(Session session, DependencyCoordinate dependency) { - return build(session, dependency, PathScope.MAIN_RUNTIME); + static DependencyResolverRequest build(Session session, RequestType requestType, DependencyCoordinate dependency) { + return build(session, requestType, dependency, PathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, DependencyCoordinate dependency, PathScope scope) { + static DependencyResolverRequest build( + Session session, RequestType requestType, DependencyCoordinate dependency, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) + .requestType(requestType) .dependency(dependency) .pathScope(scope) .build(); } @Nonnull - static DependencyResolverRequest build(Session session, List dependencies) { - return build(session, dependencies, PathScope.MAIN_RUNTIME); + static DependencyResolverRequest build( + Session session, RequestType requestType, List dependencies) { + return build(session, requestType, dependencies, PathScope.MAIN_RUNTIME); } @Nonnull - static DependencyResolverRequest build(Session session, List dependencies, PathScope scope) { + static DependencyResolverRequest build( + Session session, RequestType requestType, List dependencies, PathScope scope) { return new DependencyResolverRequestBuilder() .session(session) + .requestType(requestType) .dependencies(dependencies) .pathScope(scope) .build(); } @NotThreadSafe - class DependencyResolverRequestBuilder extends DependencyCollectorRequestBuilder { + class DependencyResolverRequestBuilder { + + Session session; + RequestType requestType; + Project project; + Artifact rootArtifact; + DependencyCoordinate root; + List dependencies = Collections.emptyList(); + List managedDependencies = Collections.emptyList(); + boolean verbose; PathScope pathScope; - Predicate pathTypeFilter; + DependencyResolverRequestBuilder() {} + @Nonnull - @Override public DependencyResolverRequestBuilder session(@Nonnull Session session) { - super.session(session); + this.session = session; + return this; + } + + @Nonnull + public DependencyResolverRequestBuilder requestType(@Nonnull RequestType requestType) { + this.requestType = requestType; return this; } @Nonnull - @Override public DependencyResolverRequestBuilder project(@Nullable Project project) { - super.project(project); + this.project = project; return this; } + /** + * Sets the root artifact for the dependency graph. + * This must not be confused with {@link #root(DependencyCoordinate)}: The root dependency, like any + * other specified dependency, will be subject to dependency collection/resolution, i.e. should have an artifact + * descriptor and a corresponding artifact file. The root artifact on the other hand is only used + * as a label for the root node of the graph in case no root dependency was specified. As such, the configured + * root artifact is ignored if {@link #root(DependencyCoordinate)} has been set. + * + * @param rootArtifact the root artifact for the dependency graph, may be {@code null} + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder rootArtifact(@Nullable Artifact rootArtifact) { - super.rootArtifact(rootArtifact); + this.rootArtifact = rootArtifact; return this; } + /** + * @param root The root dependency + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override - public DependencyResolverRequestBuilder root(@Nullable DependencyCoordinate root) { - super.root(root); + public DependencyResolverRequestBuilder root(@Nonnull DependencyCoordinate root) { + this.root = root; return this; } + /** + * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the + * direct dependencies from the request will be merged with the direct dependencies from the root dependency's + * artifact descriptor, giving higher priority to the dependencies from the request. + * + * @param dependencies the direct dependencies, may be {@code null} + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder dependencies(@Nullable List dependencies) { - super.dependencies(dependencies); + this.dependencies = (dependencies != null) ? dependencies : Collections.emptyList(); return this; } + /** + * Adds the specified direct dependency. + * + * @param dependency the dependency to add, may be {@code null} + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder dependency(@Nullable DependencyCoordinate dependency) { - super.dependency(dependency); + if (dependency != null) { + if (this.dependencies.isEmpty()) { + this.dependencies = new ArrayList<>(); + } + this.dependencies.add(dependency); + } return this; } + /** + * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not + * apply to + * the direct dependencies of the root node. + * + * @param managedDependencies the dependency management, may be {@code null} + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder managedDependencies( @Nullable List managedDependencies) { - super.managedDependencies(managedDependencies); + this.managedDependencies = (managedDependencies != null) ? managedDependencies : Collections.emptyList(); return this; } + /** + * Adds the specified managed dependency. + * + * @param managedDependency The managed dependency to add, may be {@code null} in which case the call + * will have no effect. + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder managedDependency(@Nullable DependencyCoordinate managedDependency) { - super.managedDependency(managedDependency); + if (managedDependency != null) { + if (this.managedDependencies.isEmpty()) { + this.managedDependencies = new ArrayList<>(); + } + this.managedDependencies.add(managedDependency); + } return this; } + /** + * Specifies that the collection should be verbose. + * + * @param verbose whether the collection should be verbose or not + * @return this request for chaining, never {@code null} + */ @Nonnull - @Override public DependencyResolverRequestBuilder verbose(boolean verbose) { - super.verbose(verbose); + this.verbose = verbose; return this; } @Nonnull - public DependencyResolverRequestBuilder pathScope(@Nonnull PathScope pathScope) { + public DependencyResolverRequestBuilder pathScope(@Nullable PathScope pathScope) { this.pathScope = pathScope; return this; } @@ -200,10 +327,11 @@ public DependencyResolverRequestBuilder pathTypeFilter(@Nonnull Collection dependencies; + private final Collection managedDependencies; + private final boolean verbose; private final PathScope pathScope; - private final Predicate pathTypeFilter; + /** + * Creates a request with the specified properties. + * + * @param session {@link Session} + * @param rootArtifact The root dependency whose transitive dependencies should be collected, may be {@code + * null}. + */ DefaultDependencyResolverRequest( - Session session, - Project project, - Artifact rootArtifact, - DependencyCoordinate root, - Collection dependencies, - Collection managedDependencies, + @Nonnull Session session, + @Nonnull RequestType requestType, + @Nullable Project project, + @Nullable Artifact rootArtifact, + @Nullable DependencyCoordinate root, + @Nonnull Collection dependencies, + @Nonnull Collection managedDependencies, boolean verbose, - PathScope pathScope, - Predicate pathTypeFilter) { - super(session, project, rootArtifact, root, dependencies, managedDependencies, verbose); - this.pathScope = nonNull(pathScope, "pathScope cannot be null"); + @Nullable PathScope pathScope, + @Nullable Predicate pathTypeFilter) { + super(session); + this.requestType = nonNull(requestType, "requestType cannot be null"); + this.project = project; + this.rootArtifact = rootArtifact; + this.root = root; + this.dependencies = unmodifiable(nonNull(dependencies, "dependencies cannot be null")); + this.managedDependencies = + unmodifiable(nonNull(managedDependencies, "managedDependencies cannot be null")); + this.verbose = verbose; + this.pathScope = pathScope; this.pathTypeFilter = (pathTypeFilter != null) ? pathTypeFilter : (t) -> true; - if (verbose) { - throw new IllegalArgumentException("verbose cannot be true for resolving dependencies"); + if (verbose && requestType != RequestType.COLLECT) { + throw new IllegalArgumentException("verbose cannot only be true when collecting dependencies"); } } @Nonnull + @Override + public RequestType getRequestType() { + return requestType; + } + + @Nonnull + @Override + public Optional getProject() { + return Optional.ofNullable(project); + } + + @Nonnull + @Override + public Optional getRootArtifact() { + return Optional.ofNullable(rootArtifact); + } + + @Nonnull + @Override + public Optional getRoot() { + return Optional.ofNullable(root); + } + + @Nonnull + @Override + public Collection getDependencies() { + return dependencies; + } + + @Nonnull + @Override + public Collection getManagedDependencies() { + return managedDependencies; + } + + @Override + public boolean getVerbose() { + return verbose; + } + @Override public PathScope getPathScope() { return pathScope; @@ -248,6 +437,12 @@ public PathScope getPathScope() { public Predicate getPathTypeFilter() { return pathTypeFilter; } + + @Nonnull + @Override + public String toString() { + return getRoot() + " -> " + getDependencies(); + } } } } diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java index 9579ad6d17ad..e7ab86d01105 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverResult.java @@ -29,9 +29,32 @@ import org.apache.maven.api.PathType; import org.apache.maven.api.annotations.Experimental; import org.apache.maven.api.annotations.Nonnull; +import org.apache.maven.api.annotations.Nullable; +/** + * The result of a dependency resolution request. + * + * @since 4.0.0 + * @see DependencyResolver#resolve(DependencyResolverRequest) + */ @Experimental -public interface DependencyResolverResult extends DependencyCollectorResult { +public interface DependencyResolverResult { + + /** + * Gets the exceptions that occurred while building the dependency graph. + * + * @return the exceptions that occurred, never {@code null} + */ + @Nonnull + List getExceptions(); + + /** + * Gets the root node of the dependency graph. + * + * @return the root node of the dependency graph or {@code null} if none + */ + @Nullable + Node getRoot(); /** * The ordered list of the flattened dependency nodes. diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java index 348be6135b96..2247aa7b2edf 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java @@ -75,5 +75,5 @@ public interface ProjectBuilderResult { * @return the result of the dependency resolution for the project */ @Nonnull - Optional getDependencyResolverResult(); + Optional getDependencyResolverResult(); } diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index 464941d23cfc..d8a3a10f5748 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -596,39 +596,41 @@ public DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency depen } /** - * Shortcut for getService(DependencyCollector.class).collect(...) + * Shortcut for getService(DependencyResolver.class).collect(...) * - * @throws DependencyCollectorException if the dependency collection failed - * @see DependencyCollector#collect(Session, Artifact) + * @throws DependencyResolverException if the dependency collection failed + * @see DependencyResolver#collect(Session, Artifact) */ @Nonnull @Override public Node collectDependencies(@Nonnull Artifact artifact) { - return getService(DependencyCollector.class).collect(this, artifact).getRoot(); + return getService(DependencyResolver.class).collect(this, artifact).getRoot(); } /** - * Shortcut for getService(DependencyCollector.class).collect(...) + * Shortcut for getService(DependencyResolver.class).collect(...) * - * @throws DependencyCollectorException if the dependency collection failed - * @see DependencyCollector#collect(Session, Project) + * @throws DependencyResolverException if the dependency collection failed + * @see DependencyResolver#collect(Session, Project) */ @Nonnull @Override public Node collectDependencies(@Nonnull Project project) { - return getService(DependencyCollector.class).collect(this, project).getRoot(); + return getService(DependencyResolver.class).collect(this, project).getRoot(); } /** - * Shortcut for getService(DependencyCollector.class).collect(...) + * Shortcut for getService(DependencyResolver.class).collect(...) * - * @throws DependencyCollectorException if the dependency collection failed - * @see DependencyCollector#collect(Session, DependencyCoordinate) + * @throws DependencyResolverException if the dependency collection failed + * @see DependencyResolver#collect(Session, DependencyCoordinate) */ @Nonnull @Override public Node collectDependencies(@Nonnull DependencyCoordinate dependency) { - return getService(DependencyCollector.class).collect(this, dependency).getRoot(); + Node root = + getService(DependencyResolver.class).collect(this, dependency).getRoot(); + return root.getChildren().iterator().next(); } @Nonnull @@ -662,6 +664,7 @@ public Map> resolveDependencies( return getService(DependencyResolver.class) .resolve(DependencyResolverRequest.builder() .session(this) + .requestType(DependencyResolverRequest.RequestType.RESOLVE) .dependency(dependency) .pathScope(scope) .pathTypeFilter(desiredTypes) @@ -675,6 +678,7 @@ public Map> resolveDependencies( return getService(DependencyResolver.class) .resolve(DependencyResolverRequest.builder() .session(this) + .requestType(DependencyResolverRequest.RequestType.RESOLVE) .project(project) .pathScope(scope) .pathTypeFilter(desiredTypes) diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java deleted file mode 100644 index bd63ca128087..000000000000 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java +++ /dev/null @@ -1,109 +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 java.util.Collection; -import java.util.List; - -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.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; -import org.eclipse.aether.collection.CollectResult; -import org.eclipse.aether.collection.DependencyCollectionException; -import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; -import org.eclipse.aether.util.graph.transformer.ConflictResolver; - -import static org.apache.maven.internal.impl.Utils.nonNull; - -@Named -@Singleton -public class DefaultDependencyCollector implements DependencyCollector { - - @Nonnull - @Override - public DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest request) - throws DependencyCollectorException, IllegalArgumentException { - nonNull(request, "request"); - InternalSession session = InternalSession.from(request.getSession()); - - Artifact rootArtifact; - DependencyCoordinate root; - Collection dependencies; - Collection managedDependencies; - List remoteRepositories; - if (request.getProject().isPresent()) { - Project project = request.getProject().get(); - rootArtifact = project.getPomArtifact(); - root = null; - dependencies = project.getDependencies(); - managedDependencies = project.getManagedDependencies(); - remoteRepositories = session.getService(ProjectManager.class).getRemoteProjectRepositories(project); - } else { - rootArtifact = request.getRootArtifact().orElse(null); - root = request.getRoot().orElse(null); - dependencies = request.getDependencies(); - managedDependencies = request.getManagedDependencies(); - remoteRepositories = session.getRemoteRepositories(); - } - CollectRequest collectRequest = new CollectRequest() - .setRootArtifact(rootArtifact != null ? session.toArtifact(rootArtifact) : null) - .setRoot(root != null ? session.toDependency(root, false) : null) - .setDependencies(session.toDependencies(dependencies, false)) - .setManagedDependencies(session.toDependencies(managedDependencies, true)) - .setRepositories(session.toRepositories(remoteRepositories)); - - RepositorySystemSession systemSession = session.getSession(); - if (request.getVerbose()) { - systemSession = new DefaultRepositorySystemSession(systemSession) - .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true) - .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true); - } - - try { - final CollectResult result = - session.getRepositorySystem().collectDependencies(systemSession, collectRequest); - return new DependencyCollectorResult() { - @Override - public List getExceptions() { - return result.getExceptions(); - } - - @Override - public Node getRoot() { - return session.getNode(result.getRoot(), request.getVerbose()); - } - }; - } catch (DependencyCollectionException e) { - throw new DependencyCollectorException("Unable to collect dependencies", e); - } - } -} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java new file mode 100644 index 000000000000..1105c2ab5da6 --- /dev/null +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java @@ -0,0 +1,182 @@ +/* + * 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.io.IOException; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +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.Node; +import org.apache.maven.api.PathType; +import org.apache.maven.api.Session; +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.*; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.collection.CollectResult; +import org.eclipse.aether.collection.DependencyCollectionException; +import org.eclipse.aether.graph.DependencyFilter; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.util.graph.manager.DependencyManagerUtils; +import org.eclipse.aether.util.graph.transformer.ConflictResolver; + +import static org.apache.maven.internal.impl.Utils.cast; +import static org.apache.maven.internal.impl.Utils.map; +import static org.apache.maven.internal.impl.Utils.nonNull; + +@Named +@Singleton +public class DefaultDependencyResolver implements DependencyResolver { + + @Nonnull + @Override + public DependencyResolverResult collect(@Nonnull DependencyResolverRequest request) + throws DependencyResolverException, IllegalArgumentException { + nonNull(request, "request"); + InternalSession session = InternalSession.from(request.getSession()); + + Artifact rootArtifact; + DependencyCoordinate root; + Collection dependencies; + Collection managedDependencies; + List remoteRepositories; + if (request.getProject().isPresent()) { + Project project = request.getProject().get(); + rootArtifact = project.getPomArtifact(); + root = null; + dependencies = project.getDependencies(); + managedDependencies = project.getManagedDependencies(); + remoteRepositories = session.getService(ProjectManager.class).getRemoteProjectRepositories(project); + } else { + rootArtifact = request.getRootArtifact().orElse(null); + root = request.getRoot().orElse(null); + dependencies = request.getDependencies(); + managedDependencies = request.getManagedDependencies(); + remoteRepositories = session.getRemoteRepositories(); + } + CollectRequest collectRequest = new CollectRequest() + .setRootArtifact(rootArtifact != null ? session.toArtifact(rootArtifact) : null) + .setRoot(root != null ? session.toDependency(root, false) : null) + .setDependencies(session.toDependencies(dependencies, false)) + .setManagedDependencies(session.toDependencies(managedDependencies, true)) + .setRepositories(session.toRepositories(remoteRepositories)); + + RepositorySystemSession systemSession = session.getSession(); + if (request.getVerbose()) { + systemSession = new DefaultRepositorySystemSession(systemSession) + .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true) + .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true); + } + + try { + final CollectResult result = + session.getRepositorySystem().collectDependencies(systemSession, collectRequest); + return new DefaultDependencyResolverResult( + null, result.getExceptions(), session.getNode(result.getRoot(), request.getVerbose()), 0); + } catch (DependencyCollectionException e) { + throw new DependencyResolverException("Unable to collect dependencies", e); + } + } + + @Override + public List flatten(Session s, Node node, PathScope scope) throws DependencyResolverException { + InternalSession session = InternalSession.from(s); + DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode(); + List dependencies = session.getRepositorySystem() + .flattenDependencyNodes(session.getSession(), root, getScopeDependencyFilter(scope)); + dependencies.remove(root); + return map(dependencies, session::getNode); + } + + private static DependencyFilter getScopeDependencyFilter(PathScope scope) { + Set scopes = + scope.dependencyScopes().stream().map(DependencyScope::id).collect(Collectors.toSet()); + return (n, p) -> { + org.eclipse.aether.graph.Dependency d = n.getDependency(); + return d == null || scopes.contains(d.getScope()); + }; + } + + /** + * Collects, flattens and resolves the dependencies. + * + * @param request the request to resolve + * @return the result of the resolution + */ + @Override + public DependencyResolverResult resolve(DependencyResolverRequest request) + throws DependencyResolverException, DependencyResolverException, ArtifactResolverException { + InternalSession session = + InternalSession.from(nonNull(request, "request").getSession()); + DependencyResolverResult result; + DependencyResolverResult collectorResult = collect(request); + if (request.getRequestType() == DependencyResolverRequest.RequestType.COLLECT) { + result = collectorResult; + } else { + List nodes = flatten(session, collectorResult.getRoot(), request.getPathScope()); + List coordinates = nodes.stream() + .map(Node::getDependency) + .filter(Objects::nonNull) + .map(Artifact::toCoordinate) + .collect(Collectors.toList()); + Predicate filter = request.getPathTypeFilter(); + if (request.getRequestType() == DependencyResolverRequest.RequestType.FLATTEN) { + DefaultDependencyResolverResult flattenResult = new DefaultDependencyResolverResult( + null, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size()); + for (Node node : nodes) { + flattenResult.addNode(node); + } + result = flattenResult; + } else { + PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache. + DefaultDependencyResolverResult resolverResult = new DefaultDependencyResolverResult( + cache, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size()); + Map artifacts = session.resolveArtifacts(coordinates); + for (Node node : nodes) { + Dependency d = node.getDependency(); + Path path = (d != null) ? artifacts.get(d) : null; + try { + resolverResult.addDependency(node, d, filter, path); + } catch (IOException e) { + throw cannotReadModuleInfo(path, e); + } + } + result = resolverResult; + } + } + return result; + } + + private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) { + return new DependencyResolverException("Cannot read module information of " + path, cause); + } +} diff --git a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java index baf7b44424ae..ffad2adab514 100644 --- a/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java +++ b/maven-api-impl/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolverResult.java @@ -94,7 +94,7 @@ class DefaultDependencyResolverResult implements DependencyResolverResult { /** * Creates an initially empty result. Callers should add path elements by calls - * to {@link #addDependency(Node, Dependency, Predicate, Path, PathModularizationCache)}. + * to {@link #addDependency(Node, Dependency, Predicate, Path)}. * * @param cache cache of module information about each dependency * @param exceptions the exceptions that occurred while building the dependency graph @@ -201,6 +201,15 @@ void addOutputDirectory(Path main, Path test) throws IOException { } } + /** + * Adds a dependency node to the result. + * + * @param node the dependency node + */ + void addNode(Node node) { + nodes.add(node); + } + /** * Adds a dependency to the result. This method populates the {@link #nodes}, {@link #paths}, * {@link #dispatchedPaths} and {@link #dependencies} collections with the given arguments. 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 index b6e2bbc815da..750aa9c084e6 100644 --- 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 @@ -85,7 +85,7 @@ public static Session createSession() { injector.bindImplicit(DefaultArtifactInstaller.class); injector.bindImplicit(DefaultArtifactResolver.class); injector.bindImplicit(DefaultChecksumAlgorithmService.class); - injector.bindImplicit(DefaultDependencyCollector.class); + injector.bindImplicit(DefaultDependencyResolver.class); injector.bindImplicit(DefaultDependencyCoordinateFactory.class); injector.bindImplicit(DefaultLocalRepositoryManager.class); injector.bindImplicit(DefaultMessageBuilderFactory.class); diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java deleted file mode 100644 index 254ee13f06f8..000000000000 --- a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyResolver.java +++ /dev/null @@ -1,110 +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.Named; -import javax.inject.Singleton; - -import java.io.IOException; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Predicate; -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.Node; -import org.apache.maven.api.PathType; -import org.apache.maven.api.Session; -import org.apache.maven.api.services.*; -import org.eclipse.aether.graph.DependencyFilter; -import org.eclipse.aether.graph.DependencyNode; - -import static org.apache.maven.internal.impl.Utils.cast; -import static org.apache.maven.internal.impl.Utils.map; -import static org.apache.maven.internal.impl.Utils.nonNull; - -@Named -@Singleton -public class DefaultDependencyResolver implements DependencyResolver { - - @Override - public List flatten(Session s, Node node, PathScope scope) throws DependencyResolverException { - InternalSession session = InternalSession.from(s); - DependencyNode root = cast(AbstractNode.class, node, "node").getDependencyNode(); - List dependencies = session.getRepositorySystem() - .flattenDependencyNodes(session.getSession(), root, getScopeDependencyFilter(scope)); - dependencies.remove(root); - return map(dependencies, session::getNode); - } - - private static DependencyFilter getScopeDependencyFilter(PathScope scope) { - Set scopes = - scope.dependencyScopes().stream().map(DependencyScope::id).collect(Collectors.toSet()); - return (n, p) -> { - org.eclipse.aether.graph.Dependency d = n.getDependency(); - return d == null || scopes.contains(d.getScope()); - }; - } - - /** - * Collects, flattens and resolves the dependencies. - * - * @param request the request to resolve - * @return the result of the resolution - */ - @Override - public DependencyResolverResult resolve(DependencyResolverRequest request) - throws DependencyCollectorException, DependencyResolverException, ArtifactResolverException { - InternalSession session = - InternalSession.from(nonNull(request, "request").getSession()); - Predicate filter = request.getPathTypeFilter(); - PathModularizationCache cache = new PathModularizationCache(); // TODO: should be project-wide cache. - DependencyCollectorResult collectorResult = - session.getService(DependencyCollector.class).collect(request); - List nodes = flatten(session, collectorResult.getRoot(), request.getPathScope()); - List coordinates = nodes.stream() - .map(Node::getDependency) - .filter(Objects::nonNull) - .map(Artifact::toCoordinate) - .collect(Collectors.toList()); - Map artifacts = session.resolveArtifacts(coordinates); - DefaultDependencyResolverResult result = new DefaultDependencyResolverResult( - cache, collectorResult.getExceptions(), collectorResult.getRoot(), nodes.size()); - for (Node node : nodes) { - Dependency d = node.getDependency(); - Path path = (d != null) ? artifacts.get(d) : null; - try { - result.addDependency(node, d, filter, path); - } catch (IOException e) { - throw cannotReadModuleInfo(path, e); - } - } - return result; - } - - private static DependencyResolverException cannotReadModuleInfo(final Path path, final IOException cause) { - return new DependencyResolverException("Cannot read module information of " + path, cause); - } -} 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 d785dad9f82f..cbc2e0afd782 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 @@ -31,11 +31,10 @@ import java.util.List; import java.util.Optional; -import org.apache.maven.api.Node; import org.apache.maven.api.Project; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.services.BuilderProblem; -import org.apache.maven.api.services.DependencyCollectorResult; +import org.apache.maven.api.services.DependencyResolverResult; import org.apache.maven.api.services.ProjectBuilder; import org.apache.maven.api.services.ProjectBuilderException; import org.apache.maven.api.services.ProjectBuilderRequest; @@ -170,19 +169,10 @@ public Severity getSeverity() { @Nonnull @Override - public Optional getDependencyResolverResult() { + public Optional getDependencyResolverResult() { return Optional.ofNullable(res.getDependencyResolutionResult()) - .map(r -> new DependencyCollectorResult() { - @Override - public List getExceptions() { - return r.getCollectionErrors(); - } - - @Override - public Node getRoot() { - return session.getNode(r.getDependencyGraph()); - } - }); + .map(r -> new DefaultDependencyResolverResult( + null, r.getCollectionErrors(), session.getNode(r.getDependencyGraph()), 0)); } }; } catch (ProjectBuildingException e) { diff --git a/maven-core/src/main/resources/META-INF/maven/org.apache.maven.api.di.Inject b/maven-core/src/main/resources/META-INF/maven/org.apache.maven.api.di.Inject index 285f768d41fb..dbbc28f99d1e 100644 --- a/maven-core/src/main/resources/META-INF/maven/org.apache.maven.api.di.Inject +++ b/maven-core/src/main/resources/META-INF/maven/org.apache.maven.api.di.Inject @@ -11,8 +11,8 @@ org.apache.maven.internal.impl.DefaultArtifactFactory org.apache.maven.internal.impl.DefaultArtifactInstaller org.apache.maven.internal.impl.DefaultArtifactResolver org.apache.maven.internal.impl.DefaultChecksumAlgorithmService -org.apache.maven.internal.impl.DefaultDependencyCollector org.apache.maven.internal.impl.DefaultDependencyCoordinateFactory +org.apache.maven.internal.impl.DefaultDependencyResolver org.apache.maven.internal.impl.DefaultLocalRepositoryManager org.apache.maven.internal.impl.DefaultMessageBuilderFactory org.apache.maven.internal.impl.DefaultModelUrlNormalizer