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 2017/01/22 14:01:58 UTC

[03/54] [abbrv] [partial] maven-resolver git commit: [MNG-6007] renamed Aether to Maven Artifact Resolver

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/LocalRepositoryManager.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/LocalRepositoryManager.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/LocalRepositoryManager.java
new file mode 100644
index 0000000..649707c
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/LocalRepositoryManager.java
@@ -0,0 +1,127 @@
+package org.eclipse.aether.repository;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * Manages access to a local repository.
+ * 
+ * @see RepositorySystemSession#getLocalRepositoryManager()
+ * @see org.eclipse.aether.RepositorySystem#newLocalRepositoryManager(RepositorySystemSession, LocalRepository)
+ */
+public interface LocalRepositoryManager
+{
+
+    /**
+     * Gets the description of the local repository being managed.
+     * 
+     * @return The description of the local repository, never {@code null}.
+     */
+    LocalRepository getRepository();
+
+    /**
+     * Gets the relative path for a locally installed artifact. Note that the artifact need not actually exist yet at
+     * the returned location, the path merely indicates where the artifact would eventually be stored. The path uses the
+     * forward slash as directory separator regardless of the underlying file system.
+     * 
+     * @param artifact The artifact for which to determine the path, must not be {@code null}.
+     * @return The path, relative to the local repository's base directory.
+     */
+    String getPathForLocalArtifact( Artifact artifact );
+
+    /**
+     * Gets the relative path for an artifact cached from a remote repository. Note that the artifact need not actually
+     * exist yet at the returned location, the path merely indicates where the artifact would eventually be stored. The
+     * path uses the forward slash as directory separator regardless of the underlying file system.
+     * 
+     * @param artifact The artifact for which to determine the path, must not be {@code null}.
+     * @param repository The source repository of the artifact, must not be {@code null}.
+     * @param context The resolution context in which the artifact is being requested, may be {@code null}.
+     * @return The path, relative to the local repository's base directory.
+     */
+    String getPathForRemoteArtifact( Artifact artifact, RemoteRepository repository, String context );
+
+    /**
+     * Gets the relative path for locally installed metadata. Note that the metadata need not actually exist yet at the
+     * returned location, the path merely indicates where the metadata would eventually be stored. The path uses the
+     * forward slash as directory separator regardless of the underlying file system.
+     * 
+     * @param metadata The metadata for which to determine the path, must not be {@code null}.
+     * @return The path, relative to the local repository's base directory.
+     */
+    String getPathForLocalMetadata( Metadata metadata );
+
+    /**
+     * Gets the relative path for metadata cached from a remote repository. Note that the metadata need not actually
+     * exist yet at the returned location, the path merely indicates where the metadata would eventually be stored. The
+     * path uses the forward slash as directory separator regardless of the underlying file system.
+     * 
+     * @param metadata The metadata for which to determine the path, must not be {@code null}.
+     * @param repository The source repository of the metadata, must not be {@code null}.
+     * @param context The resolution context in which the metadata is being requested, may be {@code null}.
+     * @return The path, relative to the local repository's base directory.
+     */
+    String getPathForRemoteMetadata( Metadata metadata, RemoteRepository repository, String context );
+
+    /**
+     * Queries for the existence of an artifact in the local repository. The request could be satisfied by a locally
+     * installed artifact or a previously downloaded artifact.
+     * 
+     * @param session The repository system session during which the request is made, must not be {@code null}.
+     * @param request The artifact request, must not be {@code null}.
+     * @return The result of the request, never {@code null}.
+     */
+    LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request );
+
+    /**
+     * Registers an installed or resolved artifact with the local repository. Note that artifact registration is merely
+     * concerned about updating the local repository's internal state, not about actually installing the artifact or its
+     * accompanying metadata.
+     * 
+     * @param session The repository system session during which the registration is made, must not be {@code null}.
+     * @param request The registration request, must not be {@code null}.
+     */
+    void add( RepositorySystemSession session, LocalArtifactRegistration request );
+
+    /**
+     * Queries for the existence of metadata in the local repository. The request could be satisfied by locally
+     * installed or previously downloaded metadata.
+     * 
+     * @param session The repository system session during which the request is made, must not be {@code null}.
+     * @param request The metadata request, must not be {@code null}.
+     * @return The result of the request, never {@code null}.
+     */
+    LocalMetadataResult find( RepositorySystemSession session, LocalMetadataRequest request );
+
+    /**
+     * Registers installed or resolved metadata with the local repository. Note that metadata registration is merely
+     * concerned about updating the local repository's internal state, not about actually installing the metadata.
+     * However, this method MUST be called after the actual install to give the repository manager the opportunity to
+     * inspect the added metadata.
+     * 
+     * @param session The repository system session during which the registration is made, must not be {@code null}.
+     * @param request The registration request, must not be {@code null}.
+     */
+    void add( RepositorySystemSession session, LocalMetadataRegistration request );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/MirrorSelector.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/MirrorSelector.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/MirrorSelector.java
new file mode 100644
index 0000000..d50262c
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/MirrorSelector.java
@@ -0,0 +1,39 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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.
+ */
+
+/**
+ * Selects a mirror for a given remote repository.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getMirrorSelector()
+ */
+public interface MirrorSelector
+{
+
+    /**
+     * Selects a mirror for the specified repository.
+     * 
+     * @param repository The repository to select a mirror for, must not be {@code null}.
+     * @return The selected mirror or {@code null} if none.
+     * @see RemoteRepository#getMirroredRepositories()
+     */
+    RemoteRepository getMirror( RemoteRepository repository );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java
new file mode 100644
index 0000000..c804821
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java
@@ -0,0 +1,102 @@
+package org.eclipse.aether.repository;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of an unsupported local repository type.
+ */
+public class NoLocalRepositoryManagerException
+    extends RepositoryException
+{
+
+    private final transient LocalRepository repository;
+
+    /**
+     * Creates a new exception with the specified repository.
+     * 
+     * @param repository The local repository for which no support is available, may be {@code null}.
+     */
+    public NoLocalRepositoryManagerException( LocalRepository repository )
+    {
+        this( repository, toMessage( repository ) );
+    }
+
+    /**
+     * Creates a new exception with the specified repository and detail message.
+     * 
+     * @param repository The local repository for which no support is available, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public NoLocalRepositoryManagerException( LocalRepository repository, String message )
+    {
+        super( message );
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new exception with the specified repository and cause.
+     * 
+     * @param repository The local repository for which no support is available, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public NoLocalRepositoryManagerException( LocalRepository repository, Throwable cause )
+    {
+        this( repository, toMessage( repository ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified repository, detail message and cause.
+     * 
+     * @param repository The local repository for which no support is available, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public NoLocalRepositoryManagerException( LocalRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.repository = repository;
+    }
+
+    private static String toMessage( LocalRepository repository )
+    {
+        if ( repository != null )
+        {
+            return "No manager available for local repository (" + repository.getBasedir().getAbsolutePath()
+                + ") of type " + repository.getContentType();
+        }
+        else
+        {
+            return "No manager available for local repository";
+        }
+    }
+
+    /**
+     * Gets the local repository whose content type is not supported.
+     * 
+     * @return The unsupported local repository or {@code null} if unknown.
+     */
+    public LocalRepository getRepository()
+    {
+        return repository;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/Proxy.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/Proxy.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/Proxy.java
new file mode 100644
index 0000000..8e8cba1
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/Proxy.java
@@ -0,0 +1,158 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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 proxy to use for connections to a repository.
+ */
+public final class Proxy
+{
+
+    /**
+     * Type denoting a proxy for HTTP transfers.
+     */
+    public static final String TYPE_HTTP = "http";
+
+    /**
+     * Type denoting a proxy for HTTPS transfers.
+     */
+    public static final String TYPE_HTTPS = "https";
+
+    private final String type;
+
+    private final String host;
+
+    private final int port;
+
+    private final Authentication auth;
+
+    /**
+     * Creates a new proxy with the specified properties and no authentication.
+     * 
+     * @param type The type of the proxy, e.g. "http", may be {@code null}.
+     * @param host The host of the proxy, may be {@code null}.
+     * @param port The port of the proxy.
+     */
+    public Proxy( String type, String host, int port )
+    {
+        this( type, host, port, null );
+    }
+
+    /**
+     * Creates a new proxy with the specified properties.
+     * 
+     * @param type The type of the proxy, e.g. "http", may be {@code null}.
+     * @param host The host of the proxy, may be {@code null}.
+     * @param port The port of the proxy.
+     * @param auth The authentication to use for the proxy connection, may be {@code null}.
+     */
+    public Proxy( String type, String host, int port, Authentication auth )
+    {
+        this.type = ( type != null ) ? type : "";
+        this.host = ( host != null ) ? host : "";
+        this.port = port;
+        this.auth = auth;
+    }
+
+    /**
+     * Gets the type of this proxy.
+     * 
+     * @return The type of this proxy, never {@code null}.
+     */
+    public String getType()
+    {
+        return type;
+    }
+
+    /**
+     * Gets the host for this proxy.
+     * 
+     * @return The host for this proxy, never {@code null}.
+     */
+    public String getHost()
+    {
+        return host;
+    }
+
+    /**
+     * Gets the port number for this proxy.
+     * 
+     * @return The port number for this proxy.
+     */
+    public int getPort()
+    {
+        return port;
+    }
+
+    /**
+     * Gets the authentication to use for the proxy connection.
+     * 
+     * @return The authentication to use or {@code null} if none.
+     */
+    public Authentication getAuthentication()
+    {
+        return auth;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getHost() + ':' + getPort();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        Proxy that = (Proxy) obj;
+
+        return eq( type, that.type ) && eq( host, that.host ) && port == that.port && eq( auth, that.auth );
+    }
+
+    private static <T> boolean eq( T s1, T s2 )
+    {
+        return s1 != null ? s1.equals( s2 ) : s2 == null;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + hash( host );
+        hash = hash * 31 + hash( type );
+        hash = hash * 31 + port;
+        hash = hash * 31 + hash( auth );
+        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/repository/ProxySelector.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/ProxySelector.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/ProxySelector.java
new file mode 100644
index 0000000..29b9e4e
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/ProxySelector.java
@@ -0,0 +1,38 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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.
+ */
+
+/**
+ * Selects a proxy for a given remote repository.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getProxySelector()
+ */
+public interface ProxySelector
+{
+
+    /**
+     * Selects a proxy for the specified remote repository.
+     * 
+     * @param repository The repository for which to select a proxy, must not be {@code null}.
+     * @return The selected proxy or {@code null} if none.
+     */
+    Proxy getProxy( RemoteRepository repository );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java
new file mode 100644
index 0000000..31259ca
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RemoteRepository.java
@@ -0,0 +1,582 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A repository on a remote server.
+ */
+public final class RemoteRepository
+    implements ArtifactRepository
+{
+
+    private static final Pattern URL_PATTERN =
+        Pattern.compile( "([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*" );
+
+    private final String id;
+
+    private final String type;
+
+    private final String url;
+
+    private final String host;
+
+    private final String protocol;
+
+    private final RepositoryPolicy releasePolicy;
+
+    private final RepositoryPolicy snapshotPolicy;
+
+    private final Proxy proxy;
+
+    private final Authentication authentication;
+
+    private final List<RemoteRepository> mirroredRepositories;
+
+    private final boolean repositoryManager;
+
+    RemoteRepository( Builder builder )
+    {
+        if ( builder.prototype != null )
+        {
+            id = ( builder.delta & Builder.ID ) != 0 ? builder.id : builder.prototype.id;
+            type = ( builder.delta & Builder.TYPE ) != 0 ? builder.type : builder.prototype.type;
+            url = ( builder.delta & Builder.URL ) != 0 ? builder.url : builder.prototype.url;
+            releasePolicy =
+                ( builder.delta & Builder.RELEASES ) != 0 ? builder.releasePolicy : builder.prototype.releasePolicy;
+            snapshotPolicy =
+                ( builder.delta & Builder.SNAPSHOTS ) != 0 ? builder.snapshotPolicy : builder.prototype.snapshotPolicy;
+            proxy = ( builder.delta & Builder.PROXY ) != 0 ? builder.proxy : builder.prototype.proxy;
+            authentication =
+                ( builder.delta & Builder.AUTH ) != 0 ? builder.authentication : builder.prototype.authentication;
+            repositoryManager =
+                ( builder.delta & Builder.REPOMAN ) != 0 ? builder.repositoryManager
+                                : builder.prototype.repositoryManager;
+            mirroredRepositories =
+                ( builder.delta & Builder.MIRRORED ) != 0 ? copy( builder.mirroredRepositories )
+                                : builder.prototype.mirroredRepositories;
+        }
+        else
+        {
+            id = builder.id;
+            type = builder.type;
+            url = builder.url;
+            releasePolicy = builder.releasePolicy;
+            snapshotPolicy = builder.snapshotPolicy;
+            proxy = builder.proxy;
+            authentication = builder.authentication;
+            repositoryManager = builder.repositoryManager;
+            mirroredRepositories = copy( builder.mirroredRepositories );
+        }
+
+        Matcher m = URL_PATTERN.matcher( url );
+        if ( m.matches() )
+        {
+            protocol = m.group( 1 );
+            String host = m.group( 5 );
+            this.host = ( host != null ) ? host : "";
+        }
+        else
+        {
+            protocol = host = "";
+        }
+    }
+
+    private static List<RemoteRepository> copy( List<RemoteRepository> repos )
+    {
+        if ( repos == null || repos.isEmpty() )
+        {
+            return Collections.emptyList();
+        }
+        return Collections.unmodifiableList( Arrays.asList( repos.toArray( new RemoteRepository[repos.size()] ) ) );
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public String getContentType()
+    {
+        return type;
+    }
+
+    /**
+     * Gets the (base) URL of this repository.
+     * 
+     * @return The (base) URL of this repository, never {@code null}.
+     */
+    public String getUrl()
+    {
+        return url;
+    }
+
+    /**
+     * Gets the protocol part from the repository's URL, for example {@code file} or {@code http}. As suggested by RFC
+     * 2396, section 3.1 "Scheme Component", the protocol name should be treated case-insensitively.
+     * 
+     * @return The protocol or an empty string if none, never {@code null}.
+     */
+    public String getProtocol()
+    {
+        return protocol;
+    }
+
+    /**
+     * Gets the host part from the repository's URL.
+     * 
+     * @return The host or an empty string if none, never {@code null}.
+     */
+    public String getHost()
+    {
+        return host;
+    }
+
+    /**
+     * Gets the policy to apply for snapshot/release artifacts.
+     * 
+     * @param snapshot {@code true} to retrieve the snapshot policy, {@code false} to retrieve the release policy.
+     * @return The requested repository policy, never {@code null}.
+     */
+    public RepositoryPolicy getPolicy( boolean snapshot )
+    {
+        return snapshot ? snapshotPolicy : releasePolicy;
+    }
+
+    /**
+     * Gets the proxy that has been selected for this repository.
+     * 
+     * @return The selected proxy or {@code null} if none.
+     */
+    public Proxy getProxy()
+    {
+        return proxy;
+    }
+
+    /**
+     * Gets the authentication that has been selected for this repository.
+     * 
+     * @return The selected authentication or {@code null} if none.
+     */
+    public Authentication getAuthentication()
+    {
+        return authentication;
+    }
+
+    /**
+     * Gets the repositories that this repository serves as a mirror for.
+     * 
+     * @return The (read-only) repositories being mirrored by this repository, never {@code null}.
+     */
+    public List<RemoteRepository> getMirroredRepositories()
+    {
+        return mirroredRepositories;
+    }
+
+    /**
+     * Indicates whether this repository refers to a repository manager or not.
+     * 
+     * @return {@code true} if this repository is a repository manager, {@code false} otherwise.
+     */
+    public boolean isRepositoryManager()
+    {
+        return repositoryManager;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+        buffer.append( getId() );
+        buffer.append( " (" ).append( getUrl() );
+        buffer.append( ", " ).append( getContentType() );
+        boolean r = getPolicy( false ).isEnabled(), s = getPolicy( true ).isEnabled();
+        if ( r && s )
+        {
+            buffer.append( ", releases+snapshots" );
+        }
+        else if ( r )
+        {
+            buffer.append( ", releases" );
+        }
+        else if ( s )
+        {
+            buffer.append( ", snapshots" );
+        }
+        else
+        {
+            buffer.append( ", disabled" );
+        }
+        if ( isRepositoryManager() )
+        {
+            buffer.append( ", managed" );
+        }
+        buffer.append( ")" );
+        return buffer.toString();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        RemoteRepository that = (RemoteRepository) obj;
+
+        return eq( url, that.url ) && eq( type, that.type ) && eq( id, that.id )
+            && eq( releasePolicy, that.releasePolicy ) && eq( snapshotPolicy, that.snapshotPolicy )
+            && eq( proxy, that.proxy ) && eq( authentication, that.authentication )
+            && eq( mirroredRepositories, that.mirroredRepositories ) && repositoryManager == that.repositoryManager;
+    }
+
+    private static <T> boolean eq( T s1, T s2 )
+    {
+        return s1 != null ? s1.equals( s2 ) : s2 == null;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + hash( url );
+        hash = hash * 31 + hash( type );
+        hash = hash * 31 + hash( id );
+        hash = hash * 31 + hash( releasePolicy );
+        hash = hash * 31 + hash( snapshotPolicy );
+        hash = hash * 31 + hash( proxy );
+        hash = hash * 31 + hash( authentication );
+        hash = hash * 31 + hash( mirroredRepositories );
+        hash = hash * 31 + ( repositoryManager ? 1 : 0 );
+        return hash;
+    }
+
+    private static int hash( Object obj )
+    {
+        return obj != null ? obj.hashCode() : 0;
+    }
+
+    /**
+     * A builder to create remote repositories.
+     */
+    public static final class Builder
+    {
+
+        private static final RepositoryPolicy DEFAULT_POLICY = new RepositoryPolicy();
+
+        static final int ID = 0x0001, TYPE = 0x0002, URL = 0x0004, RELEASES = 0x0008, SNAPSHOTS = 0x0010,
+                        PROXY = 0x0020, AUTH = 0x0040, MIRRORED = 0x0080, REPOMAN = 0x0100;
+
+        int delta;
+
+        RemoteRepository prototype;
+
+        String id;
+
+        String type;
+
+        String url;
+
+        RepositoryPolicy releasePolicy = DEFAULT_POLICY;
+
+        RepositoryPolicy snapshotPolicy = DEFAULT_POLICY;
+
+        Proxy proxy;
+
+        Authentication authentication;
+
+        List<RemoteRepository> mirroredRepositories;
+
+        boolean repositoryManager;
+
+        /**
+         * Creates a new repository builder.
+         * 
+         * @param id The identifier of the repository, may be {@code null}.
+         * @param type The type of the repository, may be {@code null}.
+         * @param url The (base) URL of the repository, may be {@code null}.
+         */
+        public Builder( String id, String type, String url )
+        {
+            this.id = ( id != null ) ? id : "";
+            this.type = ( type != null ) ? type : "";
+            this.url = ( url != null ) ? url : "";
+        }
+
+        /**
+         * Creates a new repository builder which uses the specified remote repository as a prototype for the new one.
+         * All properties which have not been set on the builder will be copied from the prototype when building the
+         * repository.
+         * 
+         * @param prototype The remote repository to use as prototype, must not be {@code null}.
+         */
+        public Builder( RemoteRepository prototype )
+        {
+            if ( prototype == null )
+            {
+                throw new IllegalArgumentException( "repository prototype missing" );
+            }
+            this.prototype = prototype;
+        }
+
+        /**
+         * Builds a new remote repository from the current values of this builder. The state of the builder itself
+         * remains unchanged.
+         * 
+         * @return The remote repository, never {@code null}.
+         */
+        public RemoteRepository build()
+        {
+            if ( prototype != null && delta == 0 )
+            {
+                return prototype;
+            }
+            return new RemoteRepository( this );
+        }
+
+        private <T> void delta( int flag, T builder, T prototype )
+        {
+            boolean equal = ( builder != null ) ? builder.equals( prototype ) : prototype == null;
+            if ( equal )
+            {
+                delta &= ~flag;
+            }
+            else
+            {
+                delta |= flag;
+            }
+        }
+
+        /**
+         * Sets the identifier of the repository.
+         * 
+         * @param id The identifier of the repository, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setId( String id )
+        {
+            this.id = ( id != null ) ? id : "";
+            if ( prototype != null )
+            {
+                delta( ID, this.id, prototype.getId() );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the type of the repository, e.g. "default".
+         * 
+         * @param type The type of the repository, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setContentType( String type )
+        {
+            this.type = ( type != null ) ? type : "";
+            if ( prototype != null )
+            {
+                delta( TYPE, this.type, prototype.getContentType() );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the (base) URL of the repository.
+         * 
+         * @param url The URL of the repository, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setUrl( String url )
+        {
+            this.url = ( url != null ) ? url : "";
+            if ( prototype != null )
+            {
+                delta( URL, this.url, prototype.getUrl() );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the policy to apply for snapshot and release artifacts.
+         * 
+         * @param policy The repository policy to set, may be {@code null} to use a default policy.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setPolicy( RepositoryPolicy policy )
+        {
+            this.releasePolicy = this.snapshotPolicy = ( policy != null ) ? policy : DEFAULT_POLICY;
+            if ( prototype != null )
+            {
+                delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) );
+                delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the policy to apply for release artifacts.
+         * 
+         * @param releasePolicy The repository policy to set, may be {@code null} to use a default policy.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setReleasePolicy( RepositoryPolicy releasePolicy )
+        {
+            this.releasePolicy = ( releasePolicy != null ) ? releasePolicy : DEFAULT_POLICY;
+            if ( prototype != null )
+            {
+                delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the policy to apply for snapshot artifacts.
+         * 
+         * @param snapshotPolicy The repository policy to set, may be {@code null} to use a default policy.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setSnapshotPolicy( RepositoryPolicy snapshotPolicy )
+        {
+            this.snapshotPolicy = ( snapshotPolicy != null ) ? snapshotPolicy : DEFAULT_POLICY;
+            if ( prototype != null )
+            {
+                delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the proxy to use in order to access the repository.
+         * 
+         * @param proxy The proxy to use, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setProxy( Proxy proxy )
+        {
+            this.proxy = proxy;
+            if ( prototype != null )
+            {
+                delta( PROXY, this.proxy, prototype.getProxy() );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the authentication to use in order to access the repository.
+         * 
+         * @param authentication The authentication to use, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setAuthentication( Authentication authentication )
+        {
+            this.authentication = authentication;
+            if ( prototype != null )
+            {
+                delta( AUTH, this.authentication, prototype.getAuthentication() );
+            }
+            return this;
+        }
+
+        /**
+         * Sets the repositories being mirrored by the repository.
+         * 
+         * @param mirroredRepositories The repositories being mirrored by the repository, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setMirroredRepositories( List<RemoteRepository> mirroredRepositories )
+        {
+            if ( this.mirroredRepositories == null )
+            {
+                this.mirroredRepositories = new ArrayList<RemoteRepository>();
+            }
+            else
+            {
+                this.mirroredRepositories.clear();
+            }
+            if ( mirroredRepositories != null )
+            {
+                this.mirroredRepositories.addAll( mirroredRepositories );
+            }
+            if ( prototype != null )
+            {
+                delta( MIRRORED, this.mirroredRepositories, prototype.getMirroredRepositories() );
+            }
+            return this;
+        }
+
+        /**
+         * Adds the specified repository to the list of repositories being mirrored by the repository. If this builder
+         * was {@link #RemoteRepository.Builder(RemoteRepository) constructed from a prototype}, the given repository
+         * will be added to the list of mirrored repositories from the prototype.
+         * 
+         * @param mirroredRepository The repository being mirrored by the repository, may be {@code null}.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder addMirroredRepository( RemoteRepository mirroredRepository )
+        {
+            if ( mirroredRepository != null )
+            {
+                if ( this.mirroredRepositories == null )
+                {
+                    this.mirroredRepositories = new ArrayList<RemoteRepository>();
+                    if ( prototype != null )
+                    {
+                        mirroredRepositories.addAll( prototype.getMirroredRepositories() );
+                    }
+                }
+                mirroredRepositories.add( mirroredRepository );
+                if ( prototype != null )
+                {
+                    delta |= MIRRORED;
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Marks the repository as a repository manager or not.
+         * 
+         * @param repositoryManager {@code true} if the repository points at a repository manager, {@code false} if the
+         *            repository is just serving static contents.
+         * @return This builder for chaining, never {@code null}.
+         */
+        public Builder setRepositoryManager( boolean repositoryManager )
+        {
+            this.repositoryManager = repositoryManager;
+            if ( prototype != null )
+            {
+                delta( REPOMAN, this.repositoryManager, prototype.isRepositoryManager() );
+            }
+            return this;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RepositoryPolicy.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RepositoryPolicy.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RepositoryPolicy.java
new file mode 100644
index 0000000..18fb850
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/RepositoryPolicy.java
@@ -0,0 +1,161 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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 policy controlling access to a repository.
+ */
+public final class RepositoryPolicy
+{
+
+    /**
+     * Never update locally cached data.
+     */
+    public static final String UPDATE_POLICY_NEVER = "never";
+
+    /**
+     * Always update locally cached data.
+     */
+    public static final String UPDATE_POLICY_ALWAYS = "always";
+
+    /**
+     * Update locally cached data once a day.
+     */
+    public static final String UPDATE_POLICY_DAILY = "daily";
+
+    /**
+     * Update locally cached data every X minutes as given by "interval:X".
+     */
+    public static final String UPDATE_POLICY_INTERVAL = "interval";
+
+    /**
+     * Verify checksums and fail the resolution if they do not match.
+     */
+    public static final String CHECKSUM_POLICY_FAIL = "fail";
+
+    /**
+     * Verify checksums and warn if they do not match.
+     */
+    public static final String CHECKSUM_POLICY_WARN = "warn";
+
+    /**
+     * Do not verify checksums.
+     */
+    public static final String CHECKSUM_POLICY_IGNORE = "ignore";
+
+    private final boolean enabled;
+
+    private final String updatePolicy;
+
+    private final String checksumPolicy;
+
+    /**
+     * Creates a new policy with checksum warnings and daily update checks.
+     */
+    public RepositoryPolicy()
+    {
+        this( true, UPDATE_POLICY_DAILY, CHECKSUM_POLICY_WARN );
+    }
+
+    /**
+     * Creates a new policy with the specified settings.
+     * 
+     * @param enabled A flag whether the associated repository should be accessed or not.
+     * @param updatePolicy The update interval after which locally cached data from the repository is considered stale
+     *            and should be refetched, may be {@code null}.
+     * @param checksumPolicy The way checksum verification should be handled, may be {@code null}.
+     */
+    public RepositoryPolicy( boolean enabled, String updatePolicy, String checksumPolicy )
+    {
+        this.enabled = enabled;
+        this.updatePolicy = ( updatePolicy != null ) ? updatePolicy : "";
+        this.checksumPolicy = ( checksumPolicy != null ) ? checksumPolicy : "";
+    }
+
+    /**
+     * Indicates whether the associated repository should be contacted or not.
+     * 
+     * @return {@code true} if the repository should be contacted, {@code false} otherwise.
+     */
+    public boolean isEnabled()
+    {
+        return enabled;
+    }
+
+    /**
+     * Gets the update policy for locally cached data from the repository.
+     * 
+     * @return The update policy, never {@code null}.
+     */
+    public String getUpdatePolicy()
+    {
+        return updatePolicy;
+    }
+
+    /**
+     * Gets the policy for checksum validation.
+     * 
+     * @return The checksum policy, never {@code null}.
+     */
+    public String getChecksumPolicy()
+    {
+        return checksumPolicy;
+    }
+
+    @Override
+    public String toString()
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+        buffer.append( "enabled=" ).append( isEnabled() );
+        buffer.append( ", checksums=" ).append( getChecksumPolicy() );
+        buffer.append( ", updates=" ).append( getUpdatePolicy() );
+        return buffer.toString();
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+
+        if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        RepositoryPolicy that = (RepositoryPolicy) obj;
+
+        return enabled == that.enabled && updatePolicy.equals( that.updatePolicy )
+            && checksumPolicy.equals( that.checksumPolicy );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + ( enabled ? 1 : 0 );
+        hash = hash * 31 + updatePolicy.hashCode();
+        hash = hash * 31 + checksumPolicy.hashCode();
+        return hash;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceReader.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceReader.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceReader.java
new file mode 100644
index 0000000..d1140f3
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceReader.java
@@ -0,0 +1,58 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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.List;
+
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * Manages a repository backed by the IDE workspace, a build session or a similar ad-hoc collection of artifacts.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getWorkspaceReader()
+ */
+public interface WorkspaceReader
+{
+
+    /**
+     * Gets a description of the workspace repository.
+     * 
+     * @return The repository description, never {@code null}.
+     */
+    WorkspaceRepository getRepository();
+
+    /**
+     * Locates the specified artifact.
+     * 
+     * @param artifact The artifact to locate, must not be {@code null}.
+     * @return The path to the artifact or {@code null} if the artifact is not available.
+     */
+    File findArtifact( Artifact artifact );
+
+    /**
+     * Determines all available versions of the specified artifact.
+     * 
+     * @param artifact The artifact whose versions should be listed, must not be {@code null}.
+     * @return The available versions of the artifact, must not be {@code null}.
+     */
+    List<String> findVersions( Artifact artifact );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceRepository.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceRepository.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceRepository.java
new file mode 100644
index 0000000..38dc5c5
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/WorkspaceRepository.java
@@ -0,0 +1,122 @@
+package org.eclipse.aether.repository;
+
+/*
+ * 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.UUID;
+
+/**
+ * A repository backed by an IDE workspace, the output of a build session or similar ad-hoc collection of artifacts. As
+ * far as the repository system is concerned, a workspace repository is read-only, i.e. can only be used for artifact
+ * resolution but not installation/deployment. Note that this class merely describes such a repository, actual access to
+ * the contained artifacts is handled by a {@link WorkspaceReader}.
+ */
+public final class WorkspaceRepository
+    implements ArtifactRepository
+{
+
+    private final String type;
+
+    private final Object key;
+
+    /**
+     * Creates a new workspace repository of type {@code "workspace"} and a random key.
+     */
+    public WorkspaceRepository()
+    {
+        this( "workspace" );
+    }
+
+    /**
+     * Creates a new workspace repository with the specified type and a random key.
+     * 
+     * @param type The type of the repository, may be {@code null}.
+     */
+    public WorkspaceRepository( String type )
+    {
+        this( type, null );
+    }
+
+    /**
+     * Creates a new workspace repository with the specified type and key. The key is used to distinguish one workspace
+     * from another and should be sensitive to the artifacts that are (potentially) available in the workspace.
+     * 
+     * @param type The type of the repository, may be {@code null}.
+     * @param key The (comparison) key for the repository, may be {@code null} to generate a unique random key.
+     */
+    public WorkspaceRepository( String type, Object key )
+    {
+        this.type = ( type != null ) ? type : "";
+        this.key = ( key != null ) ? key : UUID.randomUUID().toString().replace( "-", "" );
+    }
+
+    public String getContentType()
+    {
+        return type;
+    }
+
+    public String getId()
+    {
+        return "workspace";
+    }
+
+    /**
+     * Gets the key of this workspace repository. The key is used to distinguish one workspace from another and should
+     * be sensitive to the artifacts that are (potentially) available in the workspace.
+     * 
+     * @return The (comparison) key for this workspace repository, never {@code null}.
+     */
+    public Object getKey()
+    {
+        return key;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "(" + getContentType() + ")";
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        WorkspaceRepository that = (WorkspaceRepository) obj;
+
+        return getContentType().equals( that.getContentType() ) && getKey().equals( that.getKey() );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + getKey().hashCode();
+        hash = hash * 31 + getContentType().hashCode();
+        return hash;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/repository/package-info.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/repository/package-info.java b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/package-info.java
new file mode 100644
index 0000000..538e7f1
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/repository/package-info.java
@@ -0,0 +1,24 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/*
+ * 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 definition of various kinds of repositories that host artifacts.
+ */
+package org.eclipse.aether.repository;
+

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorException.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorException.java b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorException.java
new file mode 100644
index 0000000..d645a82
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorException.java
@@ -0,0 +1,91 @@
+package org.eclipse.aether.resolution;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of an unreadable or unresolvable artifact descriptor.
+ */
+public class ArtifactDescriptorException
+    extends RepositoryException
+{
+
+    private final transient ArtifactDescriptorResult result;
+
+    /**
+     * Creates a new exception with the specified result.
+     * 
+     * @param result The descriptor result at the point the exception occurred, may be {@code null}.
+     */
+    public ArtifactDescriptorException( ArtifactDescriptorResult result )
+    {
+        super( "Failed to read artifact descriptor"
+            + ( result != null ? " for " + result.getRequest().getArtifact() : "" ), getCause( result ) );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result and detail message.
+     * 
+     * @param result The descriptor result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public ArtifactDescriptorException( ArtifactDescriptorResult result, String message )
+    {
+        super( message, getCause( result ) );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result, detail message and cause.
+     * 
+     * @param result The descriptor result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public ArtifactDescriptorException( ArtifactDescriptorResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    /**
+     * Gets the descriptor result at the point the exception occurred. Despite being incomplete, callers might want to
+     * use this result to fail gracefully and continue their operation with whatever interim data has been gathered.
+     * 
+     * @return The descriptor result or {@code null} if unknown.
+     */
+    public ArtifactDescriptorResult getResult()
+    {
+        return result;
+    }
+
+    private static Throwable getCause( ArtifactDescriptorResult result )
+    {
+        Throwable cause = null;
+        if ( result != null && !result.getExceptions().isEmpty() )
+        {
+            cause = result.getExceptions().get( 0 );
+        }
+        return cause;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java
new file mode 100644
index 0000000..c4de9b2
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java
@@ -0,0 +1,61 @@
+package org.eclipse.aether.resolution;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * Controls the handling of errors related to reading an artifact descriptor.
+ * 
+ * @see RepositorySystemSession#getArtifactDescriptorPolicy()
+ */
+public interface ArtifactDescriptorPolicy
+{
+
+    /**
+     * Bit mask indicating that errors while reading the artifact descriptor should not be tolerated.
+     */
+    int STRICT = 0x00;
+
+    /**
+     * Bit flag indicating that missing artifact descriptors should be silently ignored.
+     */
+    int IGNORE_MISSING = 0x01;
+
+    /**
+     * Bit flag indicating that existent but invalid artifact descriptors should be silently ignored.
+     */
+    int IGNORE_INVALID = 0x02;
+
+    /**
+     * Bit mask indicating that all errors should be silently ignored.
+     */
+    int IGNORE_ERRORS = IGNORE_MISSING | IGNORE_INVALID;
+
+    /**
+     * Gets the error policy for an artifact's descriptor.
+     * 
+     * @param session The repository session during which the policy is determined, must not be {@code null}.
+     * @param request The policy request holding further details, must not be {@code null}.
+     * @return The bit mask describing the desired error policy.
+     */
+    int getPolicy( RepositorySystemSession session, ArtifactDescriptorPolicyRequest request );
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java
new file mode 100644
index 0000000..ffaac16
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java
@@ -0,0 +1,106 @@
+package org.eclipse.aether.resolution;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * A query for the error policy for a given artifact's descriptor.
+ * 
+ * @see ArtifactDescriptorPolicy
+ */
+public final class ArtifactDescriptorPolicyRequest
+{
+
+    private Artifact artifact;
+
+    private String context = "";
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public ArtifactDescriptorPolicyRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request for the specified artifact.
+     * 
+     * @param artifact The artifact for whose descriptor to determine the error policy, may be {@code null}.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public ArtifactDescriptorPolicyRequest( Artifact artifact, String context )
+    {
+        setArtifact( artifact );
+        setRequestContext( context );
+    }
+
+    /**
+     * Gets the artifact for whose descriptor to determine the error policy.
+     * 
+     * @return The artifact for whose descriptor to determine the error policy or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact for whose descriptor to determine the error policy.
+     * 
+     * @param artifact The artifact for whose descriptor to determine the error policy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorPolicyRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the context in which this request is made.
+     * 
+     * @return The context, never {@code null}.
+     */
+    public String getRequestContext()
+    {
+        return context;
+    }
+
+    /**
+     * Sets the context in which this request is made.
+     * 
+     * @param context The context, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorPolicyRequest setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getArtifact() );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java
new file mode 100644
index 0000000..387b1dc
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java
@@ -0,0 +1,190 @@
+package org.eclipse.aether.resolution;
+
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to read an artifact descriptor.
+ * 
+ * @see RepositorySystem#readArtifactDescriptor(RepositorySystemSession, ArtifactDescriptorRequest)
+ */
+public final class ArtifactDescriptorRequest
+{
+
+    private Artifact artifact;
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public ArtifactDescriptorRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param artifact The artifact whose descriptor should be read, may be {@code null}.
+     * @param repositories The repositories to resolve the descriptor from, may be {@code null}.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public ArtifactDescriptorRequest( Artifact artifact, List<RemoteRepository> repositories, String context )
+    {
+        setArtifact( artifact );
+        setRepositories( repositories );
+        setRequestContext( context );
+    }
+
+    /**
+     * Gets the artifact whose descriptor shall be read.
+     * 
+     * @return The artifact or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact whose descriptor shall be read. Eventually, a valid request must have an artifact set.
+     * 
+     * @param artifact The artifact, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the repositories to resolve the descriptor from.
+     * 
+     * @return The repositories, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to resolve the descriptor from.
+     * 
+     * @param repositories The repositories, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for the resolution of the artifact descriptor.
+     * 
+     * @param repository The repository to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorRequest addRepository( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            if ( this.repositories.isEmpty() )
+            {
+                this.repositories = new ArrayList<RemoteRepository>();
+            }
+            this.repositories.add( repository );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the context in which this request is made.
+     * 
+     * @return The context, never {@code null}.
+     */
+    public String getRequestContext()
+    {
+        return context;
+    }
+
+    /**
+     * Sets the context in which this request is made.
+     * 
+     * @param context The context, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorRequest setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    /**
+     * Gets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @return The trace information about the higher level operation or {@code null} if none.
+     */
+    public RequestTrace getTrace()
+    {
+        return trace;
+    }
+
+    /**
+     * Sets the trace information that describes the higher level request/operation in which this request is issued.
+     * 
+     * @param trace The trace information about the higher level operation, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " < " + getRepositories();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven-resolver/blob/3a1b8ae0/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorResult.java
----------------------------------------------------------------------
diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorResult.java b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorResult.java
new file mode 100644
index 0000000..4c53b6e
--- /dev/null
+++ b/maven-resolver-api/src/main/java/org/eclipse/aether/resolution/ArtifactDescriptorResult.java
@@ -0,0 +1,466 @@
+package org.eclipse.aether.resolution;
+
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.ArtifactRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * The result from reading an artifact descriptor.
+ * 
+ * @see RepositorySystem#readArtifactDescriptor(RepositorySystemSession, ArtifactDescriptorRequest)
+ */
+public final class ArtifactDescriptorResult
+{
+
+    private final ArtifactDescriptorRequest request;
+
+    private List<Exception> exceptions;
+
+    private List<Artifact> relocations;
+
+    private Collection<Artifact> aliases;
+
+    private Artifact artifact;
+
+    private ArtifactRepository repository;
+
+    private List<Dependency> dependencies;
+
+    private List<Dependency> managedDependencies;
+
+    private List<RemoteRepository> repositories;
+
+    private Map<String, Object> properties;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The descriptor request, must not be {@code null}.
+     */
+    public ArtifactDescriptorResult( ArtifactDescriptorRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "artifact descriptor request has not been specified" );
+        }
+        this.request = request;
+        artifact = request.getArtifact();
+        exceptions = Collections.emptyList();
+        relocations = Collections.emptyList();
+        aliases = Collections.emptyList();
+        dependencies = managedDependencies = Collections.emptyList();
+        repositories = Collections.emptyList();
+        properties = Collections.emptyMap();
+    }
+
+    /**
+     * Gets the descriptor request that was made.
+     * 
+     * @return The descriptor request, never {@code null}.
+     */
+    public ArtifactDescriptorRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the exceptions that occurred while reading the artifact descriptor.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Sets the exceptions that occurred while reading the artifact descriptor.
+     * 
+     * @param exceptions The exceptions that occurred, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setExceptions( List<Exception> exceptions )
+    {
+        if ( exceptions == null )
+        {
+            this.exceptions = Collections.emptyList();
+        }
+        else
+        {
+            this.exceptions = exceptions;
+        }
+        return this;
+    }
+
+    /**
+     * Records the specified exception while reading the artifact descriptor.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the relocations that were processed to read the artifact descriptor. The returned list denotes the hops that
+     * lead to the final artifact coordinates as given by {@link #getArtifact()}.
+     * 
+     * @return The relocations that were processed, never {@code null}.
+     */
+    public List<Artifact> getRelocations()
+    {
+        return relocations;
+    }
+
+    /**
+     * Sets the relocations that were processed to read the artifact descriptor.
+     * 
+     * @param relocations The relocations that were processed, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setRelocations( List<Artifact> relocations )
+    {
+        if ( relocations == null )
+        {
+            this.relocations = Collections.emptyList();
+        }
+        else
+        {
+            this.relocations = relocations;
+        }
+        return this;
+    }
+
+    /**
+     * Records the specified relocation hop while locating the artifact descriptor.
+     * 
+     * @param artifact The artifact that got relocated, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addRelocation( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( relocations.isEmpty() )
+            {
+                relocations = new ArrayList<Artifact>();
+            }
+            relocations.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the known aliases for this artifact. An alias denotes a different artifact with (almost) the same contents
+     * and can be used to mark a patched rebuild of some other artifact as such, thereby allowing conflict resolution to
+     * consider the patched and the original artifact as a conflict.
+     * 
+     * @return The aliases of the artifact, never {@code null}.
+     */
+    public Collection<Artifact> getAliases()
+    {
+        return aliases;
+    }
+
+    /**
+     * Sets the aliases of the artifact.
+     * 
+     * @param aliases The aliases of the artifact, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setAliases( Collection<Artifact> aliases )
+    {
+        if ( aliases == null )
+        {
+            this.aliases = Collections.emptyList();
+        }
+        else
+        {
+            this.aliases = aliases;
+        }
+        return this;
+    }
+
+    /**
+     * Records the specified alias.
+     * 
+     * @param alias The alias for the artifact, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addAlias( Artifact alias )
+    {
+        if ( alias != null )
+        {
+            if ( aliases.isEmpty() )
+            {
+                aliases = new ArrayList<Artifact>();
+            }
+            aliases.add( alias );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the artifact whose descriptor was read. This can be a different artifact than originally requested in case
+     * relocations were encountered.
+     * 
+     * @return The artifact after following any relocations, never {@code null}.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact whose descriptor was read.
+     * 
+     * @param artifact The artifact whose descriptor was read, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the repository from which the descriptor was eventually resolved.
+     * 
+     * @return The repository from which the descriptor was resolved or {@code null} if unknown.
+     */
+    public ArtifactRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository from which the descriptor was resolved.
+     * 
+     * @param repository The repository from which the descriptor was resolved, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setRepository( ArtifactRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    /**
+     * Gets the list of direct dependencies of the artifact.
+     * 
+     * @return The list of direct dependencies, never {@code null}
+     */
+    public List<Dependency> getDependencies()
+    {
+        return dependencies;
+    }
+
+    /**
+     * Sets the list of direct dependencies of the artifact.
+     * 
+     * @param dependencies The list of direct dependencies, may be {@code null}
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setDependencies( List<Dependency> dependencies )
+    {
+        if ( dependencies == null )
+        {
+            this.dependencies = Collections.emptyList();
+        }
+        else
+        {
+            this.dependencies = dependencies;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified direct dependency.
+     * 
+     * @param dependency The direct dependency to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addDependency( Dependency dependency )
+    {
+        if ( dependency != null )
+        {
+            if ( dependencies.isEmpty() )
+            {
+                dependencies = new ArrayList<Dependency>();
+            }
+            dependencies.add( dependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the dependency management information.
+     * 
+     * @return The dependency management information.
+     */
+    public List<Dependency> getManagedDependencies()
+    {
+        return managedDependencies;
+    }
+
+    /**
+     * Sets the dependency management information.
+     * 
+     * @param dependencies The dependency management information, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setManagedDependencies( List<Dependency> dependencies )
+    {
+        if ( dependencies == null )
+        {
+            this.managedDependencies = Collections.emptyList();
+        }
+        else
+        {
+            this.managedDependencies = dependencies;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified managed dependency.
+     * 
+     * @param dependency The managed dependency to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addManagedDependency( Dependency dependency )
+    {
+        if ( dependency != null )
+        {
+            if ( managedDependencies.isEmpty() )
+            {
+                managedDependencies = new ArrayList<Dependency>();
+            }
+            managedDependencies.add( dependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the remote repositories listed in the artifact descriptor.
+     * 
+     * @return The remote repositories listed in the artifact descriptor, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the remote repositories listed in the artifact descriptor.
+     * 
+     * @param repositories The remote repositories listed in the artifact descriptor, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified remote repository.
+     * 
+     * @param repository The remote repository to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult addRepository( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            if ( repositories.isEmpty() )
+            {
+                repositories = new ArrayList<RemoteRepository>();
+            }
+            repositories.add( repository );
+        }
+        return this;
+    }
+
+    /**
+     * Gets any additional information about the artifact in form of key-value pairs. <em>Note:</em> Regardless of their
+     * actual type, all property values must be treated as being read-only.
+     * 
+     * @return The additional information about the artifact, never {@code null}.
+     */
+    public Map<String, Object> getProperties()
+    {
+        return properties;
+    }
+
+    /**
+     * Sets any additional information about the artifact in form of key-value pairs.
+     * 
+     * @param properties The additional information about the artifact, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactDescriptorResult setProperties( Map<String, Object> properties )
+    {
+        if ( properties == null )
+        {
+            this.properties = Collections.emptyMap();
+        }
+        else
+        {
+            this.properties = properties;
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " -> " + getDependencies();
+    }
+
+}