http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/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-resolver/blob/3a1b8ae0/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-resolver/blob/3a1b8ae0/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-resolver/blob/3a1b8ae0/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..c2d1718
--- /dev/null
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositoryException.java
@@ -0,0 +1,69 @@
+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.
+     */
+    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-resolver/blob/3a1b8ae0/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 );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..8706f89
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystem.java
@@ -0,0 +1,277 @@
+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.Collection;
+import java.util.List;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.CollectResult;
+import org.eclipse.aether.collection.DependencyCollectionException;
+import org.eclipse.aether.deployment.DeployRequest;
+import org.eclipse.aether.deployment.DeployResult;
+import org.eclipse.aether.deployment.DeploymentException;
+import org.eclipse.aether.installation.InstallRequest;
+import org.eclipse.aether.installation.InstallResult;
+import org.eclipse.aether.installation.InstallationException;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactDescriptorException;
+import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyRequest;
+import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
+import org.eclipse.aether.resolution.MetadataRequest;
+import org.eclipse.aether.resolution.MetadataResult;
+import org.eclipse.aether.resolution.VersionRangeRequest;
+import org.eclipse.aether.resolution.VersionRangeResolutionException;
+import org.eclipse.aether.resolution.VersionRangeResult;
+import org.eclipse.aether.resolution.VersionRequest;
+import org.eclipse.aether.resolution.VersionResolutionException;
+import org.eclipse.aether.resolution.VersionResult;
+
+/**
+ * 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.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface RepositorySystem
+{
+
+    /**
+     * Expands a version range to a list of matching versions, in ascending 
order. For example, resolves "[3.8,4.0)" to
+     * "3.8", "3.8.1", "3.8.2". Note that the returned list of versions is 
only dependent on the configured repositories
+     * and their contents, the list is not processed by the {@link 
RepositorySystemSession#getVersionFilter() session's
+     * version filter}.
+     * <p>
+     * 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.
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    VersionRangeResult resolveVersionRange( RepositorySystemSession session, 
VersionRangeRequest request )
+        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}.
+     * @throws VersionResolutionException If the metaversion could not be 
resolved.
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    VersionResult resolveVersion( RepositorySystemSession session, 
VersionRequest request )
+        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}.
+     * @throws ArtifactDescriptorException If the artifact descriptor could 
not be read.
+     * @see RepositorySystemSession#getArtifactDescriptorPolicy()
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession 
session, ArtifactDescriptorRequest request )
+        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}.
+     * @throws DependencyCollectionException If the dependency tree could not 
be built.
+     * @see RepositorySystemSession#getDependencyTraverser()
+     * @see RepositorySystemSession#getDependencyManager()
+     * @see RepositorySystemSession#getDependencySelector()
+     * @see RepositorySystemSession#getVersionFilter()
+     * @see RepositorySystemSession#getDependencyGraphTransformer()
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    CollectResult collectDependencies( RepositorySystemSession session, 
CollectRequest request )
+        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.
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    DependencyResult resolveDependencies( RepositorySystemSession session, 
DependencyRequest request )
+        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}.
+     * @throws ArtifactResolutionException If the artifact could not be 
resolved.
+     * @see Artifact#getFile()
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    ArtifactResult resolveArtifact( RepositorySystemSession session, 
ArtifactRequest request )
+        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 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.
+     * @see Artifact#getFile()
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    List<ArtifactResult> resolveArtifacts( RepositorySystemSession session,
+                                           Collection<? extends 
ArtifactRequest> requests )
+        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 requests The resolution requests, must not be {@code null}.
+     * @return The resolution results (in request order), never {@code null}.
+     * @see Metadata#getFile()
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    List<MetadataResult> resolveMetadata( RepositorySystemSession session,
+                                          Collection<? extends 
MetadataRequest> requests );
+
+    /**
+     * 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;
+
+    /**
+     * 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}.
+     * @throws DeploymentException If any artifact/metadata from the request 
could not be deployed.
+     * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository)
+     */
+    DeployResult deploy( RepositorySystemSession session, DeployRequest 
request )
+        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. 
<em>Note:</em> 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 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.
+     */
+    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.
+     * @return The synchronization context, never {@code null}.
+     */
+    SyncContext newSyncContext( RepositorySystemSession session, boolean 
shared );
+
+    /**
+     * Forms remote repositories suitable for artifact resolution by applying 
the session's authentication selector and
+     * similar network configuration to the given repository prototypes. As 
noted for
+     * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the 
remote repositories passed to e.g.
+     * {@link #resolveArtifact(RepositorySystemSession, ArtifactRequest) 
resolveArtifact()} are used as is and expected
+     * 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 repositories The repository prototypes from which to derive the 
resolution repositories, must not be
+     *            {@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.
+     * @see #newDeploymentRepository(RepositorySystemSession, RemoteRepository)
+     */
+    List<RemoteRepository> newResolutionRepositories( RepositorySystemSession 
session,
+                                                      List<RemoteRepository> 
repositories );
+
+    /**
+     * Forms a remote repository suitable for artifact deployment by applying 
the session's authentication selector and
+     * similar network configuration to the given repository prototype. As 
noted for
+     * {@link RepositorySystemSession#getAuthenticationSelector()} etc. the 
remote repository passed to
+     * {@link #deploy(RepositorySystemSession, DeployRequest) deploy()} is 
used as is and expected 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 deploy request.
+     * 
+     * @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}.
+     * @return The deployment repository, never {@code null}.
+     * @see #newResolutionRepositories(RepositorySystemSession, List)
+     */
+    RemoteRepository newDeploymentRepository( RepositorySystemSession session, 
RemoteRepository repository );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..888f29c
--- /dev/null
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/RepositorySystemSession.java
@@ -0,0 +1,263 @@
+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.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.MirrorSelector;
+import org.eclipse.aether.repository.ProxySelector;
+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;
+
+/**
+ * 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.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface RepositorySystemSession
+{
+
+    /**
+     * Indicates whether the repository system operates in offline mode and 
avoids/refuses any access to remote
+     * repositories.
+     * 
+     * @return {@code true} if the repository system is in offline mode, 
{@code false} otherwise.
+     */
+    boolean isOffline();
+
+    /**
+     * Indicates 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.
+     * 
+     * @return {@code true} if additional repositories from artifact 
descriptors are ignored, {@code false} to merge
+     *         those with the originally specified repositories.
+     */
+    boolean isIgnoreArtifactDescriptorRepositories();
+
+    /**
+     * Gets the policy which controls whether resolutions errors from remote 
repositories should be cached.
+     * 
+     * @return The resolution error policy for this session or {@code null} if 
resolution errors should generally not be
+     *         cached.
+     */
+    ResolutionErrorPolicy getResolutionErrorPolicy();
+
+    /**
+     * Gets the policy which controls how errors related to reading artifact 
descriptors should be handled.
+     * 
+     * @return The descriptor error policy for this session or {@code null} if 
descriptor errors should generally not be
+     *         tolerated.
+     */
+    ArtifactDescriptorPolicy getArtifactDescriptorPolicy();
+
+    /**
+     * Gets the global checksum policy. If set, the global checksum policy 
overrides the checksum policies of the remote
+     * repositories being used for resolution.
+     * 
+     * @return The global checksum policy or {@code null}/empty if not set and 
the per-repository policies apply.
+     * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL
+     * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE
+     * @see RepositoryPolicy#CHECKSUM_POLICY_WARN
+     */
+    String getChecksumPolicy();
+
+    /**
+     * Gets the global update policy. If set, the global update policy 
overrides the update policies of the remote
+     * repositories being used for resolution.
+     * 
+     * @return The global update policy or {@code null}/empty if not set and 
the per-repository policies apply.
+     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
+     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
+     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
+     */
+    String getUpdatePolicy();
+
+    /**
+     * Gets the local repository used during this session. This is a 
convenience method for
+     * {@link LocalRepositoryManager#getRepository()}.
+     * 
+     * @return The local repository being during this session, never {@code 
null}.
+     */
+    LocalRepository getLocalRepository();
+
+    /**
+     * Gets the local repository manager used during this session.
+     * 
+     * @return The local repository manager used during this session, never 
{@code null}.
+     */
+    LocalRepositoryManager getLocalRepositoryManager();
+
+    /**
+     * Gets the workspace reader used during this session. If set, the 
workspace reader will usually be consulted first
+     * to resolve artifacts.
+     * 
+     * @return The workspace reader for this session or {@code null} if none.
+     */
+    WorkspaceReader getWorkspaceReader();
+
+    /**
+     * Gets the listener being notified of actions in the repository system.
+     * 
+     * @return The repository listener or {@code null} if none.
+     */
+    RepositoryListener getRepositoryListener();
+
+    /**
+     * Gets the listener being notified of uploads/downloads by the repository 
system.
+     * 
+     * @return The transfer listener or {@code null} if none.
+     */
+    TransferListener getTransferListener();
+
+    /**
+     * Gets 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.
+     * 
+     * @return The (read-only) system properties, never {@code null}.
+     */
+    Map<String, String> getSystemProperties();
+
+    /**
+     * Gets 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.
+     * 
+     * @return The (read-only) user properties, never {@code null}.
+     */
+    Map<String, String> getUserProperties();
+
+    /**
+     * Gets the configuration properties used to tweak internal aspects of the 
repository system (e.g. thread pooling,
+     * connector-specific behavior, etc.)
+     * 
+     * @return The (read-only) configuration properties, never {@code null}.
+     * @see ConfigurationProperties
+     */
+    Map<String, Object> getConfigProperties();
+
+    /**
+     * Gets 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.
+     * 
+     * @return The mirror selector to use, never {@code null}.
+     * @see 
RepositorySystem#newResolutionRepositories(RepositorySystemSession, 
java.util.List)
+     */
+    MirrorSelector getMirrorSelector();
+
+    /**
+     * Gets 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.
+     * 
+     * @return The proxy selector to use, never {@code null}.
+     * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
+     * @see 
RepositorySystem#newResolutionRepositories(RepositorySystemSession, 
java.util.List)
+     */
+    ProxySelector getProxySelector();
+
+    /**
+     * Gets 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.
+     * 
+     * @return The authentication selector to use, never {@code null}.
+     * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
+     * @see 
RepositorySystem#newResolutionRepositories(RepositorySystemSession, 
java.util.List)
+     */
+    AuthenticationSelector getAuthenticationSelector();
+
+    /**
+     * Gets the registry of artifact types recognized by this session, for 
instance when processing artifact
+     * descriptors.
+     * 
+     * @return The artifact type registry, never {@code null}.
+     */
+    ArtifactTypeRegistry getArtifactTypeRegistry();
+
+    /**
+     * Gets the dependency traverser to use for building dependency graphs.
+     * 
+     * @return The dependency traverser to use for building dependency graphs 
or {@code null} if dependencies are
+     *         unconditionally traversed.
+     */
+    DependencyTraverser getDependencyTraverser();
+
+    /**
+     * Gets the dependency manager to use for building dependency graphs.
+     * 
+     * @return The dependency manager to use for building dependency graphs or 
{@code null} if dependency management is
+     *         not performed.
+     */
+    DependencyManager getDependencyManager();
+
+    /**
+     * Gets the dependency selector to use for building dependency graphs.
+     * 
+     * @return The dependency selector to use for building dependency graphs 
or {@code null} if dependencies are
+     *         unconditionally included.
+     */
+    DependencySelector getDependencySelector();
+
+    /**
+     * Gets the version filter to use for building dependency graphs.
+     * 
+     * @return The version filter to use for building dependency graphs or 
{@code null} if versions aren't filtered.
+     */
+    VersionFilter getVersionFilter();
+
+    /**
+     * Gets the dependency graph transformer to use for building dependency 
graphs.
+     * 
+     * @return The dependency graph transformer to use for building dependency 
graphs or {@code null} if none.
+     */
+    DependencyGraphTransformer getDependencyGraphTransformer();
+
+    /**
+     * Gets the custom data associated with this session.
+     * 
+     * @return The session data, never {@code null}.
+     */
+    SessionData getData();
+
+    /**
+     * Gets the cache the repository system may use to save data for future 
reuse during the session.
+     * 
+     * @return The repository cache or {@code null} if none.
+     */
+    RepositoryCache getCache();
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java
----------------------------------------------------------------------
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java 
b/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java
new file mode 100644
index 0000000..86aaa78
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/RequestTrace.java
@@ -0,0 +1,117 @@
+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 trace of nested requests that are performed by the repository system. 
This trace information can be used to
+ * correlate repository events with higher level operations in the application 
code that eventually caused the events. A
+ * single trace can carry an arbitrary object as data which is meant to 
describe a request/operation that is currently
+ * executed. For call hierarchies within the repository system itself, this 
data will usually be the {@code *Request}
+ * object that is currently processed. When invoking methods on the repository 
system, client code may provide a request
+ * trace that has been prepopulated with whatever data is useful for the 
application to indicate its state for later
+ * evaluation when processing the repository events.
+ * 
+ * @see RepositoryEvent#getTrace()
+ */
+public class RequestTrace
+{
+
+    private final RequestTrace parent;
+
+    private final Object data;
+
+    /**
+     * Creates a child of the specified request trace. This method is 
basically a convenience that will invoke
+     * {@link RequestTrace#newChild(Object) parent.newChild()} when the 
specified parent trace is not {@code null} or
+     * otherwise instantiante a new root trace.
+     * 
+     * @param parent The parent request trace, may be {@code null}.
+     * @param data The data to associate with the child trace, may be {@code 
null}.
+     * @return The child trace, never {@code null}.
+     */
+    public static RequestTrace newChild( RequestTrace parent, Object data )
+    {
+        if ( parent == null )
+        {
+            return new RequestTrace( data );
+        }
+        return parent.newChild( data );
+    }
+
+    /**
+     * Creates a new root trace with the specified data.
+     * 
+     * @param data The data to associate with the trace, may be {@code null}.
+     */
+    public RequestTrace( Object data )
+    {
+        this( null, data );
+    }
+
+    /**
+     * Creates a new trace with the specified data and parent
+     * 
+     * @param parent The parent trace, may be {@code null} for a root trace.
+     * @param data The data to associate with the trace, may be {@code null}.
+     */
+    protected RequestTrace( RequestTrace parent, Object data )
+    {
+        this.parent = parent;
+        this.data = data;
+    }
+
+    /**
+     * Gets the data associated with this trace.
+     * 
+     * @return The data associated with this trace or {@code null} if none.
+     */
+    public final Object getData()
+    {
+        return data;
+    }
+
+    /**
+     * Gets the parent of this trace.
+     * 
+     * @return The parent of this trace or {@code null} if this is the root of 
the trace stack.
+     */
+    public final RequestTrace getParent()
+    {
+        return parent;
+    }
+
+    /**
+     * Creates a new child of this trace.
+     * 
+     * @param data The data to associate with the child, may be {@code null}.
+     * @return The child trace, never {@code null}.
+     */
+    public RequestTrace newChild( Object data )
+    {
+        return new RequestTrace( this, data );
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getData() );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java
----------------------------------------------------------------------
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java 
b/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java
new file mode 100644
index 0000000..b6efeac
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SessionData.java
@@ -0,0 +1,66 @@
+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 container for data that is specific to a repository system session. Both 
components within the repository system
+ * and clients of the system may use this storage to associate arbitrary data 
with a session.
+ * <p>
+ * Unlike a cache, this session data is not subject to purging. For this same 
reason, session data should also not be
+ * abused as a cache (i.e. for storing values that can be re-calculated) to 
avoid memory exhaustion.
+ * <p>
+ * <strong>Note:</strong> Actual implementations must be thread-safe.
+ * 
+ * @see RepositorySystemSession#getData()
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface SessionData
+{
+
+    /**
+     * Associates the specified session data with the given key.
+     * 
+     * @param key The key under which to store the session data, must not be 
{@code null}.
+     * @param value The data to associate with the key, may be {@code null} to 
remove the mapping.
+     */
+    void set( Object key, Object value );
+
+    /**
+     * Associates the specified session data with the given key if the key is 
currently mapped to the given value. This
+     * method provides an atomic compare-and-update of some key's value.
+     * 
+     * @param key The key under which to store the session data, must not be 
{@code null}.
+     * @param oldValue The expected data currently associated with the key, 
may be {@code null}.
+     * @param newValue The data to associate with the key, may be {@code null} 
to remove the mapping.
+     * @return {@code true} if the key mapping was successfully updated from 
the old value to the new value,
+     *         {@code false} if the current key mapping didn't match the 
expected value and was not updated.
+     */
+    boolean set( Object key, Object oldValue, Object newValue );
+
+    /**
+     * Gets the session data associated with the specified key.
+     * 
+     * @param key The key for which to retrieve the session data, must not be 
{@code null}.
+     * @return The session data associated with the key or {@code null} if 
none.
+     */
+    Object get( Object key );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
----------------------------------------------------------------------
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java 
b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
new file mode 100644
index 0000000..2d751c0
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/SyncContext.java
@@ -0,0 +1,76 @@
+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.Closeable;
+import java.util.Collection;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * A synchronization context used to coordinate concurrent access to artifacts 
or metadatas. The typical usage of a
+ * synchronization context looks like this:
+ * 
+ * <pre>
+ * SyncContext syncContext = repositorySystem.newSyncContext( ... );
+ * try {
+ *     syncContext.acquire( artifacts, metadatas );
+ *     // work with the artifacts and metadatas
+ * } finally {
+ *     syncContext.close();
+ * }
+ * </pre>
+ * 
+ * Within one thread, synchronization contexts may be nested which can 
naturally happen in a hierarchy of method calls.
+ * The nested synchronization contexts may also acquire overlapping sets of 
artifacts/metadatas as long as the following
+ * conditions are met. If the outer-most context holding a particular resource 
is exclusive, that resource can be
+ * reacquired in any nested context. If however the outer-most context is 
shared, the resource may only be reacquired by
+ * nested contexts if these are also shared.
+ * <p>
+ * A synchronization context is meant to be utilized by only one thread and as 
such is not thread-safe.
+ * <p>
+ * Note that the level of actual synchronization is subject to the 
implementation and might range from OS-wide to none.
+ * 
+ * @see RepositorySystem#newSyncContext(RepositorySystemSession, boolean)
+ */
+public interface SyncContext
+    extends Closeable
+{
+
+    /**
+     * Acquires synchronized access to the specified artifacts and metadatas. 
The invocation will potentially block
+     * until all requested resources can be acquired by the calling thread. 
Acquiring resources that are already
+     * acquired by this synchronization context has no effect. Please also see 
the class-level documentation for
+     * information regarding reentrancy. The method may be invoked multiple 
times on a synchronization context until all
+     * desired resources have been acquired.
+     * 
+     * @param artifacts The artifacts to acquire, may be {@code null} or empty 
if none.
+     * @param metadatas The metadatas to acquire, may be {@code null} or empty 
if none.
+     */
+    void acquire( Collection<? extends Artifact> artifacts, Collection<? 
extends Metadata> metadatas );
+
+    /**
+     * Releases all previously acquired artifacts/metadatas. If no resources 
have been acquired before or if this
+     * synchronization context has already been closed, this method does 
nothing.
+     */
+    void close();
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java
----------------------------------------------------------------------
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java
 
b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java
new file mode 100644
index 0000000..d89260b
--- /dev/null
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/AbstractArtifact.java
@@ -0,0 +1,230 @@
+package org.eclipse.aether.artifact;
+
+/*
+ * 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.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A skeleton class for artifacts.
+ */
+public abstract class AbstractArtifact
+    implements Artifact
+{
+
+    private static final String SNAPSHOT = "SNAPSHOT";
+
+    private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile( 
"^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$" );
+
+    public boolean isSnapshot()
+    {
+        return isSnapshot( getVersion() );
+    }
+
+    private static boolean isSnapshot( String version )
+    {
+        return version.endsWith( SNAPSHOT ) || SNAPSHOT_TIMESTAMP.matcher( 
version ).matches();
+    }
+
+    public String getBaseVersion()
+    {
+        return toBaseVersion( getVersion() );
+    }
+
+    private static String toBaseVersion( String version )
+    {
+        String baseVersion;
+
+        if ( version == null )
+        {
+            baseVersion = version;
+        }
+        else if ( version.startsWith( "[" ) || version.startsWith( "(" ) )
+        {
+            baseVersion = version;
+        }
+        else
+        {
+            Matcher m = SNAPSHOT_TIMESTAMP.matcher( version );
+            if ( m.matches() )
+            {
+                if ( m.group( 1 ) != null )
+                {
+                    baseVersion = m.group( 1 ) + SNAPSHOT;
+                }
+                else
+                {
+                    baseVersion = SNAPSHOT;
+                }
+            }
+            else
+            {
+                baseVersion = version;
+            }
+        }
+
+        return baseVersion;
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates, properties and 
file.
+     * 
+     * @param version The version of the artifact, may be {@code null}.
+     * @param properties The properties of the artifact, may be {@code null} 
if none. The method may assume immutability
+     *            of the supplied map, i.e. need not copy it.
+     * @param file The resolved file of the artifact, may be {@code null}.
+     * @return The new artifact instance, never {@code null}.
+     */
+    private Artifact newInstance( String version, Map<String, String> 
properties, File file )
+    {
+        return new DefaultArtifact( getGroupId(), getArtifactId(), 
getClassifier(), getExtension(), version, file,
+                                    properties );
+    }
+
+    public Artifact setVersion( String version )
+    {
+        String current = getVersion();
+        if ( current.equals( version ) || ( version == null && 
current.length() <= 0 ) )
+        {
+            return this;
+        }
+        return newInstance( version, getProperties(), getFile() );
+    }
+
+    public Artifact setFile( File file )
+    {
+        File current = getFile();
+        if ( ( current == null ) ? file == null : current.equals( file ) )
+        {
+            return this;
+        }
+        return newInstance( getVersion(), getProperties(), file );
+    }
+
+    public Artifact setProperties( Map<String, String> properties )
+    {
+        Map<String, String> current = getProperties();
+        if ( current.equals( properties ) || ( properties == null && 
current.isEmpty() ) )
+        {
+            return this;
+        }
+        return newInstance( getVersion(), copyProperties( properties ), 
getFile() );
+    }
+
+    public String getProperty( String key, String defaultValue )
+    {
+        String value = getProperties().get( key );
+        return ( value != null ) ? value : defaultValue;
+    }
+
+    /**
+     * Copies the specified artifact properties. This utility method should be 
used when creating new artifact instances
+     * with caller-supplied properties.
+     * 
+     * @param properties The properties to copy, may be {@code null}.
+     * @return The copied and read-only properties, never {@code null}.
+     */
+    protected static Map<String, String> copyProperties( Map<String, String> 
properties )
+    {
+        if ( properties != null && !properties.isEmpty() )
+        {
+            return Collections.unmodifiableMap( new HashMap<String, String>( 
properties ) );
+        }
+        else
+        {
+            return Collections.emptyMap();
+        }
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder( 128 );
+        buffer.append( getGroupId() );
+        buffer.append( ':' ).append( getArtifactId() );
+        buffer.append( ':' ).append( getExtension() );
+        if ( getClassifier().length() > 0 )
+        {
+            buffer.append( ':' ).append( getClassifier() );
+        }
+        buffer.append( ':' ).append( getVersion() );
+        return buffer.toString();
+    }
+
+    /**
+     * Compares this artifact with the specified object.
+     * 
+     * @param obj The object to compare this artifact against, may be {@code 
null}.
+     * @return {@code true} if and only if the specified object is another 
{@link Artifact} with equal coordinates,
+     *         properties and file, {@code false} otherwise.
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+        else if ( !( obj instanceof Artifact ) )
+        {
+            return false;
+        }
+
+        Artifact that = (Artifact) obj;
+
+        return getArtifactId().equals( that.getArtifactId() ) && 
getGroupId().equals( that.getGroupId() )
+            && getVersion().equals( that.getVersion() ) && 
getExtension().equals( that.getExtension() )
+            && getClassifier().equals( that.getClassifier() ) && eq( 
getFile(), that.getFile() )
+            && getProperties().equals( that.getProperties() );
+    }
+
+    private static <T> boolean eq( T s1, T s2 )
+    {
+        return s1 != null ? s1.equals( s2 ) : s2 == null;
+    }
+
+    /**
+     * Returns a hash code for this artifact.
+     * 
+     * @return A hash code for the artifact.
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + getGroupId().hashCode();
+        hash = hash * 31 + getArtifactId().hashCode();
+        hash = hash * 31 + getExtension().hashCode();
+        hash = hash * 31 + getClassifier().hashCode();
+        hash = hash * 31 + getVersion().hashCode();
+        hash = hash * 31 + hash( getFile() );
+        return hash;
+    }
+
+    private static int hash( Object obj )
+    {
+        return ( obj != null ) ? obj.hashCode() : 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java
----------------------------------------------------------------------
diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java 
b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java
new file mode 100644
index 0000000..6323243
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/artifact/Artifact.java
@@ -0,0 +1,143 @@
+package org.eclipse.aether.artifact;
+
+/*
+ * 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.Map;
+
+/**
+ * A specific artifact. In a nutshell, an artifact has identifying coordinates 
and optionally a file that denotes its
+ * data. <em>Note:</em> Artifact instances are supposed to be immutable, e.g. 
any exposed mutator method returns a new
+ * artifact instance and leaves the original instance unchanged. 
<em>Note:</em> Implementors are strongly advised to
+ * inherit from {@link AbstractArtifact} instead of directly implementing this 
interface.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface Artifact
+{
+
+    /**
+     * Gets the group identifier of this artifact, for example 
"org.apache.maven".
+     * 
+     * @return The group identifier, never {@code null}.
+     */
+    String getGroupId();
+
+    /**
+     * Gets the artifact identifier of this artifact, for example 
"maven-model".
+     * 
+     * @return The artifact identifier, never {@code null}.
+     */
+    String getArtifactId();
+
+    /**
+     * Gets the version of this artifact, for example "1.0-20100529-1213". 
Note that in case of meta versions like
+     * "1.0-SNAPSHOT", the artifact's version depends on the state of the 
artifact. Artifacts that have been resolved or
+     * deployed will usually have the meta version expanded.
+     * 
+     * @return The version, never {@code null}.
+     */
+    String getVersion();
+
+    /**
+     * Sets the version of the artifact.
+     * 
+     * @param version The version of this artifact, may be {@code null} or 
empty.
+     * @return The new artifact, never {@code null}.
+     */
+    Artifact setVersion( String version );
+
+    /**
+     * Gets the base version of this artifact, for example "1.0-SNAPSHOT". In 
contrast to the {@link #getVersion()}, the
+     * base version will always refer to the unresolved meta version.
+     * 
+     * @return The base version, never {@code null}.
+     */
+    String getBaseVersion();
+
+    /**
+     * Determines whether this artifact uses a snapshot version.
+     * 
+     * @return {@code true} if the artifact is a snapshot, {@code false} 
otherwise.
+     */
+    boolean isSnapshot();
+
+    /**
+     * Gets the classifier of this artifact, for example "sources".
+     * 
+     * @return The classifier or an empty string if none, never {@code null}.
+     */
+    String getClassifier();
+
+    /**
+     * Gets the (file) extension of this artifact, for example "jar" or 
"tar.gz".
+     * 
+     * @return The file extension (without leading period), never {@code null}.
+     */
+    String getExtension();
+
+    /**
+     * Gets the file of this artifact. Note that only resolved artifacts have 
a file associated with them. In general,
+     * callers must not assume any relationship between an artifact's filename 
and its coordinates.
+     * 
+     * @return The file or {@code null} if the artifact isn't resolved.
+     */
+    File getFile();
+
+    /**
+     * Sets the file of the artifact.
+     * 
+     * @param file The file of the artifact, may be {@code null}
+     * @return The new artifact, never {@code null}.
+     */
+    Artifact setFile( File file );
+
+    /**
+     * Gets the specified property.
+     * 
+     * @param key The name of the property, must not be {@code null}.
+     * @param defaultValue The default value to return in case the property is 
not set, may be {@code null}.
+     * @return The requested property value or {@code null} if the property is 
not set and no default value was
+     *         provided.
+     * @see ArtifactProperties
+     */
+    String getProperty( String key, String defaultValue );
+
+    /**
+     * Gets the properties of this artifact. Clients may use these properties 
to associate non-persistent values with an
+     * artifact that help later processing when the artifact gets passed 
around within the application.
+     * 
+     * @return The (read-only) properties, never {@code null}.
+     * @see ArtifactProperties
+     */
+    Map<String, String> getProperties();
+
+    /**
+     * Sets the properties for the artifact. Note that these properties exist 
merely in memory and are not persisted
+     * when the artifact gets installed/deployed to a repository.
+     * 
+     * @param properties The properties for the artifact, may be {@code null}.
+     * @return The new artifact, never {@code null}.
+     * @see ArtifactProperties
+     */
+    Artifact setProperties( Map<String, String> properties );
+
+}

Reply via email to