diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java index 8fe24c1ab5..ad19ffece0 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java @@ -8,9 +8,9 @@ * 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 @@ -20,7 +20,6 @@ */ import java.util.Map; -import java.util.function.Consumer; import org.eclipse.aether.artifact.ArtifactTypeRegistry; import org.eclipse.aether.collection.DependencyGraphTransformer; @@ -44,7 +43,7 @@ * create a subclass and implement {@link #getSession()}. */ public abstract class AbstractForwardingRepositorySystemSession - implements RepositorySystemSession + implements RepositorySystemSession { /** @@ -58,7 +57,7 @@ protected AbstractForwardingRepositorySystemSession() * Gets the repository system session to which this instance forwards calls. It's worth noting that this class does * not save/cache the returned reference but queries this method before each forwarding. Hence, the session * forwarded to may change over time or depending on the context (e.g. calling thread). - * + * * @return The repository system session to forward calls to, never {@code null}. */ protected abstract RepositorySystemSession getSession(); @@ -212,19 +211,13 @@ public RepositoryCache getCache() { return getSession().getCache(); } - + @Override public FileTransformerManager getFileTransformerManager() { return getSession().getFileTransformerManager(); } - @Override - public final void addOnCloseHandler( Consumer handler ) - { - getSession().addOnCloseHandler( handler ); - } - @Override public final boolean isClosed() { @@ -232,14 +225,15 @@ public final boolean isClosed() } /** - * This method is special: by default it throws (nested session should never be closed), the "top level" session - * should be closed instead. Still, this method is NOT {@code final}, to allow implementations overriding it, - * and in case when needed, handle forwarded session as "top level" session. + * This method is special: by default it does nothing, to allow proper resource-like handling of this session, + * and assumes that forwarded session will be closed on some higher level. + *

+ * Still, this method is NOT {@code final}, allowing implementations to override it, in case when needed, handle + * forwarded session as "top level" session. */ @Override public void close() { - throw new IllegalStateException( "Forwarding session should not be closed, " - + "close the top-level (forwarded) session instead." ); + // nothing } } diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java index 7ed9313a50..95c9cf1dcf 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java @@ -8,9 +8,9 @@ * 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 @@ -19,16 +19,11 @@ * under the License. */ -import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static java.util.Objects.requireNonNull; - -import java.util.Collection; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.ArtifactType; @@ -54,6 +49,8 @@ import org.eclipse.aether.transform.FileTransformer; import org.eclipse.aether.transform.FileTransformerManager; +import static java.util.Objects.requireNonNull; + /** * A simple repository system session. *

@@ -61,9 +58,15 @@ * initialization phase and that the session itself is not changed once initialized and being used by the repository * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent * accidental manipulation of it afterwards. + *

+ * WARNING: onCloseHandler registered with instances of this class are NOT executed when instances of this class are + * closed! They are executed when the repository system is shut down! + * + * @deprecated Use {@link RepositorySystem#newRepositorySystemSession()} to obtain session instances. */ +@Deprecated public final class DefaultRepositorySystemSession - implements RepositorySystemSession + implements MutableRepositorySystemSession { private final AtomicBoolean closed; @@ -130,7 +133,10 @@ public final class DefaultRepositorySystemSession * Creates an uninitialized session. Note: The new session is not ready to use, as a bare minimum, * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also * need to be customized to achieve meaningful behavior. + * + * @deprecated Use {@link RepositorySystem#newRepositorySystemSession()} instead. */ + @Deprecated public DefaultRepositorySystemSession() { closed = new AtomicBoolean( false ); @@ -155,7 +161,9 @@ public DefaultRepositorySystemSession() * copied and will be shared with the original session unless reconfigured. * * @param session The session to copy, must not be {@code null}. + * @deprecated Use {@link RepositorySystem#newRepositorySystemSession(RepositorySystemSession)} instead. */ + @Deprecated public DefaultRepositorySystemSession( RepositorySystemSession session ) { requireNonNull( session, "repository system session cannot be null" ); @@ -196,7 +204,7 @@ public boolean isOffline() /** * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote * repositories. - * + * * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise. * @return This session for chaining, never {@code null}. */ @@ -215,9 +223,10 @@ public boolean isIgnoreArtifactDescriptorRepositories() /** * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency * collection. If enabled, only the repositories originally provided with the collect request will be considered. - * + * * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact - * descriptors, {@code false} to merge those with the originally specified repositories. + * descriptors, {@code false} to merge those with the originally + * specified repositories. * @return This session for chaining, never {@code null}. */ public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories( @@ -235,9 +244,9 @@ public ResolutionErrorPolicy getResolutionErrorPolicy() /** * Sets the policy which controls whether resolutions errors from remote repositories should be cached. - * + * * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution - * errors should generally not be cached. + * errors should generally not be cached. * @return This session for chaining, never {@code null}. */ public DefaultRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy ) @@ -254,9 +263,9 @@ public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() /** * Sets the policy which controls how errors related to reading artifact descriptors should be handled. - * + * * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor - * errors should generally not be tolerated. + * errors should generally not be tolerated. * @return This session for chaining, never {@code null}. */ public DefaultRepositorySystemSession setArtifactDescriptorPolicy( @@ -275,7 +284,7 @@ public String getChecksumPolicy() /** * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote * repositories being used for resolution. - * + * * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies. * @return This session for chaining, never {@code null}. * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL @@ -297,7 +306,7 @@ public String getUpdatePolicy() /** * Sets the global update policy. If set, the global update policy overrides the update policies of the remote * repositories being used for resolution. - * + * * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies. * @return This session for chaining, never {@code null}. * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS @@ -325,7 +334,7 @@ public LocalRepositoryManager getLocalRepositoryManager() /** * Sets the local repository manager used during this session. Note: Eventually, a valid session must have * a local repository manager set. - * + * * @param localRepositoryManager The local repository manager used during this session, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -361,7 +370,7 @@ public WorkspaceReader getWorkspaceReader() /** * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first * to resolve artifacts. - * + * * @param workspaceReader The workspace reader for this session, may be {@code null} if none. * @return This session for chaining, never {@code null}. */ @@ -379,7 +388,7 @@ public RepositoryListener getRepositoryListener() /** * Sets the listener being notified of actions in the repository system. - * + * * @param repositoryListener The repository listener, may be {@code null} if none. * @return This session for chaining, never {@code null}. */ @@ -397,7 +406,7 @@ public TransferListener getTransferListener() /** * Sets the listener being notified of uploads/downloads by the repository system. - * + * * @param transferListener The transfer listener, may be {@code null} if none. * @return This session for chaining, never {@code null}. */ @@ -446,7 +455,7 @@ public Map getSystemProperties() *

* Note: System properties are of type {@code Map} and any key-value pair in the input map * that doesn't match this type will be silently ignored. - * + * * @param systemProperties The system properties, may be {@code null} or empty if none. * @return This session for chaining, never {@code null}. */ @@ -460,8 +469,8 @@ public DefaultRepositorySystemSession setSystemProperties( Map systemPrope /** * Sets the specified system property. - * - * @param key The property key, must not be {@code null}. + * + * @param key The property key, must not be {@code null}. * @param value The property value, may be {@code null} to remove/unset the property. * @return This session for chaining, never {@code null}. */ @@ -491,7 +500,7 @@ public Map getUserProperties() *

* Note: User properties are of type {@code Map} and any key-value pair in the input map * that doesn't match this type will be silently ignored. - * + * * @param userProperties The user properties, may be {@code null} or empty if none. * @return This session for chaining, never {@code null}. */ @@ -505,8 +514,8 @@ public DefaultRepositorySystemSession setUserProperties( Map userPropertie /** * Sets the specified user property. - * - * @param key The property key, must not be {@code null}. + * + * @param key The property key, must not be {@code null}. * @param value The property value, may be {@code null} to remove/unset the property. * @return This session for chaining, never {@code null}. */ @@ -535,7 +544,7 @@ public Map getConfigProperties() *

* Note: Configuration properties are of type {@code Map} and any key-value pair in the * input map that doesn't match this type will be silently ignored. - * + * * @param configProperties The configuration properties, may be {@code null} or empty if none. * @return This session for chaining, never {@code null}. */ @@ -549,8 +558,8 @@ public DefaultRepositorySystemSession setConfigProperties( Map configPrope /** * Sets the specified configuration property. - * - * @param key The property key, must not be {@code null}. + * + * @param key The property key, must not be {@code null}. * @param value The property value, may be {@code null} to remove/unset the property. * @return This session for chaining, never {@code null}. */ @@ -577,7 +586,7 @@ public MirrorSelector getMirrorSelector() * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is * not used for remote repositories which are passed as request parameters to the repository system, those * repositories are supposed to denote the effective repositories. - * + * * @param mirrorSelector The mirror selector to use, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -601,7 +610,7 @@ public ProxySelector getProxySelector() * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is * not used for remote repositories which are passed as request parameters to the repository system, those * repositories are supposed to have their proxy (if any) already set. - * + * * @param proxySelector The proxy selector to use, may be {@code null}. * @return This session for chaining, never {@code null}. * @see org.eclipse.aether.repository.RemoteRepository#getProxy() @@ -626,7 +635,7 @@ public AuthenticationSelector getAuthenticationSelector() * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this * selector is not used for remote repositories which are passed as request parameters to the repository system, * those repositories are supposed to have their authentication (if any) already set. - * + * * @param authenticationSelector The authentication selector to use, may be {@code null}. * @return This session for chaining, never {@code null}. * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication() @@ -649,7 +658,7 @@ public ArtifactTypeRegistry getArtifactTypeRegistry() /** * Sets the registry of artifact types recognized by this session. - * + * * @param artifactTypeRegistry The artifact type registry, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -671,7 +680,7 @@ public DependencyTraverser getDependencyTraverser() /** * Sets the dependency traverser to use for building dependency graphs. - * + * * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -689,7 +698,7 @@ public DependencyManager getDependencyManager() /** * Sets the dependency manager to use for building dependency graphs. - * + * * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -707,7 +716,7 @@ public DependencySelector getDependencySelector() /** * Sets the dependency selector to use for building dependency graphs. - * + * * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -725,9 +734,9 @@ public VersionFilter getVersionFilter() /** * Sets the version filter to use for building dependency graphs. - * + * * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter - * versions. + * versions. * @return This session for chaining, never {@code null}. */ public DefaultRepositorySystemSession setVersionFilter( VersionFilter versionFilter ) @@ -744,9 +753,9 @@ public DependencyGraphTransformer getDependencyGraphTransformer() /** * Sets the dependency graph transformer to use for building dependency graphs. - * + * * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be - * {@code null}. + * {@code null}. * @return This session for chaining, never {@code null}. */ public DefaultRepositorySystemSession setDependencyGraphTransformer( @@ -764,7 +773,7 @@ public SessionData getData() /** * Sets the custom data associated with this session. - * + * * @param data The session data, may be {@code null}. * @return This session for chaining, never {@code null}. */ @@ -786,7 +795,7 @@ public RepositoryCache getCache() /** * Sets the cache the repository system may use to save data for future reuse during the session. - * + * * @param cache The repository cache, may be {@code null} if none. * @return This session for chaining, never {@code null}. */ @@ -823,7 +832,7 @@ private void verifyStateForMutation() } static class NullProxySelector - implements ProxySelector + implements ProxySelector { public static final ProxySelector INSTANCE = new NullProxySelector(); @@ -837,7 +846,7 @@ public Proxy getProxy( RemoteRepository repository ) } static class NullMirrorSelector - implements MirrorSelector + implements MirrorSelector { public static final MirrorSelector INSTANCE = new NullMirrorSelector(); @@ -851,7 +860,7 @@ public RemoteRepository getMirror( RemoteRepository repository ) } static class NullAuthenticationSelector - implements AuthenticationSelector + implements AuthenticationSelector { public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector(); @@ -865,7 +874,7 @@ public Authentication getAuthentication( RemoteRepository repository ) } static final class NullArtifactTypeRegistry - implements ArtifactTypeRegistry + implements ArtifactTypeRegistry { public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry(); @@ -888,20 +897,6 @@ public Collection getTransformersForArtifact( Artifact artifact } } - private final CopyOnWriteArrayList> onCloseHandlers - = new CopyOnWriteArrayList<>(); - - @Override - public void addOnCloseHandler( Consumer handler ) - { - requireNonNull( handler, "handler cannot be null" ); - if ( closed.get() ) - { - throw new IllegalStateException( "repository system session is already closed" ); - } - onCloseHandlers.add( 0, handler ); - } - @Override public boolean isClosed() { @@ -911,21 +906,6 @@ public boolean isClosed() @Override public void close() { - if ( closed.compareAndSet( false, true ) ) - { - ArrayList exceptions = new ArrayList<>(); - for ( Consumer onCloseHandler : onCloseHandlers ) - { - try - { - onCloseHandler.accept( this ); - } - catch ( Exception e ) - { - exceptions.add( e ); - } - } - MultiRuntimeException.mayThrow( "session on-close handler failures", exceptions ); - } + closed.set( true ); } } diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/MutableRepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/MutableRepositorySystemSession.java new file mode 100644 index 0000000000..c2470857a9 --- /dev/null +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/MutableRepositorySystemSession.java @@ -0,0 +1,325 @@ +package org.eclipse.aether; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; +import org.eclipse.aether.transform.FileTransformerManager; + +/** + * A mutable repository system session. + * + * @since 1.9.0 + */ +public interface MutableRepositorySystemSession + extends RepositorySystemSession +{ + + /** + * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote + * repositories. + * + * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setOffline( boolean offline ); + + /** + * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency + * collection. If enabled, only the repositories originally provided with the collect request will be considered. + * + * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact + * descriptors, {@code false} to merge those with the originally + * specified repositories. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setIgnoreArtifactDescriptorRepositories( + boolean ignoreArtifactDescriptorRepositories ); + + /** + * Sets the policy which controls whether resolutions errors from remote repositories should be cached. + * + * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution + * errors should generally not be cached. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy ); + + /** + * Sets the policy which controls how errors related to reading artifact descriptors should be handled. + * + * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor + * errors should generally not be tolerated. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setArtifactDescriptorPolicy( ArtifactDescriptorPolicy artifactDescriptorPolicy ); + + /** + * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote + * repositories being used for resolution. + * + * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL + * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE + * @see RepositoryPolicy#CHECKSUM_POLICY_WARN + */ + MutableRepositorySystemSession setChecksumPolicy( String checksumPolicy ); + + /** + * Sets the global update policy. If set, the global update policy overrides the update policies of the remote + * repositories being used for resolution. + * + * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS + * @see RepositoryPolicy#UPDATE_POLICY_DAILY + * @see RepositoryPolicy#UPDATE_POLICY_NEVER + */ + MutableRepositorySystemSession setUpdatePolicy( String updatePolicy ); + + /** + * Sets the local repository manager used during this session. Note: Eventually, a valid session must have + * a local repository manager set. + * + * @param localRepositoryManager The local repository manager used during this session, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setLocalRepositoryManager( LocalRepositoryManager localRepositoryManager ); + + /** + * Sets file transformer manager. Deprecated, without replacement. + * + * @return This session for chaining, never {@code null}. + */ + @Deprecated + MutableRepositorySystemSession setFileTransformerManager( FileTransformerManager fileTransformerManager ); + + /** + * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first + * to resolve artifacts. + * + * @param workspaceReader The workspace reader for this session, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader ); + + /** + * Sets the listener being notified of actions in the repository system. + * + * @param repositoryListener The repository listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener ); + + /** + * Sets the listener being notified of uploads/downloads by the repository system. + * + * @param transferListener The transfer listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setTransferListener( TransferListener transferListener ); + + /** + * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually + * collected from the runtime environment like {@link System#getProperties()} and environment variables. + *

+ * Note: System properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param systemProperties The system properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setSystemProperties( Map systemProperties ); + + /** + * Sets the specified system property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setSystemProperty( String key, String value ); + + /** + * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to + * system properties but are set on the discretion of the user and hence are considered of higher priority than + * system properties in case of conflicts. + *

+ * Note: User properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param userProperties The user properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setUserProperties( Map userProperties ); + + /** + * Sets the specified user property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setUserProperty( String key, String value ); + + /** + * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling, + * connector-specific behavior, etc.). + *

+ * Note: Configuration properties are of type {@code Map} and any key-value pair in the + * input map that doesn't match this type will be silently ignored. + * + * @param configProperties The configuration properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setConfigProperties( Map configProperties ); + + /** + * Sets the specified configuration property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setConfigProperty( String key, Object value ); + + /** + * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to denote the effective repositories. + * + * @param mirrorSelector The mirror selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector ); + + /** + * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to have their proxy (if any) already set. + * + * @param proxySelector The proxy selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see RemoteRepository#getProxy() + */ + MutableRepositorySystemSession setProxySelector( ProxySelector proxySelector ); + + /** + * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this + * selector is not used for remote repositories which are passed as request parameters to the repository system, + * those repositories are supposed to have their authentication (if any) already set. + * + * @param authenticationSelector The authentication selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see RemoteRepository#getAuthentication() + */ + MutableRepositorySystemSession setAuthenticationSelector( AuthenticationSelector authenticationSelector ); + + /** + * Sets the registry of artifact types recognized by this session. + * + * @param artifactTypeRegistry The artifact type registry, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry ); + + /** + * Sets the dependency traverser to use for building dependency graphs. + * + * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser ); + + /** + * Sets the dependency manager to use for building dependency graphs. + * + * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setDependencyManager( DependencyManager dependencyManager ); + + /** + * Sets the dependency selector to use for building dependency graphs. + * + * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setDependencySelector( DependencySelector dependencySelector ); + + /** + * Sets the version filter to use for building dependency graphs. + * + * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter + * versions. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setVersionFilter( VersionFilter versionFilter ); + + /** + * Sets the dependency graph transformer to use for building dependency graphs. + * + * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be + * {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setDependencyGraphTransformer( + DependencyGraphTransformer dependencyGraphTransformer ); + + /** + * Sets the custom data associated with this session. + * + * @param data The session data, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setData( SessionData data ); + + /** + * Sets the cache the repository system may use to save data for future reuse during the session. + * + * @param cache The repository cache, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + MutableRepositorySystemSession setCache( RepositoryCache cache ); + + /** + * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception. + * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable + * though. + */ + void setReadOnly(); +} diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java index e6c30f30b6..88d563d538 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java @@ -8,9 +8,9 @@ * 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 @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.List; +import java.util.function.Consumer; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.collection.CollectRequest; @@ -58,7 +59,10 @@ * The main entry point to the repository system and its functionality. Note that obtaining a concrete implementation of * this interface (e.g. via dependency injection, service locator, etc.) is dependent on the application and its * specific needs, please consult the online documentation for examples and directions on booting the system. - * + *

+ * When the repository system or the application that is using is about to exist, invoke the {@link #shutdown()} to let + * resolver system perform possible resource cleanups. + * * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. */ @@ -73,21 +77,21 @@ public interface RepositorySystem *

* The supplied request may also refer to a single concrete version rather than a version range. In this case * though, the result contains simply the (parsed) input version, regardless of the repositories and their contents. - * + * * @param session The repository session, must not be {@code null}. * @param request The version range request, must not be {@code null}. * @return The version range result, never {@code null}. * @throws VersionRangeResolutionException If the requested range could not be parsed. Note that an empty range does - * not raise an exception. + * not raise an exception. * @see #newResolutionRepositories(RepositorySystemSession, List) */ VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) - throws VersionRangeResolutionException; + throws VersionRangeResolutionException; /** * Resolves an artifact's meta version (if any) to a concrete version. For example, resolves "1.0-SNAPSHOT" to * "1.0-20090208.132618-23". - * + * * @param session The repository session, must not be {@code null}. * @param request The version request, must not be {@code null}. * @return The version result, never {@code null}. @@ -95,11 +99,11 @@ VersionRangeResult resolveVersionRange( RepositorySystemSession session, Version * @see #newResolutionRepositories(RepositorySystemSession, List) */ VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) - throws VersionResolutionException; + throws VersionResolutionException; /** * Gets information about an artifact like its direct dependencies and potential relocations. - * + * * @param session The repository session, must not be {@code null}. * @param request The descriptor request, must not be {@code null}. * @return The descriptor result, never {@code null}. @@ -109,13 +113,13 @@ VersionResult resolveVersion( RepositorySystemSession session, VersionRequest re */ ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) - throws ArtifactDescriptorException; + throws ArtifactDescriptorException; /** * Collects the transitive dependencies of an artifact and builds a dependency graph. Note that this operation is * only concerned about determining the coordinates of the transitive dependencies. To also resolve the actual * artifact files, use {@link #resolveDependencies(RepositorySystemSession, DependencyRequest)}. - * + * * @param session The repository session, must not be {@code null}. * @param request The collection request, must not be {@code null}. * @return The collection result, never {@code null}. @@ -128,29 +132,29 @@ ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session * @see #newResolutionRepositories(RepositorySystemSession, List) */ CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request ) - throws DependencyCollectionException; + throws DependencyCollectionException; /** * Collects and resolves the transitive dependencies of an artifact. This operation is essentially a combination of * {@link #collectDependencies(RepositorySystemSession, CollectRequest)} and * {@link #resolveArtifacts(RepositorySystemSession, Collection)}. - * + * * @param session The repository session, must not be {@code null}. * @param request The dependency request, must not be {@code null}. * @return The dependency result, never {@code null}. * @throws DependencyResolutionException If the dependency tree could not be built or any dependency artifact could - * not be resolved. + * not be resolved. * @see #newResolutionRepositories(RepositorySystemSession, List) */ DependencyResult resolveDependencies( RepositorySystemSession session, DependencyRequest request ) - throws DependencyResolutionException; + throws DependencyResolutionException; /** * Resolves the path for an artifact. The artifact will be downloaded to the local repository if necessary. An * artifact that is already resolved will be skipped and is not re-resolved. In general, callers must not assume any * relationship between an artifact's resolved filename and its coordinates. Note that this method assumes that any * relocations have already been processed. - * + * * @param session The repository session, must not be {@code null}. * @param request The resolution request, must not be {@code null}. * @return The resolution result, never {@code null}. @@ -159,15 +163,15 @@ DependencyResult resolveDependencies( RepositorySystemSession session, Dependenc * @see #newResolutionRepositories(RepositorySystemSession, List) */ ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request ) - throws ArtifactResolutionException; + throws ArtifactResolutionException; /** * Resolves the paths for a collection of artifacts. Artifacts will be downloaded to the local repository if * necessary. Artifacts that are already resolved will be skipped and are not re-resolved. In general, callers must * not assume any relationship between an artifact's filename and its coordinates. Note that this method assumes * that any relocations have already been processed. - * - * @param session The repository session, must not be {@code null}. + * + * @param session The repository session, must not be {@code null}. * @param requests The resolution requests, must not be {@code null}. * @return The resolution results (in request order), never {@code null}. * @throws ArtifactResolutionException If any artifact could not be resolved. @@ -176,13 +180,13 @@ ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest */ List resolveArtifacts( RepositorySystemSession session, Collection requests ) - throws ArtifactResolutionException; + throws ArtifactResolutionException; /** * Resolves the paths for a collection of metadata. Metadata will be downloaded to the local repository if * necessary, e.g. because it hasn't been cached yet or the cache is deemed outdated. - * - * @param session The repository session, must not be {@code null}. + * + * @param session The repository session, must not be {@code null}. * @param requests The resolution requests, must not be {@code null}. * @return The resolution results (in request order), never {@code null}. * @see Metadata#getFile() @@ -193,18 +197,18 @@ List resolveMetadata( RepositorySystemSession session, /** * Installs a collection of artifacts and their accompanying metadata to the local repository. - * + * * @param session The repository session, must not be {@code null}. * @param request The installation request, must not be {@code null}. * @return The installation result, never {@code null}. * @throws InstallationException If any artifact/metadata from the request could not be installed. */ InstallResult install( RepositorySystemSession session, InstallRequest request ) - throws InstallationException; + throws InstallationException; /** * Uploads a collection of artifacts and their accompanying metadata to a remote repository. - * + * * @param session The repository session, must not be {@code null}. * @param request The deployment request, must not be {@code null}. * @return The deployment result, never {@code null}. @@ -212,29 +216,30 @@ InstallResult install( RepositorySystemSession session, InstallRequest request ) * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) */ DeployResult deploy( RepositorySystemSession session, DeployRequest request ) - throws DeploymentException; + throws DeploymentException; /** * Creates a new manager for the specified local repository. If the specified local repository has no type, the * default local repository type of the system will be used. Note: It is expected that this method * invocation is one of the last steps of setting up a new session, in particular any configuration properties * should have been set already. - * - * @param session The repository system session from which to configure the manager, must not be {@code null}. + * + * @param session The repository system session from which to configure the manager, must not be + * {@code null}. * @param localRepository The local repository to create a manager for, must not be {@code null}. * @return The local repository manager, never {@code null}. * @throws IllegalArgumentException If the specified repository type is not recognized or no base directory is - * given. + * given. */ LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository localRepository ); /** * Creates a new synchronization context. - * + * * @param session The repository session during which the context will be used, must not be {@code null}. - * @param shared A flag indicating whether access to the artifacts/metadata associated with the new context can be - * shared among concurrent readers or whether access needs to be exclusive to the calling thread. + * @param shared A flag indicating whether access to the artifacts/metadata associated with the new context can be + * shared among concurrent readers or whether access needs to be exclusive to the calling thread. * @return The synchronization context, never {@code null}. */ SyncContext newSyncContext( RepositorySystemSession session, boolean shared ); @@ -247,13 +252,14 @@ LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession sessio * to already carry any required authentication or proxy configuration. This method can be used to apply the * authentication/proxy configuration from a session to a bare repository definition to obtain the complete * repository definition for use in the resolution request. - * - * @param session The repository system session from which to configure the repositories, must not be {@code null}. + * + * @param session The repository system session from which to configure the repositories, must not be + * {@code null}. * @param repositories The repository prototypes from which to derive the resolution repositories, must not be - * {@code null} or contain {@code null} elements. + * {@code null} or contain {@code null} elements. * @return The resolution repositories, never {@code null}. Note that there is generally no 1:1 relationship of the - * obtained repositories to the original inputs due to mirror selection potentially aggregating multiple - * repositories. + * obtained repositories to the original inputs due to mirror selection potentially aggregating multiple + * repositories. * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository) */ List newResolutionRepositories( RepositorySystemSession session, @@ -267,13 +273,68 @@ List newResolutionRepositories( RepositorySystemSession sessio * required authentication or proxy configuration. This method can be used to apply the authentication/proxy * configuration from a session to a bare repository definition to obtain the complete repository definition for use * in the deploy request. - * - * @param session The repository system session from which to configure the repository, must not be {@code null}. + * + * @param session The repository system session from which to configure the repository, must not be {@code null}. * @param repository The repository prototype from which to derive the deployment repository, must not be - * {@code null}. + * {@code null}. * @return The deployment repository, never {@code null}. * @see #newResolutionRepositories(RepositorySystemSession, List) */ RemoteRepository newDeploymentRepository( RepositorySystemSession session, RemoteRepository repository ); + /** + * Creates a new repository system session. Returned session instance must be treated as a resource, best in + * try-with-resource construct. + *

+ * Creates an uninitialized session. Note: The new session is not ready to use, as a bare minimum, + * {@link MutableRepositorySystemSession#setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but + * usually other settings also need to be customized to achieve meaningful behavior. + * + * @return The new instance of mutable repository system session, never {@code null}. + * @since 1.9.0 + */ + MutableRepositorySystemSession newRepositorySystemSession(); + + /** + * Creates a shallow copy repository system session. Consider {@link AbstractForwardingRepositorySystemSession} as + * well. Returned session instance must be treated as a resource, best in try-with-resource construct. + *

+ * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding + * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself + * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not + * copied and will be shared with the original session unless reconfigured. + * + * @param session The repository system session from which to create copy, must not be {@code null}. + * @return The new instance of mutable repository system session, never {@code null}. + * @since 1.9.0 + */ + MutableRepositorySystemSession newRepositorySystemSession( RepositorySystemSession session ); + + /** + * Registers an "on session end" handler, executed when given session is closed. + * + * @param session The repository system session for which to register handler, must not be {@code null}. + * @param handler The handler, must not be {@code null}. + * @since 1.9.0 + */ + void addOnSessionEndedHandler( RepositorySystemSession session, Consumer handler ); + + /** + * Registers an "on system end" handler, executed when repository system is shut down. + * + * @param handler The handler, must not be {@code null}. + * @since 1.9.0 + */ + void addOnSystemEndedHandler( Runnable handler ); + + /** + * Signals to repository system to shut down. Shut down instance is not to be used anymore. + *

+ * Repository system may perform some resource cleanup, if applicable. Not using this method may cause leaks or + * unclean shutdown of some subsystem. Best to integrate this method into some container hook, or integrating + * application invoke it directly on shut down, depending on how resolver is integrated. + * + * @since 1.9.0 + */ + void shutdown(); } diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java index 2046176360..8e24e1820b 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java @@ -43,8 +43,20 @@ /** * Defines settings and components that control the repository system. Once initialized, the session object itself is * supposed to be immutable and hence can safely be shared across an entire application and any concurrent threads - * reading it. Components that wish to tweak some aspects of an existing session should use the copy constructor of - * {@link DefaultRepositorySystemSession} and its mutators to derive a custom session. + * reading it. Components that wish to tweak some aspects of an existing session should use the copy method of + * {@link RepositorySystem#newRepositorySystemSession(RepositorySystemSession)} and its mutators to derive a custom + * session. + *

+ * Session implements {@link AutoCloseable} and should be treated as a resource, best within try-with-resource block. + * To obtain new session instance use {@link RepositorySystem#newRepositorySystemSession()}. Ideally, in applications + * there is only one "top level" session created (in other words, same session instance is reused during one execution). + * In case of derived sessions, depending on use case, the following should be done: for "throwaway" + * sessions (created/derived used locally, within a method or some clearly isolated block) the + * derived session should be "boxed" within "top level" session, in a nested try-with-resource construct. In + * other cases, when resolver session is to be "swapped out" (code receives session already created, and needs to + * derive it, and then continue execution with it), the best is to use forwarding + * {@link AbstractForwardingRepositorySystemSession} class with + * {@link AbstractForwardingRepositorySystemSession#close()} method overridden to close original "top level" session. * * @noimplement This interface is not intended to be implemented by clients. * @noextend This interface is not intended to be extended by clients. @@ -272,16 +284,6 @@ public interface RepositorySystemSession extends AutoCloseable @Deprecated FileTransformerManager getFileTransformerManager(); - /** - * Adds "on close" handler to this session, it must not be {@code null}. Note: when handlers are invoked, the - * passed in (this) session is ALREADY CLOSED (the {@link #isClosed()} method returns {@code true}). This implies, - * that handlers cannot use {@link RepositorySystem} to resolve/collect/and so on, handlers are meant to perform - * some internal cleanup on session close. Attempt to add handler to closed session will throw. - * - * @since 1.9.0 - */ - void addOnCloseHandler( Consumer handler ); - /** * Returns {@code true} if this instance was already closed. Closed sessions should NOT be used anymore. * @@ -292,8 +294,9 @@ public interface RepositorySystemSession extends AutoCloseable /** * Closes this session and possibly releases related resources by invoking "on close" handlers added by - * {@link #addOnCloseHandler(Consumer)} method. This method may be invoked multiple times, - * but only first invocation will actually invoke handlers, subsequent invocations will be no-op. + * {@link RepositorySystem#addOnSessionEndedHandler(RepositorySystemSession, Consumer)} method. This method may be + * invoked multiple times, but only first invocation will actually invoke handlers, subsequent invocations will be + * no-op. *

* When close action happens, all the registered handlers will be invoked (even if some throws), and at end * of operation a {@link MultiRuntimeException} may be thrown signaling that some handler(s) failed. This exception @@ -306,8 +309,8 @@ public interface RepositorySystemSession extends AutoCloseable * "on close" handler registrations, but those registrations are passed to delegated session, and will be invoked * once the "top level" (delegated) session is closed. *

- * New session "copy" instances created using copy-constructor - * {@link DefaultRepositorySystemSession#DefaultRepositorySystemSession(RepositorySystemSession)} result in new, + * New session "copy" instances created using + * {@link RepositorySystem#newRepositorySystemSession(RepositorySystemSession)} method result in new, * independent session instances, and they do NOT share states like "read-only", "closed" and "on close handlers" * with the copied session. Hence, they should be treated as "top level" sessions as well. *

diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java index 7b4e8f4746..69cfc2c83b 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/DefaultServiceLocator.java @@ -31,6 +31,7 @@ import static java.util.Objects.requireNonNull; import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.internal.impl.LocalPathComposer; import org.eclipse.aether.internal.impl.DefaultLocalPathComposer; import org.eclipse.aether.internal.impl.DefaultArtifactResolver; @@ -229,6 +230,7 @@ public DefaultServiceLocator() addService( ChecksumAlgorithmFactorySelector.class, DefaultChecksumAlgorithmFactorySelector.class ); addService( LocalPathComposer.class, DefaultLocalPathComposer.class ); addService( RemoteRepositoryFilterManager.class, DefaultRemoteRepositoryFilterManager.class ); + addService( RepositorySystemLifecycle.class, DefaultRepositorySystemLifecycle.class ); } private Entry getEntry( Class type, boolean create ) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java new file mode 100644 index 0000000000..3f89cb7c9f --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/RepositorySystemLifecycle.java @@ -0,0 +1,98 @@ +package org.eclipse.aether.impl; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.function.Consumer; + +import org.eclipse.aether.AbstractForwardingRepositorySystemSession; +import org.eclipse.aether.MutableRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.LocalRepositoryManager; + +/** + * Lifecycle managing component for repository system and session. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * @provisional This type is provisional and can be changed, moved or removed without prior notice. + * @since 1.9.0 + */ +public interface RepositorySystemLifecycle +{ + /** + * Creates a new repository system session. Returned session instance must be treated as a resource, best in + * try-with-resource construct. + *

+ * Throws if repository system is already shut down. + *

+ * Creates an initialized session, ready to use. Note: The new session is ready to use, as a bare minimum, + * {@link MutableRepositorySystemSession#setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but + * usually other settings also need to be customized to achieve meaningful behavior. + * + * @return The new instance of mutable repository system session, never {@code null}. + */ + MutableRepositorySystemSession newRepositorySystemSession(); + + /** + * Creates a shallow copy repository system session. Consider {@link AbstractForwardingRepositorySystemSession} as + * well. Returned session instance must be treated as a resource, best in try-with-resource construct. + *

+ * Throws if repository system is already shut down. + *

+ * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding + * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself + * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not + * copied and will be shared with the original session unless reconfigured. + * + * @param session The repository system session from which to create copy, must not be {@code null}. + * @return The new instance of mutable repository system session, never {@code null}. + */ + MutableRepositorySystemSession newRepositorySystemSession( RepositorySystemSession session ); + + /** + * Marks the specified session as ended: the "on session close" handlers registered for session will be invoked, + * if any. + *

+ * Throws if repository system is already shut down. + * + * @param session The repository system session that ended, must not be {@code null}. + */ + void sessionEnded( RepositorySystemSession session ); + + /** + * Marks the repository system as ended (shut down): all "on close" handlers will be invoked (even for the + * sessions). This method may be invoked multiple times, only once will execute, subsequent calls will be no-op. + */ + void systemEnded(); + + /** + * Registers an "on session end" handler. + *

+ * Throws if repository system is already shut down. + */ + void addOnSessionEndedHandler( RepositorySystemSession session, Consumer handler ); + + /** + * Registers an "on system end" handler. + *

+ * Throws if repository system is already shut down. + */ + void addOnSystemEndedHandler( Runnable handler ); +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java index 33db93168d..54e047889b 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/impl/guice/AetherModule.java @@ -41,7 +41,9 @@ 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.internal.impl.DefaultLocalPathPrefixComposerFactory; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.internal.impl.LocalPathComposer; import org.eclipse.aether.internal.impl.DefaultLocalPathComposer; import org.eclipse.aether.internal.impl.DefaultTrackingFileManager; @@ -64,6 +66,8 @@ import org.eclipse.aether.internal.impl.resolution.TrustedChecksumsArtifactResolverPostProcessor; import org.eclipse.aether.internal.impl.synccontext.DefaultSyncContextFactory; import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; +import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector; +import org.eclipse.aether.internal.impl.synccontext.named.ParameterizedNamedLockFactorySelector; import org.eclipse.aether.internal.impl.synccontext.named.providers.DiscriminatingNameMapperProvider; import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider; import org.eclipse.aether.internal.impl.synccontext.named.providers.FileHashingGAVNameMapperProvider; @@ -222,6 +226,10 @@ protected void configure() bind( ChecksumAlgorithmFactorySelector.class ) .to( DefaultChecksumAlgorithmFactorySelector.class ).in ( Singleton.class ); + bind( RepositorySystemLifecycle.class ) + .to( DefaultRepositorySystemLifecycle.class ).in( Singleton.class ); + + bind( NamedLockFactorySelector.class ).toInstance( new ParameterizedNamedLockFactorySelector() ); bind( SyncContextFactory.class ).to( DefaultSyncContextFactory.class ).in( Singleton.class ); bind( org.eclipse.aether.impl.SyncContextFactory.class ) .to( org.eclipse.aether.internal.impl.synccontext.legacy.DefaultSyncContextFactory.class ) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultCloseableRepositorySystemSession.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultCloseableRepositorySystemSession.java new file mode 100644 index 0000000000..b717492a46 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultCloseableRepositorySystemSession.java @@ -0,0 +1,903 @@ +package org.eclipse.aether.internal.impl; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.aether.DefaultSessionData; +import org.eclipse.aether.MutableRepositorySystemSession; +import org.eclipse.aether.RepositoryCache; +import org.eclipse.aether.RepositoryListener; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.SessionData; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactType; +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.collection.DependencyGraphTransformer; +import org.eclipse.aether.collection.DependencyManager; +import org.eclipse.aether.collection.DependencySelector; +import org.eclipse.aether.collection.DependencyTraverser; +import org.eclipse.aether.collection.VersionFilter; +import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.repository.Authentication; +import org.eclipse.aether.repository.AuthenticationSelector; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.LocalRepositoryManager; +import org.eclipse.aether.repository.MirrorSelector; +import org.eclipse.aether.repository.Proxy; +import org.eclipse.aether.repository.ProxySelector; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.repository.WorkspaceReader; +import org.eclipse.aether.resolution.ArtifactDescriptorPolicy; +import org.eclipse.aether.resolution.ResolutionErrorPolicy; +import org.eclipse.aether.transfer.TransferListener; +import org.eclipse.aether.transform.FileTransformer; +import org.eclipse.aether.transform.FileTransformerManager; + +import static java.util.Objects.requireNonNull; + +/** + * A closeable repository system session implementation. + * + * @since 1.9.0 + */ +final class DefaultCloseableRepositorySystemSession + implements MutableRepositorySystemSession +{ + private final RepositorySystemLifecycle repositorySystemLifecycle; + + private final AtomicBoolean closed; + + private boolean readOnly; + + private boolean offline; + + private boolean ignoreArtifactDescriptorRepositories; + + private ResolutionErrorPolicy resolutionErrorPolicy; + + private ArtifactDescriptorPolicy artifactDescriptorPolicy; + + private String checksumPolicy; + + private String updatePolicy; + + private LocalRepositoryManager localRepositoryManager; + + @Deprecated + private FileTransformerManager fileTransformerManager; + + private WorkspaceReader workspaceReader; + + private RepositoryListener repositoryListener; + + private TransferListener transferListener; + + private Map systemProperties; + + private Map systemPropertiesView; + + private Map userProperties; + + private Map userPropertiesView; + + private Map configProperties; + + private Map configPropertiesView; + + private MirrorSelector mirrorSelector; + + private ProxySelector proxySelector; + + private AuthenticationSelector authenticationSelector; + + private ArtifactTypeRegistry artifactTypeRegistry; + + private DependencyTraverser dependencyTraverser; + + private DependencyManager dependencyManager; + + private DependencySelector dependencySelector; + + private VersionFilter versionFilter; + + private DependencyGraphTransformer dependencyGraphTransformer; + + private SessionData data; + + private RepositoryCache cache; + + /** + * Creates an uninitialized session. Note: The new session is not ready to use, as a bare minimum, + * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also + * need to be customized to achieve meaningful behavior. + */ + DefaultCloseableRepositorySystemSession( RepositorySystemLifecycle repositorySystemLifecycle ) + { + this.repositorySystemLifecycle = requireNonNull( repositorySystemLifecycle ); + closed = new AtomicBoolean( false ); + systemProperties = new HashMap<>(); + systemPropertiesView = Collections.unmodifiableMap( systemProperties ); + userProperties = new HashMap<>(); + userPropertiesView = Collections.unmodifiableMap( userProperties ); + configProperties = new HashMap<>(); + configPropertiesView = Collections.unmodifiableMap( configProperties ); + mirrorSelector = NullMirrorSelector.INSTANCE; + proxySelector = NullProxySelector.INSTANCE; + authenticationSelector = NullAuthenticationSelector.INSTANCE; + artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE; + fileTransformerManager = NullFileTransformerManager.INSTANCE; + data = new DefaultSessionData(); + } + + /** + * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding + * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself + * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not + * copied and will be shared with the original session unless reconfigured. + * + * @param session The session to copy, must not be {@code null}. + */ + DefaultCloseableRepositorySystemSession( RepositorySystemLifecycle repositorySystemLifecycle, + RepositorySystemSession session ) + { + requireNonNull( session, "repository system session cannot be null" ); + + this.repositorySystemLifecycle = requireNonNull( repositorySystemLifecycle ); + closed = new AtomicBoolean( false ); + setOffline( session.isOffline() ); + setIgnoreArtifactDescriptorRepositories( session.isIgnoreArtifactDescriptorRepositories() ); + setResolutionErrorPolicy( session.getResolutionErrorPolicy() ); + setArtifactDescriptorPolicy( session.getArtifactDescriptorPolicy() ); + setChecksumPolicy( session.getChecksumPolicy() ); + setUpdatePolicy( session.getUpdatePolicy() ); + setLocalRepositoryManager( session.getLocalRepositoryManager() ); + setWorkspaceReader( session.getWorkspaceReader() ); + setRepositoryListener( session.getRepositoryListener() ); + setTransferListener( session.getTransferListener() ); + setSystemProperties( session.getSystemProperties() ); + setUserProperties( session.getUserProperties() ); + setConfigProperties( session.getConfigProperties() ); + setMirrorSelector( session.getMirrorSelector() ); + setProxySelector( session.getProxySelector() ); + setAuthenticationSelector( session.getAuthenticationSelector() ); + setArtifactTypeRegistry( session.getArtifactTypeRegistry() ); + setDependencyTraverser( session.getDependencyTraverser() ); + setDependencyManager( session.getDependencyManager() ); + setDependencySelector( session.getDependencySelector() ); + setVersionFilter( session.getVersionFilter() ); + setDependencyGraphTransformer( session.getDependencyGraphTransformer() ); + setFileTransformerManager( session.getFileTransformerManager() ); + setData( session.getData() ); + setCache( session.getCache() ); + } + + public boolean isOffline() + { + return offline; + } + + public DefaultCloseableRepositorySystemSession setOffline( boolean offline ) + { + verifyStateForMutation(); + this.offline = offline; + return this; + } + + public boolean isIgnoreArtifactDescriptorRepositories() + { + return ignoreArtifactDescriptorRepositories; + } + + public DefaultCloseableRepositorySystemSession setIgnoreArtifactDescriptorRepositories( + boolean ignoreArtifactDescriptorRepositories ) + { + verifyStateForMutation(); + this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories; + return this; + } + + public ResolutionErrorPolicy getResolutionErrorPolicy() + { + return resolutionErrorPolicy; + } + + /** + * Sets the policy which controls whether resolutions errors from remote repositories should be cached. + * + * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution + * errors should generally not be cached. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setResolutionErrorPolicy( + ResolutionErrorPolicy resolutionErrorPolicy ) + { + verifyStateForMutation(); + this.resolutionErrorPolicy = resolutionErrorPolicy; + return this; + } + + public ArtifactDescriptorPolicy getArtifactDescriptorPolicy() + { + return artifactDescriptorPolicy; + } + + /** + * Sets the policy which controls how errors related to reading artifact descriptors should be handled. + * + * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor + * errors should generally not be tolerated. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setArtifactDescriptorPolicy( + ArtifactDescriptorPolicy artifactDescriptorPolicy ) + { + verifyStateForMutation(); + this.artifactDescriptorPolicy = artifactDescriptorPolicy; + return this; + } + + public String getChecksumPolicy() + { + return checksumPolicy; + } + + /** + * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote + * repositories being used for resolution. + * + * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL + * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE + * @see RepositoryPolicy#CHECKSUM_POLICY_WARN + */ + public DefaultCloseableRepositorySystemSession setChecksumPolicy( String checksumPolicy ) + { + verifyStateForMutation(); + this.checksumPolicy = checksumPolicy; + return this; + } + + public String getUpdatePolicy() + { + return updatePolicy; + } + + /** + * Sets the global update policy. If set, the global update policy overrides the update policies of the remote + * repositories being used for resolution. + * + * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies. + * @return This session for chaining, never {@code null}. + * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS + * @see RepositoryPolicy#UPDATE_POLICY_DAILY + * @see RepositoryPolicy#UPDATE_POLICY_NEVER + */ + public DefaultCloseableRepositorySystemSession setUpdatePolicy( String updatePolicy ) + { + verifyStateForMutation(); + this.updatePolicy = updatePolicy; + return this; + } + + public LocalRepository getLocalRepository() + { + LocalRepositoryManager lrm = getLocalRepositoryManager(); + return ( lrm != null ) ? lrm.getRepository() : null; + } + + public LocalRepositoryManager getLocalRepositoryManager() + { + return localRepositoryManager; + } + + /** + * Sets the local repository manager used during this session. Note: Eventually, a valid session must have + * a local repository manager set. + * + * @param localRepositoryManager The local repository manager used during this session, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setLocalRepositoryManager( + LocalRepositoryManager localRepositoryManager ) + { + verifyStateForMutation(); + this.localRepositoryManager = localRepositoryManager; + return this; + } + + @Deprecated + @Override + public FileTransformerManager getFileTransformerManager() + { + return fileTransformerManager; + } + + @Deprecated + @Override + public DefaultCloseableRepositorySystemSession setFileTransformerManager( + FileTransformerManager fileTransformerManager ) + { + verifyStateForMutation(); + this.fileTransformerManager = fileTransformerManager; + if ( this.fileTransformerManager == null ) + { + this.fileTransformerManager = NullFileTransformerManager.INSTANCE; + } + return this; + } + + public WorkspaceReader getWorkspaceReader() + { + return workspaceReader; + } + + /** + * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first + * to resolve artifacts. + * + * @param workspaceReader The workspace reader for this session, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader ) + { + verifyStateForMutation(); + this.workspaceReader = workspaceReader; + return this; + } + + public RepositoryListener getRepositoryListener() + { + return repositoryListener; + } + + /** + * Sets the listener being notified of actions in the repository system. + * + * @param repositoryListener The repository listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener ) + { + verifyStateForMutation(); + this.repositoryListener = repositoryListener; + return this; + } + + public TransferListener getTransferListener() + { + return transferListener; + } + + /** + * Sets the listener being notified of uploads/downloads by the repository system. + * + * @param transferListener The transfer listener, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setTransferListener( TransferListener transferListener ) + { + verifyStateForMutation(); + this.transferListener = transferListener; + return this; + } + + @SuppressWarnings( "checkstyle:magicnumber" ) + private Map copySafe( Map table, Class valueType ) + { + Map map; + if ( table == null || table.isEmpty() ) + { + map = new HashMap<>(); + } + else + { + map = new HashMap<>( (int) ( table.size() / 0.75f ) + 1 ); + for ( Map.Entry entry : table.entrySet() ) + { + Object key = entry.getKey(); + if ( key instanceof String ) + { + Object value = entry.getValue(); + if ( valueType.isInstance( value ) ) + { + map.put( key.toString(), valueType.cast( value ) ); + } + } + } + } + return map; + } + + public Map getSystemProperties() + { + return systemPropertiesView; + } + + /** + * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually + * collected from the runtime environment like {@link System#getProperties()} and environment variables. + *

+ * Note: System properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param systemProperties The system properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setSystemProperties( Map systemProperties ) + { + verifyStateForMutation(); + this.systemProperties = copySafe( systemProperties, String.class ); + systemPropertiesView = Collections.unmodifiableMap( this.systemProperties ); + return this; + } + + /** + * Sets the specified system property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setSystemProperty( String key, String value ) + { + verifyStateForMutation(); + if ( value != null ) + { + systemProperties.put( key, value ); + } + else + { + systemProperties.remove( key ); + } + return this; + } + + public Map getUserProperties() + { + return userPropertiesView; + } + + /** + * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to + * system properties but are set on the discretion of the user and hence are considered of higher priority than + * system properties in case of conflicts. + *

+ * Note: User properties are of type {@code Map} and any key-value pair in the input map + * that doesn't match this type will be silently ignored. + * + * @param userProperties The user properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setUserProperties( Map userProperties ) + { + verifyStateForMutation(); + this.userProperties = copySafe( userProperties, String.class ); + userPropertiesView = Collections.unmodifiableMap( this.userProperties ); + return this; + } + + /** + * Sets the specified user property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setUserProperty( String key, String value ) + { + verifyStateForMutation(); + if ( value != null ) + { + userProperties.put( key, value ); + } + else + { + userProperties.remove( key ); + } + return this; + } + + public Map getConfigProperties() + { + return configPropertiesView; + } + + /** + * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling, + * connector-specific behavior, etc.). + *

+ * Note: Configuration properties are of type {@code Map} and any key-value pair in the + * input map that doesn't match this type will be silently ignored. + * + * @param configProperties The configuration properties, may be {@code null} or empty if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setConfigProperties( Map configProperties ) + { + verifyStateForMutation(); + this.configProperties = copySafe( configProperties, Object.class ); + configPropertiesView = Collections.unmodifiableMap( this.configProperties ); + return this; + } + + /** + * Sets the specified configuration property. + * + * @param key The property key, must not be {@code null}. + * @param value The property value, may be {@code null} to remove/unset the property. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setConfigProperty( String key, Object value ) + { + verifyStateForMutation(); + if ( value != null ) + { + configProperties.put( key, value ); + } + else + { + configProperties.remove( key ); + } + return this; + } + + public MirrorSelector getMirrorSelector() + { + return mirrorSelector; + } + + /** + * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to denote the effective repositories. + * + * @param mirrorSelector The mirror selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector ) + { + verifyStateForMutation(); + this.mirrorSelector = mirrorSelector; + if ( this.mirrorSelector == null ) + { + this.mirrorSelector = NullMirrorSelector.INSTANCE; + } + return this; + } + + public ProxySelector getProxySelector() + { + return proxySelector; + } + + /** + * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is + * not used for remote repositories which are passed as request parameters to the repository system, those + * repositories are supposed to have their proxy (if any) already set. + * + * @param proxySelector The proxy selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see RemoteRepository#getProxy() + */ + public DefaultCloseableRepositorySystemSession setProxySelector( ProxySelector proxySelector ) + { + verifyStateForMutation(); + this.proxySelector = proxySelector; + if ( this.proxySelector == null ) + { + this.proxySelector = NullProxySelector.INSTANCE; + } + return this; + } + + public AuthenticationSelector getAuthenticationSelector() + { + return authenticationSelector; + } + + /** + * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this + * selector is not used for remote repositories which are passed as request parameters to the repository system, + * those repositories are supposed to have their authentication (if any) already set. + * + * @param authenticationSelector The authentication selector to use, may be {@code null}. + * @return This session for chaining, never {@code null}. + * @see RemoteRepository#getAuthentication() + */ + public DefaultCloseableRepositorySystemSession setAuthenticationSelector( + AuthenticationSelector authenticationSelector ) + { + verifyStateForMutation(); + this.authenticationSelector = authenticationSelector; + if ( this.authenticationSelector == null ) + { + this.authenticationSelector = NullAuthenticationSelector.INSTANCE; + } + return this; + } + + public ArtifactTypeRegistry getArtifactTypeRegistry() + { + return artifactTypeRegistry; + } + + /** + * Sets the registry of artifact types recognized by this session. + * + * @param artifactTypeRegistry The artifact type registry, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry ) + { + verifyStateForMutation(); + this.artifactTypeRegistry = artifactTypeRegistry; + if ( this.artifactTypeRegistry == null ) + { + this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE; + } + return this; + } + + public DependencyTraverser getDependencyTraverser() + { + return dependencyTraverser; + } + + /** + * Sets the dependency traverser to use for building dependency graphs. + * + * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser ) + { + verifyStateForMutation(); + this.dependencyTraverser = dependencyTraverser; + return this; + } + + public DependencyManager getDependencyManager() + { + return dependencyManager; + } + + /** + * Sets the dependency manager to use for building dependency graphs. + * + * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setDependencyManager( DependencyManager dependencyManager ) + { + verifyStateForMutation(); + this.dependencyManager = dependencyManager; + return this; + } + + public DependencySelector getDependencySelector() + { + return dependencySelector; + } + + /** + * Sets the dependency selector to use for building dependency graphs. + * + * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setDependencySelector( DependencySelector dependencySelector ) + { + verifyStateForMutation(); + this.dependencySelector = dependencySelector; + return this; + } + + public VersionFilter getVersionFilter() + { + return versionFilter; + } + + /** + * Sets the version filter to use for building dependency graphs. + * + * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter + * versions. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setVersionFilter( VersionFilter versionFilter ) + { + verifyStateForMutation(); + this.versionFilter = versionFilter; + return this; + } + + public DependencyGraphTransformer getDependencyGraphTransformer() + { + return dependencyGraphTransformer; + } + + /** + * Sets the dependency graph transformer to use for building dependency graphs. + * + * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be + * {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setDependencyGraphTransformer( + DependencyGraphTransformer dependencyGraphTransformer ) + { + verifyStateForMutation(); + this.dependencyGraphTransformer = dependencyGraphTransformer; + return this; + } + + public SessionData getData() + { + return data; + } + + /** + * Sets the custom data associated with this session. + * + * @param data The session data, may be {@code null}. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setData( SessionData data ) + { + verifyStateForMutation(); + this.data = data; + if ( this.data == null ) + { + this.data = new DefaultSessionData(); + } + return this; + } + + public RepositoryCache getCache() + { + return cache; + } + + /** + * Sets the cache the repository system may use to save data for future reuse during the session. + * + * @param cache The repository cache, may be {@code null} if none. + * @return This session for chaining, never {@code null}. + */ + public DefaultCloseableRepositorySystemSession setCache( RepositoryCache cache ) + { + verifyStateForMutation(); + this.cache = cache; + return this; + } + + /** + * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception. + * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable + * though. + */ + public void setReadOnly() + { + readOnly = true; + } + + /** + * Verifies this instance state for mutation operations: mutated instance must not be read-only or closed. + */ + private void verifyStateForMutation() + { + if ( readOnly ) + { + throw new IllegalStateException( "repository system session is read-only" ); + } + if ( closed.get() ) + { + throw new IllegalStateException( "repository system session is already closed" ); + } + } + + static class NullProxySelector + implements ProxySelector + { + + public static final ProxySelector INSTANCE = new NullProxySelector(); + + public Proxy getProxy( RemoteRepository repository ) + { + requireNonNull( repository, "repository cannot be null" ); + return repository.getProxy(); + } + + } + + static class NullMirrorSelector + implements MirrorSelector + { + + public static final MirrorSelector INSTANCE = new NullMirrorSelector(); + + public RemoteRepository getMirror( RemoteRepository repository ) + { + requireNonNull( repository, "repository cannot be null" ); + return null; + } + + } + + static class NullAuthenticationSelector + implements AuthenticationSelector + { + + public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector(); + + public Authentication getAuthentication( RemoteRepository repository ) + { + requireNonNull( repository, "repository cannot be null" ); + return repository.getAuthentication(); + } + + } + + static final class NullArtifactTypeRegistry + implements ArtifactTypeRegistry + { + + public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry(); + + public ArtifactType get( String typeId ) + { + return null; + } + + } + + static final class NullFileTransformerManager implements FileTransformerManager + { + public static final FileTransformerManager INSTANCE = new NullFileTransformerManager(); + + @Override + public Collection getTransformersForArtifact( Artifact artifact ) + { + return Collections.emptyList(); + } + } + + @Override + public boolean isClosed() + { + return closed.get(); + } + + @Override + public void close() + { + if ( closed.compareAndSet( false, true ) ) + { + repositorySystemLifecycle.sessionEnded( this ); + } + } +} 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 1f7a1c2e68..fc6bd65de9 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 @@ -8,9 +8,9 @@ * 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 @@ -19,15 +19,17 @@ * under the License. */ -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import static java.util.Objects.requireNonNull; - 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 java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import org.eclipse.aether.MutableRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; @@ -49,7 +51,7 @@ import org.eclipse.aether.impl.LocalRepositoryProvider; import org.eclipse.aether.impl.MetadataResolver; import org.eclipse.aether.impl.RemoteRepositoryManager; -import org.eclipse.aether.spi.synccontext.SyncContextFactory; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.impl.VersionResolver; import org.eclipse.aether.installation.InstallRequest; @@ -80,16 +82,21 @@ import org.eclipse.aether.resolution.VersionResult; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; +import org.eclipse.aether.spi.synccontext.SyncContextFactory; import org.eclipse.aether.util.graph.visitor.FilteringDependencyVisitor; import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor; +import static java.util.Objects.requireNonNull; + /** + * */ @Singleton @Named public class DefaultRepositorySystem - implements RepositorySystem, Service + implements RepositorySystem, Service { + private final AtomicBoolean shutdown; private VersionResolver versionResolver; @@ -113,9 +120,12 @@ public class DefaultRepositorySystem private RemoteRepositoryManager remoteRepositoryManager; + private RepositorySystemLifecycle repositorySystemLifecycle; + public DefaultRepositorySystem() { // enables default constructor + this.shutdown = new AtomicBoolean( false ); } @SuppressWarnings( "checkstyle:parameternumber" ) @@ -125,8 +135,10 @@ public DefaultRepositorySystem() ArtifactDescriptorReader artifactDescriptorReader, DependencyCollector dependencyCollector, Installer installer, Deployer deployer, LocalRepositoryProvider localRepositoryProvider, SyncContextFactory syncContextFactory, - RemoteRepositoryManager remoteRepositoryManager ) + RemoteRepositoryManager remoteRepositoryManager, + RepositorySystemLifecycle repositorySystemLifecycle ) { + this.shutdown = new AtomicBoolean( false ); setVersionResolver( versionResolver ); setVersionRangeResolver( versionRangeResolver ); setArtifactResolver( artifactResolver ); @@ -138,8 +150,10 @@ public DefaultRepositorySystem() setLocalRepositoryProvider( localRepositoryProvider ); setSyncContextFactory( syncContextFactory ); setRemoteRepositoryManager( remoteRepositoryManager ); + setRepositorySystemLifecycle( repositorySystemLifecycle ); } + @Override public void initService( ServiceLocator locator ) { setVersionResolver( locator.getService( VersionResolver.class ) ); @@ -153,6 +167,7 @@ public void initService( ServiceLocator locator ) setLocalRepositoryProvider( locator.getService( LocalRepositoryProvider.class ) ); setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); setSyncContextFactory( locator.getService( SyncContextFactory.class ) ); + setRepositorySystemLifecycle( locator.getService( RepositorySystemLifecycle.class ) ); } /** @@ -235,8 +250,16 @@ public DefaultRepositorySystem setRemoteRepositoryManager( RemoteRepositoryManag return this; } + public DefaultRepositorySystem setRepositorySystemLifecycle( RepositorySystemLifecycle repositorySystemLifecycle ) + { + this.repositorySystemLifecycle = requireNonNull( + repositorySystemLifecycle, "repository system lifecycle cannot be null" ); + return this; + } + + @Override public VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request ) - throws VersionResolutionException + throws VersionResolutionException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -244,8 +267,9 @@ public VersionResult resolveVersion( RepositorySystemSession session, VersionReq return versionResolver.resolveVersion( session, request ); } + @Override public VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request ) - throws VersionRangeResolutionException + throws VersionRangeResolutionException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -253,9 +277,10 @@ public VersionRangeResult resolveVersionRange( RepositorySystemSession session, return versionRangeResolver.resolveVersionRange( session, request ); } + @Override public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session, ArtifactDescriptorRequest request ) - throws ArtifactDescriptorException + throws ArtifactDescriptorException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -263,8 +288,9 @@ public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession return artifactDescriptorReader.readArtifactDescriptor( session, request ); } + @Override public ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request ) - throws ArtifactResolutionException + throws ArtifactResolutionException { validateSession( session ); requireNonNull( session, "session cannot be null" ); @@ -272,9 +298,10 @@ public ArtifactResult resolveArtifact( RepositorySystemSession session, Artifact return artifactResolver.resolveArtifact( session, request ); } + @Override public List resolveArtifacts( RepositorySystemSession session, Collection requests ) - throws ArtifactResolutionException + throws ArtifactResolutionException { validateSession( session ); requireNonNull( requests, "requests cannot be null" ); @@ -282,6 +309,7 @@ public List resolveArtifacts( RepositorySystemSession session, return artifactResolver.resolveArtifacts( session, requests ); } + @Override public List resolveMetadata( RepositorySystemSession session, Collection requests ) { @@ -291,8 +319,9 @@ public List resolveMetadata( RepositorySystemSession session, return metadataResolver.resolveMetadata( session, requests ); } + @Override public CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request ) - throws DependencyCollectionException + throws DependencyCollectionException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -300,8 +329,9 @@ public CollectResult collectDependencies( RepositorySystemSession session, Colle return dependencyCollector.collectDependencies( session, request ); } + @Override public DependencyResult resolveDependencies( RepositorySystemSession session, DependencyRequest request ) - throws DependencyResolutionException + throws DependencyResolutionException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -389,8 +419,9 @@ private void updateNodesWithResolvedArtifacts( List results ) } } + @Override public InstallResult install( RepositorySystemSession session, InstallRequest request ) - throws InstallationException + throws InstallationException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -398,8 +429,9 @@ public InstallResult install( RepositorySystemSession session, InstallRequest re return installer.install( session, request ); } + @Override public DeployResult deploy( RepositorySystemSession session, DeployRequest request ) - throws DeploymentException + throws DeploymentException { validateSession( session ); requireNonNull( request, "request cannot be null" ); @@ -407,6 +439,7 @@ public DeployResult deploy( RepositorySystemSession session, DeployRequest reque return deployer.deploy( session, request ); } + @Override public LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession session, LocalRepository localRepository ) { @@ -423,12 +456,14 @@ public LocalRepositoryManager newLocalRepositoryManager( RepositorySystemSession } } + @Override public SyncContext newSyncContext( RepositorySystemSession session, boolean shared ) { validateSession( session ); return syncContextFactory.newInstance( session, shared ); } + @Override public List newResolutionRepositories( RepositorySystemSession session, List repositories ) { @@ -436,11 +471,12 @@ public List newResolutionRepositories( RepositorySystemSession validateRepositories( repositories ); repositories = - remoteRepositoryManager.aggregateRepositories( session, new ArrayList(), repositories, - true ); + remoteRepositoryManager.aggregateRepositories( session, new ArrayList(), repositories, + true ); return repositories; } + @Override public RemoteRepository newDeploymentRepository( RepositorySystemSession session, RemoteRepository repository ) { validateSession( session ); @@ -454,6 +490,39 @@ public RemoteRepository newDeploymentRepository( RepositorySystemSession session return builder.build(); } + @Override + public MutableRepositorySystemSession newRepositorySystemSession() + { + return repositorySystemLifecycle.newRepositorySystemSession(); + } + + @Override + public MutableRepositorySystemSession newRepositorySystemSession( RepositorySystemSession session ) + { + return repositorySystemLifecycle.newRepositorySystemSession( session ); + } + + @Override + public void addOnSessionEndedHandler( RepositorySystemSession session, Consumer handler ) + { + repositorySystemLifecycle.addOnSessionEndedHandler( session, handler ); + } + + @Override + public void addOnSystemEndedHandler( Runnable handler ) + { + repositorySystemLifecycle.addOnSystemEndedHandler( handler ); + } + + @Override + public void shutdown() + { + if ( shutdown.compareAndSet( false, true ) ) + { + repositorySystemLifecycle.systemEnded(); + } + } + private void validateSession( RepositorySystemSession session ) { requireNonNull( session, "repository system session cannot be null" ); @@ -470,12 +539,16 @@ private void validateSession( RepositorySystemSession session ) { throw new IllegalStateException( "session is already closed" ); } + if ( shutdown.get() ) + { + throw new IllegalStateException( "repository system is already shut down" ); + } } private void validateRepositories( List repositories ) { requireNonNull( repositories, "repositories cannot be null" ); - for ( RemoteRepository repository: repositories ) + for ( RemoteRepository repository : repositories ) { requireNonNull( repository, "repository cannot be null" ); } @@ -485,5 +558,4 @@ private void invalidSession( Object obj, String name ) { requireNonNull( obj, "repository system session's " + name + " cannot be null" ); } - } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java new file mode 100644 index 0000000000..f6677d61cf --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemLifecycle.java @@ -0,0 +1,218 @@ +package org.eclipse.aether.internal.impl; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +import org.eclipse.aether.MultiRuntimeException; +import org.eclipse.aether.MutableRepositorySystemSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.impl.RepositorySystemLifecycle; + +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toList; + +/** + * + */ +@Singleton +@Named +public class DefaultRepositorySystemLifecycle + implements RepositorySystemLifecycle +{ + private final AtomicBoolean shutdown; + + private final CopyOnWriteArrayList onSystemEndedHandlers; + + private final ConcurrentHashMap onSessionEndedHandlers; + + @Inject + public DefaultRepositorySystemLifecycle() + { + this.shutdown = new AtomicBoolean( false ); + this.onSystemEndedHandlers = new CopyOnWriteArrayList<>(); + this.onSessionEndedHandlers = new ConcurrentHashMap<>(); + } + + @Override + public MutableRepositorySystemSession newRepositorySystemSession() + { + requireNotShutdown(); + return new DefaultCloseableRepositorySystemSession( this ); + } + + @Override + public MutableRepositorySystemSession newRepositorySystemSession( RepositorySystemSession session ) + { + requireNotShutdown(); + return new DefaultCloseableRepositorySystemSession( this, session ); + } + + @Override + public void sessionEnded( RepositorySystemSession session ) + { + requireNotShutdown(); + doSessionEnded( session ); + } + + private void doSessionEnded( RepositorySystemSession session ) + { + SessionRegistration sessionRegistration = onSessionEndedHandlers.remove( sessionKey( session ) ); + if ( sessionRegistration != null ) + { + ArrayList exceptions = new ArrayList<>(); + for ( Consumer onCloseHandler : sessionRegistration.onCloseHandlers ) + { + try + { + onCloseHandler.accept( session ); + } + catch ( Exception e ) + { + exceptions.add( e ); + } + } + MultiRuntimeException.mayThrow( "session on-close handler failures", exceptions ); + } + } + + @Override + public void systemEnded() + { + if ( shutdown.compareAndSet( false, true ) ) + { + final List sessions = onSessionEndedHandlers.keySet().stream() + .map( k -> k.session ) + .collect( toList() ); + final ArrayList exceptions = new ArrayList<>(); + for ( RepositorySystemSession session : sessions ) + { + try + { + doSessionEnded( session ); + } + catch ( Exception e ) + { + exceptions.add( e ); + } + } + for ( Runnable onCloseHandler : onSystemEndedHandlers ) + { + try + { + onCloseHandler.run(); + } + catch ( Exception e ) + { + exceptions.add( e ); + } + } + MultiRuntimeException.mayThrow( "system on-close handler failures", exceptions ); + } + } + + @Override + public void addOnSessionEndedHandler( RepositorySystemSession session, Consumer handler ) + { + requireNonNull( session, "session cannot be null" ); + requireNonNull( handler, "handler cannot be null" ); + requireNotShutdown(); + if ( session.isClosed() ) + { + throw new IllegalStateException( "session is already closed" ); + } + onSessionEndedHandlers.computeIfAbsent( sessionKey( session ), k -> new SessionRegistration() ) + .onCloseHandlers.add( 0, handler ); + } + + @Override + public void addOnSystemEndedHandler( Runnable handler ) + { + requireNonNull( handler, "handler cannot be null" ); + requireNotShutdown(); + onSystemEndedHandlers.add( 0, handler ); + } + + private void requireNotShutdown() + { + if ( shutdown.get() ) + { + throw new IllegalStateException( "repository system is already shut down" ); + } + } + + private SessionKey sessionKey( RepositorySystemSession session ) + { + return new SessionKey( session ); + } + + /* + * Keyed by session instance! session.data CANNOT be used for session ID as it is shared with copy-constructor. + */ + private static class SessionKey + { + private final RepositorySystemSession session; + + private SessionKey( RepositorySystemSession session ) + { + this.session = session; + } + + @Override + public boolean equals( Object o ) + { + if ( this == o ) + { + return true; + } + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + SessionKey that = (SessionKey) o; + return session == that.session; + } + + @Override + public int hashCode() + { + return System.identityHashCode( session ); + } + } + + private static class SessionRegistration + { + private final CopyOnWriteArrayList> onCloseHandlers; + + private SessionRegistration() + { + this.onCloseHandlers = new CopyOnWriteArrayList<>(); + } + } +} diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java index 05ceef90b1..ac362a2441 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSource.java @@ -40,6 +40,7 @@ import org.eclipse.aether.MultiRuntimeException; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.internal.impl.LocalPathComposer; import org.eclipse.aether.repository.ArtifactRepository; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; @@ -112,11 +113,15 @@ public final class SummaryFileTrustedChecksumsSource private final LocalPathComposer localPathComposer; + private final RepositorySystemLifecycle repositorySystemLifecycle; + @Inject - public SummaryFileTrustedChecksumsSource( LocalPathComposer localPathComposer ) + public SummaryFileTrustedChecksumsSource( LocalPathComposer localPathComposer, + RepositorySystemLifecycle repositorySystemLifecycle ) { super( NAME ); this.localPathComposer = requireNonNull( localPathComposer ); + this.repositorySystemLifecycle = requireNonNull( repositorySystemLifecycle ); } @Override @@ -161,7 +166,7 @@ protected SummaryFileWriter doGetTrustedArtifactChecksumsWriter( RepositorySyste { if ( onCloseHandlerRegistered( session ).compareAndSet( false, true ) ) { - session.addOnCloseHandler( this::saveSessionRecordedLines ); + repositorySystemLifecycle.addOnSessionEndedHandler( session, this::saveSessionRecordedLines ); } return new SummaryFileWriter( session, cache( session ), getBasedir( session, true ), isOriginAware( session ) ); diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java index 0897cc6835..dd46210556 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DependencyCollectorDelegate.java @@ -27,7 +27,7 @@ import java.util.List; import java.util.Map; -import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.MutableRepositorySystemSession; import org.eclipse.aether.RepositoryException; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.RequestTrace; @@ -45,6 +45,7 @@ import org.eclipse.aether.impl.ArtifactDescriptorReader; import org.eclipse.aether.impl.DependencyCollector; import org.eclipse.aether.impl.RemoteRepositoryManager; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.repository.ArtifactRepository; import org.eclipse.aether.repository.RemoteRepository; @@ -80,6 +81,8 @@ public abstract class DependencyCollectorDelegate implements DependencyCollector protected final Logger logger = LoggerFactory.getLogger( getClass() ); + private RepositorySystemLifecycle repositorySystemLifecycle; + protected RemoteRepositoryManager remoteRepositoryManager; protected ArtifactDescriptorReader descriptorReader; @@ -98,12 +101,14 @@ protected DependencyCollectorDelegate() } protected DependencyCollectorDelegate( RemoteRepositoryManager remoteRepositoryManager, - ArtifactDescriptorReader artifactDescriptorReader, - VersionRangeResolver versionRangeResolver ) + ArtifactDescriptorReader artifactDescriptorReader, + VersionRangeResolver versionRangeResolver, + RepositorySystemLifecycle repositorySystemLifecycle ) { setRemoteRepositoryManager( remoteRepositoryManager ); setArtifactDescriptorReader( artifactDescriptorReader ); setVersionRangeResolver( versionRangeResolver ); + setRepositorySystemLifecycle( repositorySystemLifecycle ); } public void initService( ServiceLocator locator ) @@ -111,6 +116,7 @@ public void initService( ServiceLocator locator ) setRemoteRepositoryManager( locator.getService( RemoteRepositoryManager.class ) ); setArtifactDescriptorReader( locator.getService( ArtifactDescriptorReader.class ) ); setVersionRangeResolver( locator.getService( VersionRangeResolver.class ) ); + setRepositorySystemLifecycle( locator.getService( RepositorySystemLifecycle.class ) ); } public DependencyCollector setRemoteRepositoryManager( RemoteRepositoryManager remoteRepositoryManager ) @@ -133,6 +139,13 @@ public DependencyCollector setVersionRangeResolver( VersionRangeResolver version return this; } + public DependencyCollector setRepositorySystemLifecycle( RepositorySystemLifecycle repositorySystemLifecycle ) + { + this.repositorySystemLifecycle = + requireNonNull( repositorySystemLifecycle, "repository system lifecycle cannot be null" ); + return this; + } + @SuppressWarnings( "checkstyle:methodlength" ) @Override public final CollectResult collectDependencies( RepositorySystemSession session, CollectRequest request ) @@ -327,7 +340,7 @@ protected abstract void doCollectDependencies( RepositorySystemSession session, protected RepositorySystemSession optimizeSession( RepositorySystemSession session ) { - DefaultRepositorySystemSession optimized = new DefaultRepositorySystemSession( session ); + MutableRepositorySystemSession optimized = repositorySystemLifecycle.newRepositorySystemSession( session ); optimized.setArtifactTypeRegistry( CachingArtifactTypeRegistry.newInstance( session ) ); return optimized; } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector.java index 7e99676992..4cb0228f5d 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollector.java @@ -58,6 +58,7 @@ import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.impl.ArtifactDescriptorReader; import org.eclipse.aether.impl.RemoteRepositoryManager; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.internal.impl.collect.DataPool; import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext; @@ -129,9 +130,10 @@ public BfDependencyCollector() @Inject BfDependencyCollector( RemoteRepositoryManager remoteRepositoryManager, ArtifactDescriptorReader artifactDescriptorReader, - VersionRangeResolver versionRangeResolver ) + VersionRangeResolver versionRangeResolver, + RepositorySystemLifecycle repositorySystemLifecycle ) { - super( remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver ); + super( remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver, repositorySystemLifecycle ); } @SuppressWarnings( "checkstyle:parameternumber" ) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector.java index 268100f0ec..fe63716c75 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollector.java @@ -39,6 +39,7 @@ import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.impl.ArtifactDescriptorReader; import org.eclipse.aether.impl.RemoteRepositoryManager; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.impl.VersionRangeResolver; import org.eclipse.aether.internal.impl.collect.DataPool; import org.eclipse.aether.internal.impl.collect.DefaultDependencyCollectionContext; @@ -85,9 +86,10 @@ public DfDependencyCollector() @Inject DfDependencyCollector( RemoteRepositoryManager remoteRepositoryManager, ArtifactDescriptorReader artifactDescriptorReader, - VersionRangeResolver versionRangeResolver ) + VersionRangeResolver versionRangeResolver, + RepositorySystemLifecycle repositorySystemLifecycle ) { - super( remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver ); + super( remoteRepositoryManager, artifactDescriptorReader, versionRangeResolver, repositorySystemLifecycle ); } @SuppressWarnings( "checkstyle:parameternumber" ) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java index 14c7a2acc1..ecc30b0175 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSource.java @@ -41,6 +41,7 @@ import org.eclipse.aether.MultiRuntimeException; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.metadata.Metadata; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactResult; @@ -51,6 +52,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static java.util.Objects.requireNonNull; + /** * Remote repository filter source filtering on G coordinate. It is backed by a file that lists all allowed groupIds * and groupId not present in this file are filtered out. @@ -96,10 +99,13 @@ public final class GroupIdRemoteRepositoryFilterSource private static final Logger LOGGER = LoggerFactory.getLogger( GroupIdRemoteRepositoryFilterSource.class ); + private final RepositorySystemLifecycle repositorySystemLifecycle; + @Inject - public GroupIdRemoteRepositoryFilterSource() + public GroupIdRemoteRepositoryFilterSource( RepositorySystemLifecycle repositorySystemLifecycle ) { super( NAME ); + this.repositorySystemLifecycle = requireNonNull( repositorySystemLifecycle ); } @Override @@ -122,7 +128,7 @@ public void postProcess( RepositorySystemSession session, List a { if ( onCloseHandlerRegistered( session ).compareAndSet( false, true ) ) { - session.addOnCloseHandler( this::saveSessionRecordedLines ); + repositorySystemLifecycle.addOnSessionEndedHandler( session, this::saveSessionRecordedLines ); } ConcurrentHashMap> cache = cache( session ); for ( ArtifactResult artifactResult : artifactResults ) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory.java index d7f6bd6c76..9fbc5f669c 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/DefaultSyncContextFactory.java @@ -23,27 +23,15 @@ import javax.inject.Named; import javax.inject.Singleton; -import java.util.HashMap; -import java.util.Map; - import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.SyncContext; -import org.eclipse.aether.internal.impl.synccontext.named.NameMapper; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactoryAdapter; -import org.eclipse.aether.internal.impl.synccontext.named.providers.DiscriminatingNameMapperProvider; -import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider; -import org.eclipse.aether.internal.impl.synccontext.named.providers.FileHashingGAVNameMapperProvider; -import org.eclipse.aether.internal.impl.synccontext.named.providers.GAVNameMapperProvider; -import org.eclipse.aether.internal.impl.synccontext.named.providers.StaticNameMapperProvider; -import org.eclipse.aether.named.NamedLockFactory; -import org.eclipse.aether.named.providers.FileLockNamedLockFactory; -import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory; -import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory; -import org.eclipse.aether.named.providers.NoopNamedLockFactory; +import org.eclipse.aether.internal.impl.synccontext.named.NamedLockFactorySelector; +import org.eclipse.aether.internal.impl.synccontext.named.ParameterizedNamedLockFactorySelector; import org.eclipse.aether.spi.locator.Service; import org.eclipse.aether.spi.locator.ServiceLocator; import org.eclipse.aether.spi.synccontext.SyncContextFactory; -import org.eclipse.aether.util.ConfigUtils; import static java.util.Objects.requireNonNull; @@ -55,29 +43,18 @@ public final class DefaultSyncContextFactory implements SyncContextFactory, Service { - private static final String ADAPTER_KEY = DefaultSyncContextFactory.class.getName() + ".adapter"; - - private static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; - - private static final String DEFAULT_NAME_MAPPER_NAME = GAVNameMapperProvider.NAME; - - private static final String FACTORY_KEY = "aether.syncContext.named.factory"; - - private static final String DEFAULT_FACTORY_NAME = LocalReadWriteLockNamedLockFactory.NAME; - - private Map nameMappers; - - private Map namedLockFactories; + private NamedLockFactoryAdapter namedLockFactoryAdapter; /** * Constructor used with DI, where factories are injected and selected based on key. */ @Inject - public DefaultSyncContextFactory( final Map nameMappers, - final Map namedLockFactories ) + public DefaultSyncContextFactory( final RepositorySystemLifecycle repositorySystemLifecycle, + final NamedLockFactorySelector selector ) { - this.nameMappers = requireNonNull( nameMappers ); - this.namedLockFactories = requireNonNull( namedLockFactories ); + repositorySystemLifecycle.addOnSystemEndedHandler( this::shutDownAdapter ); + this.namedLockFactoryAdapter = + new NamedLockFactoryAdapter( selector.getSelectedNameMapper(), selector.getSelectedNamedLockFactory() ); } /** @@ -94,59 +71,24 @@ public DefaultSyncContextFactory() @Override public void initService( final ServiceLocator locator ) { - HashMap mappers = new HashMap<>(); - mappers.put( StaticNameMapperProvider.NAME, new StaticNameMapperProvider().get() ); - mappers.put( GAVNameMapperProvider.NAME, new GAVNameMapperProvider().get() ); - mappers.put( DiscriminatingNameMapperProvider.NAME, new DiscriminatingNameMapperProvider().get() ); - mappers.put( FileGAVNameMapperProvider.NAME, new FileGAVNameMapperProvider().get() ); - mappers.put( FileHashingGAVNameMapperProvider.NAME, new FileHashingGAVNameMapperProvider().get() ); - this.nameMappers = mappers; - - HashMap factories = new HashMap<>(); - factories.put( NoopNamedLockFactory.NAME, new NoopNamedLockFactory() ); - factories.put( LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory() ); - factories.put( LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory() ); - factories.put( FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory() ); - this.namedLockFactories = factories; + locator.getService( RepositorySystemLifecycle.class ).addOnSystemEndedHandler( this::shutDownAdapter ); + NamedLockFactorySelector selector = new ParameterizedNamedLockFactorySelector(); + this.namedLockFactoryAdapter = + new NamedLockFactoryAdapter( selector.getSelectedNameMapper(), selector.getSelectedNamedLockFactory() ); } @Override public SyncContext newInstance( final RepositorySystemSession session, final boolean shared ) { requireNonNull( session, "session cannot be null" ); - NamedLockFactoryAdapter adapter = getOrCreateSessionAdapter( session ); - return adapter.newInstance( session, shared ); - } - - private NamedLockFactoryAdapter getOrCreateSessionAdapter( final RepositorySystemSession session ) - { - return (NamedLockFactoryAdapter) session.getData().computeIfAbsent( ADAPTER_KEY, () -> - { - String nameMapperName = ConfigUtils.getString( session, DEFAULT_NAME_MAPPER_NAME, NAME_MAPPER_KEY ); - String namedLockFactoryName = ConfigUtils.getString( session, DEFAULT_FACTORY_NAME, FACTORY_KEY ); - NameMapper nameMapper = nameMappers.get( nameMapperName ); - if ( nameMapper == null ) - { - throw new IllegalArgumentException( "Unknown NameMapper name: " + nameMapperName - + ", known ones: " + nameMappers.keySet() ); - } - NamedLockFactory namedLockFactory = namedLockFactories.get( namedLockFactoryName ); - if ( namedLockFactory == null ) - { - throw new IllegalArgumentException( "Unknown NamedLockFactory name: " + namedLockFactoryName - + ", known ones: " + namedLockFactories.keySet() ); - } - session.addOnCloseHandler( this::shutDownSessionAdapter ); - return new NamedLockFactoryAdapter( nameMapper, namedLockFactory ); - } ); + return namedLockFactoryAdapter.newInstance( session, shared ); } - private void shutDownSessionAdapter( RepositorySystemSession session ) + private void shutDownAdapter() { - NamedLockFactoryAdapter adapter = (NamedLockFactoryAdapter) session.getData().get( ADAPTER_KEY ); - if ( adapter != null ) + if ( namedLockFactoryAdapter != null ) { - adapter.shutdown(); + namedLockFactoryAdapter.shutdown(); } } } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactorySelector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactorySelector.java new file mode 100644 index 0000000000..db9ceefb24 --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/NamedLockFactorySelector.java @@ -0,0 +1,41 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.named.NamedLockFactory; + +/** + * Selector for {@link NamedLockFactory} and {@link NameMapper} that selects and exposes selected ones. Essentially + * all the named locks configuration is here. Implementations may use different strategies to perform selection. + * + * @since 1.7.3 + */ +public interface NamedLockFactorySelector +{ + /** + * Returns the selected {@link NamedLockFactory}, never {@code null}. + */ + NamedLockFactory getSelectedNamedLockFactory(); + + /** + * Returns the selected {@link NameMapper}, never {@code null}. + */ + NameMapper getSelectedNameMapper(); +} \ No newline at end of file diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ParameterizedNamedLockFactorySelector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ParameterizedNamedLockFactorySelector.java new file mode 100644 index 0000000000..9d13fa146c --- /dev/null +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/synccontext/named/ParameterizedNamedLockFactorySelector.java @@ -0,0 +1,147 @@ +package org.eclipse.aether.internal.impl.synccontext.named; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.aether.internal.impl.synccontext.named.providers.DiscriminatingNameMapperProvider; +import org.eclipse.aether.internal.impl.synccontext.named.providers.FileGAVNameMapperProvider; +import org.eclipse.aether.internal.impl.synccontext.named.providers.FileHashingGAVNameMapperProvider; +import org.eclipse.aether.internal.impl.synccontext.named.providers.GAVNameMapperProvider; +import org.eclipse.aether.internal.impl.synccontext.named.providers.StaticNameMapperProvider; +import org.eclipse.aether.named.NamedLockFactory; +import org.eclipse.aether.named.providers.FileLockNamedLockFactory; +import org.eclipse.aether.named.providers.LocalReadWriteLockNamedLockFactory; +import org.eclipse.aether.named.providers.LocalSemaphoreNamedLockFactory; +import org.eclipse.aether.named.providers.NoopNamedLockFactory; + +/** + * Parameterized selector implementation that selects based on injected parameters. + * + * @since 1.9.0 + */ +@Singleton +@Named +public final class ParameterizedNamedLockFactorySelector + implements NamedLockFactorySelector +{ + private static final String FACTORY_KEY = "aether.syncContext.named.factory"; + + private static final String NAME_MAPPER_KEY = "aether.syncContext.named.nameMapper"; + + private static final Map FACTORIES; + + private static final String DEFAULT_FACTORY = LocalReadWriteLockNamedLockFactory.NAME; + + private static final Map NAME_MAPPERS; + + private static final String DEFAULT_NAME_MAPPER = GAVNameMapperProvider.NAME; + + static + { + HashMap factories = new HashMap<>(); + factories.put( NoopNamedLockFactory.NAME, new NoopNamedLockFactory() ); + factories.put( LocalReadWriteLockNamedLockFactory.NAME, new LocalReadWriteLockNamedLockFactory() ); + factories.put( LocalSemaphoreNamedLockFactory.NAME, new LocalSemaphoreNamedLockFactory() ); + factories.put( FileLockNamedLockFactory.NAME, new FileLockNamedLockFactory() ); + FACTORIES = factories; + + HashMap mappers = new HashMap<>(); + mappers.put( StaticNameMapperProvider.NAME, new StaticNameMapperProvider().get() ); + mappers.put( GAVNameMapperProvider.NAME, new GAVNameMapperProvider().get() ); + mappers.put( DiscriminatingNameMapperProvider.NAME, new DiscriminatingNameMapperProvider().get() ); + mappers.put( FileGAVNameMapperProvider.NAME, new FileGAVNameMapperProvider().get() ); + mappers.put( FileHashingGAVNameMapperProvider.NAME, new FileHashingGAVNameMapperProvider().get() ); + NAME_MAPPERS = mappers; + } + + private final NamedLockFactory namedLockFactory; + + private final NameMapper nameMapper; + + /** + * Default constructor for non Eclipse Sisu uses. + */ + public ParameterizedNamedLockFactorySelector() + { + this( FACTORIES, DEFAULT_FACTORY, NAME_MAPPERS, DEFAULT_NAME_MAPPER ); + } + + /** + * Constructor that uses Eclipse Sisu parameter injection. + */ + @SuppressWarnings( "checkstyle:LineLength" ) + @Inject + public ParameterizedNamedLockFactorySelector( final Map factories, + @Named( "${" + FACTORY_KEY + ":-" + DEFAULT_FACTORY + "}" ) final String selectedFactoryName, + final Map nameMappers, + @Named( "${" + NAME_MAPPER_KEY + ":-" + DEFAULT_NAME_MAPPER + "}" ) final String selectedMapperName ) + { + this.namedLockFactory = selectNamedLockFactory( factories, selectedFactoryName ); + this.nameMapper = selectNameMapper( nameMappers, selectedMapperName ); + } + + /** + * Returns the selected {@link NamedLockFactory}, never null. + */ + @Override + public NamedLockFactory getSelectedNamedLockFactory() + { + return namedLockFactory; + } + + /** + * Returns the selected {@link NameMapper}, never null. + */ + @Override + public NameMapper getSelectedNameMapper() + { + return nameMapper; + } + + private static NamedLockFactory selectNamedLockFactory( final Map factories, + final String factoryName ) + { + NamedLockFactory factory = factories.get( factoryName ); + if ( factory == null ) + { + throw new IllegalArgumentException( "Unknown NamedLockFactory name: " + factoryName + + ", known ones: " + factories.keySet() ); + } + return factory; + } + + private static NameMapper selectNameMapper( final Map nameMappers, + final String nameMapperName ) + { + NameMapper nameMapper = nameMappers.get( nameMapperName ); + if ( nameMapper == null ) + { + throw new IllegalArgumentException( "Unknown NameMapper name: " + nameMapperName + + ", known ones: " + nameMappers.keySet() ); + } + return nameMapper; + } +} \ No newline at end of file diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceTestSupport.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceTestSupport.java index 494f942f05..3504d394a8 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceTestSupport.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/FileTrustedChecksumsSourceTestSupport.java @@ -27,6 +27,8 @@ import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.impl.RepositorySystemLifecycle; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.internal.test.util.TestUtils; import org.eclipse.aether.spi.checksums.TrustedChecksumsSource; import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory; @@ -54,6 +56,8 @@ public abstract class FileTrustedChecksumsSourceTestSupport private ChecksumAlgorithmFactory checksumAlgorithmFactory; + private RepositorySystemLifecycle repositorySystemLifecycle; + private FileTrustedChecksumsSourceSupport subject; private boolean checksumWritten; @@ -64,7 +68,8 @@ public void before() throws Exception session = TestUtils.newSession(); // populate local repository checksumAlgorithmFactory = new Sha1ChecksumAlgorithmFactory(); - subject = prepareSubject(); + repositorySystemLifecycle = new DefaultRepositorySystemLifecycle(); + subject = prepareSubject( repositorySystemLifecycle ); checksumWritten = false; try ( DefaultRepositorySystemSession prepareSession = new DefaultRepositorySystemSession( session ) ) @@ -81,10 +86,11 @@ public void before() throws Exception checksumWritten = true; } } + repositorySystemLifecycle.sessionEnded( prepareSession ); } } - protected abstract FileTrustedChecksumsSourceSupport prepareSubject(); + protected abstract FileTrustedChecksumsSourceSupport prepareSubject( RepositorySystemLifecycle lifecycle ); protected abstract void enableSource( DefaultRepositorySystemSession session ); diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSourceTest.java index 767276763b..51c56a86e9 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSourceTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SparseDirectoryTrustedChecksumsSourceTest.java @@ -21,13 +21,14 @@ import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.internal.impl.DefaultFileProcessor; import org.eclipse.aether.internal.impl.DefaultLocalPathComposer; public class SparseDirectoryTrustedChecksumsSourceTest extends FileTrustedChecksumsSourceTestSupport { @Override - protected FileTrustedChecksumsSourceSupport prepareSubject() + protected FileTrustedChecksumsSourceSupport prepareSubject( RepositorySystemLifecycle lifecycle ) { return new SparseDirectoryTrustedChecksumsSource( new DefaultFileProcessor(), new DefaultLocalPathComposer() ); } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java index 4d27f4efbc..83b8be44cd 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/checksum/SummaryFileTrustedChecksumsSourceTest.java @@ -20,14 +20,15 @@ */ import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.impl.RepositorySystemLifecycle; import org.eclipse.aether.internal.impl.DefaultLocalPathComposer; public class SummaryFileTrustedChecksumsSourceTest extends FileTrustedChecksumsSourceTestSupport { @Override - protected FileTrustedChecksumsSourceSupport prepareSubject() + protected FileTrustedChecksumsSourceSupport prepareSubject( RepositorySystemLifecycle lifecycle ) { - return new SummaryFileTrustedChecksumsSource( new DefaultLocalPathComposer() ); + return new SummaryFileTrustedChecksumsSource( new DefaultLocalPathComposer(), lifecycle ); } @Override diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollectorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollectorTest.java index 6f3ea1dcc6..1e6213f3f3 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollectorTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/bf/BfDependencyCollectorTest.java @@ -31,6 +31,7 @@ import org.eclipse.aether.collection.DependencyCollectionException; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.Exclusion; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.internal.impl.StubRemoteRepositoryManager; import org.eclipse.aether.internal.impl.StubVersionRangeResolver; import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegateTestSupport; @@ -68,6 +69,7 @@ protected void setupCollector() collector.setArtifactDescriptorReader( newReader( "" ) ); collector.setVersionRangeResolver( new StubVersionRangeResolver() ); collector.setRemoteRepositoryManager( new StubRemoteRepositoryManager() ); + collector.setRepositorySystemLifecycle( new DefaultRepositorySystemLifecycle() ); } private Dependency newDep( String coords, String scope, Collection exclusions ) diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollectorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollectorTest.java index 131e24c417..807459d8e4 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollectorTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/df/DfDependencyCollectorTest.java @@ -19,6 +19,7 @@ * under the License. */ +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.internal.impl.StubRemoteRepositoryManager; import org.eclipse.aether.internal.impl.StubVersionRangeResolver; import org.eclipse.aether.internal.impl.collect.DependencyCollectorDelegateTestSupport; @@ -35,5 +36,6 @@ protected void setupCollector() collector.setArtifactDescriptorReader( newReader( "" ) ); collector.setVersionRangeResolver( new StubVersionRangeResolver() ); collector.setRemoteRepositoryManager( new StubRemoteRepositoryManager() ); + collector.setRepositorySystemLifecycle( new DefaultRepositorySystemLifecycle() ); } } \ No newline at end of file diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java index 8b8f799043..fa8ced259c 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/filter/GroupIdRemoteRepositoryFilterSourceTest.java @@ -27,6 +27,7 @@ import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.internal.impl.DefaultRepositorySystemLifecycle; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResult; @@ -36,11 +37,13 @@ */ public class GroupIdRemoteRepositoryFilterSourceTest extends RemoteRepositoryFilterSourceTestSupport { + private final DefaultRepositorySystemLifecycle lifecycle = new DefaultRepositorySystemLifecycle(); + @Override protected GroupIdRemoteRepositoryFilterSource getRemoteRepositoryFilterSource( DefaultRepositorySystemSession session, RemoteRepository remoteRepository ) { - return new GroupIdRemoteRepositoryFilterSource(); + return new GroupIdRemoteRepositoryFilterSource( lifecycle ); } @Override @@ -66,6 +69,7 @@ protected void allowArtifact( DefaultRepositorySystemSession session, RemoteRepo + ".record", Boolean.TRUE.toString() ); getRemoteRepositoryFilterSource( newSession, remoteRepository ) .postProcess( newSession, artifactResults ); + lifecycle.sessionEnded( newSession ); } catch ( IOException e ) {