You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2016/09/03 20:23:29 UTC
[06/51] [partial] maven-aether git commit: [MNG-6007] rename Aether
to Maven Artifact Resolver
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractRepositoryListener.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractRepositoryListener.java b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractRepositoryListener.java
new file mode 100644
index 0000000..f42d15e
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/AbstractRepositoryListener.java
@@ -0,0 +1,112 @@
+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.
+ */
+
+/**
+ * A skeleton implementation for custom repository listeners. The callback methods in this class do nothing.
+ */
+public abstract class AbstractRepositoryListener
+ implements RepositoryListener
+{
+
+ /**
+ * Enables subclassing.
+ */
+ protected AbstractRepositoryListener()
+ {
+ }
+
+ public void artifactDeployed( RepositoryEvent event )
+ {
+ }
+
+ public void artifactDeploying( RepositoryEvent event )
+ {
+ }
+
+ public void artifactDescriptorInvalid( RepositoryEvent event )
+ {
+ }
+
+ public void artifactDescriptorMissing( RepositoryEvent event )
+ {
+ }
+
+ public void artifactDownloaded( RepositoryEvent event )
+ {
+ }
+
+ public void artifactDownloading( RepositoryEvent event )
+ {
+ }
+
+ public void artifactInstalled( RepositoryEvent event )
+ {
+ }
+
+ public void artifactInstalling( RepositoryEvent event )
+ {
+ }
+
+ public void artifactResolved( RepositoryEvent event )
+ {
+ }
+
+ public void artifactResolving( RepositoryEvent event )
+ {
+ }
+
+ public void metadataDeployed( RepositoryEvent event )
+ {
+ }
+
+ public void metadataDeploying( RepositoryEvent event )
+ {
+ }
+
+ public void metadataDownloaded( RepositoryEvent event )
+ {
+ }
+
+ public void metadataDownloading( RepositoryEvent event )
+ {
+ }
+
+ public void metadataInstalled( RepositoryEvent event )
+ {
+ }
+
+ public void metadataInstalling( RepositoryEvent event )
+ {
+ }
+
+ public void metadataInvalid( RepositoryEvent event )
+ {
+ }
+
+ public void metadataResolved( RepositoryEvent event )
+ {
+ }
+
+ public void metadataResolving( RepositoryEvent event )
+ {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java b/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
new file mode 100644
index 0000000..b96a754
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
@@ -0,0 +1,174 @@
+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.
+ */
+
+/**
+ * The keys and defaults for common configuration properties.
+ *
+ * @see RepositorySystemSession#getConfigProperties()
+ */
+public final class ConfigurationProperties
+{
+
+ private static final String PREFIX_AETHER = "aether.";
+
+ private static final String PREFIX_CONNECTOR = PREFIX_AETHER + "connector.";
+
+ /**
+ * The prefix for properties that control the priority of pluggable extensions like transporters. For example, for
+ * an extension with the fully qualified class name "org.eclipse.MyExtensionFactory", the configuration properties
+ * "aether.priority.org.eclipse.MyExtensionFactory", "aether.priority.MyExtensionFactory" and
+ * "aether.priority.MyExtension" will be consulted for the priority, in that order (obviously, the last key is only
+ * tried if the class name ends with "Factory"). The corresponding value is a float and the special value
+ * {@link Float#NaN} or "NaN" (case-sensitive) can be used to disable the extension.
+ */
+ public static final String PREFIX_PRIORITY = PREFIX_AETHER + "priority.";
+
+ /**
+ * A flag indicating whether the priorities of pluggable extensions are implicitly given by their iteration order
+ * such that the first extension has the highest priority. If set, an extension's built-in priority as well as any
+ * corresponding {@code aether.priority.*} configuration properties are ignored when searching for a suitable
+ * implementation among the available extensions. This priority mode is meant for cases where the application will
+ * present/inject extensions in the desired search order.
+ *
+ * @see #DEFAULT_IMPLICIT_PRIORITIES
+ */
+ public static final String IMPLICIT_PRIORITIES = PREFIX_PRIORITY + "implicit";
+
+ /**
+ * The default extension priority mode if {@link #IMPLICIT_PRIORITIES} isn't set.
+ */
+ public static final boolean DEFAULT_IMPLICIT_PRIORITIES = false;
+
+ /**
+ * A flag indicating whether interaction with the user is allowed.
+ *
+ * @see #DEFAULT_INTERACTIVE
+ */
+ public static final String INTERACTIVE = PREFIX_AETHER + "interactive";
+
+ /**
+ * The default interactive mode if {@link #INTERACTIVE} isn't set.
+ */
+ public static final boolean DEFAULT_INTERACTIVE = false;
+
+ /**
+ * The user agent that repository connectors should report to servers.
+ *
+ * @see #DEFAULT_USER_AGENT
+ */
+ public static final String USER_AGENT = PREFIX_CONNECTOR + "userAgent";
+
+ /**
+ * The default user agent to use if {@link #USER_AGENT} isn't set.
+ */
+ public static final String DEFAULT_USER_AGENT = "Aether";
+
+ /**
+ * The maximum amount of time (in milliseconds) to wait for a successful connection to a remote server. Non-positive
+ * values indicate no timeout.
+ *
+ * @see #DEFAULT_CONNECT_TIMEOUT
+ */
+ public static final String CONNECT_TIMEOUT = PREFIX_CONNECTOR + "connectTimeout";
+
+ /**
+ * The default connect timeout to use if {@link #CONNECT_TIMEOUT} isn't set.
+ */
+ public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000;
+
+ /**
+ * The maximum amount of time (in milliseconds) to wait for remaining data to arrive from a remote server. Note that
+ * this timeout does not restrict the overall duration of a request, it only restricts the duration of inactivity
+ * between consecutive data packets. Non-positive values indicate no timeout.
+ *
+ * @see #DEFAULT_REQUEST_TIMEOUT
+ */
+ public static final String REQUEST_TIMEOUT = PREFIX_CONNECTOR + "requestTimeout";
+
+ /**
+ * The default request timeout to use if {@link #REQUEST_TIMEOUT} isn't set.
+ */
+ public static final int DEFAULT_REQUEST_TIMEOUT = 1800 * 1000;
+
+ /**
+ * The request headers to use for HTTP-based repository connectors. The headers are specified using a
+ * {@code Map<String, String>}, mapping a header name to its value. Besides this general key, clients may also
+ * specify headers for a specific remote repository by appending the suffix {@code .<repoId>} to this key when
+ * storing the headers map. The repository-specific headers map is supposed to be complete, i.e. is not merged with
+ * the general headers map.
+ */
+ public static final String HTTP_HEADERS = PREFIX_CONNECTOR + "http.headers";
+
+ /**
+ * The encoding/charset to use when exchanging credentials with HTTP servers. Besides this general key, clients may
+ * also specify the encoding for a specific remote repository by appending the suffix {@code .<repoId>} to this key
+ * when storing the charset name.
+ *
+ * @see #DEFAULT_HTTP_CREDENTIAL_ENCODING
+ */
+ public static final String HTTP_CREDENTIAL_ENCODING = PREFIX_CONNECTOR + "http.credentialEncoding";
+
+ /**
+ * The default encoding/charset to use if {@link #HTTP_CREDENTIAL_ENCODING} isn't set.
+ */
+ public static final String DEFAULT_HTTP_CREDENTIAL_ENCODING = "ISO-8859-1";
+
+ /**
+ * An option indicating whether authentication configured for a HTTP repository should also be used with any host
+ * that the original server might redirect requests to. Unless enabled, credentials are only exchanged with the
+ * original host from the repository URL and not supplied to different hosts encountered during redirects. The
+ * option value can either be a boolean flag or a comma-separated list of host names denoting the whitelist of
+ * original hosts whose redirects can be trusted and should use the configured authentication no matter the
+ * destination host(s). Alternatively, the suffix {@code .<repoId>} can be appended to this configuration key to
+ * control the behavior for a specific repository id.
+ *
+ * @see #DEFAULT_HTTP_REDIRECTED_AUTHENTICATION
+ * @since 1.1.0
+ */
+ public static final String HTTP_REDIRECTED_AUTHENTICATION = PREFIX_CONNECTOR + "http.redirectedAuthentication";
+
+ /**
+ * The default handling of authentication during HTTP redirects if {@link #HTTP_REDIRECTED_AUTHENTICATION} isn't
+ * set.
+ *
+ * @since 1.1.0
+ */
+ public static final String DEFAULT_HTTP_REDIRECTED_AUTHENTICATION = "false";
+
+ /**
+ * A flag indicating whether checksums which are retrieved during checksum validation should be persisted in the
+ * local filesystem next to the file they provide the checksum for.
+ *
+ * @see #DEFAULT_PERSISTED_CHECKSUMS
+ */
+ public static final String PERSISTED_CHECKSUMS = PREFIX_CONNECTOR + "persistedChecksums";
+
+ /**
+ * The default checksum persistence mode if {@link #PERSISTED_CHECKSUMS} isn't set.
+ */
+ public static final boolean DEFAULT_PERSISTED_CHECKSUMS = true;
+
+ private ConfigurationProperties()
+ {
+ // hide constructor
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositoryCache.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositoryCache.java b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositoryCache.java
new file mode 100644
index 0000000..b645f43
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositoryCache.java
@@ -0,0 +1,52 @@
+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 java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A simplistic repository cache backed by a thread-safe map. The simplistic nature of this cache makes it only suitable
+ * for use with short-lived repository system sessions where pruning of cache data is not required.
+ */
+public final class DefaultRepositoryCache
+ implements RepositoryCache
+{
+
+ private final Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>( 256 );
+
+ public Object get( RepositorySystemSession session, Object key )
+ {
+ return cache.get( key );
+ }
+
+ public void put( RepositorySystemSession session, Object key, Object data )
+ {
+ if ( data != null )
+ {
+ cache.put( key, data );
+ }
+ else
+ {
+ cache.remove( key );
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..93ebaca
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultRepositorySystemSession.java
@@ -0,0 +1,834 @@
+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.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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.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;
+
+/**
+ * A simple repository system session.
+ * <p>
+ * <strong>Note:</strong> This class is not thread-safe. It is assumed that the mutators get only called during an
+ * 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.
+ */
+public final class DefaultRepositorySystemSession
+ implements RepositorySystemSession
+{
+
+ private boolean readOnly;
+
+ private boolean offline;
+
+ private boolean ignoreArtifactDescriptorRepositories;
+
+ private ResolutionErrorPolicy resolutionErrorPolicy;
+
+ private ArtifactDescriptorPolicy artifactDescriptorPolicy;
+
+ private String checksumPolicy;
+
+ private String updatePolicy;
+
+ private LocalRepositoryManager localRepositoryManager;
+
+ private WorkspaceReader workspaceReader;
+
+ private RepositoryListener repositoryListener;
+
+ private TransferListener transferListener;
+
+ private Map<String, String> systemProperties;
+
+ private Map<String, String> systemPropertiesView;
+
+ private Map<String, String> userProperties;
+
+ private Map<String, String> userPropertiesView;
+
+ private Map<String, Object> configProperties;
+
+ private Map<String, Object> 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. <em>Note:</em> 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.
+ */
+ public DefaultRepositorySystemSession()
+ {
+ systemProperties = new HashMap<String, String>();
+ systemPropertiesView = Collections.unmodifiableMap( systemProperties );
+ userProperties = new HashMap<String, String>();
+ userPropertiesView = Collections.unmodifiableMap( userProperties );
+ configProperties = new HashMap<String, Object>();
+ configPropertiesView = Collections.unmodifiableMap( configProperties );
+ mirrorSelector = NullMirrorSelector.INSTANCE;
+ proxySelector = NullProxySelector.INSTANCE;
+ authenticationSelector = NullAuthenticationSelector.INSTANCE;
+ artifactTypeRegistry = NullArtifactTypeRegistry.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}.
+ */
+ public DefaultRepositorySystemSession( RepositorySystemSession session )
+ {
+ if ( session == null )
+ {
+ throw new IllegalArgumentException( "repository system session not specified" );
+ }
+
+ 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() );
+ setData( session.getData() );
+ setCache( session.getCache() );
+ }
+
+ public boolean isOffline()
+ {
+ return offline;
+ }
+
+ /**
+ * 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}.
+ */
+ public DefaultRepositorySystemSession setOffline( boolean offline )
+ {
+ failIfReadOnly();
+ this.offline = offline;
+ return this;
+ }
+
+ public boolean isIgnoreArtifactDescriptorRepositories()
+ {
+ return ignoreArtifactDescriptorRepositories;
+ }
+
+ /**
+ * 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}.
+ */
+ public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories( boolean ignoreArtifactDescriptorRepositories )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setArtifactDescriptorPolicy( ArtifactDescriptorPolicy artifactDescriptorPolicy )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setChecksumPolicy( String checksumPolicy )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setUpdatePolicy( String updatePolicy )
+ {
+ failIfReadOnly();
+ 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. <em>Note:</em> 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 DefaultRepositorySystemSession setLocalRepositoryManager( LocalRepositoryManager localRepositoryManager )
+ {
+ failIfReadOnly();
+ this.localRepositoryManager = localRepositoryManager;
+ 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 DefaultRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setTransferListener( TransferListener transferListener )
+ {
+ failIfReadOnly();
+ this.transferListener = transferListener;
+ return this;
+ }
+
+ private <T> Map<String, T> copySafe( Map<?, ?> table, Class<T> valueType )
+ {
+ Map<String, T> map;
+ if ( table == null || table.isEmpty() )
+ {
+ map = new HashMap<String, T>();
+ }
+ else
+ {
+ map = new HashMap<String, T>( (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<String, String> 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.
+ * <p>
+ * <em>Note:</em> System properties are of type {@code Map<String, String>} 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 DefaultRepositorySystemSession setSystemProperties( Map<?, ?> systemProperties )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setSystemProperty( String key, String value )
+ {
+ failIfReadOnly();
+ if ( value != null )
+ {
+ systemProperties.put( key, value );
+ }
+ else
+ {
+ systemProperties.remove( key );
+ }
+ return this;
+ }
+
+ public Map<String, String> 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.
+ * <p>
+ * <em>Note:</em> User properties are of type {@code Map<String, String>} 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 DefaultRepositorySystemSession setUserProperties( Map<?, ?> userProperties )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setUserProperty( String key, String value )
+ {
+ failIfReadOnly();
+ if ( value != null )
+ {
+ userProperties.put( key, value );
+ }
+ else
+ {
+ userProperties.remove( key );
+ }
+ return this;
+ }
+
+ public Map<String, Object> getConfigProperties()
+ {
+ return configPropertiesView;
+ }
+
+ /**
+ * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
+ * connector-specific behavior, etc.).
+ * <p>
+ * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} 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 DefaultRepositorySystemSession setConfigProperties( Map<?, ?> configProperties )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setConfigProperty( String key, Object value )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector )
+ {
+ failIfReadOnly();
+ 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 org.eclipse.aether.repository.RemoteRepository#getProxy()
+ */
+ public DefaultRepositorySystemSession setProxySelector( ProxySelector proxySelector )
+ {
+ failIfReadOnly();
+ 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 org.eclipse.aether.repository.RemoteRepository#getAuthentication()
+ */
+ public DefaultRepositorySystemSession setAuthenticationSelector( AuthenticationSelector authenticationSelector )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setDependencyManager( DependencyManager dependencyManager )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setDependencySelector( DependencySelector dependencySelector )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setVersionFilter( VersionFilter versionFilter )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setDependencyGraphTransformer( DependencyGraphTransformer dependencyGraphTransformer )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setData( SessionData data )
+ {
+ failIfReadOnly();
+ 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 DefaultRepositorySystemSession setCache( RepositoryCache cache )
+ {
+ failIfReadOnly();
+ 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;
+ }
+
+ private void failIfReadOnly()
+ {
+ if ( readOnly )
+ {
+ throw new IllegalStateException( "repository system session is read-only" );
+ }
+ }
+
+ static class NullProxySelector
+ implements ProxySelector
+ {
+
+ public static final ProxySelector INSTANCE = new NullProxySelector();
+
+ public Proxy getProxy( RemoteRepository repository )
+ {
+ return repository.getProxy();
+ }
+
+ }
+
+ static class NullMirrorSelector
+ implements MirrorSelector
+ {
+
+ public static final MirrorSelector INSTANCE = new NullMirrorSelector();
+
+ public RemoteRepository getMirror( RemoteRepository repository )
+ {
+ return null;
+ }
+
+ }
+
+ static class NullAuthenticationSelector
+ implements AuthenticationSelector
+ {
+
+ public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector();
+
+ public Authentication getAuthentication( RemoteRepository repository )
+ {
+ return repository.getAuthentication();
+ }
+
+ }
+
+ static final class NullArtifactTypeRegistry
+ implements ArtifactTypeRegistry
+ {
+
+ public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
+
+ public ArtifactType get( String typeId )
+ {
+ return null;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java
new file mode 100644
index 0000000..e78df3a
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/DefaultSessionData.java
@@ -0,0 +1,91 @@
+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.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * A simple session data storage backed by a thread-safe map.
+ */
+public final class DefaultSessionData
+ implements SessionData
+{
+
+ private final ConcurrentMap<Object, Object> data;
+
+ public DefaultSessionData()
+ {
+ data = new ConcurrentHashMap<Object, Object>();
+ }
+
+ public void set( Object key, Object value )
+ {
+ if ( key == null )
+ {
+ throw new IllegalArgumentException( "key must not be null" );
+ }
+
+ if ( value != null )
+ {
+ data.put( key, value );
+ }
+ else
+ {
+ data.remove( key );
+ }
+ }
+
+ public boolean set( Object key, Object oldValue, Object newValue )
+ {
+ if ( key == null )
+ {
+ throw new IllegalArgumentException( "key must not be null" );
+ }
+
+ if ( newValue != null )
+ {
+ if ( oldValue == null )
+ {
+ return data.putIfAbsent( key, newValue ) == null;
+ }
+ return data.replace( key, oldValue, newValue );
+ }
+ else
+ {
+ if ( oldValue == null )
+ {
+ return !data.containsKey( key );
+ }
+ return data.remove( key, oldValue );
+ }
+ }
+
+ public Object get( Object key )
+ {
+ if ( key == null )
+ {
+ throw new IllegalArgumentException( "key must not be null" );
+ }
+
+ return data.get( key );
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java
new file mode 100644
index 0000000..6f9f114
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryCache.java
@@ -0,0 +1,59 @@
+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.
+ */
+
+/**
+ * Caches auxiliary data used during repository access like already processed metadata. The data in the cache is meant
+ * for exclusive consumption by the repository system and is opaque to the cache implementation. <strong>Note:</strong>
+ * Actual cache implementations must be thread-safe.
+ *
+ * @see RepositorySystemSession#getCache()
+ */
+public interface RepositoryCache
+{
+
+ /**
+ * Puts the specified data into the cache. It is entirely up to the cache implementation how long this data will be
+ * kept before being purged, i.e. callers must not make any assumptions about the lifetime of cached data.
+ * <p>
+ * <em>Warning:</em> The cache will directly save the provided reference. If the cached data is mutable, i.e. could
+ * be modified after being put into the cache, the caller is responsible for creating a copy of the original data
+ * and store the copy in the cache.
+ *
+ * @param session The repository session during which the cache is accessed, must not be {@code null}.
+ * @param key The key to use for lookup of the data, must not be {@code null}.
+ * @param data The data to store in the cache, may be {@code null}.
+ */
+ void put( RepositorySystemSession session, Object key, Object data );
+
+ /**
+ * Gets the specified data from the cache.
+ * <p>
+ * <em>Warning:</em> The cache will directly return the saved reference. If the cached data is to be modified after
+ * its retrieval, the caller is responsible to create a copy of the returned data and use this instead of the cache
+ * record.
+ *
+ * @param session The repository session during which the cache is accessed, must not be {@code null}.
+ * @param key The key to use for lookup of the data, must not be {@code null}.
+ * @return The requested data or {@code null} if none was present in the cache.
+ */
+ Object get( RepositorySystemSession session, Object key );
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java
new file mode 100644
index 0000000..33816ba
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryEvent.java
@@ -0,0 +1,442 @@
+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.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.ArtifactRepository;
+
+/**
+ * An event describing an action performed by the repository system. Note that events which indicate the end of an
+ * action like {@link EventType#ARTIFACT_RESOLVED} are generally fired in both the success and the failure case. Use
+ * {@link #getException()} to check whether an event denotes success or failure.
+ *
+ * @see RepositoryListener
+ * @see RepositoryEvent.Builder
+ */
+public final class RepositoryEvent
+{
+
+ /**
+ * The type of the repository event.
+ */
+ public enum EventType
+ {
+
+ /**
+ * @see RepositoryListener#artifactDescriptorInvalid(RepositoryEvent)
+ */
+ ARTIFACT_DESCRIPTOR_INVALID,
+
+ /**
+ * @see RepositoryListener#artifactDescriptorMissing(RepositoryEvent)
+ */
+ ARTIFACT_DESCRIPTOR_MISSING,
+
+ /**
+ * @see RepositoryListener#metadataInvalid(RepositoryEvent)
+ */
+ METADATA_INVALID,
+
+ /**
+ * @see RepositoryListener#artifactResolving(RepositoryEvent)
+ */
+ ARTIFACT_RESOLVING,
+
+ /**
+ * @see RepositoryListener#artifactResolved(RepositoryEvent)
+ */
+ ARTIFACT_RESOLVED,
+
+ /**
+ * @see RepositoryListener#metadataResolving(RepositoryEvent)
+ */
+ METADATA_RESOLVING,
+
+ /**
+ * @see RepositoryListener#metadataResolved(RepositoryEvent)
+ */
+ METADATA_RESOLVED,
+
+ /**
+ * @see RepositoryListener#artifactDownloading(RepositoryEvent)
+ */
+ ARTIFACT_DOWNLOADING,
+
+ /**
+ * @see RepositoryListener#artifactDownloaded(RepositoryEvent)
+ */
+ ARTIFACT_DOWNLOADED,
+
+ /**
+ * @see RepositoryListener#metadataDownloading(RepositoryEvent)
+ */
+ METADATA_DOWNLOADING,
+
+ /**
+ * @see RepositoryListener#metadataDownloaded(RepositoryEvent)
+ */
+ METADATA_DOWNLOADED,
+
+ /**
+ * @see RepositoryListener#artifactInstalling(RepositoryEvent)
+ */
+ ARTIFACT_INSTALLING,
+
+ /**
+ * @see RepositoryListener#artifactInstalled(RepositoryEvent)
+ */
+ ARTIFACT_INSTALLED,
+
+ /**
+ * @see RepositoryListener#metadataInstalling(RepositoryEvent)
+ */
+ METADATA_INSTALLING,
+
+ /**
+ * @see RepositoryListener#metadataInstalled(RepositoryEvent)
+ */
+ METADATA_INSTALLED,
+
+ /**
+ * @see RepositoryListener#artifactDeploying(RepositoryEvent)
+ */
+ ARTIFACT_DEPLOYING,
+
+ /**
+ * @see RepositoryListener#artifactDeployed(RepositoryEvent)
+ */
+ ARTIFACT_DEPLOYED,
+
+ /**
+ * @see RepositoryListener#metadataDeploying(RepositoryEvent)
+ */
+ METADATA_DEPLOYING,
+
+ /**
+ * @see RepositoryListener#metadataDeployed(RepositoryEvent)
+ */
+ METADATA_DEPLOYED
+
+ }
+
+ private final EventType type;
+
+ private final RepositorySystemSession session;
+
+ private final Artifact artifact;
+
+ private final Metadata metadata;
+
+ private final ArtifactRepository repository;
+
+ private final File file;
+
+ private final List<Exception> exceptions;
+
+ private final RequestTrace trace;
+
+ RepositoryEvent( Builder builder )
+ {
+ type = builder.type;
+ session = builder.session;
+ artifact = builder.artifact;
+ metadata = builder.metadata;
+ repository = builder.repository;
+ file = builder.file;
+ exceptions = builder.exceptions;
+ trace = builder.trace;
+ }
+
+ /**
+ * Gets the type of the event.
+ *
+ * @return The type of the event, never {@code null}.
+ */
+ public EventType getType()
+ {
+ return type;
+ }
+
+ /**
+ * Gets the repository system session during which the event occurred.
+ *
+ * @return The repository system session during which the event occurred, never {@code null}.
+ */
+ public RepositorySystemSession getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Gets the artifact involved in the event (if any).
+ *
+ * @return The involved artifact or {@code null} if none.
+ */
+ public Artifact getArtifact()
+ {
+ return artifact;
+ }
+
+ /**
+ * Gets the metadata involved in the event (if any).
+ *
+ * @return The involved metadata or {@code null} if none.
+ */
+ public Metadata getMetadata()
+ {
+ return metadata;
+ }
+
+ /**
+ * Gets the file involved in the event (if any).
+ *
+ * @return The involved file or {@code null} if none.
+ */
+ public File getFile()
+ {
+ return file;
+ }
+
+ /**
+ * Gets the repository involved in the event (if any).
+ *
+ * @return The involved repository or {@code null} if none.
+ */
+ public ArtifactRepository getRepository()
+ {
+ return repository;
+ }
+
+ /**
+ * Gets the exception that caused the event (if any). As a rule of thumb, an event accompanied by an exception
+ * indicates a failure of the corresponding action. If multiple exceptions occurred, this method returns the first
+ * exception.
+ *
+ * @return The exception or {@code null} if none.
+ */
+ public Exception getException()
+ {
+ return exceptions.isEmpty() ? null : exceptions.get( 0 );
+ }
+
+ /**
+ * Gets the exceptions that caused the event (if any). As a rule of thumb, an event accompanied by exceptions
+ * indicates a failure of the corresponding action.
+ *
+ * @return The exceptions, never {@code null}.
+ */
+ public List<Exception> getExceptions()
+ {
+ return exceptions;
+ }
+
+ /**
+ * Gets the trace information about the request during which the event occurred.
+ *
+ * @return The trace information or {@code null} if none.
+ */
+ public RequestTrace getTrace()
+ {
+ return trace;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder buffer = new StringBuilder( 256 );
+ buffer.append( getType() );
+ if ( getArtifact() != null )
+ {
+ buffer.append( " " ).append( getArtifact() );
+ }
+ if ( getMetadata() != null )
+ {
+ buffer.append( " " ).append( getMetadata() );
+ }
+ if ( getFile() != null )
+ {
+ buffer.append( " (" ).append( getFile() ).append( ")" );
+ }
+ if ( getRepository() != null )
+ {
+ buffer.append( " @ " ).append( getRepository() );
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * A builder to create events.
+ */
+ public static final class Builder
+ {
+
+ EventType type;
+
+ RepositorySystemSession session;
+
+ Artifact artifact;
+
+ Metadata metadata;
+
+ ArtifactRepository repository;
+
+ File file;
+
+ List<Exception> exceptions = Collections.emptyList();
+
+ RequestTrace trace;
+
+ /**
+ * Creates a new event builder for the specified session and event type.
+ *
+ * @param session The repository system session, must not be {@code null}.
+ * @param type The type of the event, must not be {@code null}.
+ */
+ public Builder( RepositorySystemSession session, EventType type )
+ {
+ if ( session == null )
+ {
+ throw new IllegalArgumentException( "session not specified" );
+ }
+ this.session = session;
+ if ( type == null )
+ {
+ throw new IllegalArgumentException( "event type not specified" );
+ }
+ this.type = type;
+ }
+
+ /**
+ * Sets the artifact involved in the event.
+ *
+ * @param artifact The involved artifact, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setArtifact( Artifact artifact )
+ {
+ this.artifact = artifact;
+ return this;
+ }
+
+ /**
+ * Sets the metadata involved in the event.
+ *
+ * @param metadata The involved metadata, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setMetadata( Metadata metadata )
+ {
+ this.metadata = metadata;
+ return this;
+ }
+
+ /**
+ * Sets the repository involved in the event.
+ *
+ * @param repository The involved repository, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setRepository( ArtifactRepository repository )
+ {
+ this.repository = repository;
+ return this;
+ }
+
+ /**
+ * Sets the file involved in the event.
+ *
+ * @param file The involved file, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setFile( File file )
+ {
+ this.file = file;
+ return this;
+ }
+
+ /**
+ * Sets the exception causing the event.
+ *
+ * @param exception The exception causing the event, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setException( Exception exception )
+ {
+ if ( exception != null )
+ {
+ this.exceptions = Collections.singletonList( exception );
+ }
+ else
+ {
+ this.exceptions = Collections.emptyList();
+ }
+ return this;
+ }
+
+ /**
+ * Sets the exceptions causing the event.
+ *
+ * @param exceptions The exceptions causing the event, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setExceptions( List<Exception> exceptions )
+ {
+ if ( exceptions != null )
+ {
+ this.exceptions = exceptions;
+ }
+ else
+ {
+ this.exceptions = Collections.emptyList();
+ }
+ return this;
+ }
+
+ /**
+ * Sets the trace information about the request during which the event occurred.
+ *
+ * @param trace The trace information, may be {@code null}.
+ * @return This event builder for chaining, never {@code null}.
+ */
+ public Builder setTrace( RequestTrace trace )
+ {
+ this.trace = trace;
+ return this;
+ }
+
+ /**
+ * Builds a new event from the current values of this builder. The state of the builder itself remains
+ * unchanged.
+ *
+ * @return The event, never {@code null}.
+ */
+ public RepositoryEvent build()
+ {
+ return new RepositoryEvent( this );
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java
new file mode 100644
index 0000000..83a6cac
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java
@@ -0,0 +1,72 @@
+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.
+ */
+
+/**
+ * The base class for exceptions thrown by the repository system. <em>Note:</em> Unless otherwise noted, instances of
+ * this class and its subclasses will not persist fields carrying extended error information during serialization.
+ */
+public class RepositoryException
+ extends Exception
+{
+
+ /**
+ * Creates a new exception with the specified detail message.
+ *
+ * @param message The detail message, may be {@code null}.
+ */
+ public RepositoryException( String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Creates a new exception with the specified detail message and cause.
+ *
+ * @param message The detail message, may be {@code null}.
+ * @param cause The exception that caused this one, may be {@code null}.
+ */
+ public RepositoryException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+
+ /**
+ * @noreference This method is not intended to be used by clients.
+ * @param prefix A message prefix for the cause.
+ * @param cause The error cause.
+ * @return The error message for the cause.
+ */
+ protected static String getMessage( String prefix, Throwable cause )
+ {
+ String msg = "";
+ if ( cause != null )
+ {
+ msg = cause.getMessage();
+ if ( msg == null || msg.length() <= 0 )
+ {
+ msg = cause.getClass().getSimpleName();
+ }
+ msg = prefix + msg;
+ }
+ return msg;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/maven-aether/blob/27f8bd73/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java
new file mode 100644
index 0000000..d654630
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryListener.java
@@ -0,0 +1,222 @@
+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.
+ */
+
+/**
+ * A listener being notified of events from the repository system. In general, the system sends events upon termination
+ * of an operation like {@link #artifactResolved(RepositoryEvent)} regardless whether it succeeded or failed so
+ * listeners need to inspect the event details carefully. Also, the listener may be called from an arbitrary thread.
+ * <em>Note:</em> Implementors are strongly advised to inherit from {@link AbstractRepositoryListener} instead of
+ * directly implementing this interface.
+ *
+ * @see org.eclipse.aether.RepositorySystemSession#getRepositoryListener()
+ * @see org.eclipse.aether.transfer.TransferListener
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface RepositoryListener
+{
+
+ /**
+ * Notifies the listener of a syntactically or semantically invalid artifact descriptor.
+ * {@link RepositoryEvent#getArtifact()} indicates the artifact whose descriptor is invalid and
+ * {@link RepositoryEvent#getExceptions()} carries the encountered errors. Depending on the session's
+ * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort
+ * with an exception or ignore the invalid descriptor.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDescriptorInvalid( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of a missing artifact descriptor. {@link RepositoryEvent#getArtifact()} indicates the
+ * artifact whose descriptor is missing. Depending on the session's
+ * {@link org.eclipse.aether.resolution.ArtifactDescriptorPolicy}, the underlying repository operation might abort
+ * with an exception or ignore the missing descriptor.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDescriptorMissing( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of syntactically or semantically invalid metadata. {@link RepositoryEvent#getMetadata()}
+ * indicates the invalid metadata and {@link RepositoryEvent#getExceptions()} carries the encountered errors. The
+ * underlying repository operation might still succeed, depending on whether the metadata in question is actually
+ * needed to carry out the resolution process.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataInvalid( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact that is about to be resolved. {@link RepositoryEvent#getArtifact()} denotes
+ * the artifact in question. Unlike the {@link #artifactDownloading(RepositoryEvent)} event, this event is fired
+ * regardless whether the artifact already exists locally or not.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactResolving( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact whose resolution has been completed, either successfully or not.
+ * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the
+ * {@link #artifactDownloaded(RepositoryEvent)} event, this event is fired regardless whether the artifact already
+ * exists locally or not.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactResolved( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata that is about to be resolved. {@link RepositoryEvent#getMetadata()}
+ * denotes the metadata in question. Unlike the {@link #metadataDownloading(RepositoryEvent)} event, this event is
+ * fired regardless whether the metadata already exists locally or not.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataResolving( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata whose resolution has been completed, either successfully or not.
+ * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the resolution succeeded or failed. Unlike the
+ * {@link #metadataDownloaded(RepositoryEvent)} event, this event is fired regardless whether the metadata already
+ * exists locally or not.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataResolved( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact that is about to be downloaded from a remote repository.
+ * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getRepository()} the source repository. Unlike the
+ * {@link #artifactResolving(RepositoryEvent)} event, this event is only fired when the artifact does not already
+ * exist locally.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDownloading( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact whose download has been completed, either successfully or not.
+ * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the
+ * {@link #artifactResolved(RepositoryEvent)} event, this event is only fired when the artifact does not already
+ * exist locally.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDownloaded( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata that is about to be downloaded from a remote repository.
+ * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getRepository()} the source repository. Unlike the
+ * {@link #metadataResolving(RepositoryEvent)} event, this event is only fired when the metadata does not already
+ * exist locally.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataDownloading( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata whose download has been completed, either successfully or not.
+ * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the download succeeded or failed. Unlike the
+ * {@link #metadataResolved(RepositoryEvent)} event, this event is only fired when the metadata does not already
+ * exist locally.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataDownloaded( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact that is about to be installed to the local repository.
+ * {@link RepositoryEvent#getArtifact()} denotes the artifact in question.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactInstalling( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact whose installation to the local repository has been completed, either
+ * successfully or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactInstalled( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata that is about to be installed to the local repository.
+ * {@link RepositoryEvent#getMetadata()} denotes the metadata in question.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataInstalling( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata whose installation to the local repository has been completed, either
+ * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the installation succeeded or failed.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataInstalled( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact that is about to be uploaded to a remote repository.
+ * {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getRepository()} the destination repository.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDeploying( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of an artifact whose upload to a remote repository has been completed, either successfully
+ * or not. {@link RepositoryEvent#getArtifact()} denotes the artifact in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void artifactDeployed( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata that is about to be uploaded to a remote repository.
+ * {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getRepository()} the destination repository.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataDeploying( RepositoryEvent event );
+
+ /**
+ * Notifies the listener of some metadata whose upload to a remote repository has been completed, either
+ * successfully or not. {@link RepositoryEvent#getMetadata()} denotes the metadata in question and
+ * {@link RepositoryEvent#getExceptions()} indicates whether the upload succeeded or failed.
+ *
+ * @param event The event details, must not be {@code null}.
+ */
+ void metadataDeployed( RepositoryEvent event );
+
+}