This is an automated email from the ASF dual-hosted git repository. cstamas pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push: new 6caeda24 [MRESOLVER-687] Validator SPI (#671) 6caeda24 is described below commit 6caeda24f14a04fa7da2d19965cf04a526e9d1b7 Author: Tamas Cservenak <ta...@cservenak.net> AuthorDate: Wed Mar 19 13:03:31 2025 +0100 [MRESOLVER-687] Validator SPI (#671) A new extension point that validates values coming into main entry point, the repository system. Provides ability to "hook in" and validate values. Resolver by itself does NOT provide any validator, it is up to integrating app to provide one, if wants. --- https://issues.apache.org/jira/browse/MRESOLVER-687 --- .../aether/impl/RepositorySystemValidator.java | 61 ++++ .../internal/impl/DefaultRepositorySystem.java | 41 +-- .../impl/DefaultRepositorySystemValidator.java | 318 +++++++++++++++++++++ .../internal/impl/DefaultRepositorySystemTest.java | 3 +- .../eclipse/aether/spi/validator/Validator.java | 72 +++++ .../aether/spi/validator/ValidatorFactory.java | 36 +++ .../eclipse/aether/spi/validator/package-info.java | 43 +++ .../aether/supplier/RepositorySystemSupplier.java | 36 ++- .../aether/supplier/RepositorySystemSupplier.java | 36 ++- 9 files changed, 626 insertions(+), 20 deletions(-) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemValidator.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemValidator.java new file mode 100644 index 00000000..030f677b --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemValidator.java @@ -0,0 +1,61 @@ +/* + * 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.eclipse.aether.impl; + +import java.util.Collection; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRequest; + +/** + * Validator used by {@link org.eclipse.aether.RepositorySystem}. All method throw {@link IllegalArgumentException}. + */ +public interface RepositorySystemValidator { + void validateVersionRequest(RepositorySystemSession session, VersionRequest request); + + void validateVersionRangeRequest(RepositorySystemSession session, VersionRangeRequest request); + + void validateArtifactDescriptorRequest(RepositorySystemSession session, ArtifactDescriptorRequest request); + + void validateArtifactRequests(RepositorySystemSession session, Collection<? extends ArtifactRequest> requests); + + void validateMetadataRequests(RepositorySystemSession session, Collection<? extends MetadataRequest> requests); + + void validateCollectRequest(RepositorySystemSession session, CollectRequest request); + + void validateDependencyRequest(RepositorySystemSession session, DependencyRequest request); + + void validateInstallRequest(RepositorySystemSession session, InstallRequest request); + + void validateDeployRequest(RepositorySystemSession session, DeployRequest request); + + void validateLocalRepositories(RepositorySystemSession session, Collection<LocalRepository> repositories); + + void validateRemoteRepositories(RepositorySystemSession session, Collection<RemoteRepository> repositories); +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java index 11ea54d1..947e079d 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java @@ -25,6 +25,7 @@ import javax.inject.Singleton; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -57,6 +58,7 @@ import org.eclipse.aether.impl.LocalRepositoryProvider; import org.eclipse.aether.impl.MetadataResolver; import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.impl.RepositorySystemValidator; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.installation.InstallRequest; @@ -133,7 +135,9 @@ public class DefaultRepositorySystem implements RepositorySystem { private final RepositorySystemLifecycle repositorySystemLifecycle; - protected final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories; + private final Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories; + + private final RepositorySystemValidator repositorySystemValidator; @SuppressWarnings("checkstyle:parameternumber") @Inject @@ -150,7 +154,8 @@ public class DefaultRepositorySystem implements RepositorySystem { SyncContextFactory syncContextFactory, RemoteRepositoryManager remoteRepositoryManager, RepositorySystemLifecycle repositorySystemLifecycle, - Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories) { + Map<String, ArtifactDecoratorFactory> artifactDecoratorFactories, + RepositorySystemValidator repositorySystemValidator) { this.shutdown = new AtomicBoolean(false); this.sessionIdCounter = new AtomicInteger(0); this.versionResolver = requireNonNull(versionResolver, "version resolver cannot be null"); @@ -171,6 +176,8 @@ public class DefaultRepositorySystem implements RepositorySystem { requireNonNull(repositorySystemLifecycle, "repository system lifecycle cannot be null"); this.artifactDecoratorFactories = requireNonNull(artifactDecoratorFactories, "artifact decorator factories cannot be null"); + this.repositorySystemValidator = + requireNonNull(repositorySystemValidator, "repository system validator cannot be null"); } @Override @@ -178,7 +185,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws VersionResolutionException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateVersionRequest(session, request); return versionResolver.resolveVersion(session, request); } @@ -187,7 +194,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws VersionRangeResolutionException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateVersionRangeRequest(session, request); return versionRangeResolver.resolveVersionRange(session, request); } @@ -196,7 +203,7 @@ public class DefaultRepositorySystem implements RepositorySystem { RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateArtifactDescriptorRequest(session, request); ArtifactDescriptorResult descriptorResult = artifactDescriptorReader.readArtifactDescriptor(session, request); for (ArtifactDecorator decorator : Utils.getArtifactDecorators(session, artifactDecoratorFactories)) { descriptorResult.setArtifact(decorator.decorateArtifact(descriptorResult)); @@ -209,7 +216,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws ArtifactResolutionException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateArtifactRequests(session, Collections.singleton(request)); return artifactResolver.resolveArtifact(session, request); } @@ -219,7 +226,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws ArtifactResolutionException { validateSession(session); requireNonNull(requests, "requests cannot be null"); - + repositorySystemValidator.validateArtifactRequests(session, requests); return artifactResolver.resolveArtifacts(session, requests); } @@ -228,7 +235,7 @@ public class DefaultRepositorySystem implements RepositorySystem { RepositorySystemSession session, Collection<? extends MetadataRequest> requests) { validateSession(session); requireNonNull(requests, "requests cannot be null"); - + repositorySystemValidator.validateMetadataRequests(session, requests); return metadataResolver.resolveMetadata(session, requests); } @@ -237,7 +244,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws DependencyCollectionException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateCollectRequest(session, request); return dependencyCollector.collectDependencies(session, request); } @@ -246,7 +253,7 @@ public class DefaultRepositorySystem implements RepositorySystem { throws DependencyResolutionException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateDependencyRequest(session, request); RequestTrace trace = RequestTrace.newChild(request.getTrace(), request); DependencyResult result = new DependencyResult(request); @@ -360,7 +367,7 @@ public class DefaultRepositorySystem implements RepositorySystem { public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateInstallRequest(session, request); return installer.install(session, request); } @@ -368,7 +375,7 @@ public class DefaultRepositorySystem implements RepositorySystem { public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException { validateSession(session); requireNonNull(request, "request cannot be null"); - + repositorySystemValidator.validateDeployRequest(session, request); return deployer.deploy(session, request); } @@ -378,7 +385,7 @@ public class DefaultRepositorySystem implements RepositorySystem { requireNonNull(session, "session cannot be null"); requireNonNull(localRepository, "localRepository cannot be null"); validateSystem(); - + repositorySystemValidator.validateLocalRepositories(session, Collections.singleton(localRepository)); return createLocalRepositoryManager(session, localRepository); } @@ -388,7 +395,7 @@ public class DefaultRepositorySystem implements RepositorySystem { requireNonNull(session, "session cannot be null"); requireNonNull(localRepositories, "localRepositories cannot be null"); validateSystem(); - + repositorySystemValidator.validateLocalRepositories(session, Arrays.asList(localRepositories)); return createLocalRepositoryManager(session, Arrays.asList(localRepositories)); } @@ -398,7 +405,7 @@ public class DefaultRepositorySystem implements RepositorySystem { requireNonNull(session, "session cannot be null"); requireNonNull(localRepositories, "localRepositories cannot be null"); validateSystem(); - + repositorySystemValidator.validateLocalRepositories(session, localRepositories); return createLocalRepositoryManager(session, localRepositories); } @@ -437,7 +444,7 @@ public class DefaultRepositorySystem implements RepositorySystem { RepositorySystemSession session, List<RemoteRepository> repositories) { validateSession(session); validateRepositories(repositories); - + repositorySystemValidator.validateRemoteRepositories(session, repositories); repositories = remoteRepositoryManager.aggregateRepositories(session, new ArrayList<>(), repositories, true); return repositories; } @@ -446,7 +453,7 @@ public class DefaultRepositorySystem implements RepositorySystem { public RemoteRepository newDeploymentRepository(RepositorySystemSession session, RemoteRepository repository) { validateSession(session); requireNonNull(repository, "repository cannot be null"); - + repositorySystemValidator.validateRemoteRepositories(session, Collections.singletonList(repository)); RemoteRepository.Builder builder = new RemoteRepository.Builder(repository); Authentication auth = session.getAuthenticationSelector().getAuthentication(repository); builder.setAuthentication(auth); diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java new file mode 100644 index 00000000..15c85f20 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemValidator.java @@ -0,0 +1,318 @@ +/* + * 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.eclipse.aether.internal.impl; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.deployment.DeployRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.impl.RepositorySystemValidator; +import org.eclipse.aether.installation.InstallRequest; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactDescriptorRequest; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.MetadataRequest; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRequest; +import org.eclipse.aether.spi.validator.Validator; +import org.eclipse.aether.spi.validator.ValidatorFactory; + +import static java.util.Objects.requireNonNull; + +@Singleton +@Named +public class DefaultRepositorySystemValidator implements RepositorySystemValidator { + private final List<ValidatorFactory> validatorFactories; + + @Inject + public DefaultRepositorySystemValidator(List<ValidatorFactory> validatorFactories) { + this.validatorFactories = requireNonNull(validatorFactories, "validatorFactories cannot be null"); + } + + private void mayThrow(List<Exception> exceptions, String message) { + if (!exceptions.isEmpty()) { + IllegalArgumentException result = new IllegalArgumentException(message); + exceptions.forEach(result::addSuppressed); + throw result; + } + } + + @Override + public void validateVersionRequest(RepositorySystemSession session, VersionRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + try { + validator.validateArtifact(request.getArtifact()); + } catch (Exception e) { + exceptions.add(e); + } + for (RemoteRepository repository : request.getRepositories()) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Version Request: " + request); + } + + @Override + public void validateVersionRangeRequest(RepositorySystemSession session, VersionRangeRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + try { + validator.validateArtifact(request.getArtifact()); + } catch (Exception e) { + exceptions.add(e); + } + for (RemoteRepository repository : request.getRepositories()) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Version Range Request: " + request); + } + + @Override + public void validateArtifactDescriptorRequest(RepositorySystemSession session, ArtifactDescriptorRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + try { + validator.validateArtifact(request.getArtifact()); + } catch (Exception e) { + exceptions.add(e); + } + for (RemoteRepository repository : request.getRepositories()) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Artifact Descriptor Request: " + request); + } + + @Override + public void validateArtifactRequests( + RepositorySystemSession session, Collection<? extends ArtifactRequest> requests) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (ArtifactRequest request : requests) { + try { + validator.validateArtifact(request.getArtifact()); + } catch (Exception e) { + exceptions.add(e); + } + for (RemoteRepository repository : request.getRepositories()) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + } + mayThrow(exceptions, "Invalid Artifact Requests: " + requests); + } + + @Override + public void validateMetadataRequests( + RepositorySystemSession session, Collection<? extends MetadataRequest> requests) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (MetadataRequest request : requests) { + try { + validator.validateMetadata(request.getMetadata()); + } catch (Exception e) { + exceptions.add(e); + } + try { + if (request.getRepository() != null) { + validator.validateRemoteRepository(request.getRepository()); + } + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Metadata Requests: " + requests); + } + + @Override + public void validateCollectRequest(RepositorySystemSession session, CollectRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + if (request.getRootArtifact() != null) { + try { + validator.validateArtifact(request.getRootArtifact()); + } catch (Exception e) { + exceptions.add(e); + } + } + if (request.getRoot() != null) { + try { + validator.validateDependency(request.getRoot()); + } catch (Exception e) { + exceptions.add(e); + } + } + for (Dependency dependency : request.getDependencies()) { + try { + validator.validateDependency(dependency); + } catch (Exception e) { + exceptions.add(e); + } + } + for (Dependency managedDependency : request.getManagedDependencies()) { + try { + validator.validateDependency(managedDependency); + } catch (Exception e) { + exceptions.add(e); + } + } + for (RemoteRepository repository : request.getRepositories()) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Collect Request: " + request); + } + + @Override + public void validateDependencyRequest(RepositorySystemSession session, DependencyRequest request) { + if (request.getCollectRequest() != null) { + try { + validateCollectRequest(session, request.getCollectRequest()); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid Dependency Request: " + request, e); + } + } + } + + @Override + public void validateInstallRequest(RepositorySystemSession session, InstallRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (Artifact artifact : request.getArtifacts()) { + try { + validator.validateArtifact(artifact); + } catch (Exception e) { + exceptions.add(e); + } + } + for (Metadata metadata : request.getMetadata()) { + try { + validator.validateMetadata(metadata); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid Install Request: " + request); + } + + @Override + public void validateDeployRequest(RepositorySystemSession session, DeployRequest request) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (Artifact artifact : request.getArtifacts()) { + try { + validator.validateArtifact(artifact); + } catch (Exception e) { + exceptions.add(e); + } + } + for (Metadata metadata : request.getMetadata()) { + try { + validator.validateMetadata(metadata); + } catch (Exception e) { + exceptions.add(e); + } + } + try { + if (request.getRepository() != null) { + validator.validateRemoteRepository(request.getRepository()); + } + } catch (Exception e) { + exceptions.add(e); + } + } + mayThrow(exceptions, "Invalid Deploy Request: " + request); + } + + @Override + public void validateLocalRepositories(RepositorySystemSession session, Collection<LocalRepository> repositories) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (LocalRepository repository : repositories) { + try { + validator.validateLocalRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid LocalRepositories: " + repositories); + } + + @Override + public void validateRemoteRepositories(RepositorySystemSession session, Collection<RemoteRepository> repositories) { + ArrayList<Exception> exceptions = new ArrayList<>(); + for (ValidatorFactory factory : validatorFactories) { + Validator validator = factory.newInstance(session); + for (RemoteRepository repository : repositories) { + try { + validator.validateRemoteRepository(repository); + } catch (Exception e) { + exceptions.add(e); + } + } + } + mayThrow(exceptions, "Invalid RemoteRepositories: " + repositories); + } +} diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java index aa554d49..08b75df3 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemTest.java @@ -66,7 +66,8 @@ public class DefaultRepositorySystemTest { new DefaultRemoteRepositoryManager( new DefaultUpdatePolicyAnalyzer(), new DefaultChecksumPolicyProvider()), new DefaultRepositorySystemLifecycle(), - Collections.emptyMap()); + Collections.emptyMap(), + new DefaultRepositorySystemValidator(Collections.emptyList())); session = TestUtils.newSession(); } diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java new file mode 100644 index 00000000..b4175760 --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/Validator.java @@ -0,0 +1,72 @@ +/* + * 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.eclipse.aether.spi.validator; + +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.metadata.Metadata; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; + +/** + * A repository system main input validator; this validator is used in repository system "main entry methods". + * + * @since 2.0.8 + */ +public interface Validator { + /** + * Validates artifact. + * + * @param artifact The artifact to validate, never {@code null}. + * @throws IllegalArgumentException if artifact is invalid. + */ + default void validateArtifact(Artifact artifact) throws IllegalArgumentException {} + + /** + * Validates metadata. + * + * @param metadata The metadata to validate, never {@code null}. + * @throws IllegalArgumentException if artifact is invalid. + */ + default void validateMetadata(Metadata metadata) throws IllegalArgumentException {} + + /** + * Validates dependency. + * + * @param dependency The dependency to validate, never {@code null}. + * @throws IllegalArgumentException if dependency is invalid. + */ + default void validateDependency(Dependency dependency) throws IllegalArgumentException {} + + /** + * Validates local repository. + * + * @param localRepository The local repository to validate, never {@code null}. + * @throws IllegalArgumentException if local repository is invalid. + */ + default void validateLocalRepository(LocalRepository localRepository) throws IllegalArgumentException {} + + /** + * Validates remote repository. + * + * @param remoteRepository The remote repository to validate, never {@code null}. + * @throws IllegalArgumentException if remote repository is invalid. + */ + default void validateRemoteRepository(RemoteRepository remoteRepository) throws IllegalArgumentException {} +} diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java new file mode 100644 index 00000000..23e59a8f --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/ValidatorFactory.java @@ -0,0 +1,36 @@ +/* + * 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.eclipse.aether.spi.validator; + +import org.eclipse.aether.RepositorySystemSession; + +/** + * A factory to create validators. + * + * @since 2.0.8 + */ +public interface ValidatorFactory { + /** + * Creates a new validator for the session. + * + * @param session The repository system session from which to configure the validator, must not be {@code null}. + * @return The validator for the session, never {@code null}. + */ + Validator newInstance(RepositorySystemSession session); +} diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/package-info.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/package-info.java new file mode 100644 index 00000000..b90abbc2 --- /dev/null +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/validator/package-info.java @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/** + * Validator SPI. + * <p> + * This package provides callback extension points, that are invoked + * from Repository System, that is "main entry point" to Resolver. + * Validator is invoked before artifact would be resolved, installed or deployed. Given + * Resolver treats all coordinate elements as opaque strings, this extension + * provides ability for integrating application for early detection of any + * unwanted operation or bug, like "leaks" of un-interpolated artifacts + * asked to be resolved/installed/deployed. Resolver itself have no + * notion of "interpolation" nor "placeholders", again, it handles + * all received coordinates as opaque string and uses them to build + * resource URIs according to layout, but still, it is 100% that + * un-interpolated value will result in "no artifact found" error + * in case of resolution, but it may be and usually is due user + * error like having a typo in some property in POM for example. + * <p> + * Resolver does NOT provide this component, and is fully operable + * without it. It is left to integrating apps to decide do they + * want to provide components like this or not. + * + * @since 2.0.8 + */ +package org.eclipse.aether.spi.validator; diff --git a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java index a1616deb..851d3f8a 100644 --- a/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java +++ b/maven-resolver-supplier-mvn3/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java @@ -18,7 +18,9 @@ */ package org.eclipse.aether.supplier; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -50,6 +52,7 @@ import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.RepositoryConnectorProvider; import org.eclipse.aether.impl.RepositoryEventDispatcher; import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.impl.RepositorySystemValidator; import org.eclipse.aether.impl.UpdateCheckManager; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; import org.eclipse.aether.impl.VersionRangeResolver; @@ -72,6 +75,7 @@ import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemValidator; import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; import org.eclipse.aether.internal.impl.DefaultTransporterProvider; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; @@ -133,6 +137,7 @@ import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; import org.eclipse.aether.spi.synccontext.SyncContextFactory; +import org.eclipse.aether.spi.validator.ValidatorFactory; import org.eclipse.aether.transport.apache.ApacheTransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.util.version.GenericVersionScheme; @@ -1031,6 +1036,34 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> { return new DefaultModelCacheFactory(); } + private List<ValidatorFactory> validatorFactories; + + public final List<ValidatorFactory> getValidatorFactories() { + checkClosed(); + if (validatorFactories == null) { + validatorFactories = createValidatorFactories(); + } + return validatorFactories; + } + + protected List<ValidatorFactory> createValidatorFactories() { + return new ArrayList<>(); + } + + private RepositorySystemValidator repositorySystemValidator; + + public final RepositorySystemValidator getRepositorySystemValidator() { + checkClosed(); + if (repositorySystemValidator == null) { + repositorySystemValidator = createRepositorySystemValidator(); + } + return repositorySystemValidator; + } + + protected RepositorySystemValidator createRepositorySystemValidator() { + return new DefaultRepositorySystemValidator(getValidatorFactories()); + } + private RepositorySystem repositorySystem; public final RepositorySystem getRepositorySystem() { @@ -1055,7 +1088,8 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> { getSyncContextFactory(), getRemoteRepositoryManager(), getRepositorySystemLifecycle(), - getArtifactDecoratorFactories()); + getArtifactDecoratorFactories(), + getRepositorySystemValidator()); } @Override diff --git a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java index ca3f1ac6..220ca806 100644 --- a/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java +++ b/maven-resolver-supplier-mvn4/src/main/java/org/eclipse/aether/supplier/RepositorySystemSupplier.java @@ -18,8 +18,10 @@ */ package org.eclipse.aether.supplier; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -54,6 +56,7 @@ import org.eclipse.aether.impl.RemoteRepositoryManager; import org.eclipse.aether.impl.RepositoryConnectorProvider; import org.eclipse.aether.impl.RepositoryEventDispatcher; import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.impl.RepositorySystemValidator; import org.eclipse.aether.impl.UpdateCheckManager; import org.eclipse.aether.impl.UpdatePolicyAnalyzer; import org.eclipse.aether.impl.VersionRangeResolver; @@ -76,6 +79,7 @@ import org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher; import org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider; import org.eclipse.aether.internal.impl.DefaultRepositorySystem; import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemValidator; import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; import org.eclipse.aether.internal.impl.DefaultTransporterProvider; import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager; @@ -137,6 +141,7 @@ import org.eclipse.aether.spi.io.PathProcessor; import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory; import org.eclipse.aether.spi.resolution.ArtifactResolverPostProcessor; import org.eclipse.aether.spi.synccontext.SyncContextFactory; +import org.eclipse.aether.spi.validator.ValidatorFactory; import org.eclipse.aether.transport.apache.ApacheTransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.util.version.GenericVersionScheme; @@ -1056,6 +1061,34 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> { return new DefaultModelCacheFactory(); } + private List<ValidatorFactory> validatorFactories; + + public final List<ValidatorFactory> getValidatorFactories() { + checkClosed(); + if (validatorFactories == null) { + validatorFactories = createValidatorFactories(); + } + return validatorFactories; + } + + protected List<ValidatorFactory> createValidatorFactories() { + return new ArrayList<>(); + } + + private RepositorySystemValidator repositorySystemValidator; + + public final RepositorySystemValidator getRepositorySystemValidator() { + checkClosed(); + if (repositorySystemValidator == null) { + repositorySystemValidator = createRepositorySystemValidator(); + } + return repositorySystemValidator; + } + + protected RepositorySystemValidator createRepositorySystemValidator() { + return new DefaultRepositorySystemValidator(getValidatorFactories()); + } + private RepositorySystem repositorySystem; public final RepositorySystem getRepositorySystem() { @@ -1080,7 +1113,8 @@ public class RepositorySystemSupplier implements Supplier<RepositorySystem> { getSyncContextFactory(), getRemoteRepositoryManager(), getRepositorySystemLifecycle(), - getArtifactDecoratorFactories()); + getArtifactDecoratorFactories(), + getRepositorySystemValidator()); } @Override