Deal with the deprecation of Eclipse Aether
authorMathieu Baudier <mbaudier@argeo.org>
Mon, 13 Nov 2017 13:05:37 +0000 (14:05 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Mon, 13 Nov 2017 13:05:37 +0000 (14:05 +0100)
166 files changed:
demo/slc_localrepo.properties
dist/pom.xml
org.argeo.slc.client.ui.dist/src/org/argeo/slc/client/ui/dist/commands/NormalizeDistribution.java
org.argeo.slc.repo/.classpath
org.argeo.slc.repo/.gitignore
org.argeo.slc.repo/bnd.bnd
org.argeo.slc.repo/build.properties [new file with mode: 0644]
org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java [new file with mode: 0644]
org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml [new file with mode: 0644]
org.argeo.slc.repo/src/org/argeo/slc/repo/ArtifactIndexer.java
org.argeo.slc.repo/src/org/argeo/slc/repo/ModularDistributionIndexer.java
org.argeo.slc.repo/src/org/argeo/slc/repo/PdeSourcesIndexer.java
org.argeo.slc.repo/src/org/argeo/slc/repo/RepoUtils.java
org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/argeo/slc/repo/maven/GenerateBinaries.java
org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java [deleted file]
org.argeo.slc.repo/src/org/argeo/slc/repo/maven/MavenConventionsUtils.java
org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/ArchiveWrapper.java
org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/MavenWrapper.java
org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/NormalizeGroup.java
org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java [new file with mode: 0644]
org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java [new file with mode: 0644]
org.argeo.slc.server.repo/META-INF/spring/maven.xml [deleted file]
org.argeo.slc.server.repo/META-INF/spring/repo-osgi.xml
org.argeo.slc.server.repo/META-INF/spring/services.xml
org.argeo.slc.server.repo/repository-h2.xml [deleted file]
org.argeo.slc.server.repo/repository-localfs.xml [deleted file]
org.argeo.slc.server.repo/repository-pg-dist.xml [deleted file]
org.argeo.slc.server.repo/repository-pg-docs.xml [deleted file]
org.argeo.slc.server.repo/repository-pg-java.xml [deleted file]
org.argeo.slc.server.repo/repository-pg-rpm.xml [deleted file]
org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java [deleted file]
org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java [deleted file]
pom.xml

index 9e34647a0c6f435b9c7ad689058c072cdf41b29a..a897633020de9c73c099cfea0a379d1d78beefec 100644 (file)
@@ -22,8 +22,8 @@ slc.executionModules=org.argeo.tp.factory.core,\
 org.argeo.tp.factory.extras,\
 org.argeo.tp.factory.rcp
 
-argeo.node.repo.type=localfs
-argeo.node.useradmin.uris=ipa:///
+argeo.node.repo.type=h2
+#argeo.node.useradmin.uris=ipa:///
 
 #org.osgi.framework.security=osgi
 java.security.manager=
index 8cb68dce6bce6f5831b9e4ffef33b60e180a96e1..2abac18a09093ac2a9bcf2d6a654d2dd3cc444e7 100644 (file)
@@ -12,7 +12,7 @@
        <name>SLC Distribution</name>
        <modules>
                <module>slc</module>
-               <module>slc-maven</module>
+<!--           <module>slc-maven</module> -->
        </modules>
        <!-- <profiles> -->
        <!-- <profile> -->
index ab4f333031d5acfe642e7305bd6eb82c62fdc7d5..57aa1edecf3d07c23e003b524a776197c2ed99ff 100644 (file)
@@ -39,12 +39,12 @@ import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
-import org.argeo.slc.aether.AetherUtils;
 import org.argeo.slc.client.ui.dist.DistPlugin;
 import org.argeo.slc.repo.ArtifactIndexer;
 import org.argeo.slc.repo.JarFileIndexer;
 import org.argeo.slc.repo.RepoConstants;
 import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.maven.AetherUtils;
 import org.argeo.slc.repo.maven.MavenConventionsUtils;
 import org.argeo.slc.repo.osgi.NormalizeGroup;
 import org.eclipse.aether.artifact.Artifact;
index bc86c42397ef126c77ef584a0472c9bec18d36ac..70b08e83018b29c72264fa37f2b23597484264ee 100644 (file)
@@ -1,7 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
        <classpathentry kind="src" output="target/classes" path="src"/>
+       <classpathentry kind="src" path="ext/test"/>
        <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>>>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
index b83d22266ac8aa2f8df2edef68082c789727841d..0f630157f4bf530f9697788f383cabaab83dc2e8 100644 (file)
@@ -1 +1,2 @@
 /target/
+/bin/
index d40b307f8a30523d05313598606bf7c7dbfae99d..6ead58491b7a5a5a7cff119a585ddf4be53f31b1 100644 (file)
@@ -3,8 +3,11 @@ org.xml.sax.*,\
 javax.xml.transform.*,\
 javax.xml.parsers.*,\
 javax.jcr.nodetype,\
+org.eclipse.aether.*;version=1.0.1,\
 *
 
+Private-Package: org.eclipse.aether.*
+
 Require-Capability: cms.datamodel; filter:="(name=node)",\
 cms.datamodel; filter:="(name=slc)"
 Provide-Capability: cms.datamodel; name=java,\
diff --git a/org.argeo.slc.repo/build.properties b/org.argeo.slc.repo/build.properties
new file mode 100644 (file)
index 0000000..31b02d2
--- /dev/null
@@ -0,0 +1 @@
+additional.bundles = org.junit
diff --git a/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/AetherUtilsTest.java
new file mode 100644 (file)
index 0000000..61824e4
--- /dev/null
@@ -0,0 +1,69 @@
+package org.argeo.slc.repo.internal;
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed 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 junit.framework.TestCase;
+
+import org.argeo.slc.repo.maven.AetherUtils;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+
+public class AetherUtilsTest extends TestCase {
+       public void testConvertPathToArtifact() throws Exception {
+               checkPathConversion("my.group.id:my-artifactId:pom:1.2.3",
+                               "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3.pom");
+               checkPathConversion("my.group.id:my-artifactId:pom:1.2.3-SNAPSHOT",
+                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT.pom");
+               checkPathConversion("my.group.id:my-artifactId:pom:myClassifier:1.2.3",
+                               "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3-myClassifier.pom");
+               checkPathConversion(
+                               "my.group.id:my-artifactId:pom:myClassifier:1.2.3-SNAPSHOT",
+                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT-myClassifier.pom");
+               checkPathConversion(
+                               "my.group.id:my-artifactId:pom:myClassifier:20110828.223836-2",
+                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-20110828.223836-2-myClassifier.pom");
+       }
+
+       public void testConvertPathToArtifactRealLife() throws Exception {
+               checkPathConversion(
+                               "org.apache.maven.plugins:maven-antrun-plugin:pom:1.1",
+                               "org/apache/maven/plugins/maven-antrun-plugin/1.1/maven-antrun-plugin-1.1.pom");
+               checkPathConversion(
+                               "org.apache.maven.plugins:maven-plugin-parent:pom:2.0.1",
+                               "org/apache/maven/plugins/maven-plugin-parent/2.0.1/maven-plugin-parent-2.0.1.pom");
+               checkPathConversion(
+                               "org.apache.avalon.framework:avalon-framework-impl:pom:4.3.1",
+                               "org/apache/avalon/framework/avalon-framework-impl/4.3.1/avalon-framework-impl-4.3.1.pom");
+               checkPathConversion(
+                               "org.apache.maven.shared:maven-dependency-tree:pom:1.2",
+                               "org/apache/maven/shared/maven-dependency-tree/1.2/maven-dependency-tree-1.2.pom");
+               checkPathConversion(
+                               "org.argeo.maven.plugins:maven-argeo-osgi-plugin:pom:1.0.33",
+                               "org/argeo/maven/plugins/maven-argeo-osgi-plugin/1.0.33/maven-argeo-osgi-plugin-1.0.33.pom");
+               checkPathConversion(
+                               "org.apache.maven.plugins:maven-clean-plugin:pom:2.4.1",
+                               "org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom");
+       }
+
+       protected void checkPathConversion(String expectedArtifact, String path) {
+               Artifact artifact = AetherUtils.convertPathToArtifact(path, null);
+               if (expectedArtifact == null)
+                       assertNull(artifact);
+               else
+                       assertEquals(new DefaultArtifact(expectedArtifact), artifact);
+       }
+}
diff --git a/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml b/org.argeo.slc.repo/ext/test/org/argeo/slc/repo/internal/pom.xml
new file mode 100644 (file)
index 0000000..b12659b
--- /dev/null
@@ -0,0 +1,209 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+       <modelVersion>4.0.0</modelVersion>
+       <parent>
+               <groupId>org.argeo.commons</groupId>
+               <artifactId>argeo-commons</artifactId>
+               <version>2.1.70-SNAPSHOT</version>
+       </parent>
+       <groupId>org.argeo.slc</groupId>
+       <artifactId>argeo-slc</artifactId>
+       <packaging>pom</packaging>
+       <name>Argeo SLC</name>
+       <version>2.1.10-SNAPSHOT</version>
+       <properties>
+               <developmentCycle.slc>2.1</developmentCycle.slc>
+               <developmentCycle.startDate>2015-02-12</developmentCycle.startDate>
+               <version.argeo-rcp>2.1.15</version.argeo-rcp>
+               <version.slc>2.1.10-SNAPSHOT</version.slc>
+               <version.equinox>3.11.1.v20160708-1632</version.equinox>
+               <!-- Embedded Maven -->
+               <version.maven>3.2.5</version.maven>
+       </properties>
+       <modules>
+               <!-- Runtime -->
+               <module>org.argeo.slc.api</module>
+               <module>org.argeo.slc.core</module>
+               <module>org.argeo.slc.unit</module>
+               <module>org.argeo.slc.support</module>
+               <module>org.argeo.slc.support.maven</module>
+               <module>org.argeo.slc.repo</module>
+               <module>org.argeo.slc.factory</module>
+               <module>org.argeo.slc.launcher</module>
+
+               <!-- Modules -->
+               <module>org.argeo.slc.agent</module>
+               <module>org.argeo.slc.agent.jcr</module>
+               <module>org.argeo.slc.server.repo</module>
+
+               <!-- UI -->
+               <module>org.argeo.slc.client.ui</module>
+               <module>org.argeo.slc.client.ui.dist</module>
+               <module>org.argeo.slc.client.rap</module>
+               <!-- <module>org.argeo.slc.client.rcp</module> -->
+
+               <module>lib</module>
+               <module>dep</module>
+               <module>dist</module>
+               <module>demo</module>
+       </modules>
+       <url>http://projects.argeo.org/slc/</url>
+       <scm>
+               <connection>scm:git:http://git.argeo.org/apache2/argeo-slc.git</connection>
+               <url>http://git.argeo.org/?p=apache2/argeo-slc.git;a=summary</url>
+               <developerConnection>scm:git:https://code.argeo.org/git/apache2/argeo-slc.git</developerConnection>
+               <tag>HEAD</tag>
+       </scm>
+       <inceptionYear>2007</inceptionYear>
+       <licenses>
+               <license>
+                       <name>Apache 2</name>
+                       <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+                       <distribution>repo</distribution>
+                       <comments><![CDATA[
+SLC (Software Life Cycle) framework
+                          
+Copyright (C) 2007-2012 Argeo GmbH
+
+Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
+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 &quot;AS IS&quot; 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.
+]]>
+                       </comments>
+               </license>
+       </licenses>
+       <developers>
+               <developer>
+                       <id>mbaudier</id>
+                       <name>Mathieu Baudier</name>
+                       <email><![CDATA[http://mailhide.recaptcha.net/d?k=01EM7GpnvY3k8woQ2tnnZLUA==&c=crsNpHjhOBDPswHG6HD_gXaqymhC69wmBf7wlagcSHw=]]></email>
+                       <organization>Argeo</organization>
+                       <organizationUrl>http://www.argeo.org</organizationUrl>
+                       <roles>
+                               <role>architect</role>
+                               <role>developer</role>
+                               <role>QA</role>
+                       </roles>
+               </developer>
+               <developer>
+                       <id>ocapillo</id>
+                       <name>Olivier Capillon</name>
+                       <email><![CDATA[http://mailhide.recaptcha.net/d?k=01EM7GpnvY3k8woQ2tnnZLUA==&c=BYw8i94WiejnvegUKJoCZQQr0h-mYlKCNKZVe_3WPIA=]]></email>
+                       <organization>Argeo</organization>
+                       <organizationUrl>http://www.argeo.org</organizationUrl>
+                       <roles>
+                               <role>developer</role>
+                       </roles>
+               </developer>
+               <developer>
+                       <id>bsinou</id>
+                       <name>Bruno Sinou</name>
+                       <email><![CDATA[http://www.google.com/recaptcha/mailhide/d?k=01SZoYvDnJzcw0KOR7M7u6Qg==&c=SVgEjXA_Uu9ZrNzLES92w1ght6puLFiVpoNUddCfSU8=]]></email>
+                       <organization>Argeo</organization>
+                       <organizationUrl>http://www.argeo.org</organizationUrl>
+                       <roles>
+                               <role>developer</role>
+                       </roles>
+               </developer>
+       </developers>
+       <build>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-site-plugin</artifactId>
+                               <inherited>false</inherited>
+                               <configuration>
+                                       <skip>false</skip>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <artifactId>maven-javadoc-plugin</artifactId>
+                               <configuration>
+                                       <skip>true</skip>
+                               </configuration>
+                       </plugin>
+               </plugins>
+       </build>
+       <repositories>
+               <repository>
+                       <id>argeo</id>
+                       <url>http://forge.argeo.org/data/java/argeo-2.1/</url>
+                       <releases>
+                               <enabled>true</enabled>
+                               <updatePolicy>daily</updatePolicy>
+                               <checksumPolicy>warn</checksumPolicy>
+                       </releases>
+               </repository>
+               <repository>
+                       <id>argeo-rcp</id>
+                       <url>http://forge.argeo.org/data/java/argeo-rcp-2.1</url>
+                       <releases>
+                               <enabled>true</enabled>
+                               <updatePolicy>daily</updatePolicy>
+                               <checksumPolicy>warn</checksumPolicy>
+                       </releases>
+               </repository>
+
+               <!-- Disable Maven default repository -->
+               <repository>
+                       <id>central</id>
+                       <url>http://repo1.maven.org/maven2</url>
+                       <releases>
+                               <enabled>false</enabled>
+                       </releases>
+                       <snapshots>
+                               <enabled>false</enabled>
+                       </snapshots>
+               </repository>
+       </repositories>
+       <profiles>
+               <profile>
+                       <id>localrepo</id>
+                       <repositories>
+                               <repository>
+                                       <id>argeo-tp</id>
+                                       <url>http://localhost:7070/data/java/argeo-${developmentCycle.argeo-commons}</url>
+                                       <releases>
+                                               <enabled>true</enabled>
+                                               <updatePolicy>daily</updatePolicy>
+                                               <checksumPolicy>warn</checksumPolicy>
+                                       </releases>
+                               </repository>
+                               <!-- <repository> -->
+                               <!-- <id>argeo-tp-extras</id> -->
+                               <!-- <url>http://localhost:7080/data/java/argeo-tp-extras-2.1</url> -->
+                               <!-- <releases> -->
+                               <!-- <enabled>true</enabled> -->
+                               <!-- <updatePolicy>daily</updatePolicy> -->
+                               <!-- <checksumPolicy>warn</checksumPolicy> -->
+                               <!-- </releases> -->
+                               <!-- </repository> -->
+                               <repository>
+                                       <id>argeo-commons</id>
+                                       <url>http://localhost:7070/data/java/argeo-${developmentCycle.argeo-commons}</url>
+                                       <releases>
+                                               <enabled>true</enabled>
+                                               <updatePolicy>daily</updatePolicy>
+                                               <checksumPolicy>warn</checksumPolicy>
+                                       </releases>
+                               </repository>
+                       </repositories>
+                       <distributionManagement>
+                               <repository>
+                                       <id>staging</id>
+                                       <url>dav:http://localhost:7070/data/java/argeo-slc-${developmentCycle.slc}</url>
+                               </repository>
+                               <site>
+                                       <id>staging</id>
+                                       <url>dav:http://localhost:7070/data/docs/argeo-slc-${developmentCycle.slc}</url>
+                               </site>
+                       </distributionManagement>
+               </profile>
+       </profiles>
+</project>
index 214269c5fb68267332aa17e9c0c7854f125de238..a3c1b5d4d3b6903f88b626570f0c9a574e255c75 100644 (file)
@@ -24,9 +24,9 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.AetherUtils;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
+import org.argeo.slc.repo.maven.AetherUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.osgi.framework.Constants;
 
index 594168d511ea4042dc2c0c18dd8bfe03108e3a45..65238df5583d6e5913aa0d6de34b41ad03a94846 100644 (file)
@@ -24,10 +24,10 @@ import org.argeo.slc.CategorizedNameVersion;
 import org.argeo.slc.DefaultNameVersion;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.AetherUtils;
-import org.argeo.slc.build.Distribution;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
+import org.argeo.slc.build.Distribution;
+import org.argeo.slc.repo.maven.AetherUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.osgi.framework.Constants;
index bcaa7302ec68b992efc3da7237c8e9de6694565b..793f9bd9e82bb7efa099d88b30ee15adc728f70c 100644 (file)
@@ -27,7 +27,7 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.AetherUtils;
+import org.argeo.slc.repo.maven.AetherUtils;
 import org.argeo.slc.repo.maven.MavenConventionsUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
index 056d7164c3277229232c8fd2d88193a6ad140a2b..13ad7583dc0f14f40c3c0cbe63a741a96e0b2c97 100644 (file)
@@ -60,9 +60,9 @@ import org.argeo.node.security.Keyring;
 import org.argeo.slc.DefaultNameVersion;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
+import org.argeo.slc.repo.maven.ArtifactIdComparator;
 import org.argeo.slc.repo.maven.MavenConventionsUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/AetherUtils.java
new file mode 100644 (file)
index 0000000..fcc9b05
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.repo.maven;
+
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.graph.DependencyNode;
+
+/** Utilities related to Aether */
+public class AetherUtils {
+       public final static String SNAPSHOT = "SNAPSHOT";
+       // hacked from aether
+       public static final Pattern SNAPSHOT_TIMESTAMP = Pattern
+                       .compile("^(.*-)?([0-9]{8}.[0-9]{6}-[0-9]+)$");
+
+       private final static Log log = LogFactory.getLog(AetherUtils.class);
+
+       /** Logs a dependency node and its transitive dependencies as a tree. */
+       public static void logDependencyNode(int depth,
+                       DependencyNode dependencyNode) {
+               if (!log.isDebugEnabled())
+                       return;
+
+               StringBuffer prefix = new StringBuffer(depth * 2 + 2);
+               // prefix.append("|-");
+               for (int i = 0; i < depth * 2; i++) {
+                       prefix.append(' ');
+               }
+               Artifact artifact = dependencyNode.getDependency().getArtifact();
+               log.debug(prefix + "|-> " + artifact.getArtifactId() + " ["
+                               + artifact.getVersion() + "]"
+                               + (dependencyNode.getDependency().isOptional() ? " ?" : ""));
+               for (DependencyNode child : dependencyNode.getChildren()) {
+                       logDependencyNode(depth + 1, child);
+               }
+       }
+
+       /**
+        * Converts a path (relative to a repository root) to an {@link Artifact}.
+        * 
+        * @param path
+        *            the relative path
+        * @param type
+        *            the layout type, currently ignored because only the 'default'
+        *            Maven 2 layout is currently supported:
+        *            /my/group/id/artifactId/
+        *            version/artifactId-version[-classifier].extension
+        * @return the related artifact or null if the file is not an artifact
+        *         (Maven medata data XML files, check sums, etc.)
+        */
+       public static Artifact convertPathToArtifact(String path, String type) {
+               // TODO rewrite it with regexp (unit tests first!)
+
+               // normalize
+               if (path.startsWith("/"))
+                       path = path.substring(1);
+
+               // parse group id
+               String[] tokensSlash = path.split("/");
+               if (tokensSlash.length < 4)
+                       return null;
+               StringBuffer groupId = new StringBuffer(path.length());
+               for (int i = 0; i < tokensSlash.length - 3; i++) {
+                       if (i != 0)
+                               groupId.append('.');
+                       groupId.append(tokensSlash[i]);
+               }
+               String artifactId = tokensSlash[tokensSlash.length - 3];
+               String baseVersion = tokensSlash[tokensSlash.length - 2];
+               String fileName = tokensSlash[tokensSlash.length - 1];
+
+               if (!fileName.startsWith(artifactId))
+                       return null;
+               // FIXME make it configurable? (via an argument?)
+               if (FilenameUtils.isExtension(fileName, new String[] { "sha1", "md5" }))
+                       return null;
+
+               String extension = FilenameUtils.getExtension(fileName);
+               String baseName = FilenameUtils.getBaseName(fileName);
+
+               // check since we assume hereafter
+               if (!baseName.startsWith(artifactId))
+                       throw new SlcException("Base name '" + baseName
+                                       + " does not start with artifact id '" + artifactId
+                                       + "' in " + path);
+
+               boolean isSnapshot = baseVersion.endsWith("-" + SNAPSHOT);
+               String baseBaseVersion = isSnapshot ? baseVersion.substring(0,
+                               baseVersion.length() - SNAPSHOT.length() - 1) : baseVersion;
+               int artifactAndBaseBaseVersionLength = artifactId.length() + 1
+                               + baseBaseVersion.length() + 1;
+               String classifier = null;
+               if (baseName.length() > artifactAndBaseBaseVersionLength) {
+                       String dashRest = baseName
+                                       .substring(artifactAndBaseBaseVersionLength);
+                       String[] dashes = dashRest.split("-");
+
+                       if (isSnapshot) {
+                               if (dashes[0].equals(SNAPSHOT)) {
+                                       if (dashRest.length() > SNAPSHOT.length() + 1)
+                                               classifier = dashRest.substring(SNAPSHOT.length() + 1);
+
+                               } else {
+                                       if (dashes.length > 2)// assume no '-' in classifier
+                                               classifier = dashes[2];
+                               }
+                       } else {
+                               if (dashes.length > 0)
+                                       classifier = dashes[0];
+                       }
+               }
+
+               // classifier
+               // String classifier = null;
+               // int firstDash = baseName.indexOf('-');
+               // int classifierDash = baseName.lastIndexOf('-');
+               // if (classifierDash > 0 && classifierDash != firstDash) {
+               // classifier = baseName.substring(classifierDash + 1);
+               // }
+               // if (isSnapshot && classifier != null) {
+               // if (classifier.equals(SNAPSHOT))
+               // classifier = null;
+               // else
+               // try {
+               // Long.parseLong(classifier); // build number
+               // // if not failed this is a timestamped version
+               // classifier = null;
+               // } catch (NumberFormatException e) {
+               // // silent
+               // }
+               // }
+
+               // version
+               String version = baseName.substring(artifactId.length() + 1);
+               if (classifier != null)
+                       version = version.substring(0,
+                                       version.length() - classifier.length() - 1);
+
+               // consistency checks
+               if (!isSnapshot && !version.equals(baseVersion))
+                       throw new SlcException("Base version '" + baseVersion
+                                       + "' and version '" + version + "' not in line in " + path);
+               if (!isSnapshot && isSnapshotVersion(version))
+                       throw new SlcException("SNAPSHOT base version '" + baseVersion
+                                       + "' and version '" + version + "' not in line in " + path);
+
+               DefaultArtifact artifact = new DefaultArtifact(groupId.toString(),
+                               artifactId, classifier, extension, version);
+               return artifact;
+       }
+
+       /** Hacked from aether */
+       public static boolean isSnapshotVersion(String version) {
+               return version.endsWith(SNAPSHOT)
+                               || SNAPSHOT_TIMESTAMP.matcher(version).matches();
+       }
+
+}
diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ArtifactIdComparator.java
new file mode 100644 (file)
index 0000000..98d2d1d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007-2012 Argeo GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *         http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.argeo.slc.repo.maven;
+
+import java.util.Comparator;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * Compare two artifacts, for use in {@link TreeSet} / {@link TreeMap}, consider
+ * artifactId first THEN groupId
+ */
+public class ArtifactIdComparator implements Comparator<Artifact> {
+       public int compare(Artifact o1, Artifact o2) {
+               if (o1.getArtifactId().equals(o2.getArtifactId()))
+                       return o1.getGroupId().compareTo(o2.getGroupId());
+               return o1.getArtifactId().compareTo(o2.getArtifactId());
+       }
+
+}
index 063b408c74b4894b2b58e44e31b9bc6f3d4768e3..83335e9a5eef80982abd477cffeb91fb2a7a98da 100644 (file)
@@ -33,7 +33,6 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.jcr.JcrMonitor;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
 import org.argeo.slc.repo.ArtifactIndexer;
diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/maven/ImportMavenDependencies.java
deleted file mode 100644 (file)
index 009d1f9..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.repo.maven;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Properties;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.jcr.Node;
-import javax.jcr.NodeIterator;
-import javax.jcr.Repository;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.slc.NameVersion;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.AetherTemplate;
-import org.argeo.slc.aether.ArtifactIdComparator;
-import org.argeo.slc.repo.ArtifactIndexer;
-import org.argeo.slc.repo.JarFileIndexer;
-import org.argeo.slc.repo.RepoConstants;
-import org.argeo.slc.repo.RepoUtils;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.graph.DependencyNode;
-
-/**
- * Import all the dependencies listed in a POM and their dependency graphs to a
- * workspace.
- */
-public class ImportMavenDependencies implements Runnable {
-       private final static Log log = LogFactory
-                       .getLog(ImportMavenDependencies.class);
-
-       private AetherTemplate aetherTemplate;
-       private String rootCoordinates = "org.argeo.dep:versions-all:pom:1.2.0";
-       private String distCoordinates = "org.argeo.tp:dist:pom:1.3.0";
-       private String parentPomCoordinates = "org.argeo:parent:1.2.0";
-       private Set<String> excludedArtifacts = new HashSet<String>();
-
-       private Repository repository;
-       private String workspace;
-
-       private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH;
-
-       private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
-       private JarFileIndexer jarFileIndexer = new JarFileIndexer();
-       private Comparator<Artifact> artifactComparator = new ArtifactIdComparator();
-
-       public void run() {
-               // resolve
-               Set<Artifact> artifacts = resolveDistribution();
-
-               // sync
-               sync(artifacts);
-       }
-
-       void sync(Set<Artifact> artifacts) {
-               Session session = null;
-               try {
-                       session = JcrUtils.loginOrCreateWorkspace(repository, workspace);
-                       // clear
-                       NodeIterator nit = session.getNode(artifactBasePath).getNodes();
-                       while (nit.hasNext()) {
-                               Node node = nit.nextNode();
-                               if (node.isNodeType(NodeType.NT_FOLDER)
-                                               || node.isNodeType(NodeType.NT_UNSTRUCTURED))
-                                       node.remove();
-                       }
-                       session.save();
-
-                       // sync
-                       syncDistribution(session, artifacts);
-               } catch (Exception e) {
-                       throw new SlcException("Cannot import distribution", e);
-               } finally {
-                       JcrUtils.logoutQuietly(session);
-               }
-       }
-
-       /**
-        * Generate a POM with all the artifacts declared in root coordinates as
-        * dependencies AND in dependency management.
-        */
-       void createDistPom() {
-               try {
-                       Artifact pomArtifact = new DefaultArtifact(rootCoordinates);
-
-                       Set<Artifact> registeredArtifacts = new TreeSet<Artifact>(
-                                       artifactComparator);
-                       MavenConventionsUtils.gatherPomDependencies(aetherTemplate,
-                                       registeredArtifacts, pomArtifact);
-                       Artifact sdkArtifact = new DefaultArtifact(distCoordinates);
-                       String sdkPom = MavenConventionsUtils.artifactsAsDependencyPom(
-                                       sdkArtifact, registeredArtifacts, new DefaultArtifact(
-                                                       parentPomCoordinates));
-                       if (log.isDebugEnabled())
-                               log.debug("Gathered " + registeredArtifacts.size()
-                                               + " artifacts:\n" + sdkPom);
-               } catch (Exception e) {
-                       throw new SlcException("Cannot resolve distribution", e);
-               }
-       }
-
-       /** Returns all transitive dependencies of dist POM */
-       private Set<Artifact> resolveDistribution() {
-               try {
-                       Artifact distArtifact = new DefaultArtifact(distCoordinates);
-                       Set<Artifact> artifacts = new TreeSet<Artifact>(artifactComparator);
-
-                       DependencyNode node = aetherTemplate
-                                       .resolveDependencies(distArtifact);
-                       addDependencies(artifacts, node, null);
-
-                       if (log.isDebugEnabled()) {
-                               log.debug("Resolved " + artifacts.size() + " artifacts");
-
-                               // Properties distributionDescriptor =
-                               // generateDistributionDescriptor(artifacts);
-                               // ByteArrayOutputStream out = new ByteArrayOutputStream();
-                               // distributionDescriptor.store(out, "");
-                               // log.debug(new String(out.toByteArray()));
-                               // out.close();
-                       }
-
-                       /*
-                        * for (Artifact artifact : registeredArtifacts) { try { Boolean
-                        * wasAdded = addArtifact(artifacts, artifact); if (wasAdded) {
-                        * DependencyNode node = aetherTemplate
-                        * .resolveDependencies(artifact); addDependencies(artifacts, node,
-                        * null); } } catch (Exception e) {
-                        * log.error("Could not resolve dependencies of " + artifact + ": "
-                        * + e.getCause().getMessage()); }
-                        * 
-                        * }
-                        * 
-                        * if (log.isDebugEnabled()) log.debug("Resolved " +
-                        * artifacts.size() + " artifacts");
-                        * 
-                        * // distribution descriptor // Properties distributionDescriptor =
-                        * // generateDistributionDescriptor(artifacts); //
-                        * ByteArrayOutputStream out = new ByteArrayOutputStream(); //
-                        * distributionDescriptor.store(out, ""); // log.debug(new
-                        * String(out.toByteArray())); // out.close();
-                        */
-                       return artifacts;
-               } catch (Exception e) {
-                       throw new SlcException("Cannot resolve distribution", e);
-               }
-       }
-
-       protected Properties generateDistributionDescriptor(Set<Artifact> artifacts) {
-               Properties distributionDescriptor = new Properties();
-               for (Artifact artifact : artifacts) {
-                       log.debug(artifact.getArtifactId() + " [" + artifact.getVersion()
-                                       + "]\t(" + artifact + ")");
-                       distributionDescriptor.setProperty(artifact.getArtifactId() + ":"
-                                       + artifact.getVersion(), artifact.toString());
-               }
-               return distributionDescriptor;
-       }
-
-       /** Write artifacts to the target workspace, skipping excluded ones */
-       protected void syncDistribution(Session jcrSession, Set<Artifact> artifacts) {
-               Set<Artifact> artifactsWithoutSources = new TreeSet<Artifact>(
-                               artifactComparator);
-               Long begin = System.currentTimeMillis();
-               try {
-                       JcrUtils.mkfolders(jcrSession, artifactBasePath);
-                       artifacts: for (Artifact artifact : artifacts) {
-                               // skip excluded
-                               if (excludedArtifacts.contains(artifact.getGroupId() + ":"
-                                               + artifact.getArtifactId())) {
-                                       if (log.isDebugEnabled())
-                                               log.debug("Exclude " + artifact);
-                                       continue artifacts;
-                               }
-
-                               File jarFile = MavenConventionsUtils.artifactToFile(artifact);
-                               if (!jarFile.exists()) {
-                                       log.warn("Generated file " + jarFile + " for " + artifact
-                                                       + " does not exist");
-                                       continue artifacts;
-                               }
-                               artifact.setFile(jarFile);
-
-                               try {
-                                       String parentPath = MavenConventionsUtils
-                                                       .artifactParentPath(artifactBasePath, artifact);
-                                       Node parentNode;
-                                       if (!jcrSession.itemExists(parentPath))
-                                               parentNode = JcrUtils.mkfolders(jcrSession, parentPath);
-                                       else
-                                               parentNode = jcrSession.getNode(parentPath);
-
-                                       Node fileNode;
-                                       if (!parentNode.hasNode(jarFile.getName())) {
-                                               fileNode = createFileNode(parentNode, jarFile);
-                                       } else {
-                                               fileNode = parentNode.getNode(jarFile.getName());
-                                       }
-
-                                       if (artifactIndexer.support(fileNode.getPath()))
-                                               artifactIndexer.index(fileNode);
-                                       if (jarFileIndexer.support(fileNode.getPath()))
-                                               jarFileIndexer.index(fileNode);
-                                       jcrSession.save();
-
-                                       addPdeSource(jcrSession, artifact, jarFile,
-                                                       artifactsWithoutSources);
-                                       jcrSession.save();
-
-                                       if (log.isDebugEnabled())
-                                               log.debug("Synchronized " + fileNode);
-                               } catch (Exception e) {
-                                       log.error("Could not synchronize " + artifact, e);
-                                       jcrSession.refresh(false);
-                                       throw e;
-                               }
-                       }
-
-                       Long duration = (System.currentTimeMillis() - begin) / 1000;
-                       if (log.isDebugEnabled()) {
-                               log.debug("Synchronized distribution in " + duration + "s");
-                               log.debug("The following artifacts have no sources:");
-                               for (Artifact artifact : artifactsWithoutSources) {
-                                       log.debug(artifact);
-                               }
-                       }
-               } catch (Exception e) {
-                       throw new SlcException("Cannot synchronize distribution", e);
-               }
-       }
-
-       /** Try to add PDE sources */
-       private void addPdeSource(Session session, Artifact artifact,
-                       File artifactFile, Set<Artifact> artifactsWithoutSources) {
-               ByteArrayOutputStream out = new ByteArrayOutputStream();
-               try {
-                       File origSourceFile = null;
-                       Artifact origSourceArtifact = new DefaultArtifact(
-                                       artifact.getGroupId(), artifact.getArtifactId(), "sources",
-                                       artifact.getExtension(), artifact.getVersion());
-                       Artifact newSourceArtifact = new DefaultArtifact(
-                                       artifact.getGroupId(),
-                                       artifact.getArtifactId() + ".source",
-                                       artifact.getExtension(), artifact.getVersion());
-                       try {
-                               origSourceFile = aetherTemplate
-                                               .getResolvedFile(origSourceArtifact);
-                       } catch (Exception e) {
-                               // also try artifact following the conventions
-                               origSourceArtifact = newSourceArtifact;
-                               origSourceFile = aetherTemplate
-                                               .getResolvedFile(origSourceArtifact);
-                       }
-
-                       String newSourceParentPath = MavenConventionsUtils
-                                       .artifactParentPath(artifactBasePath, newSourceArtifact);
-                       Node newSourceParentNode = JcrUtils.mkfolders(session,
-                                       newSourceParentPath);
-                       NameVersion bundleNameVersion = RepoUtils
-                                       .readNameVersion(artifactFile);
-                       RepoUtils.packagesAsPdeSource(origSourceFile, bundleNameVersion,
-                                       out);
-                       String newSourceFileName = MavenConventionsUtils
-                                       .artifactFileName(newSourceArtifact);
-                       JcrUtils.copyBytesAsFile(newSourceParentNode, newSourceFileName,
-                                       out.toByteArray());
-               } catch (Exception e) {
-                       log.error("Cannot add PDE source for " + artifact + ": " + e);
-                       artifactsWithoutSources.add(artifact);
-               } finally {
-                       IOUtils.closeQuietly(out);
-               }
-       }
-
-       private Node createFileNode(Node parentNode, File file) {
-               return JcrUtils.copyFile(parentNode, file);
-       }
-
-       /** Recursively adds non optional dependencies */
-       private void addDependencies(Set<Artifact> artifacts, DependencyNode node,
-                       String ancestors) {
-               // if (artifacts.contains(node.getDependency().getArtifact()))
-               // return;
-               String currentArtifactId = node.getDependency().getArtifact()
-                               .getArtifactId();
-               if (log.isDebugEnabled()) {
-                       log.debug("# Add dependency for " + currentArtifactId);
-                       if (ancestors != null)
-                               log.debug(ancestors);
-               }
-               for (DependencyNode child : node.getChildren()) {
-                       if (!child.getDependency().isOptional()) {
-                               if (willAdd(child.getDependency().getArtifact())) {
-                                       addArtifact(artifacts, child.getDependency().getArtifact());
-                                       addDependencies(artifacts, child, currentArtifactId + "\n"
-                                                       + (ancestors != null ? ancestors : ""));
-                               }
-                       }
-               }
-       }
-
-       /** @return whether it was added */
-       private Boolean addArtifact(Set<Artifact> artifacts, Artifact artifact) {
-               Boolean willAdd = willAdd(artifact);
-               if (willAdd)
-                       artifacts.add(artifact);
-               else
-                       log.info("Skip " + artifact);
-               return willAdd;
-       }
-
-       private Boolean willAdd(Artifact artifact) {
-               Boolean willAdd = true;
-               if (excludedArtifacts.contains(artifact.getGroupId() + ":"
-                               + artifact.getArtifactId()))
-                       willAdd = false;
-               else if (excludedArtifacts.contains(artifact.getGroupId() + ":*"))
-                       willAdd = false;
-               return willAdd;
-       }
-
-       public void setAetherTemplate(AetherTemplate aetherTemplate) {
-               this.aetherTemplate = aetherTemplate;
-       }
-
-       public void setExcludedArtifacts(Set<String> excludedArtifactIds) {
-               this.excludedArtifacts = excludedArtifactIds;
-       }
-
-       public void setRootCoordinates(String rootCoordinates) {
-               this.rootCoordinates = rootCoordinates;
-       }
-
-       public void setRepository(Repository repository) {
-               this.repository = repository;
-       }
-
-       public void setWorkspace(String workspace) {
-               this.workspace = workspace;
-       }
-
-       public void setDistCoordinates(String distCoordinates) {
-               this.distCoordinates = distCoordinates;
-       }
-
-       public void setArtifactBasePath(String artifactBasePath) {
-               this.artifactBasePath = artifactBasePath;
-       }
-
-}
index 09827885cc271cc4f2fbbfaebb33f6f1f91d7d02..c25e3fb7f232f594e2ce01b7680c2ca8fe271c6a 100644 (file)
 package org.argeo.slc.repo.maven;
 
 import java.io.File;
-import java.util.Properties;
 import java.util.Set;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.AetherTemplate;
 import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.DefaultArtifact;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
 
 /**
  * Static utilities around Maven which are NOT using the Maven APIs (conventions
@@ -162,66 +152,66 @@ public class MavenConventionsUtils {
                return p.toString();
        }
 
-       /**
-        * Directly parses Maven POM XML format in order to find all artifacts
-        * references under the dependency and dependencyManagement tags. This is
-        * meant to migrate existing pom registering a lot of artifacts, not to
-        * replace Maven resolving.
-        */
-       public static void gatherPomDependencies(AetherTemplate aetherTemplate, Set<Artifact> artifacts,
-                       Artifact pomArtifact) {
-               if (log.isDebugEnabled())
-                       log.debug("Gather dependencies for " + pomArtifact);
-
-               try {
-                       File file = aetherTemplate.getResolvedFile(pomArtifact);
-                       DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-                       Document doc = documentBuilder.parse(file);
-
-                       // properties
-                       Properties props = new Properties();
-                       props.setProperty("project.version", pomArtifact.getBaseVersion());
-                       NodeList properties = doc.getElementsByTagName("properties");
-                       if (properties.getLength() > 0) {
-                               NodeList propertiesElems = properties.item(0).getChildNodes();
-                               for (int i = 0; i < propertiesElems.getLength(); i++) {
-                                       if (propertiesElems.item(i) instanceof Element) {
-                                               Element property = (Element) propertiesElems.item(i);
-                                               props.put(property.getNodeName(), property.getTextContent());
-                                       }
-                               }
-                       }
-
-                       // dependencies (direct and dependencyManagement)
-                       NodeList dependencies = doc.getElementsByTagName("dependency");
-                       for (int i = 0; i < dependencies.getLength(); i++) {
-                               Element dependency = (Element) dependencies.item(i);
-                               String groupId = dependency.getElementsByTagName("groupId").item(0).getTextContent().trim();
-                               String artifactId = dependency.getElementsByTagName("artifactId").item(0).getTextContent().trim();
-                               String version = dependency.getElementsByTagName("version").item(0).getTextContent().trim();
-                               if (version.startsWith("${")) {
-                                       String versionKey = version.substring(0, version.length() - 1).substring(2);
-                                       if (!props.containsKey(versionKey))
-                                               throw new SlcException("Cannot interpret version " + version);
-                                       version = props.getProperty(versionKey);
-                               }
-                               NodeList scopes = dependency.getElementsByTagName("scope");
-                               if (scopes.getLength() > 0 && scopes.item(0).getTextContent().equals("import")) {
-                                       // recurse
-                                       gatherPomDependencies(aetherTemplate, artifacts,
-                                                       new DefaultArtifact(groupId, artifactId, "pom", version));
-                               } else {
-                                       // TODO: deal with scope?
-                                       // TODO: deal with type
-                                       String type = "jar";
-                                       Artifact artifact = new DefaultArtifact(groupId, artifactId, type, version);
-                                       artifacts.add(artifact);
-                               }
-                       }
-               } catch (Exception e) {
-                       throw new SlcException("Cannot process " + pomArtifact, e);
-               }
-       }
+//     /**
+//      * Directly parses Maven POM XML format in order to find all artifacts
+//      * references under the dependency and dependencyManagement tags. This is
+//      * meant to migrate existing pom registering a lot of artifacts, not to
+//      * replace Maven resolving.
+//      */
+//     public static void gatherPomDependencies(AetherTemplate aetherTemplate, Set<Artifact> artifacts,
+//                     Artifact pomArtifact) {
+//             if (log.isDebugEnabled())
+//                     log.debug("Gather dependencies for " + pomArtifact);
+//
+//             try {
+//                     File file = aetherTemplate.getResolvedFile(pomArtifact);
+//                     DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+//                     Document doc = documentBuilder.parse(file);
+//
+//                     // properties
+//                     Properties props = new Properties();
+//                     props.setProperty("project.version", pomArtifact.getBaseVersion());
+//                     NodeList properties = doc.getElementsByTagName("properties");
+//                     if (properties.getLength() > 0) {
+//                             NodeList propertiesElems = properties.item(0).getChildNodes();
+//                             for (int i = 0; i < propertiesElems.getLength(); i++) {
+//                                     if (propertiesElems.item(i) instanceof Element) {
+//                                             Element property = (Element) propertiesElems.item(i);
+//                                             props.put(property.getNodeName(), property.getTextContent());
+//                                     }
+//                             }
+//                     }
+//
+//                     // dependencies (direct and dependencyManagement)
+//                     NodeList dependencies = doc.getElementsByTagName("dependency");
+//                     for (int i = 0; i < dependencies.getLength(); i++) {
+//                             Element dependency = (Element) dependencies.item(i);
+//                             String groupId = dependency.getElementsByTagName("groupId").item(0).getTextContent().trim();
+//                             String artifactId = dependency.getElementsByTagName("artifactId").item(0).getTextContent().trim();
+//                             String version = dependency.getElementsByTagName("version").item(0).getTextContent().trim();
+//                             if (version.startsWith("${")) {
+//                                     String versionKey = version.substring(0, version.length() - 1).substring(2);
+//                                     if (!props.containsKey(versionKey))
+//                                             throw new SlcException("Cannot interpret version " + version);
+//                                     version = props.getProperty(versionKey);
+//                             }
+//                             NodeList scopes = dependency.getElementsByTagName("scope");
+//                             if (scopes.getLength() > 0 && scopes.item(0).getTextContent().equals("import")) {
+//                                     // recurse
+//                                     gatherPomDependencies(aetherTemplate, artifacts,
+//                                                     new DefaultArtifact(groupId, artifactId, "pom", version));
+//                             } else {
+//                                     // TODO: deal with scope?
+//                                     // TODO: deal with type
+//                                     String type = "jar";
+//                                     Artifact artifact = new DefaultArtifact(groupId, artifactId, type, version);
+//                                     artifacts.add(artifact);
+//                             }
+//                     }
+//             } catch (Exception e) {
+//                     throw new SlcException("Cannot process " + pomArtifact, e);
+//             }
+//     }
 
        /** Prevent instantiation */
        private MavenConventionsUtils() {
index 9a9e96f013147950b2be0889d8929500618e0bfd..badbbc1e8057f4d8888549691923dfb6d22a5670 100644 (file)
@@ -30,11 +30,11 @@ import org.argeo.slc.DefaultNameVersion;
 import org.argeo.slc.ModuleSet;
 import org.argeo.slc.NameVersion;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.build.Distribution;
 import org.argeo.slc.build.License;
 import org.argeo.slc.repo.OsgiFactory;
 import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.maven.ArtifactIdComparator;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.springframework.util.AntPathMatcher;
index a5b6ec9341501e08650a405a92dfc97853baf91e..40a7a8ac93d59526ab4ad60d3666437eb1d8bfca 100644 (file)
@@ -17,7 +17,6 @@ import org.argeo.slc.repo.OsgiFactory;
 import org.argeo.slc.repo.RepoUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.util.artifact.SubArtifact;
 
 /**
  * BND wrapper based on a Maven artifact available from one of the configured
index 82657b29fcd0f764a84a1907e1be696c33105ab6..1d250379970540ba02a5c4a7b8409fc6e1c31ba9 100644 (file)
@@ -35,12 +35,12 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.jcr.JcrMonitor;
 import org.argeo.jcr.JcrUtils;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.aether.ArtifactIdComparator;
 import org.argeo.slc.SlcNames;
 import org.argeo.slc.SlcTypes;
 import org.argeo.slc.repo.ArtifactIndexer;
 import org.argeo.slc.repo.RepoConstants;
 import org.argeo.slc.repo.RepoUtils;
+import org.argeo.slc.repo.maven.ArtifactIdComparator;
 import org.argeo.slc.repo.maven.MavenConventionsUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
diff --git a/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java b/org.argeo.slc.repo/src/org/argeo/slc/repo/osgi/SubArtifact.java
new file mode 100644 (file)
index 0000000..9ce8455
--- /dev/null
@@ -0,0 +1,214 @@
+package org.argeo.slc.repo.osgi;
+
+import java.io.File;
+import java.util.Map;
+
+import org.eclipse.aether.artifact.AbstractArtifact;
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * An artifact whose identity is derived from another artifact. <em>Note:</em> Instances of this class are immutable and
+ * the exposed mutators return new objects rather than changing the current instance.
+ */
+final class SubArtifact
+    extends AbstractArtifact
+{
+
+    private final Artifact mainArtifact;
+
+    private final String classifier;
+
+    private final String extension;
+
+    private final File file;
+
+    private final Map<String, String> properties;
+
+    /**
+     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
+     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
+     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
+     * used to refer to the GPG signature of an artifact.
+     * 
+     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
+     * @param classifier The classifier for this artifact, may be {@code null} if none.
+     * @param extension The extension for this artifact, may be {@code null} if none.
+     */
+    public SubArtifact( Artifact mainArtifact, String classifier, String extension )
+    {
+        this( mainArtifact, classifier, extension, (File) null );
+    }
+
+    /**
+     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
+     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
+     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
+     * used to refer to the GPG signature of an artifact.
+     * 
+     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
+     * @param classifier The classifier for this artifact, may be {@code null} if none.
+     * @param extension The extension for this artifact, may be {@code null} if none.
+     * @param file The file for this artifact, may be {@code null} if unresolved.
+     */
+    public SubArtifact( Artifact mainArtifact, String classifier, String extension, File file )
+    {
+        this( mainArtifact, classifier, extension, null, file );
+    }
+
+    /**
+     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
+     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
+     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
+     * used to refer to the GPG signature of an artifact.
+     * 
+     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
+     * @param classifier The classifier for this artifact, may be {@code null} if none.
+     * @param extension The extension for this artifact, may be {@code null} if none.
+     * @param properties The properties of the artifact, may be {@code null}.
+     */
+    public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties )
+    {
+        this( mainArtifact, classifier, extension, properties, null );
+    }
+
+    /**
+     * Creates a new sub artifact. The classifier and extension specified for this artifact may use the asterisk
+     * character "*" to refer to the corresponding property of the main artifact. For instance, the classifier
+     * "*-sources" can be used to refer to the source attachment of an artifact. Likewise, the extension "*.asc" can be
+     * used to refer to the GPG signature of an artifact.
+     * 
+     * @param mainArtifact The artifact from which to derive the identity, must not be {@code null}.
+     * @param classifier The classifier for this artifact, may be {@code null} if none.
+     * @param extension The extension for this artifact, may be {@code null} if none.
+     * @param properties The properties of the artifact, may be {@code null}.
+     * @param file The file for this artifact, may be {@code null} if unresolved.
+     */
+    public SubArtifact( Artifact mainArtifact, String classifier, String extension, Map<String, String> properties,
+                        File file )
+    {
+        if ( mainArtifact == null )
+        {
+            throw new IllegalArgumentException( "no artifact specified" );
+        }
+        this.mainArtifact = mainArtifact;
+        this.classifier = classifier;
+        this.extension = extension;
+        this.file = file;
+        this.properties = copyProperties( properties );
+    }
+
+    private SubArtifact( Artifact mainArtifact, String classifier, String extension, File file,
+                         Map<String, String> properties )
+    {
+        // NOTE: This constructor assumes immutability of the provided properties, for internal use only
+        this.mainArtifact = mainArtifact;
+        this.classifier = classifier;
+        this.extension = extension;
+        this.file = file;
+        this.properties = properties;
+    }
+
+    public String getGroupId()
+    {
+        return mainArtifact.getGroupId();
+    }
+
+    public String getArtifactId()
+    {
+        return mainArtifact.getArtifactId();
+    }
+
+    public String getVersion()
+    {
+        return mainArtifact.getVersion();
+    }
+
+    public String getBaseVersion()
+    {
+        return mainArtifact.getBaseVersion();
+    }
+
+    public boolean isSnapshot()
+    {
+        return mainArtifact.isSnapshot();
+    }
+
+    public String getClassifier()
+    {
+        return expand( classifier, mainArtifact.getClassifier() );
+    }
+
+    public String getExtension()
+    {
+        return expand( extension, mainArtifact.getExtension() );
+    }
+
+    public File getFile()
+    {
+        return file;
+    }
+
+    public Artifact setFile( File file )
+    {
+        if ( ( this.file == null ) ? file == null : this.file.equals( file ) )
+        {
+            return this;
+        }
+        return new SubArtifact( mainArtifact, classifier, extension, file, properties );
+    }
+
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+    public Artifact setProperties( Map<String, String> properties )
+    {
+        if ( this.properties.equals( properties ) || ( properties == null && this.properties.isEmpty() ) )
+        {
+            return this;
+        }
+        return new SubArtifact( mainArtifact, classifier, extension, properties, file );
+    }
+
+    private static String expand( String pattern, String replacement )
+    {
+        String result = "";
+        if ( pattern != null )
+        {
+            result = pattern.replace( "*", replacement );
+
+            if ( replacement.length() <= 0 )
+            {
+                if ( pattern.startsWith( "*" ) )
+                {
+                    int i = 0;
+                    for ( ; i < result.length(); i++ )
+                    {
+                        char c = result.charAt( i );
+                        if ( c != '-' && c != '.' )
+                        {
+                            break;
+                        }
+                    }
+                    result = result.substring( i );
+                }
+                if ( pattern.endsWith( "*" ) )
+                {
+                    int i = result.length() - 1;
+                    for ( ; i >= 0; i-- )
+                    {
+                        char c = result.charAt( i );
+                        if ( c != '-' && c != '.' )
+                        {
+                            break;
+                        }
+                    }
+                    result = result.substring( 0, i + 1 );
+                }
+            }
+        }
+        return result;
+    }
+
+}
\ No newline at end of file
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractForwardingRepositorySystemSession.java
new file mode 100644 (file)
index 0000000..590ad28
--- /dev/null
@@ -0,0 +1,180 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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.WorkspaceReader;
+import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
+import org.eclipse.aether.resolution.ResolutionErrorPolicy;
+import org.eclipse.aether.transfer.TransferListener;
+
+/**
+ * A special repository system session to enable decorating or proxying another session. To do so, clients have to
+ * create a subclass and implement {@link #getSession()}.
+ */
+public abstract class AbstractForwardingRepositorySystemSession
+    implements RepositorySystemSession
+{
+
+    /**
+     * Creates a new forwarding session.
+     */
+    protected AbstractForwardingRepositorySystemSession()
+    {
+    }
+
+    /**
+     * Gets the repository system session to which this instance forwards calls. It's worth noting that this class does
+     * not save/cache the returned reference but queries this method before each forwarding. Hence, the session
+     * forwarded to may change over time or depending on the context (e.g. calling thread).
+     * 
+     * @return The repository system session to forward calls to, never {@code null}.
+     */
+    protected abstract RepositorySystemSession getSession();
+
+    public boolean isOffline()
+    {
+        return getSession().isOffline();
+    }
+
+    public boolean isIgnoreArtifactDescriptorRepositories()
+    {
+        return getSession().isIgnoreArtifactDescriptorRepositories();
+    }
+
+    public ResolutionErrorPolicy getResolutionErrorPolicy()
+    {
+        return getSession().getResolutionErrorPolicy();
+    }
+
+    public ArtifactDescriptorPolicy getArtifactDescriptorPolicy()
+    {
+        return getSession().getArtifactDescriptorPolicy();
+    }
+
+    public String getChecksumPolicy()
+    {
+        return getSession().getChecksumPolicy();
+    }
+
+    public String getUpdatePolicy()
+    {
+        return getSession().getUpdatePolicy();
+    }
+
+    public LocalRepository getLocalRepository()
+    {
+        return getSession().getLocalRepository();
+    }
+
+    public LocalRepositoryManager getLocalRepositoryManager()
+    {
+        return getSession().getLocalRepositoryManager();
+    }
+
+    public WorkspaceReader getWorkspaceReader()
+    {
+        return getSession().getWorkspaceReader();
+    }
+
+    public RepositoryListener getRepositoryListener()
+    {
+        return getSession().getRepositoryListener();
+    }
+
+    public TransferListener getTransferListener()
+    {
+        return getSession().getTransferListener();
+    }
+
+    public Map<String, String> getSystemProperties()
+    {
+        return getSession().getSystemProperties();
+    }
+
+    public Map<String, String> getUserProperties()
+    {
+        return getSession().getUserProperties();
+    }
+
+    public Map<String, Object> getConfigProperties()
+    {
+        return getSession().getConfigProperties();
+    }
+
+    public MirrorSelector getMirrorSelector()
+    {
+        return getSession().getMirrorSelector();
+    }
+
+    public ProxySelector getProxySelector()
+    {
+        return getSession().getProxySelector();
+    }
+
+    public AuthenticationSelector getAuthenticationSelector()
+    {
+        return getSession().getAuthenticationSelector();
+    }
+
+    public ArtifactTypeRegistry getArtifactTypeRegistry()
+    {
+        return getSession().getArtifactTypeRegistry();
+    }
+
+    public DependencyTraverser getDependencyTraverser()
+    {
+        return getSession().getDependencyTraverser();
+    }
+
+    public DependencyManager getDependencyManager()
+    {
+        return getSession().getDependencyManager();
+    }
+
+    public DependencySelector getDependencySelector()
+    {
+        return getSession().getDependencySelector();
+    }
+
+    public VersionFilter getVersionFilter()
+    {
+        return getSession().getVersionFilter();
+    }
+
+    public DependencyGraphTransformer getDependencyGraphTransformer()
+    {
+        return getSession().getDependencyGraphTransformer();
+    }
+
+    public SessionData getData()
+    {
+        return getSession().getData();
+    }
+
+    public RepositoryCache getCache()
+    {
+        return getSession().getCache();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/AbstractRepositoryListener.java
new file mode 100644 (file)
index 0000000..eaaffc1
--- /dev/null
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * A skeleton implementation for custom repository listeners. The callback methods in this class do nothing.
+ */
+public abstract class AbstractRepositoryListener
+    implements RepositoryListener
+{
+
+    /**
+     * Enables subclassing.
+     */
+    protected AbstractRepositoryListener()
+    {
+    }
+
+    public void artifactDeployed( RepositoryEvent event )
+    {
+    }
+
+    public void artifactDeploying( RepositoryEvent event )
+    {
+    }
+
+    public void artifactDescriptorInvalid( RepositoryEvent event )
+    {
+    }
+
+    public void artifactDescriptorMissing( RepositoryEvent event )
+    {
+    }
+
+    public void artifactDownloaded( RepositoryEvent event )
+    {
+    }
+
+    public void artifactDownloading( RepositoryEvent event )
+    {
+    }
+
+    public void artifactInstalled( RepositoryEvent event )
+    {
+    }
+
+    public void artifactInstalling( RepositoryEvent event )
+    {
+    }
+
+    public void artifactResolved( RepositoryEvent event )
+    {
+    }
+
+    public void artifactResolving( RepositoryEvent event )
+    {
+    }
+
+    public void metadataDeployed( RepositoryEvent event )
+    {
+    }
+
+    public void metadataDeploying( RepositoryEvent event )
+    {
+    }
+
+    public void metadataDownloaded( RepositoryEvent event )
+    {
+    }
+
+    public void metadataDownloading( RepositoryEvent event )
+    {
+    }
+
+    public void metadataInstalled( RepositoryEvent event )
+    {
+    }
+
+    public void metadataInstalling( RepositoryEvent event )
+    {
+    }
+
+    public void metadataInvalid( RepositoryEvent event )
+    {
+    }
+
+    public void metadataResolved( RepositoryEvent event )
+    {
+    }
+
+    public void metadataResolving( RepositoryEvent event )
+    {
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java b/org.argeo.slc.repo/src/org/eclipse/aether/ConfigurationProperties.java
new file mode 100644 (file)
index 0000000..3cbd59c
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * The keys and defaults for common configuration properties.
+ * 
+ * @see RepositorySystemSession#getConfigProperties()
+ */
+public final class ConfigurationProperties
+{
+
+    private static final String PREFIX_AETHER = "aether.";
+
+    private static final String PREFIX_CONNECTOR = PREFIX_AETHER + "connector.";
+
+    /**
+     * The prefix for properties that control the priority of pluggable extensions like transporters. For example, for
+     * an extension with the fully qualified class name "org.eclipse.MyExtensionFactory", the configuration properties
+     * "aether.priority.org.eclipse.MyExtensionFactory", "aether.priority.MyExtensionFactory" and
+     * "aether.priority.MyExtension" will be consulted for the priority, in that order (obviously, the last key is only
+     * tried if the class name ends with "Factory"). The corresponding value is a float and the special value
+     * {@link Float#NaN} or "NaN" (case-sensitive) can be used to disable the extension.
+     */
+    public static final String PREFIX_PRIORITY = PREFIX_AETHER + "priority.";
+
+    /**
+     * A flag indicating whether the priorities of pluggable extensions are implicitly given by their iteration order
+     * such that the first extension has the highest priority. If set, an extension's built-in priority as well as any
+     * corresponding {@code aether.priority.*} configuration properties are ignored when searching for a suitable
+     * implementation among the available extensions. This priority mode is meant for cases where the application will
+     * present/inject extensions in the desired search order.
+     * 
+     * @see #DEFAULT_IMPLICIT_PRIORITIES
+     */
+    public static final String IMPLICIT_PRIORITIES = PREFIX_PRIORITY + "implicit";
+
+    /**
+     * The default extension priority mode if {@link #IMPLICIT_PRIORITIES} isn't set.
+     */
+    public static final boolean DEFAULT_IMPLICIT_PRIORITIES = false;
+
+    /**
+     * A flag indicating whether interaction with the user is allowed.
+     * 
+     * @see #DEFAULT_INTERACTIVE
+     */
+    public static final String INTERACTIVE = PREFIX_AETHER + "interactive";
+
+    /**
+     * The default interactive mode if {@link #INTERACTIVE} isn't set.
+     */
+    public static final boolean DEFAULT_INTERACTIVE = false;
+
+    /**
+     * The user agent that repository connectors should report to servers.
+     * 
+     * @see #DEFAULT_USER_AGENT
+     */
+    public static final String USER_AGENT = PREFIX_CONNECTOR + "userAgent";
+
+    /**
+     * The default user agent to use if {@link #USER_AGENT} isn't set.
+     */
+    public static final String DEFAULT_USER_AGENT = "Aether";
+
+    /**
+     * The maximum amount of time (in milliseconds) to wait for a successful connection to a remote server. Non-positive
+     * values indicate no timeout.
+     * 
+     * @see #DEFAULT_CONNECT_TIMEOUT
+     */
+    public static final String CONNECT_TIMEOUT = PREFIX_CONNECTOR + "connectTimeout";
+
+    /**
+     * The default connect timeout to use if {@link #CONNECT_TIMEOUT} isn't set.
+     */
+    public static final int DEFAULT_CONNECT_TIMEOUT = 10 * 1000;
+
+    /**
+     * The maximum amount of time (in milliseconds) to wait for remaining data to arrive from a remote server. Note that
+     * this timeout does not restrict the overall duration of a request, it only restricts the duration of inactivity
+     * between consecutive data packets. Non-positive values indicate no timeout.
+     * 
+     * @see #DEFAULT_REQUEST_TIMEOUT
+     */
+    public static final String REQUEST_TIMEOUT = PREFIX_CONNECTOR + "requestTimeout";
+
+    /**
+     * The default request timeout to use if {@link #REQUEST_TIMEOUT} isn't set.
+     */
+    public static final int DEFAULT_REQUEST_TIMEOUT = 1800 * 1000;
+
+    /**
+     * The request headers to use for HTTP-based repository connectors. The headers are specified using a
+     * {@code Map<String, String>}, mapping a header name to its value. Besides this general key, clients may also
+     * specify headers for a specific remote repository by appending the suffix {@code .<repoId>} to this key when
+     * storing the headers map. The repository-specific headers map is supposed to be complete, i.e. is not merged with
+     * the general headers map.
+     */
+    public static final String HTTP_HEADERS = PREFIX_CONNECTOR + "http.headers";
+
+    /**
+     * The encoding/charset to use when exchanging credentials with HTTP servers. Besides this general key, clients may
+     * also specify the encoding for a specific remote repository by appending the suffix {@code .<repoId>} to this key
+     * when storing the charset name.
+     * 
+     * @see #DEFAULT_HTTP_CREDENTIAL_ENCODING
+     */
+    public static final String HTTP_CREDENTIAL_ENCODING = PREFIX_CONNECTOR + "http.credentialEncoding";
+
+    /**
+     * The default encoding/charset to use if {@link #HTTP_CREDENTIAL_ENCODING} isn't set.
+     */
+    public static final String DEFAULT_HTTP_CREDENTIAL_ENCODING = "ISO-8859-1";
+
+    /**
+     * An option indicating whether authentication configured for a HTTP repository should also be used with any host
+     * that the original server might redirect requests to. Unless enabled, credentials are only exchanged with the
+     * original host from the repository URL and not supplied to different hosts encountered during redirects. The
+     * option value can either be a boolean flag or a comma-separated list of host names denoting the whitelist of
+     * original hosts whose redirects can be trusted and should use the configured authentication no matter the
+     * destination host(s). Alternatively, the suffix {@code .<repoId>} can be appended to this configuration key to
+     * control the behavior for a specific repository id.
+     * 
+     * @see #DEFAULT_HTTP_REDIRECTED_AUTHENTICATION
+     * @since 1.1.0
+     */
+    public static final String HTTP_REDIRECTED_AUTHENTICATION = PREFIX_CONNECTOR + "http.redirectedAuthentication";
+
+    /**
+     * The default handling of authentication during HTTP redirects if {@link #HTTP_REDIRECTED_AUTHENTICATION} isn't
+     * set.
+     * 
+     * @since 1.1.0
+     */
+    public static final String DEFAULT_HTTP_REDIRECTED_AUTHENTICATION = "false";
+
+    /**
+     * A flag indicating whether checksums which are retrieved during checksum validation should be persisted in the
+     * local filesystem next to the file they provide the checksum for.
+     * 
+     * @see #DEFAULT_PERSISTED_CHECKSUMS
+     */
+    public static final String PERSISTED_CHECKSUMS = PREFIX_CONNECTOR + "persistedChecksums";
+
+    /**
+     * The default checksum persistence mode if {@link #PERSISTED_CHECKSUMS} isn't set.
+     */
+    public static final boolean DEFAULT_PERSISTED_CHECKSUMS = true;
+
+    private ConfigurationProperties()
+    {
+        // hide constructor
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositoryCache.java
new file mode 100644 (file)
index 0000000..12d2789
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A simplistic repository cache backed by a thread-safe map. The simplistic nature of this cache makes it only suitable
+ * for use with short-lived repository system sessions where pruning of cache data is not required.
+ */
+public final class DefaultRepositoryCache
+    implements RepositoryCache
+{
+
+    private final Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>( 256 );
+
+    public Object get( RepositorySystemSession session, Object key )
+    {
+        return cache.get( key );
+    }
+
+    public void put( RepositorySystemSession session, Object key, Object data )
+    {
+        if ( data != null )
+        {
+            cache.put( key, data );
+        }
+        else
+        {
+            cache.remove( key );
+        }
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultRepositorySystemSession.java
new file mode 100644 (file)
index 0000000..363ede6
--- /dev/null
@@ -0,0 +1,825 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.collection.DependencyGraphTransformer;
+import org.eclipse.aether.collection.DependencyManager;
+import org.eclipse.aether.collection.DependencySelector;
+import org.eclipse.aether.collection.DependencyTraverser;
+import org.eclipse.aether.collection.VersionFilter;
+import org.eclipse.aether.repository.Authentication;
+import org.eclipse.aether.repository.AuthenticationSelector;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.MirrorSelector;
+import org.eclipse.aether.repository.Proxy;
+import org.eclipse.aether.repository.ProxySelector;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.repository.WorkspaceReader;
+import org.eclipse.aether.resolution.ArtifactDescriptorPolicy;
+import org.eclipse.aether.resolution.ResolutionErrorPolicy;
+import org.eclipse.aether.transfer.TransferListener;
+
+/**
+ * A simple repository system session.
+ * <p>
+ * <strong>Note:</strong> This class is not thread-safe. It is assumed that the mutators get only called during an
+ * initialization phase and that the session itself is not changed once initialized and being used by the repository
+ * system. It is recommended to call {@link #setReadOnly()} once the session has been fully initialized to prevent
+ * accidental manipulation of it afterwards.
+ */
+public final class DefaultRepositorySystemSession
+    implements RepositorySystemSession
+{
+
+    private boolean readOnly;
+
+    private boolean offline;
+
+    private boolean ignoreArtifactDescriptorRepositories;
+
+    private ResolutionErrorPolicy resolutionErrorPolicy;
+
+    private ArtifactDescriptorPolicy artifactDescriptorPolicy;
+
+    private String checksumPolicy;
+
+    private String updatePolicy;
+
+    private LocalRepositoryManager localRepositoryManager;
+
+    private WorkspaceReader workspaceReader;
+
+    private RepositoryListener repositoryListener;
+
+    private TransferListener transferListener;
+
+    private Map<String, String> systemProperties;
+
+    private Map<String, String> systemPropertiesView;
+
+    private Map<String, String> userProperties;
+
+    private Map<String, String> userPropertiesView;
+
+    private Map<String, Object> configProperties;
+
+    private Map<String, Object> configPropertiesView;
+
+    private MirrorSelector mirrorSelector;
+
+    private ProxySelector proxySelector;
+
+    private AuthenticationSelector authenticationSelector;
+
+    private ArtifactTypeRegistry artifactTypeRegistry;
+
+    private DependencyTraverser dependencyTraverser;
+
+    private DependencyManager dependencyManager;
+
+    private DependencySelector dependencySelector;
+
+    private VersionFilter versionFilter;
+
+    private DependencyGraphTransformer dependencyGraphTransformer;
+
+    private SessionData data;
+
+    private RepositoryCache cache;
+
+    /**
+     * Creates an uninitialized session. <em>Note:</em> The new session is not ready to use, as a bare minimum,
+     * {@link #setLocalRepositoryManager(LocalRepositoryManager)} needs to be called but usually other settings also
+     * need to be customized to achieve meaningful behavior.
+     */
+    public DefaultRepositorySystemSession()
+    {
+        systemProperties = new HashMap<String, String>();
+        systemPropertiesView = Collections.unmodifiableMap( systemProperties );
+        userProperties = new HashMap<String, String>();
+        userPropertiesView = Collections.unmodifiableMap( userProperties );
+        configProperties = new HashMap<String, Object>();
+        configPropertiesView = Collections.unmodifiableMap( configProperties );
+        mirrorSelector = NullMirrorSelector.INSTANCE;
+        proxySelector = NullProxySelector.INSTANCE;
+        authenticationSelector = NullAuthenticationSelector.INSTANCE;
+        artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
+        data = new DefaultSessionData();
+    }
+
+    /**
+     * Creates a shallow copy of the specified session. Actually, the copy is not completely shallow, all maps holding
+     * system/user/config properties are copied as well. In other words, invoking any mutator on the new session itself
+     * has no effect on the original session. Other mutable objects like the session data and cache (if any) are not
+     * copied and will be shared with the original session unless reconfigured.
+     * 
+     * @param session The session to copy, must not be {@code null}.
+     */
+    public DefaultRepositorySystemSession( RepositorySystemSession session )
+    {
+        if ( session == null )
+        {
+            throw new IllegalArgumentException( "repository system session not specified" );
+        }
+
+        setOffline( session.isOffline() );
+        setIgnoreArtifactDescriptorRepositories( session.isIgnoreArtifactDescriptorRepositories() );
+        setResolutionErrorPolicy( session.getResolutionErrorPolicy() );
+        setArtifactDescriptorPolicy( session.getArtifactDescriptorPolicy() );
+        setChecksumPolicy( session.getChecksumPolicy() );
+        setUpdatePolicy( session.getUpdatePolicy() );
+        setLocalRepositoryManager( session.getLocalRepositoryManager() );
+        setWorkspaceReader( session.getWorkspaceReader() );
+        setRepositoryListener( session.getRepositoryListener() );
+        setTransferListener( session.getTransferListener() );
+        setSystemProperties( session.getSystemProperties() );
+        setUserProperties( session.getUserProperties() );
+        setConfigProperties( session.getConfigProperties() );
+        setMirrorSelector( session.getMirrorSelector() );
+        setProxySelector( session.getProxySelector() );
+        setAuthenticationSelector( session.getAuthenticationSelector() );
+        setArtifactTypeRegistry( session.getArtifactTypeRegistry() );
+        setDependencyTraverser( session.getDependencyTraverser() );
+        setDependencyManager( session.getDependencyManager() );
+        setDependencySelector( session.getDependencySelector() );
+        setVersionFilter( session.getVersionFilter() );
+        setDependencyGraphTransformer( session.getDependencyGraphTransformer() );
+        setData( session.getData() );
+        setCache( session.getCache() );
+    }
+
+    public boolean isOffline()
+    {
+        return offline;
+    }
+
+    /**
+     * Controls whether the repository system operates in offline mode and avoids/refuses any access to remote
+     * repositories.
+     * 
+     * @param offline {@code true} if the repository system is in offline mode, {@code false} otherwise.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setOffline( boolean offline )
+    {
+        failIfReadOnly();
+        this.offline = offline;
+        return this;
+    }
+
+    public boolean isIgnoreArtifactDescriptorRepositories()
+    {
+        return ignoreArtifactDescriptorRepositories;
+    }
+
+    /**
+     * Controls whether repositories declared in artifact descriptors should be ignored during transitive dependency
+     * collection. If enabled, only the repositories originally provided with the collect request will be considered.
+     * 
+     * @param ignoreArtifactDescriptorRepositories {@code true} to ignore additional repositories from artifact
+     *            descriptors, {@code false} to merge those with the originally specified repositories.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setIgnoreArtifactDescriptorRepositories( boolean ignoreArtifactDescriptorRepositories )
+    {
+        failIfReadOnly();
+        this.ignoreArtifactDescriptorRepositories = ignoreArtifactDescriptorRepositories;
+        return this;
+    }
+
+    public ResolutionErrorPolicy getResolutionErrorPolicy()
+    {
+        return resolutionErrorPolicy;
+    }
+
+    /**
+     * Sets the policy which controls whether resolutions errors from remote repositories should be cached.
+     * 
+     * @param resolutionErrorPolicy The resolution error policy for this session, may be {@code null} if resolution
+     *            errors should generally not be cached.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setResolutionErrorPolicy( ResolutionErrorPolicy resolutionErrorPolicy )
+    {
+        failIfReadOnly();
+        this.resolutionErrorPolicy = resolutionErrorPolicy;
+        return this;
+    }
+
+    public ArtifactDescriptorPolicy getArtifactDescriptorPolicy()
+    {
+        return artifactDescriptorPolicy;
+    }
+
+    /**
+     * Sets the policy which controls how errors related to reading artifact descriptors should be handled.
+     * 
+     * @param artifactDescriptorPolicy The descriptor error policy for this session, may be {@code null} if descriptor
+     *            errors should generally not be tolerated.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setArtifactDescriptorPolicy( ArtifactDescriptorPolicy artifactDescriptorPolicy )
+    {
+        failIfReadOnly();
+        this.artifactDescriptorPolicy = artifactDescriptorPolicy;
+        return this;
+    }
+
+    public String getChecksumPolicy()
+    {
+        return checksumPolicy;
+    }
+
+    /**
+     * Sets the global checksum policy. If set, the global checksum policy overrides the checksum policies of the remote
+     * repositories being used for resolution.
+     * 
+     * @param checksumPolicy The global checksum policy, may be {@code null}/empty to apply the per-repository policies.
+     * @return This session for chaining, never {@code null}.
+     * @see RepositoryPolicy#CHECKSUM_POLICY_FAIL
+     * @see RepositoryPolicy#CHECKSUM_POLICY_IGNORE
+     * @see RepositoryPolicy#CHECKSUM_POLICY_WARN
+     */
+    public DefaultRepositorySystemSession setChecksumPolicy( String checksumPolicy )
+    {
+        failIfReadOnly();
+        this.checksumPolicy = checksumPolicy;
+        return this;
+    }
+
+    public String getUpdatePolicy()
+    {
+        return updatePolicy;
+    }
+
+    /**
+     * Sets the global update policy. If set, the global update policy overrides the update policies of the remote
+     * repositories being used for resolution.
+     * 
+     * @param updatePolicy The global update policy, may be {@code null}/empty to apply the per-repository policies.
+     * @return This session for chaining, never {@code null}.
+     * @see RepositoryPolicy#UPDATE_POLICY_ALWAYS
+     * @see RepositoryPolicy#UPDATE_POLICY_DAILY
+     * @see RepositoryPolicy#UPDATE_POLICY_NEVER
+     */
+    public DefaultRepositorySystemSession setUpdatePolicy( String updatePolicy )
+    {
+        failIfReadOnly();
+        this.updatePolicy = updatePolicy;
+        return this;
+    }
+
+    public LocalRepository getLocalRepository()
+    {
+        LocalRepositoryManager lrm = getLocalRepositoryManager();
+        return ( lrm != null ) ? lrm.getRepository() : null;
+    }
+
+    public LocalRepositoryManager getLocalRepositoryManager()
+    {
+        return localRepositoryManager;
+    }
+
+    /**
+     * Sets the local repository manager used during this session. <em>Note:</em> Eventually, a valid session must have
+     * a local repository manager set.
+     * 
+     * @param localRepositoryManager The local repository manager used during this session, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setLocalRepositoryManager( LocalRepositoryManager localRepositoryManager )
+    {
+        failIfReadOnly();
+        this.localRepositoryManager = localRepositoryManager;
+        return this;
+    }
+
+    public WorkspaceReader getWorkspaceReader()
+    {
+        return workspaceReader;
+    }
+
+    /**
+     * Sets the workspace reader used during this session. If set, the workspace reader will usually be consulted first
+     * to resolve artifacts.
+     * 
+     * @param workspaceReader The workspace reader for this session, may be {@code null} if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setWorkspaceReader( WorkspaceReader workspaceReader )
+    {
+        failIfReadOnly();
+        this.workspaceReader = workspaceReader;
+        return this;
+    }
+
+    public RepositoryListener getRepositoryListener()
+    {
+        return repositoryListener;
+    }
+
+    /**
+     * Sets the listener being notified of actions in the repository system.
+     * 
+     * @param repositoryListener The repository listener, may be {@code null} if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setRepositoryListener( RepositoryListener repositoryListener )
+    {
+        failIfReadOnly();
+        this.repositoryListener = repositoryListener;
+        return this;
+    }
+
+    public TransferListener getTransferListener()
+    {
+        return transferListener;
+    }
+
+    /**
+     * Sets the listener being notified of uploads/downloads by the repository system.
+     * 
+     * @param transferListener The transfer listener, may be {@code null} if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setTransferListener( TransferListener transferListener )
+    {
+        failIfReadOnly();
+        this.transferListener = transferListener;
+        return this;
+    }
+
+    private <T> Map<String, T> copySafe( Map<?, ?> table, Class<T> valueType )
+    {
+        Map<String, T> map;
+        if ( table == null || table.isEmpty() )
+        {
+            map = new HashMap<String, T>();
+        }
+        else
+        {
+            map = new HashMap<String, T>( (int) ( table.size() / 0.75f ) + 1 );
+            for ( Map.Entry<?, ?> entry : table.entrySet() )
+            {
+                Object key = entry.getKey();
+                if ( key instanceof String )
+                {
+                    Object value = entry.getValue();
+                    if ( valueType.isInstance( value ) )
+                    {
+                        map.put( key.toString(), valueType.cast( value ) );
+                    }
+                }
+            }
+        }
+        return map;
+    }
+
+    public Map<String, String> getSystemProperties()
+    {
+        return systemPropertiesView;
+    }
+
+    /**
+     * Sets the system properties to use, e.g. for processing of artifact descriptors. System properties are usually
+     * collected from the runtime environment like {@link System#getProperties()} and environment variables.
+     * <p>
+     * <em>Note:</em> System properties are of type {@code Map<String, String>} and any key-value pair in the input map
+     * that doesn't match this type will be silently ignored.
+     * 
+     * @param systemProperties The system properties, may be {@code null} or empty if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setSystemProperties( Map<?, ?> systemProperties )
+    {
+        failIfReadOnly();
+        this.systemProperties = copySafe( systemProperties, String.class );
+        systemPropertiesView = Collections.unmodifiableMap( this.systemProperties );
+        return this;
+    }
+
+    /**
+     * Sets the specified system property.
+     * 
+     * @param key The property key, must not be {@code null}.
+     * @param value The property value, may be {@code null} to remove/unset the property.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setSystemProperty( String key, String value )
+    {
+        failIfReadOnly();
+        if ( value != null )
+        {
+            systemProperties.put( key, value );
+        }
+        else
+        {
+            systemProperties.remove( key );
+        }
+        return this;
+    }
+
+    public Map<String, String> getUserProperties()
+    {
+        return userPropertiesView;
+    }
+
+    /**
+     * Sets the user properties to use, e.g. for processing of artifact descriptors. User properties are similar to
+     * system properties but are set on the discretion of the user and hence are considered of higher priority than
+     * system properties in case of conflicts.
+     * <p>
+     * <em>Note:</em> User properties are of type {@code Map<String, String>} and any key-value pair in the input map
+     * that doesn't match this type will be silently ignored.
+     * 
+     * @param userProperties The user properties, may be {@code null} or empty if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setUserProperties( Map<?, ?> userProperties )
+    {
+        failIfReadOnly();
+        this.userProperties = copySafe( userProperties, String.class );
+        userPropertiesView = Collections.unmodifiableMap( this.userProperties );
+        return this;
+    }
+
+    /**
+     * Sets the specified user property.
+     * 
+     * @param key The property key, must not be {@code null}.
+     * @param value The property value, may be {@code null} to remove/unset the property.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setUserProperty( String key, String value )
+    {
+        failIfReadOnly();
+        if ( value != null )
+        {
+            userProperties.put( key, value );
+        }
+        else
+        {
+            userProperties.remove( key );
+        }
+        return this;
+    }
+
+    public Map<String, Object> getConfigProperties()
+    {
+        return configPropertiesView;
+    }
+
+    /**
+     * Sets the configuration properties used to tweak internal aspects of the repository system (e.g. thread pooling,
+     * connector-specific behavior, etc.).
+     * <p>
+     * <em>Note:</em> Configuration properties are of type {@code Map<String, Object>} and any key-value pair in the
+     * input map that doesn't match this type will be silently ignored.
+     * 
+     * @param configProperties The configuration properties, may be {@code null} or empty if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setConfigProperties( Map<?, ?> configProperties )
+    {
+        failIfReadOnly();
+        this.configProperties = copySafe( configProperties, Object.class );
+        configPropertiesView = Collections.unmodifiableMap( this.configProperties );
+        return this;
+    }
+
+    /**
+     * Sets the specified configuration property.
+     * 
+     * @param key The property key, must not be {@code null}.
+     * @param value The property value, may be {@code null} to remove/unset the property.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setConfigProperty( String key, Object value )
+    {
+        failIfReadOnly();
+        if ( value != null )
+        {
+            configProperties.put( key, value );
+        }
+        else
+        {
+            configProperties.remove( key );
+        }
+        return this;
+    }
+
+    public MirrorSelector getMirrorSelector()
+    {
+        return mirrorSelector;
+    }
+
+    /**
+     * Sets the mirror selector to use for repositories discovered in artifact descriptors. Note that this selector is
+     * not used for remote repositories which are passed as request parameters to the repository system, those
+     * repositories are supposed to denote the effective repositories.
+     * 
+     * @param mirrorSelector The mirror selector to use, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setMirrorSelector( MirrorSelector mirrorSelector )
+    {
+        failIfReadOnly();
+        this.mirrorSelector = mirrorSelector;
+        if ( this.mirrorSelector == null )
+        {
+            this.mirrorSelector = NullMirrorSelector.INSTANCE;
+        }
+        return this;
+    }
+
+    public ProxySelector getProxySelector()
+    {
+        return proxySelector;
+    }
+
+    /**
+     * Sets the proxy selector to use for repositories discovered in artifact descriptors. Note that this selector is
+     * not used for remote repositories which are passed as request parameters to the repository system, those
+     * repositories are supposed to have their proxy (if any) already set.
+     * 
+     * @param proxySelector The proxy selector to use, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     * @see org.eclipse.aether.repository.RemoteRepository#getProxy()
+     */
+    public DefaultRepositorySystemSession setProxySelector( ProxySelector proxySelector )
+    {
+        failIfReadOnly();
+        this.proxySelector = proxySelector;
+        if ( this.proxySelector == null )
+        {
+            this.proxySelector = NullProxySelector.INSTANCE;
+        }
+        return this;
+    }
+
+    public AuthenticationSelector getAuthenticationSelector()
+    {
+        return authenticationSelector;
+    }
+
+    /**
+     * Sets the authentication selector to use for repositories discovered in artifact descriptors. Note that this
+     * selector is not used for remote repositories which are passed as request parameters to the repository system,
+     * those repositories are supposed to have their authentication (if any) already set.
+     * 
+     * @param authenticationSelector The authentication selector to use, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     * @see org.eclipse.aether.repository.RemoteRepository#getAuthentication()
+     */
+    public DefaultRepositorySystemSession setAuthenticationSelector( AuthenticationSelector authenticationSelector )
+    {
+        failIfReadOnly();
+        this.authenticationSelector = authenticationSelector;
+        if ( this.authenticationSelector == null )
+        {
+            this.authenticationSelector = NullAuthenticationSelector.INSTANCE;
+        }
+        return this;
+    }
+
+    public ArtifactTypeRegistry getArtifactTypeRegistry()
+    {
+        return artifactTypeRegistry;
+    }
+
+    /**
+     * Sets the registry of artifact types recognized by this session.
+     * 
+     * @param artifactTypeRegistry The artifact type registry, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setArtifactTypeRegistry( ArtifactTypeRegistry artifactTypeRegistry )
+    {
+        failIfReadOnly();
+        this.artifactTypeRegistry = artifactTypeRegistry;
+        if ( this.artifactTypeRegistry == null )
+        {
+            this.artifactTypeRegistry = NullArtifactTypeRegistry.INSTANCE;
+        }
+        return this;
+    }
+
+    public DependencyTraverser getDependencyTraverser()
+    {
+        return dependencyTraverser;
+    }
+
+    /**
+     * Sets the dependency traverser to use for building dependency graphs.
+     * 
+     * @param dependencyTraverser The dependency traverser to use for building dependency graphs, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setDependencyTraverser( DependencyTraverser dependencyTraverser )
+    {
+        failIfReadOnly();
+        this.dependencyTraverser = dependencyTraverser;
+        return this;
+    }
+
+    public DependencyManager getDependencyManager()
+    {
+        return dependencyManager;
+    }
+
+    /**
+     * Sets the dependency manager to use for building dependency graphs.
+     * 
+     * @param dependencyManager The dependency manager to use for building dependency graphs, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setDependencyManager( DependencyManager dependencyManager )
+    {
+        failIfReadOnly();
+        this.dependencyManager = dependencyManager;
+        return this;
+    }
+
+    public DependencySelector getDependencySelector()
+    {
+        return dependencySelector;
+    }
+
+    /**
+     * Sets the dependency selector to use for building dependency graphs.
+     * 
+     * @param dependencySelector The dependency selector to use for building dependency graphs, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setDependencySelector( DependencySelector dependencySelector )
+    {
+        failIfReadOnly();
+        this.dependencySelector = dependencySelector;
+        return this;
+    }
+
+    public VersionFilter getVersionFilter()
+    {
+        return versionFilter;
+    }
+
+    /**
+     * Sets the version filter to use for building dependency graphs.
+     * 
+     * @param versionFilter The version filter to use for building dependency graphs, may be {@code null} to not filter
+     *            versions.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setVersionFilter( VersionFilter versionFilter )
+    {
+        failIfReadOnly();
+        this.versionFilter = versionFilter;
+        return this;
+    }
+
+    public DependencyGraphTransformer getDependencyGraphTransformer()
+    {
+        return dependencyGraphTransformer;
+    }
+
+    /**
+     * Sets the dependency graph transformer to use for building dependency graphs.
+     * 
+     * @param dependencyGraphTransformer The dependency graph transformer to use for building dependency graphs, may be
+     *            {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setDependencyGraphTransformer( DependencyGraphTransformer dependencyGraphTransformer )
+    {
+        failIfReadOnly();
+        this.dependencyGraphTransformer = dependencyGraphTransformer;
+        return this;
+    }
+
+    public SessionData getData()
+    {
+        return data;
+    }
+
+    /**
+     * Sets the custom data associated with this session.
+     * 
+     * @param data The session data, may be {@code null}.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setData( SessionData data )
+    {
+        failIfReadOnly();
+        this.data = data;
+        if ( this.data == null )
+        {
+            this.data = new DefaultSessionData();
+        }
+        return this;
+    }
+
+    public RepositoryCache getCache()
+    {
+        return cache;
+    }
+
+    /**
+     * Sets the cache the repository system may use to save data for future reuse during the session.
+     * 
+     * @param cache The repository cache, may be {@code null} if none.
+     * @return This session for chaining, never {@code null}.
+     */
+    public DefaultRepositorySystemSession setCache( RepositoryCache cache )
+    {
+        failIfReadOnly();
+        this.cache = cache;
+        return this;
+    }
+
+    /**
+     * Marks this session as read-only such that any future attempts to call its mutators will fail with an exception.
+     * Marking an already read-only session as read-only has no effect. The session's data and cache remain writable
+     * though.
+     */
+    public void setReadOnly()
+    {
+        readOnly = true;
+    }
+
+    private void failIfReadOnly()
+    {
+        if ( readOnly )
+        {
+            throw new IllegalStateException( "repository system session is read-only" );
+        }
+    }
+
+    static class NullProxySelector
+        implements ProxySelector
+    {
+
+        public static final ProxySelector INSTANCE = new NullProxySelector();
+
+        public Proxy getProxy( RemoteRepository repository )
+        {
+            return repository.getProxy();
+        }
+
+    }
+
+    static class NullMirrorSelector
+        implements MirrorSelector
+    {
+
+        public static final MirrorSelector INSTANCE = new NullMirrorSelector();
+
+        public RemoteRepository getMirror( RemoteRepository repository )
+        {
+            return null;
+        }
+
+    }
+
+    static class NullAuthenticationSelector
+        implements AuthenticationSelector
+    {
+
+        public static final AuthenticationSelector INSTANCE = new NullAuthenticationSelector();
+
+        public Authentication getAuthentication( RemoteRepository repository )
+        {
+            return repository.getAuthentication();
+        }
+
+    }
+
+    static final class NullArtifactTypeRegistry
+        implements ArtifactTypeRegistry
+    {
+
+        public static final ArtifactTypeRegistry INSTANCE = new NullArtifactTypeRegistry();
+
+        public ArtifactType get( String typeId )
+        {
+            return null;
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java b/org.argeo.slc.repo/src/org/eclipse/aether/DefaultSessionData.java
new file mode 100644 (file)
index 0000000..738cebc
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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 );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryCache.java
new file mode 100644 (file)
index 0000000..7363844
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * 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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryEvent.java
new file mode 100644 (file)
index 0000000..2abd800
--- /dev/null
@@ -0,0 +1,433 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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 );
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryException.java
new file mode 100644 (file)
index 0000000..35f0cfd
--- /dev/null
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * The base class for exceptions thrown by the repository system. <em>Note:</em> Unless otherwise noted, instances of
+ * this class and its subclasses will not persist fields carrying extended error information during serialization.
+ */
+public class RepositoryException
+    extends Exception
+{
+
+    /**
+     * Creates a new exception with the specified detail message.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public RepositoryException( String message )
+    {
+        super( message );
+    }
+
+    /**
+     * Creates a new exception with the specified detail message and cause.
+     * 
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public RepositoryException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+    /**
+     * @noreference This method is not intended to be used by clients.
+     * @param prefix A message prefix for the cause.
+     * @param cause The error cause.
+     * @return The error message for the cause.
+     */
+    protected static String getMessage( String prefix, Throwable cause )
+    {
+        String msg = "";
+        if ( cause != null )
+        {
+            msg = cause.getMessage();
+            if ( msg == null || msg.length() <= 0 )
+            {
+                msg = cause.getClass().getSimpleName();
+            }
+            msg = prefix + msg;
+        }
+        return msg;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositoryListener.java
new file mode 100644 (file)
index 0000000..5f83923
--- /dev/null
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * 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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystem.java
new file mode 100644 (file)
index 0000000..debdb7d
--- /dev/null
@@ -0,0 +1,268 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java b/org.argeo.slc.repo/src/org/eclipse/aether/RepositorySystemSession.java
new file mode 100644 (file)
index 0000000..96f51c1
--- /dev/null
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java b/org.argeo.slc.repo/src/org/eclipse/aether/RequestTrace.java
new file mode 100644 (file)
index 0000000..c6afa8e
--- /dev/null
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * 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() );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java b/org.argeo.slc.repo/src/org/eclipse/aether/SessionData.java
new file mode 100644 (file)
index 0000000..92930e7
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+/**
+ * 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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/SyncContext.java
new file mode 100644 (file)
index 0000000..a05d512
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether;
+
+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();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/AbstractArtifact.java
new file mode 100644 (file)
index 0000000..2944ff8
--- /dev/null
@@ -0,0 +1,221 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/Artifact.java
new file mode 100644 (file)
index 0000000..5eef695
--- /dev/null
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactProperties.java
new file mode 100644 (file)
index 0000000..7fbea04
--- /dev/null
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+/**
+ * The keys for common properties of artifacts.
+ * 
+ * @see Artifact#getProperties()
+ */
+public final class ArtifactProperties
+{
+
+    /**
+     * A high-level characterization of the artifact, e.g. "maven-plugin" or "test-jar".
+     * 
+     * @see ArtifactType#getId()
+     */
+    public static final String TYPE = "type";
+
+    /**
+     * The programming language this artifact is relevant for, e.g. "java" or "none".
+     */
+    public static final String LANGUAGE = "language";
+
+    /**
+     * The (expected) path to the artifact on the local filesystem. An artifact which has this property set is assumed
+     * to be not present in any regular repository and likewise has no artifact descriptor. Artifact resolution will
+     * verify the path and resolve the artifact if the path actually denotes an existing file. If the path isn't valid,
+     * resolution will fail and no attempts to search local/remote repositories are made.
+     */
+    public static final String LOCAL_PATH = "localPath";
+
+    /**
+     * A boolean flag indicating whether the artifact presents some kind of bundle that physically includes its
+     * dependencies, e.g. a fat WAR.
+     */
+    public static final String INCLUDES_DEPENDENCIES = "includesDependencies";
+
+    /**
+     * A boolean flag indicating whether the artifact is meant to be used for the compile/runtime/test build path of a
+     * consumer project.
+     */
+    public static final String CONSTITUTES_BUILD_PATH = "constitutesBuildPath";
+
+    /**
+     * The URL to a web page from which the artifact can be manually downloaded. This URL is not contacted by the
+     * repository system but serves as a pointer for the end user to assist in getting artifacts that are not published
+     * in a proper repository.
+     */
+    public static final String DOWNLOAD_URL = "downloadUrl";
+
+    private ArtifactProperties()
+    {
+        // hide constructor
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactType.java
new file mode 100644 (file)
index 0000000..174c3c5
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+import java.util.Map;
+
+/**
+ * An artifact type describing artifact characteristics/properties that are common for certain artifacts. Artifact types
+ * are a means to simplify the description of an artifact by referring to an artifact type instead of specifying the
+ * various properties individually.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ * @see ArtifactTypeRegistry
+ * @see DefaultArtifact#DefaultArtifact(String, String, String, String, String, ArtifactType)
+ */
+public interface ArtifactType
+{
+
+    /**
+     * Gets the identifier of this type, e.g. "maven-plugin" or "test-jar".
+     * 
+     * @return The identifier of this type, never {@code null}.
+     * @see ArtifactProperties#TYPE
+     */
+    String getId();
+
+    /**
+     * Gets the file extension to use for artifacts of this type (unless explicitly overridden by the artifact).
+     * 
+     * @return The usual file extension, never {@code null}.
+     */
+    String getExtension();
+
+    /**
+     * Gets the classifier to use for artifacts of this type (unless explicitly overridden by the artifact).
+     * 
+     * @return The usual classifier or an empty string if none, never {@code null}.
+     */
+    String getClassifier();
+
+    /**
+     * Gets the properties to use for artifacts of this type (unless explicitly overridden by the artifact).
+     * 
+     * @return The (read-only) properties, never {@code null}.
+     * @see ArtifactProperties
+     */
+    Map<String, String> getProperties();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/ArtifactTypeRegistry.java
new file mode 100644 (file)
index 0000000..2addff1
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+/**
+ * A registry of known artifact types.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getArtifactTypeRegistry()
+ */
+public interface ArtifactTypeRegistry
+{
+
+    /**
+     * Gets the artifact type with the specified identifier.
+     * 
+     * @param typeId The identifier of the type, must not be {@code null}.
+     * @return The artifact type or {@code null} if no type with the requested identifier exists.
+     */
+    ArtifactType get( String typeId );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifact.java
new file mode 100644 (file)
index 0000000..9971034
--- /dev/null
@@ -0,0 +1,276 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+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 simple artifact. <em>Note:</em> Instances of this class are immutable and the exposed mutators return new objects
+ * rather than changing the current instance.
+ */
+public final class DefaultArtifact
+    extends AbstractArtifact
+{
+
+    private final String groupId;
+
+    private final String artifactId;
+
+    private final String version;
+
+    private final String classifier;
+
+    private final String extension;
+
+    private final File file;
+
+    private final Map<String, String> properties;
+
+    /**
+     * Creates a new artifact with the specified coordinates. If not specified in the artifact coordinates, the
+     * artifact's extension defaults to {@code jar} and classifier to an empty string.
+     * 
+     * @param coords The artifact coordinates in the format
+     *            {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}, must not be {@code null}.
+     */
+    public DefaultArtifact( String coords )
+    {
+        this( coords, Collections.<String, String> emptyMap() );
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates and properties. If not specified in the artifact
+     * coordinates, the artifact's extension defaults to {@code jar} and classifier to an empty string.
+     * 
+     * @param coords The artifact coordinates in the format
+     *            {@code <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>}, must not be {@code null}.
+     * @param properties The artifact properties, may be {@code null}.
+     */
+    public DefaultArtifact( String coords, Map<String, String> properties )
+    {
+        Pattern p = Pattern.compile( "([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)" );
+        Matcher m = p.matcher( coords );
+        if ( !m.matches() )
+        {
+            throw new IllegalArgumentException( "Bad artifact coordinates " + coords
+                + ", expected format is <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>" );
+        }
+        groupId = m.group( 1 );
+        artifactId = m.group( 2 );
+        extension = get( m.group( 4 ), "jar" );
+        classifier = get( m.group( 6 ), "" );
+        version = m.group( 7 );
+        file = null;
+        this.properties = copyProperties( properties );
+    }
+
+    private static String get( String value, String defaultValue )
+    {
+        return ( value == null || value.length() <= 0 ) ? defaultValue : value;
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates and no classifier. Passing {@code null} for any of the
+     * coordinates is equivalent to specifying an empty string.
+     * 
+     * @param groupId The group identifier of the artifact, may be {@code null}.
+     * @param artifactId The artifact identifier of the artifact, may be {@code null}.
+     * @param extension The file extension of the artifact, may be {@code null}.
+     * @param version The version of the artifact, may be {@code null}.
+     */
+    public DefaultArtifact( String groupId, String artifactId, String extension, String version )
+    {
+        this( groupId, artifactId, "", extension, version );
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is
+     * equivalent to specifying an empty string.
+     * 
+     * @param groupId The group identifier of the artifact, may be {@code null}.
+     * @param artifactId The artifact identifier of the artifact, may be {@code null}.
+     * @param classifier The classifier of the artifact, may be {@code null}.
+     * @param extension The file extension of the artifact, may be {@code null}.
+     * @param version The version of the artifact, may be {@code null}.
+     */
+    public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version )
+    {
+        this( groupId, artifactId, classifier, extension, version, null, (File) null );
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates. Passing {@code null} for any of the coordinates is
+     * equivalent to specifying an empty string. The optional artifact type provided to this constructor will be used to
+     * determine the artifact's classifier and file extension if the corresponding arguments for this constructor are
+     * {@code null}.
+     * 
+     * @param groupId The group identifier of the artifact, may be {@code null}.
+     * @param artifactId The artifact identifier of the artifact, may be {@code null}.
+     * @param classifier The classifier of the artifact, may be {@code null}.
+     * @param extension The file extension of the artifact, may be {@code null}.
+     * @param version The version of the artifact, may be {@code null}.
+     * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}.
+     */
+    public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version,
+                            ArtifactType type )
+    {
+        this( groupId, artifactId, classifier, extension, version, null, type );
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates and properties. Passing {@code null} for any of the
+     * coordinates is equivalent to specifying an empty string. The optional artifact type provided to this constructor
+     * will be used to determine the artifact's classifier and file extension if the corresponding arguments for this
+     * constructor are {@code null}. If the artifact type specifies properties, those will get merged with the
+     * properties passed directly into the constructor, with the latter properties taking precedence.
+     * 
+     * @param groupId The group identifier of the artifact, may be {@code null}.
+     * @param artifactId The artifact identifier of the artifact, may be {@code null}.
+     * @param classifier The classifier of the artifact, may be {@code null}.
+     * @param extension The file extension of the artifact, may be {@code null}.
+     * @param version The version of the artifact, may be {@code null}.
+     * @param properties The properties of the artifact, may be {@code null} if none.
+     * @param type The artifact type from which to query classifier, file extension and properties, may be {@code null}.
+     */
+    public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version,
+                            Map<String, String> properties, ArtifactType type )
+    {
+        this.groupId = emptify( groupId );
+        this.artifactId = emptify( artifactId );
+        if ( classifier != null || type == null )
+        {
+            this.classifier = emptify( classifier );
+        }
+        else
+        {
+            this.classifier = emptify( type.getClassifier() );
+        }
+        if ( extension != null || type == null )
+        {
+            this.extension = emptify( extension );
+        }
+        else
+        {
+            this.extension = emptify( type.getExtension() );
+        }
+        this.version = emptify( version );
+        this.file = null;
+        this.properties = merge( properties, ( type != null ) ? type.getProperties() : null );
+    }
+
+    private static Map<String, String> merge( Map<String, String> dominant, Map<String, String> recessive )
+    {
+        Map<String, String> properties;
+
+        if ( ( dominant == null || dominant.isEmpty() ) && ( recessive == null || recessive.isEmpty() ) )
+        {
+            properties = Collections.emptyMap();
+        }
+        else
+        {
+            properties = new HashMap<String, String>();
+            if ( recessive != null )
+            {
+                properties.putAll( recessive );
+            }
+            if ( dominant != null )
+            {
+                properties.putAll( dominant );
+            }
+            properties = Collections.unmodifiableMap( properties );
+        }
+
+        return properties;
+    }
+
+    /**
+     * Creates a new artifact with the specified coordinates, properties and file. Passing {@code null} for any of the
+     * coordinates is equivalent to specifying an empty string.
+     * 
+     * @param groupId The group identifier of the artifact, may be {@code null}.
+     * @param artifactId The artifact identifier of the artifact, may be {@code null}.
+     * @param classifier The classifier of the artifact, may be {@code null}.
+     * @param extension The file extension of the artifact, may be {@code null}.
+     * @param version The version of the artifact, may be {@code null}.
+     * @param properties The properties of the artifact, may be {@code null} if none.
+     * @param file The resolved file of the artifact, may be {@code null}.
+     */
+    public DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version,
+                            Map<String, String> properties, File file )
+    {
+        this.groupId = emptify( groupId );
+        this.artifactId = emptify( artifactId );
+        this.classifier = emptify( classifier );
+        this.extension = emptify( extension );
+        this.version = emptify( version );
+        this.file = file;
+        this.properties = copyProperties( properties );
+    }
+
+    DefaultArtifact( String groupId, String artifactId, String classifier, String extension, String version, File file,
+                     Map<String, String> properties )
+    {
+        // NOTE: This constructor assumes immutability of the provided properties, for internal use only
+        this.groupId = emptify( groupId );
+        this.artifactId = emptify( artifactId );
+        this.classifier = emptify( classifier );
+        this.extension = emptify( extension );
+        this.version = emptify( version );
+        this.file = file;
+        this.properties = properties;
+    }
+
+    private static String emptify( String str )
+    {
+        return ( str == null ) ? "" : str;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    public String getExtension()
+    {
+        return extension;
+    }
+
+    public File getFile()
+    {
+        return file;
+    }
+
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/DefaultArtifactType.java
new file mode 100644 (file)
index 0000000..b30cd12
--- /dev/null
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.artifact;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A simple artifact type.
+ */
+public final class DefaultArtifactType
+    implements ArtifactType
+{
+
+    private final String id;
+
+    private final String extension;
+
+    private final String classifier;
+
+    private final Map<String, String> properties;
+
+    /**
+     * Creates a new artifact type with the specified identifier. This constructor assumes the usual file extension
+     * equals the given type id and that the usual classifier is empty. Additionally, the properties
+     * {@link ArtifactProperties#LANGUAGE}, {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} and
+     * {@link ArtifactProperties#INCLUDES_DEPENDENCIES} will be set to {@code "none"}, {@code true} and {@code false},
+     * respectively.
+     * 
+     * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE}
+     *            property, must not be {@code null} or empty.
+     */
+    public DefaultArtifactType( String id )
+    {
+        this( id, id, "", "none", false, false );
+    }
+
+    /**
+     * Creates a new artifact type with the specified properties. Additionally, the properties
+     * {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} and {@link ArtifactProperties#INCLUDES_DEPENDENCIES} will be
+     * set to {@code true} and {@code false}, respectively.
+     * 
+     * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE}
+     *            property, must not be {@code null} or empty.
+     * @param extension The usual file extension for artifacts of this type, may be {@code null}.
+     * @param classifier The usual classifier for artifacts of this type, may be {@code null}.
+     * @param language The value for the {@link ArtifactProperties#LANGUAGE} property, may be {@code null}.
+     */
+    public DefaultArtifactType( String id, String extension, String classifier, String language )
+    {
+        this( id, extension, classifier, language, true, false );
+    }
+
+    /**
+     * Creates a new artifact type with the specified properties.
+     * 
+     * @param id The identifier of the type which will also be used as the value for the {@link ArtifactProperties#TYPE}
+     *            property, must not be {@code null} or empty.
+     * @param extension The usual file extension for artifacts of this type, may be {@code null}.
+     * @param classifier The usual classifier for artifacts of this type, may be {@code null}.
+     * @param language The value for the {@link ArtifactProperties#LANGUAGE} property, may be {@code null}.
+     * @param constitutesBuildPath The value for the {@link ArtifactProperties#CONSTITUTES_BUILD_PATH} property.
+     * @param includesDependencies The value for the {@link ArtifactProperties#INCLUDES_DEPENDENCIES} property.
+     */
+    public DefaultArtifactType( String id, String extension, String classifier, String language,
+                                boolean constitutesBuildPath, boolean includesDependencies )
+    {
+        if ( id == null || id.length() < 0 )
+        {
+            throw new IllegalArgumentException( "no type id specified" );
+        }
+        this.id = id;
+        this.extension = emptify( extension );
+        this.classifier = emptify( classifier );
+        Map<String, String> props = new HashMap<String, String>();
+        props.put( ArtifactProperties.TYPE, id );
+        props.put( ArtifactProperties.LANGUAGE, ( language != null && language.length() > 0 ) ? language : "none" );
+        props.put( ArtifactProperties.INCLUDES_DEPENDENCIES, Boolean.toString( includesDependencies ) );
+        props.put( ArtifactProperties.CONSTITUTES_BUILD_PATH, Boolean.toString( constitutesBuildPath ) );
+        properties = Collections.unmodifiableMap( props );
+    }
+
+    /**
+     * Creates a new artifact type with the specified properties.
+     * 
+     * @param id The identifier of the type, must not be {@code null} or empty.
+     * @param extension The usual file extension for artifacts of this type, may be {@code null}.
+     * @param classifier The usual classifier for artifacts of this type, may be {@code null}.
+     * @param properties The properties for artifacts of this type, may be {@code null}.
+     */
+    public DefaultArtifactType( String id, String extension, String classifier, Map<String, String> properties )
+    {
+        if ( id == null || id.length() < 0 )
+        {
+            throw new IllegalArgumentException( "no type id specified" );
+        }
+        this.id = id;
+        this.extension = emptify( extension );
+        this.classifier = emptify( classifier );
+        this.properties = AbstractArtifact.copyProperties( properties );
+    }
+
+    private static String emptify( String str )
+    {
+        return ( str == null ) ? "" : str;
+    }
+
+    public String getId()
+    {
+        return id;
+    }
+
+    public String getExtension()
+    {
+        return extension;
+    }
+
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/artifact/package-info.java
new file mode 100644 (file)
index 0000000..6d676d1
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The definition of an artifact, that is the primary entity managed by the repository system.
+ */
+package org.eclipse.aether.artifact;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectRequest.java
new file mode 100644 (file)
index 0000000..8568385
--- /dev/null
@@ -0,0 +1,347 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+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.graph.Dependency;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to
+ * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct
+ * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies
+ * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in
+ * which case the root node of the resulting graph has no associated dependency.
+ * 
+ * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)
+ */
+public final class CollectRequest
+{
+
+    private Artifact rootArtifact;
+
+    private Dependency root;
+
+    private List<Dependency> dependencies = Collections.emptyList();
+
+    private List<Dependency> managedDependencies = Collections.emptyList();
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public CollectRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( Dependency root, List<RemoteRepository> repositories )
+    {
+        setRoot( root );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Creates a new request with the specified properties.
+     * 
+     * @param root The root dependency whose transitive dependencies should be collected, may be {@code null}.
+     * @param dependencies The direct dependencies to merge with the direct dependencies from the root dependency's
+     *            artifact descriptor.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( Dependency root, List<Dependency> dependencies, List<RemoteRepository> repositories )
+    {
+        setRoot( root );
+        setDependencies( dependencies );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Creates a new request with the specified properties.
+     * 
+     * @param dependencies The direct dependencies of some imaginary root, may be {@code null}.
+     * @param managedDependencies The dependency management information to apply to the transitive dependencies, may be
+     *            {@code null}.
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     */
+    public CollectRequest( List<Dependency> dependencies, List<Dependency> managedDependencies,
+                           List<RemoteRepository> repositories )
+    {
+        setDependencies( dependencies );
+        setManagedDependencies( managedDependencies );
+        setRepositories( repositories );
+    }
+
+    /**
+     * Gets the root artifact for the dependency graph.
+     * 
+     * @return The root artifact for the dependency graph or {@code null} if none.
+     */
+    public Artifact getRootArtifact()
+    {
+        return rootArtifact;
+    }
+
+    /**
+     * Sets the root artifact for the dependency graph. This must not be confused with {@link #setRoot(Dependency)}: The
+     * root <em>dependency</em>, like any other specified dependency, will be subject to dependency
+     * collection/resolution, i.e. should have an artifact descriptor and a corresponding artifact file. The root
+     * <em>artifact</em> on the other hand is only used as a label for the root node of the graph in case no root
+     * dependency was specified. As such, the configured root artifact is ignored if {@link #getRoot()} does not return
+     * {@code null}.
+     * 
+     * @param rootArtifact The root artifact for the dependency graph, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRootArtifact( Artifact rootArtifact )
+    {
+        this.rootArtifact = rootArtifact;
+        return this;
+    }
+
+    /**
+     * Gets the root dependency of the graph.
+     * 
+     * @return The root dependency of the graph or {@code null} if none.
+     */
+    public Dependency getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root dependency of the graph.
+     * 
+     * @param root The root dependency of the graph, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRoot( Dependency root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    /**
+     * Gets the direct dependencies.
+     * 
+     * @return The direct dependencies, never {@code null}.
+     */
+    public List<Dependency> getDependencies()
+    {
+        return dependencies;
+    }
+
+    /**
+     * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the
+     * direct dependencies from the request will be merged with the direct dependencies from the root dependency's
+     * artifact descriptor, giving higher priority to the dependencies from the request.
+     * 
+     * @param dependencies The direct dependencies, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest 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 dependency to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest addDependency( Dependency dependency )
+    {
+        if ( dependency != null )
+        {
+            if ( this.dependencies.isEmpty() )
+            {
+                this.dependencies = new ArrayList<Dependency>();
+            }
+            this.dependencies.add( dependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the dependency management to apply to transitive dependencies.
+     * 
+     * @return The dependency management to apply to transitive dependencies, never {@code null}.
+     */
+    public List<Dependency> getManagedDependencies()
+    {
+        return managedDependencies;
+    }
+
+    /**
+     * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not apply to
+     * the direct dependencies of the root node.
+     * 
+     * @param managedDependencies The dependency management, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setManagedDependencies( List<Dependency> managedDependencies )
+    {
+        if ( managedDependencies == null )
+        {
+            this.managedDependencies = Collections.emptyList();
+        }
+        else
+        {
+            this.managedDependencies = managedDependencies;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified managed dependency.
+     * 
+     * @param managedDependency The managed dependency to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest addManagedDependency( Dependency managedDependency )
+    {
+        if ( managedDependency != null )
+        {
+            if ( this.managedDependencies.isEmpty() )
+            {
+                this.managedDependencies = new ArrayList<Dependency>();
+            }
+            this.managedDependencies.add( managedDependency );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repositories to use for the collection.
+     * 
+     * @return The repositories to use for the collection, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to use for the collection.
+     * 
+     * @param repositories The repositories to use for the collection, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for collection.
+     * 
+     * @param repository The repository to collect dependency information from, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public CollectRequest 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 CollectRequest 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 CollectRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getRoot() + " -> " + getDependencies() + " < " + getRepositories();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/CollectResult.java
new file mode 100644 (file)
index 0000000..4975190
--- /dev/null
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+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.graph.DependencyCycle;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * The result of a dependency collection request.
+ * 
+ * @see RepositorySystem#collectDependencies(RepositorySystemSession, CollectRequest)
+ */
+public final class CollectResult
+{
+
+    private final CollectRequest request;
+
+    private List<Exception> exceptions;
+
+    private List<DependencyCycle> cycles;
+
+    private DependencyNode root;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public CollectResult( CollectRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "dependency collection request has not been specified" );
+        }
+        this.request = request;
+        exceptions = Collections.emptyList();
+        cycles = Collections.emptyList();
+    }
+
+    /**
+     * Gets the collection request that was made.
+     * 
+     * @return The collection request, never {@code null}.
+     */
+    public CollectRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the exceptions that occurred while building the dependency graph.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Records the specified exception while building the dependency graph.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the dependency cycles that were encountered while building the dependency graph.
+     * 
+     * @return The dependency cycles in the (raw) graph, never {@code null}.
+     */
+    public List<DependencyCycle> getCycles()
+    {
+        return cycles;
+    }
+
+    /**
+     * Records the specified dependency cycle.
+     * 
+     * @param cycle The dependency cycle to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult addCycle( DependencyCycle cycle )
+    {
+        if ( cycle != null )
+        {
+            if ( cycles.isEmpty() )
+            {
+                cycles = new ArrayList<DependencyCycle>();
+            }
+            cycles.add( cycle );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the root node of the dependency graph.
+     * 
+     * @return The root node of the dependency graph or {@code null} if none.
+     */
+    public DependencyNode getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root node of the dependency graph.
+     * 
+     * @param root The root node of the dependency graph, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public CollectResult setRoot( DependencyNode root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getRoot() );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionContext.java
new file mode 100644 (file)
index 0000000..3b8fbc2
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+
+/**
+ * A context used during dependency collection to update the dependency manager, selector and traverser.
+ * 
+ * @see DependencyManager#deriveChildManager(DependencyCollectionContext)
+ * @see DependencyTraverser#deriveChildTraverser(DependencyCollectionContext)
+ * @see DependencySelector#deriveChildSelector(DependencyCollectionContext)
+ * @see VersionFilter#deriveChildFilter(DependencyCollectionContext)
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyCollectionContext
+{
+
+    /**
+     * Gets the repository system session during which the dependency collection happens.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    RepositorySystemSession getSession();
+
+    /**
+     * Gets the artifact whose children are to be processed next during dependency collection. For all nodes but the
+     * root, this is simply shorthand for {@code getDependency().getArtifact()}. In case of the root node however,
+     * {@link #getDependency()} might be {@code null} while the node still has an artifact which serves as its label and
+     * is not to be resolved.
+     * 
+     * @return The artifact whose children are going to be processed or {@code null} in case of the root node without
+     *         dependency and label.
+     */
+    Artifact getArtifact();
+
+    /**
+     * Gets the dependency whose children are to be processed next during dependency collection.
+     * 
+     * @return The dependency whose children are going to be processed or {@code null} in case of the root node without
+     *         dependency.
+     */
+    Dependency getDependency();
+
+    /**
+     * Gets the dependency management information that was contributed by the artifact descriptor of the current
+     * dependency.
+     * 
+     * @return The dependency management information, never {@code null}.
+     */
+    List<Dependency> getManagedDependencies();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyCollectionException.java
new file mode 100644 (file)
index 0000000..0d26674
--- /dev/null
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of bad artifact descriptors, version ranges or other issues encountered during calculation of the
+ * dependency graph.
+ */
+public class DependencyCollectionException
+    extends RepositoryException
+{
+
+    private final transient CollectResult result;
+
+    /**
+     * Creates a new exception with the specified result.
+     * 
+     * @param result The collection result at the point the exception occurred, may be {@code null}.
+     */
+    public DependencyCollectionException( CollectResult result )
+    {
+        super( "Failed to collect dependencies for " + getSource( result ), getCause( result ) );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result and detail message.
+     * 
+     * @param result The collection result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public DependencyCollectionException( CollectResult 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 collection 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 DependencyCollectionException( CollectResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    /**
+     * Gets the collection 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 collection result or {@code null} if unknown.
+     */
+    public CollectResult getResult()
+    {
+        return result;
+    }
+
+    private static String getSource( CollectResult result )
+    {
+        if ( result == null )
+        {
+            return "";
+        }
+
+        CollectRequest request = result.getRequest();
+        if ( request.getRoot() != null )
+        {
+            return request.getRoot().toString();
+        }
+        if ( request.getRootArtifact() != null )
+        {
+            return request.getRootArtifact().toString();
+        }
+
+        return request.getDependencies().toString();
+    }
+
+    private static Throwable getCause( CollectResult result )
+    {
+        Throwable cause = null;
+        if ( result != null && !result.getExceptions().isEmpty() )
+        {
+            cause = result.getExceptions().get( 0 );
+        }
+        return cause;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformationContext.java
new file mode 100644 (file)
index 0000000..d3980da
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A context used during dependency collection to exchange information within a chain of dependency graph transformers.
+ * 
+ * @see DependencyGraphTransformer
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyGraphTransformationContext
+{
+
+    /**
+     * Gets the repository system session during which the graph transformation happens.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    RepositorySystemSession getSession();
+
+    /**
+     * Gets a keyed value from the context.
+     * 
+     * @param key The key used to query the value, must not be {@code null}.
+     * @return The queried value or {@code null} if none.
+     */
+    Object get( Object key );
+
+    /**
+     * Puts a keyed value into the context.
+     * 
+     * @param key The key used to store the value, must not be {@code null}.
+     * @param value The value to store, may be {@code null} to remove the mapping.
+     * @return The previous value associated with the key or {@code null} if none.
+     */
+    Object put( Object key, Object value );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyGraphTransformer.java
new file mode 100644 (file)
index 0000000..b3deebe
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * Transforms a given dependency graph.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> Dependency graphs may generally contain cycles. As such a graph transformer that cannot assume for
+ * sure that cycles have already been eliminated must gracefully handle cyclic graphs, e.g. guard against infinite
+ * recursion.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyGraphTransformer()
+ */
+public interface DependencyGraphTransformer
+{
+
+    /**
+     * Transforms the dependency graph denoted by the specified root node. The transformer may directly change the
+     * provided input graph or create a new graph, the former is recommended for performance reasons.
+     * 
+     * @param node The root node of the (possibly cyclic!) graph to transform, must not be {@code null}.
+     * @param context The graph transformation context, must not be {@code null}.
+     * @return The result graph of the transformation, never {@code null}.
+     * @throws RepositoryException If the transformation failed.
+     */
+    DependencyNode transformGraph( DependencyNode node, DependencyGraphTransformationContext context )
+        throws RepositoryException;
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManagement.java
new file mode 100644 (file)
index 0000000..f0aac73
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.Exclusion;
+
+/**
+ * The management updates to apply to a dependency.
+ * 
+ * @see DependencyManager#manageDependency(Dependency)
+ */
+public final class DependencyManagement
+{
+
+    private String version;
+
+    private String scope;
+
+    private Boolean optional;
+
+    private Collection<Exclusion> exclusions;
+
+    private Map<String, String> properties;
+
+    /**
+     * Creates an empty management update.
+     */
+    public DependencyManagement()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Gets the new version to apply to the dependency.
+     * 
+     * @return The new version or {@code null} if the version is not managed and the existing dependency version should
+     *         remain unchanged.
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Sets the new version to apply to the dependency.
+     * 
+     * @param version The new version, may be {@code null} if the version is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setVersion( String version )
+    {
+        this.version = version;
+        return this;
+    }
+
+    /**
+     * Gets the new scope to apply to the dependency.
+     * 
+     * @return The new scope or {@code null} if the scope is not managed and the existing dependency scope should remain
+     *         unchanged.
+     */
+    public String getScope()
+    {
+        return scope;
+    }
+
+    /**
+     * Sets the new scope to apply to the dependency.
+     * 
+     * @param scope The new scope, may be {@code null} if the scope is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setScope( String scope )
+    {
+        this.scope = scope;
+        return this;
+    }
+
+    /**
+     * Gets the new optional flag to apply to the dependency.
+     * 
+     * @return The new optional flag or {@code null} if the flag is not managed and the existing optional flag of the
+     *         dependency should remain unchanged.
+     */
+    public Boolean getOptional()
+    {
+        return optional;
+    }
+
+    /**
+     * Sets the new optional flag to apply to the dependency.
+     * 
+     * @param optional The optional flag, may be {@code null} if the flag is not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setOptional( Boolean optional )
+    {
+        this.optional = optional;
+        return this;
+    }
+
+    /**
+     * Gets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of
+     * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged
+     * with information from dependency management or overridden by it.
+     * 
+     * @return The new exclusions or {@code null} if the exclusions are not managed and the existing dependency
+     *         exclusions should remain unchanged.
+     */
+    public Collection<Exclusion> getExclusions()
+    {
+        return exclusions;
+    }
+
+    /**
+     * Sets the new exclusions to apply to the dependency. Note that this collection denotes the complete set of
+     * exclusions for the dependency, i.e. the dependency manager controls whether any existing exclusions get merged
+     * with information from dependency management or overridden by it.
+     * 
+     * @param exclusions The new exclusions, may be {@code null} if the exclusions are not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setExclusions( Collection<Exclusion> exclusions )
+    {
+        this.exclusions = exclusions;
+        return this;
+    }
+
+    /**
+     * Gets the new properties to apply to the dependency. Note that this map denotes the complete set of properties,
+     * i.e. the dependency manager controls whether any existing properties get merged with the information from
+     * dependency management or overridden by it.
+     * 
+     * @return The new artifact properties or {@code null} if the properties are not managed and the existing properties
+     *         should remain unchanged.
+     */
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+    /**
+     * Sets the new properties to apply to the dependency. Note that this map denotes the complete set of properties,
+     * i.e. the dependency manager controls whether any existing properties get merged with the information from
+     * dependency management or overridden by it.
+     * 
+     * @param properties The new artifact properties, may be {@code null} if the properties are not managed.
+     * @return This management update for chaining, never {@code null}.
+     */
+    public DependencyManagement setProperties( Map<String, String> properties )
+    {
+        this.properties = properties;
+        return this;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyManager.java
new file mode 100644 (file)
index 0000000..e214f66
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.graph.Dependency;
+
+/**
+ * Applies dependency management to the dependencies of a dependency node.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyManager()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencyManager
+{
+
+    /**
+     * Applies dependency management to the specified dependency.
+     * 
+     * @param dependency The dependency to manage, must not be {@code null}.
+     * @return The management update to apply to the dependency or {@code null} if the dependency is not managed at all.
+     */
+    DependencyManagement manageDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency manager for the specified collection context. When calculating the child manager,
+     * implementors are strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency manager for the dependencies of the target node or {@code null} if dependency management
+     *         should no longer be applied.
+     */
+    DependencyManager deriveChildManager( DependencyCollectionContext context );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencySelector.java
new file mode 100644 (file)
index 0000000..de503be
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.graph.Dependency;
+
+/**
+ * Decides what dependencies to include in the dependency graph.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencySelector()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencySelector
+{
+
+    /**
+     * Decides whether the specified dependency should be included in the dependency graph.
+     * 
+     * @param dependency The dependency to check, must not be {@code null}.
+     * @return {@code false} if the dependency should be excluded from the children of the current node, {@code true}
+     *         otherwise.
+     */
+    boolean selectDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency selector for the specified collection context. When calculating the child selector,
+     * implementors are strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency selector for the target node or {@code null} if dependencies should be unconditionally
+     *         included in the sub graph.
+     */
+    DependencySelector deriveChildSelector( DependencyCollectionContext context );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/DependencyTraverser.java
new file mode 100644 (file)
index 0000000..8140395
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import org.eclipse.aether.graph.Dependency;
+
+/**
+ * Decides whether the dependencies of a dependency node should be traversed as well.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getDependencyTraverser()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface DependencyTraverser
+{
+
+    /**
+     * Decides whether the dependencies of the specified dependency should be traversed.
+     * 
+     * @param dependency The dependency to check, must not be {@code null}.
+     * @return {@code true} if the dependency graph builder should recurse into the specified dependency and process its
+     *         dependencies, {@code false} otherwise.
+     */
+    boolean traverseDependency( Dependency dependency );
+
+    /**
+     * Derives a dependency traverser that will be used to decide whether the transitive dependencies of the dependency
+     * given in the collection context shall be traversed. When calculating the child traverser, implementors are
+     * strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The dependency traverser for the target node or {@code null} if dependencies should be unconditionally
+     *         traversed in the sub graph.
+     */
+    DependencyTraverser deriveChildTraverser( DependencyCollectionContext context );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/UnsolvableVersionConflictException.java
new file mode 100644 (file)
index 0000000..8db5590
--- /dev/null
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * Thrown in case of an unsolvable conflict between different version constraints for a dependency.
+ */
+public class UnsolvableVersionConflictException
+    extends RepositoryException
+{
+
+    private final transient Collection<String> versions;
+
+    private final transient Collection<? extends List<? extends DependencyNode>> paths;
+
+    /**
+     * Creates a new exception with the specified paths to conflicting nodes in the dependency graph.
+     * 
+     * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}.
+     */
+    public UnsolvableVersionConflictException( Collection<? extends List<? extends DependencyNode>> paths )
+    {
+        super( "Could not resolve version conflict among " + toPaths( paths ) );
+        if ( paths == null )
+        {
+            this.paths = Collections.emptyList();
+            this.versions = Collections.emptyList();
+        }
+        else
+        {
+            this.paths = paths;
+            this.versions = new LinkedHashSet<String>();
+            for ( List<? extends DependencyNode> path : paths )
+            {
+                VersionConstraint constraint = path.get( path.size() - 1 ).getVersionConstraint();
+                if ( constraint != null && constraint.getRange() != null )
+                {
+                    versions.add( constraint.toString() );
+                }
+            }
+        }
+    }
+
+    private static String toPaths( Collection<? extends List<? extends DependencyNode>> paths )
+    {
+        String result = "";
+
+        if ( paths != null )
+        {
+            Collection<String> strings = new LinkedHashSet<String>();
+
+            for ( List<? extends DependencyNode> path : paths )
+            {
+                strings.add( toPath( path ) );
+            }
+
+            result = strings.toString();
+        }
+
+        return result;
+    }
+
+    private static String toPath( List<? extends DependencyNode> path )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+
+        for ( Iterator<? extends DependencyNode> it = path.iterator(); it.hasNext(); )
+        {
+            DependencyNode node = it.next();
+            if ( node.getDependency() == null )
+            {
+                continue;
+            }
+
+            Artifact artifact = node.getDependency().getArtifact();
+            buffer.append( artifact.getGroupId() );
+            buffer.append( ':' ).append( artifact.getArtifactId() );
+            buffer.append( ':' ).append( artifact.getExtension() );
+            if ( artifact.getClassifier().length() > 0 )
+            {
+                buffer.append( ':' ).append( artifact.getClassifier() );
+            }
+            buffer.append( ':' ).append( node.getVersionConstraint() );
+
+            if ( it.hasNext() )
+            {
+                buffer.append( " -> " );
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Gets the paths leading to the conflicting dependencies.
+     * 
+     * @return The (read-only) paths leading to the conflicting dependencies, never {@code null}.
+     */
+    public Collection<? extends List<? extends DependencyNode>> getPaths()
+    {
+        return paths;
+    }
+
+    /**
+     * Gets the conflicting version constraints of the dependency.
+     * 
+     * @return The (read-only) conflicting version constraints, never {@code null}.
+     */
+    public Collection<String> getVersions()
+    {
+        return versions;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/VersionFilter.java
new file mode 100644 (file)
index 0000000..02e7ab3
--- /dev/null
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.collection;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.repository.ArtifactRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * Decides which versions matching a version range should actually be considered for the dependency graph. The version
+ * filter is not invoked for dependencies that do not declare a version range but a single version.
+ * <p>
+ * <strong>Note:</strong> Implementations must be stateless.
+ * <p>
+ * <em>Warning:</em> This hook is called from a hot spot and therefore implementations should pay attention to
+ * performance. Among others, implementations should provide a semantic {@link Object#equals(Object) equals()} method.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getVersionFilter()
+ * @see org.eclipse.aether.RepositorySystem#collectDependencies(org.eclipse.aether.RepositorySystemSession,
+ *      CollectRequest)
+ */
+public interface VersionFilter
+{
+
+    /**
+     * A context used during version filtering to hold relevant data.
+     * 
+     * @noimplement This interface is not intended to be implemented by clients.
+     * @noextend This interface is not intended to be extended by clients.
+     */
+    interface VersionFilterContext
+        extends Iterable<Version>
+    {
+
+        /**
+         * Gets the repository system session during which the version filtering happens.
+         * 
+         * @return The repository system session, never {@code null}.
+         */
+        RepositorySystemSession getSession();
+
+        /**
+         * Gets the dependency whose version range is being filtered.
+         * 
+         * @return The dependency, never {@code null}.
+         */
+        Dependency getDependency();
+
+        /**
+         * Gets the total number of available versions. This count reflects any removals made during version filtering.
+         * 
+         * @return The total number of available versions.
+         */
+        int getCount();
+
+        /**
+         * Gets an iterator over the available versions of the dependency. The iterator returns versions in ascending
+         * order. Use {@link Iterator#remove()} to exclude a version from further consideration in the dependency graph.
+         * 
+         * @return The iterator of available versions, never {@code null}.
+         */
+        Iterator<Version> iterator();
+
+        /**
+         * Gets the version constraint that was parsed from the dependency's version string.
+         * 
+         * @return The parsed version constraint, never {@code null}.
+         */
+        VersionConstraint getVersionConstraint();
+
+        /**
+         * Gets the repository from which the specified version was resolved.
+         * 
+         * @param version The version whose source repository should be retrieved, must not be {@code null}.
+         * @return The repository from which the version was resolved or {@code null} if unknown.
+         */
+        ArtifactRepository getRepository( Version version );
+
+        /**
+         * Gets the remote repositories from which the versions were resolved.
+         * 
+         * @return The (read-only) list of repositories, never {@code null}.
+         */
+        List<RemoteRepository> getRepositories();
+
+    }
+
+    /**
+     * Filters the available versions for a given dependency. Implementations will usually call
+     * {@link VersionFilterContext#iterator() context.iterator()} to inspect the available versions and use
+     * {@link java.util.Iterator#remove()} to delete unacceptable versions. If no versions remain after all filtering
+     * has been performed, the dependency collection process will automatically fail, i.e. implementations need not
+     * handle this situation on their own.
+     * 
+     * @param context The version filter context, must not be {@code null}.
+     * @throws RepositoryException If the filtering could not be performed.
+     */
+    void filterVersions( VersionFilterContext context )
+        throws RepositoryException;
+
+    /**
+     * Derives a version filter for the specified collection context. The derived filter will be used to handle version
+     * ranges encountered in child dependencies of the current node. When calculating the child filter, implementors are
+     * strongly advised to simply return the current instance if nothing changed to help save memory.
+     * 
+     * @param context The dependency collection context, must not be {@code null}.
+     * @return The version filter for the target node or {@code null} if versions should not be filtered any more.
+     */
+    VersionFilter deriveChildFilter( DependencyCollectionContext context );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/collection/package-info.java
new file mode 100644 (file)
index 0000000..dd7df2e
--- /dev/null
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The types and extension points for collecting the transitive dependencies of an artifact and building a dependency
+ * graph.
+ */
+package org.eclipse.aether.collection;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployRequest.java
new file mode 100644 (file)
index 0000000..a5372dd
--- /dev/null
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.deployment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+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.metadata.Metadata;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to deploy artifacts and their accompanying metadata into the a remote repository.
+ * 
+ * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest)
+ */
+public final class DeployRequest
+{
+
+    private Collection<Artifact> artifacts = Collections.emptyList();
+
+    private Collection<Metadata> metadata = Collections.emptyList();
+
+    private RemoteRepository repository;
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public DeployRequest()
+    {
+    }
+
+    /**
+     * Gets the artifact to deploy.
+     * 
+     * @return The artifacts to deploy, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts to deploy.
+     * 
+     * @param artifacts The artifacts to deploy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts for deployment.
+     * 
+     * @param artifact The artifact to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata to deploy.
+     * 
+     * @return The metadata to deploy, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to deploy.
+     * 
+     * @param metadata The metadata to deploy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata for deployment.
+     * 
+     * @param metadata The metadata to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repository to deploy to.
+     * 
+     * @return The repository to deploy to or {@code null} if not set.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository to deploy to.
+     * 
+     * @param repository The repository to deploy to, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DeployRequest setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        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 DeployRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata() + " > " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeployResult.java
new file mode 100644 (file)
index 0000000..fcda3ca
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.deployment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * The result of deploying artifacts and their accompanying metadata into the a remote repository.
+ * 
+ * @see RepositorySystem#deploy(RepositorySystemSession, DeployRequest)
+ */
+public final class DeployResult
+{
+
+    private final DeployRequest request;
+
+    private Collection<Artifact> artifacts;
+
+    private Collection<Metadata> metadata;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The deployment request, must not be {@code null}.
+     */
+    public DeployResult( DeployRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "deploy request has not been specified" );
+        }
+        this.request = request;
+        artifacts = Collections.emptyList();
+        metadata = Collections.emptyList();
+    }
+
+    /**
+     * Gets the deploy request that was made.
+     * 
+     * @return The deploy request, never {@code null}.
+     */
+    public DeployRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the artifacts that got deployed.
+     * 
+     * @return The deployed artifacts, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts that got deployed.
+     * 
+     * @param artifacts The deployed artifacts, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts to the result.
+     * 
+     * @param artifact The deployed artifact to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata that got deployed. Note that due to automatically generated metadata, there might have been
+     * more metadata deployed than originally specified in the deploy request.
+     * 
+     * @return The deployed metadata, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata that got deployed.
+     * 
+     * @param metadata The deployed metadata, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata to this result.
+     * 
+     * @param metadata The deployed metadata to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DeployResult addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/DeploymentException.java
new file mode 100644 (file)
index 0000000..f631530
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.deployment;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of a deployment error like authentication failure.
+ */
+public class DeploymentException
+    extends RepositoryException
+{
+
+    /**
+     * Creates a new exception with the specified detail message.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public DeploymentException( 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 DeploymentException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/deployment/package-info.java
new file mode 100644 (file)
index 0000000..dd5a35d
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The types supporting the publishing of artifacts to a remote repository.
+ */
+package org.eclipse.aether.deployment;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DefaultDependencyNode.java
new file mode 100644 (file)
index 0000000..c702d23
--- /dev/null
@@ -0,0 +1,359 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * A node within a dependency graph.
+ */
+public final class DefaultDependencyNode
+    implements DependencyNode
+{
+
+    private List<DependencyNode> children;
+
+    private Dependency dependency;
+
+    private Artifact artifact;
+
+    private List<? extends Artifact> relocations;
+
+    private Collection<? extends Artifact> aliases;
+
+    private VersionConstraint versionConstraint;
+
+    private Version version;
+
+    private byte managedBits;
+
+    private List<RemoteRepository> repositories;
+
+    private String context;
+
+    private Map<Object, Object> data;
+
+    /**
+     * Creates a new node with the specified dependency.
+     * 
+     * @param dependency The dependency associated with this node, may be {@code null} for a root node.
+     */
+    public DefaultDependencyNode( Dependency dependency )
+    {
+        this.dependency = dependency;
+        artifact = ( dependency != null ) ? dependency.getArtifact() : null;
+        children = new ArrayList<DependencyNode>( 0 );
+        aliases = relocations = Collections.emptyList();
+        repositories = Collections.emptyList();
+        context = "";
+        data = Collections.emptyMap();
+    }
+
+    /**
+     * Creates a new root node with the specified artifact as its label. Note that the new node has no dependency, i.e.
+     * {@link #getDependency()} will return {@code null}. Put differently, the specified artifact will not be subject to
+     * dependency collection/resolution.
+     * 
+     * @param artifact The artifact to use as label for this node, may be {@code null}.
+     */
+    public DefaultDependencyNode( Artifact artifact )
+    {
+        this.artifact = artifact;
+        children = new ArrayList<DependencyNode>( 0 );
+        aliases = relocations = Collections.emptyList();
+        repositories = Collections.emptyList();
+        context = "";
+        data = Collections.emptyMap();
+    }
+
+    /**
+     * Creates a mostly shallow clone of the specified node. The new node has its own copy of any custom data and
+     * initially no children.
+     * 
+     * @param node The node to copy, must not be {@code null}.
+     */
+    public DefaultDependencyNode( DependencyNode node )
+    {
+        dependency = node.getDependency();
+        artifact = node.getArtifact();
+        children = new ArrayList<DependencyNode>( 0 );
+        setAliases( node.getAliases() );
+        setRequestContext( node.getRequestContext() );
+        setManagedBits( node.getManagedBits() );
+        setRelocations( node.getRelocations() );
+        setRepositories( node.getRepositories() );
+        setVersion( node.getVersion() );
+        setVersionConstraint( node.getVersionConstraint() );
+        Map<?, ?> data = node.getData();
+        setData( data.isEmpty() ? null : new HashMap<Object, Object>( data ) );
+    }
+
+    public List<DependencyNode> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren( List<DependencyNode> children )
+    {
+        if ( children == null )
+        {
+            this.children = new ArrayList<DependencyNode>( 0 );
+        }
+        else
+        {
+            this.children = children;
+        }
+    }
+
+    public Dependency getDependency()
+    {
+        return dependency;
+    }
+
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    public void setArtifact( Artifact artifact )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setArtifact( artifact );
+        this.artifact = dependency.getArtifact();
+    }
+
+    public List<? extends Artifact> getRelocations()
+    {
+        return relocations;
+    }
+
+    /**
+     * Sets the sequence of relocations that was followed to resolve this dependency's artifact.
+     * 
+     * @param relocations The sequence of relocations, may be {@code null}.
+     */
+    public void setRelocations( List<? extends Artifact> relocations )
+    {
+        if ( relocations == null || relocations.isEmpty() )
+        {
+            this.relocations = Collections.emptyList();
+        }
+        else
+        {
+            this.relocations = relocations;
+        }
+    }
+
+    public Collection<? extends Artifact> getAliases()
+    {
+        return aliases;
+    }
+
+    /**
+     * Sets the known aliases for this dependency's artifact.
+     * 
+     * @param aliases The known aliases, may be {@code null}.
+     */
+    public void setAliases( Collection<? extends Artifact> aliases )
+    {
+        if ( aliases == null || aliases.isEmpty() )
+        {
+            this.aliases = Collections.emptyList();
+        }
+        else
+        {
+            this.aliases = aliases;
+        }
+    }
+
+    public VersionConstraint getVersionConstraint()
+    {
+        return versionConstraint;
+    }
+
+    /**
+     * Sets the version constraint that was parsed from the dependency's version declaration.
+     * 
+     * @param versionConstraint The version constraint for this node, may be {@code null}.
+     */
+    public void setVersionConstraint( VersionConstraint versionConstraint )
+    {
+        this.versionConstraint = versionConstraint;
+    }
+
+    public Version getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Sets the version that was selected for the dependency's target artifact.
+     * 
+     * @param version The parsed version, may be {@code null}.
+     */
+    public void setVersion( Version version )
+    {
+        this.version = version;
+    }
+
+    public void setScope( String scope )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setScope( scope );
+    }
+
+    public void setOptional( Boolean optional )
+    {
+        if ( dependency == null )
+        {
+            throw new UnsupportedOperationException( "node does not have a dependency" );
+        }
+        dependency = dependency.setOptional( optional );
+    }
+
+    public int getManagedBits()
+    {
+        return managedBits;
+    }
+
+    /**
+     * Sets a bit field indicating which attributes of this node were subject to dependency management.
+     * 
+     * @param managedBits The bit field indicating the managed attributes or {@code 0} if dependency management wasn't
+     *            applied.
+     */
+    public void setManagedBits( int managedBits )
+    {
+        this.managedBits = (byte) ( managedBits & 0x1F );
+    }
+
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the remote repositories from which this node's artifact shall be resolved.
+     * 
+     * @param repositories The remote repositories to use for artifact resolution, may be {@code null}.
+     */
+    public void setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null || repositories.isEmpty() )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+    }
+
+    public String getRequestContext()
+    {
+        return context;
+    }
+
+    public void setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+    }
+
+    public Map<Object, Object> getData()
+    {
+        return data;
+    }
+
+    public void setData( Map<Object, Object> data )
+    {
+        if ( data == null )
+        {
+            this.data = Collections.emptyMap();
+        }
+        else
+        {
+            this.data = data;
+        }
+    }
+
+    public void setData( Object key, Object value )
+    {
+        if ( key == null )
+        {
+            throw new IllegalArgumentException( "key must not be null" );
+        }
+
+        if ( value == null )
+        {
+            if ( !data.isEmpty() )
+            {
+                data.remove( key );
+
+                if ( data.isEmpty() )
+                {
+                    data = Collections.emptyMap();
+                }
+            }
+        }
+        else
+        {
+            if ( data.isEmpty() )
+            {
+                data = new HashMap<Object, Object>( 1, 2 ); // nodes can be numerous so let's be space conservative
+            }
+            data.put( key, value );
+        }
+    }
+
+    public boolean accept( DependencyVisitor visitor )
+    {
+        if ( visitor.visitEnter( this ) )
+        {
+            for ( DependencyNode child : children )
+            {
+                if ( !child.accept( visitor ) )
+                {
+                    break;
+                }
+            }
+        }
+
+        return visitor.visitLeave( this );
+    }
+
+    @Override
+    public String toString()
+    {
+        Dependency dep = getDependency();
+        if ( dep == null )
+        {
+            return String.valueOf( getArtifact() );
+        }
+        return dep.toString();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Dependency.java
new file mode 100644 (file)
index 0000000..72ea0f6
--- /dev/null
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * A dependency to some artifact. <em>Note:</em> Instances of this class are immutable and the exposed mutators return
+ * new objects rather than changing the current instance.
+ */
+public final class Dependency
+{
+
+    private final Artifact artifact;
+
+    private final String scope;
+
+    private final Boolean optional;
+
+    private final Set<Exclusion> exclusions;
+
+    /**
+     * Creates a mandatory dependency on the specified artifact with the given scope.
+     * 
+     * @param artifact The artifact being depended on, must not be {@code null}.
+     * @param scope The scope of the dependency, may be {@code null}.
+     */
+    public Dependency( Artifact artifact, String scope )
+    {
+        this( artifact, scope, false );
+    }
+
+    /**
+     * Creates a dependency on the specified artifact with the given scope.
+     * 
+     * @param artifact The artifact being depended on, must not be {@code null}.
+     * @param scope The scope of the dependency, may be {@code null}.
+     * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}.
+     */
+    public Dependency( Artifact artifact, String scope, Boolean optional )
+    {
+        this( artifact, scope, optional, null );
+    }
+
+    /**
+     * Creates a dependency on the specified artifact with the given scope and exclusions.
+     * 
+     * @param artifact The artifact being depended on, must not be {@code null}.
+     * @param scope The scope of the dependency, may be {@code null}.
+     * @param optional A flag whether the dependency is optional or mandatory, may be {@code null}.
+     * @param exclusions The exclusions that apply to transitive dependencies, may be {@code null} if none.
+     */
+    public Dependency( Artifact artifact, String scope, Boolean optional, Collection<Exclusion> exclusions )
+    {
+        this( artifact, scope, Exclusions.copy( exclusions ), optional );
+    }
+
+    private Dependency( Artifact artifact, String scope, Set<Exclusion> exclusions, Boolean optional )
+    {
+        // NOTE: This constructor assumes immutability of the provided exclusion collection, for internal use only
+        if ( artifact == null )
+        {
+            throw new IllegalArgumentException( "no artifact specified for dependency" );
+        }
+        this.artifact = artifact;
+        this.scope = ( scope != null ) ? scope : "";
+        this.optional = optional;
+        this.exclusions = exclusions;
+    }
+
+    /**
+     * Gets the artifact being depended on.
+     * 
+     * @return The artifact, never {@code null}.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact being depended on.
+     * 
+     * @param artifact The artifact, must not be {@code null}.
+     * @return The new dependency, never {@code null}.
+     */
+    public Dependency setArtifact( Artifact artifact )
+    {
+        if ( this.artifact.equals( artifact ) )
+        {
+            return this;
+        }
+        return new Dependency( artifact, scope, exclusions, optional );
+    }
+
+    /**
+     * Gets the scope of the dependency. The scope defines in which context this dependency is relevant.
+     * 
+     * @return The scope or an empty string if not set, never {@code null}.
+     */
+    public String getScope()
+    {
+        return scope;
+    }
+
+    /**
+     * Sets the scope of the dependency, e.g. "compile".
+     * 
+     * @param scope The scope of the dependency, may be {@code null}.
+     * @return The new dependency, never {@code null}.
+     */
+    public Dependency setScope( String scope )
+    {
+        if ( this.scope.equals( scope ) || ( scope == null && this.scope.length() <= 0 ) )
+        {
+            return this;
+        }
+        return new Dependency( artifact, scope, exclusions, optional );
+    }
+
+    /**
+     * Indicates whether this dependency is optional or not. Optional dependencies can be ignored in some contexts.
+     * 
+     * @return {@code true} if the dependency is (definitively) optional, {@code false} otherwise.
+     */
+    public boolean isOptional()
+    {
+        return Boolean.TRUE.equals( optional );
+    }
+
+    /**
+     * Gets the optional flag for the dependency. Note: Most clients will usually call {@link #isOptional()} to
+     * determine the optional flag, this method is for advanced use cases where three-valued logic is required.
+     * 
+     * @return The optional flag or {@code null} if unspecified.
+     */
+    public Boolean getOptional()
+    {
+        return optional;
+    }
+
+    /**
+     * Sets the optional flag for the dependency.
+     * 
+     * @param optional {@code true} if the dependency is optional, {@code false} if the dependency is mandatory, may be
+     *            {@code null} if unspecified.
+     * @return The new dependency, never {@code null}.
+     */
+    public Dependency setOptional( Boolean optional )
+    {
+        if ( eq( this.optional, optional ) )
+        {
+            return this;
+        }
+        return new Dependency( artifact, scope, exclusions, optional );
+    }
+
+    /**
+     * Gets the exclusions for this dependency. Exclusions can be used to remove transitive dependencies during
+     * resolution.
+     * 
+     * @return The (read-only) exclusions, never {@code null}.
+     */
+    public Collection<Exclusion> getExclusions()
+    {
+        return exclusions;
+    }
+
+    /**
+     * Sets the exclusions for the dependency.
+     * 
+     * @param exclusions The exclusions, may be {@code null}.
+     * @return The new dependency, never {@code null}.
+     */
+    public Dependency setExclusions( Collection<Exclusion> exclusions )
+    {
+        if ( hasEquivalentExclusions( exclusions ) )
+        {
+            return this;
+        }
+        return new Dependency( artifact, scope, optional, exclusions );
+    }
+
+    private boolean hasEquivalentExclusions( Collection<Exclusion> exclusions )
+    {
+        if ( exclusions == null || exclusions.isEmpty() )
+        {
+            return this.exclusions.isEmpty();
+        }
+        if ( exclusions instanceof Set )
+        {
+            return this.exclusions.equals( exclusions );
+        }
+        return exclusions.size() >= this.exclusions.size() && this.exclusions.containsAll( exclusions )
+            && exclusions.containsAll( this.exclusions );
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( getArtifact() ) + " (" + getScope() + ( isOptional() ? "?" : "" ) + ")";
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+        else if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        Dependency that = (Dependency) obj;
+
+        return artifact.equals( that.artifact ) && scope.equals( that.scope ) && eq( optional, that.optional )
+            && exclusions.equals( that.exclusions );
+    }
+
+    private static <T> boolean eq( T o1, T o2 )
+    {
+        return ( o1 != null ) ? o1.equals( o2 ) : o2 == null;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + artifact.hashCode();
+        hash = hash * 31 + scope.hashCode();
+        hash = hash * 31 + ( optional != null ? optional.hashCode() : 0 );
+        hash = hash * 31 + exclusions.size();
+        return hash;
+    }
+
+    private static class Exclusions
+        extends AbstractSet<Exclusion>
+    {
+
+        private final Exclusion[] exclusions;
+
+        public static Set<Exclusion> copy( Collection<Exclusion> exclusions )
+        {
+            if ( exclusions == null || exclusions.isEmpty() )
+            {
+                return Collections.emptySet();
+            }
+            return new Exclusions( exclusions );
+        }
+
+        private Exclusions( Collection<Exclusion> exclusions )
+        {
+            if ( exclusions.size() > 1 && !( exclusions instanceof Set ) )
+            {
+                exclusions = new LinkedHashSet<Exclusion>( exclusions );
+            }
+            this.exclusions = exclusions.toArray( new Exclusion[exclusions.size()] );
+        }
+
+        @Override
+        public Iterator<Exclusion> iterator()
+        {
+            return new Iterator<Exclusion>()
+            {
+
+                private int cursor = 0;
+
+                public boolean hasNext()
+                {
+                    return cursor < exclusions.length;
+                }
+
+                public Exclusion next()
+                {
+                    try
+                    {
+                        Exclusion exclusion = exclusions[cursor];
+                        cursor++;
+                        return exclusion;
+                    }
+                    catch ( IndexOutOfBoundsException e )
+                    {
+                        throw new NoSuchElementException();
+                    }
+                }
+
+                public void remove()
+                {
+                    throw new UnsupportedOperationException();
+                }
+
+            };
+        }
+
+        @Override
+        public int size()
+        {
+            return exclusions.length;
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyCycle.java
new file mode 100644 (file)
index 0000000..68f9a32
--- /dev/null
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+import java.util.List;
+
+/**
+ * A cycle within a dependency graph, that is a sequence of dependencies d_1, d_2, ..., d_n where d_1 and d_n have the
+ * same versionless coordinates. In more practical terms, a cycle occurs when a project directly or indirectly depends
+ * on its own output artifact.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyCycle
+{
+
+    /**
+     * Gets the dependencies that lead to the first dependency on the cycle, starting from the root of the dependency
+     * graph.
+     * 
+     * @return The (read-only) sequence of dependencies that precedes the cycle in the graph, potentially empty but
+     *         never {@code null}.
+     */
+    List<Dependency> getPrecedingDependencies();
+
+    /**
+     * Gets the dependencies that actually form the cycle. For example, a -&gt; b -&gt; c -&gt; a, i.e. the last
+     * dependency in this sequence duplicates the first element and closes the cycle. Hence the length of the cycle is
+     * the size of the returned sequence minus 1.
+     * 
+     * @return The (read-only) sequence of dependencies that forms the cycle, never {@code null}.
+     */
+    List<Dependency> getCyclicDependencies();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyFilter.java
new file mode 100644 (file)
index 0000000..c776ddc
--- /dev/null
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+import java.util.List;
+
+/**
+ * A filter to include/exclude dependency nodes during other operations.
+ */
+public interface DependencyFilter
+{
+
+    /**
+     * Indicates whether the specified dependency node shall be included or excluded.
+     * 
+     * @param node The dependency node to filter, must not be {@code null}.
+     * @param parents The (read-only) chain of parent nodes that leads to the node to be filtered, must not be
+     *            {@code null}. Iterating this (possibly empty) list walks up the dependency graph towards the root
+     *            node, i.e. the immediate parent node (if any) is the first node in the list. The size of the list also
+     *            denotes the zero-based depth of the filtered node.
+     * @return {@code true} to include the dependency node, {@code false} to exclude it.
+     */
+    boolean accept( DependencyNode node, List<DependencyNode> parents );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyNode.java
new file mode 100644 (file)
index 0000000..4e34597
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * A node within a dependency graph. To conserve memory, dependency graphs may reuse a given node instance multiple
+ * times to represent reoccurring dependencies. As such clients traversing a dependency graph should be prepared to
+ * discover multiple paths leading to the same node instance unless the input graph is known to be a duplicate-free
+ * tree. <em>Note:</em> Unless otherwise noted, implementation classes are not thread-safe and dependency nodes should
+ * not be mutated by concurrent threads.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface DependencyNode
+{
+
+    /**
+     * A bit flag indicating the dependency version was subject to dependency management
+     * 
+     * @see #getManagedBits()
+     */
+    int MANAGED_VERSION = 0x01;
+
+    /**
+     * A bit flag indicating the dependency scope was subject to dependency management
+     * 
+     * @see #getManagedBits()
+     */
+    int MANAGED_SCOPE = 0x02;
+
+    /**
+     * A bit flag indicating the optional flag was subject to dependency management
+     * 
+     * @see #getManagedBits()
+     */
+    int MANAGED_OPTIONAL = 0x04;
+
+    /**
+     * A bit flag indicating the artifact properties were subject to dependency management
+     * 
+     * @see #getManagedBits()
+     */
+    int MANAGED_PROPERTIES = 0x08;
+
+    /**
+     * A bit flag indicating the exclusions were subject to dependency management
+     * 
+     * @see #getManagedBits()
+     */
+    int MANAGED_EXCLUSIONS = 0x10;
+
+    /**
+     * Gets the child nodes of this node. To conserve memory, dependency nodes with equal dependencies may share the
+     * same child list instance. Hence clients mutating the child list need to be aware that these changes might affect
+     * more than this node. Where this is not desired, the child list should be copied before mutation if the client
+     * cannot be sure whether it might be shared with other nodes in the graph.
+     * 
+     * @return The child nodes of this node, never {@code null}.
+     */
+    List<DependencyNode> getChildren();
+
+    /**
+     * Sets the child nodes of this node.
+     * 
+     * @param children The child nodes, may be {@code null}
+     */
+    void setChildren( List<DependencyNode> children );
+
+    /**
+     * Gets the dependency associated with this node. <em>Note:</em> For dependency graphs that have been constructed
+     * without a root dependency, this method will yield {@code null} when invoked on the graph's root node. The root
+     * node of such graphs may however still have a label as returned by {@link #getArtifact()}.
+     * 
+     * @return The dependency or {@code null} if none.
+     */
+    Dependency getDependency();
+
+    /**
+     * Gets the artifact associated with this node. If this node is associated with a dependency, this is equivalent to
+     * {@code getDependency().getArtifact()}. Otherwise the artifact merely provides a label for this node in which case
+     * the artifact must not be subjected to dependency collection/resolution.
+     * 
+     * @return The associated artifact or {@code null} if none.
+     */
+    Artifact getArtifact();
+
+    /**
+     * Updates the artifact of the dependency after resolution. The new artifact must have the same coordinates as the
+     * original artifact. This method may only be invoked if this node actually has a dependency, i.e. if
+     * {@link #getDependency()} is not null.
+     * 
+     * @param artifact The artifact satisfying the dependency, must not be {@code null}.
+     */
+    void setArtifact( Artifact artifact );
+
+    /**
+     * Gets the sequence of relocations that was followed to resolve the artifact referenced by the dependency.
+     * 
+     * @return The (read-only) sequence of relocations, never {@code null}.
+     */
+    List<? extends Artifact> getRelocations();
+
+    /**
+     * Gets the known aliases for this dependency's artifact. An alias 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 (read-only) set of known aliases, never {@code null}.
+     */
+    Collection<? extends Artifact> getAliases();
+
+    /**
+     * Gets the version constraint that was parsed from the dependency's version declaration.
+     * 
+     * @return The version constraint for this node or {@code null}.
+     */
+    VersionConstraint getVersionConstraint();
+
+    /**
+     * Gets the version that was selected for the dependency's target artifact.
+     * 
+     * @return The parsed version or {@code null}.
+     */
+    Version getVersion();
+
+    /**
+     * Sets the scope of the dependency. This method may only be invoked if this node actually has a dependency, i.e. if
+     * {@link #getDependency()} is not null.
+     * 
+     * @param scope The scope, may be {@code null}.
+     */
+    void setScope( String scope );
+
+    /**
+     * Sets the optional flag of the dependency. This method may only be invoked if this node actually has a dependency,
+     * i.e. if {@link #getDependency()} is not null.
+     * 
+     * @param optional The optional flag, may be {@code null}.
+     */
+    void setOptional( Boolean optional );
+
+    /**
+     * Gets a bit field indicating which attributes of this node were subject to dependency management.
+     * 
+     * @return A bit field containing any of the bits {@link #MANAGED_VERSION}, {@link #MANAGED_SCOPE},
+     *         {@link #MANAGED_OPTIONAL}, {@link #MANAGED_PROPERTIES} and {@link #MANAGED_EXCLUSIONS} if the
+     *         corresponding attribute was set via dependency management.
+     */
+    int getManagedBits();
+
+    /**
+     * Gets the remote repositories from which this node's artifact shall be resolved.
+     * 
+     * @return The (read-only) list of remote repositories to use for artifact resolution, never {@code null}.
+     */
+    List<RemoteRepository> getRepositories();
+
+    /**
+     * Gets the request context in which this dependency node was created.
+     * 
+     * @return The request context, never {@code null}.
+     */
+    String getRequestContext();
+
+    /**
+     * Sets the request context in which this dependency node was created.
+     * 
+     * @param context The context, may be {@code null}.
+     */
+    void setRequestContext( String context );
+
+    /**
+     * Gets the custom data associated with this dependency node. Clients of the repository system can use this data to
+     * annotate dependency nodes with domain-specific information. Note that the returned map is read-only and
+     * {@link #setData(Object, Object)} needs to be used to update the custom data.
+     * 
+     * @return The (read-only) key-value mappings, never {@code null}.
+     */
+    Map<?, ?> getData();
+
+    /**
+     * Sets the custom data associated with this dependency node.
+     * 
+     * @param data The new custom data, may be {@code null}.
+     */
+    void setData( Map<Object, Object> data );
+
+    /**
+     * Associates the specified dependency node data with the given key. <em>Note:</em> This method must not be called
+     * while {@link #getData()} is being iterated.
+     * 
+     * @param key The key under which to store the data, must not be {@code null}.
+     * @param value The data to associate with the key, may be {@code null} to remove the mapping.
+     */
+    void setData( Object key, Object value );
+
+    /**
+     * Traverses this node and potentially its children using the specified visitor.
+     * 
+     * @param visitor The visitor to call back, must not be {@code null}.
+     * @return {@code true} to visit siblings nodes of this node as well, {@code false} to skip siblings.
+     */
+    boolean accept( DependencyVisitor visitor );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/DependencyVisitor.java
new file mode 100644 (file)
index 0000000..d4ba213
--- /dev/null
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+/**
+ * A visitor for nodes of the dependency graph.
+ * 
+ * @see DependencyNode#accept(DependencyVisitor)
+ */
+public interface DependencyVisitor
+{
+
+    /**
+     * Notifies the visitor of a node visit before its children have been processed.
+     * 
+     * @param node The dependency node being visited, must not be {@code null}.
+     * @return {@code true} to visit child nodes of the specified node as well, {@code false} to skip children.
+     */
+    boolean visitEnter( DependencyNode node );
+
+    /**
+     * Notifies the visitor of a node visit after its children have been processed. Note that this method is always
+     * invoked regardless whether any children have actually been visited.
+     * 
+     * @param node The dependency node being visited, must not be {@code null}.
+     * @return {@code true} to visit siblings nodes of the specified node as well, {@code false} to skip siblings.
+     */
+    boolean visitLeave( DependencyNode node );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/Exclusion.java
new file mode 100644 (file)
index 0000000..4d6b7ba
--- /dev/null
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.graph;
+
+/**
+ * An exclusion of one or more transitive dependencies. <em>Note:</em> Instances of this class are immutable and the
+ * exposed mutators return new objects rather than changing the current instance.
+ * 
+ * @see Dependency#getExclusions()
+ */
+public final class Exclusion
+{
+
+    private final String groupId;
+
+    private final String artifactId;
+
+    private final String classifier;
+
+    private final String extension;
+
+    /**
+     * Creates an exclusion for artifacts with the specified coordinates.
+     * 
+     * @param groupId The group identifier, may be {@code null}.
+     * @param artifactId The artifact identifier, may be {@code null}.
+     * @param classifier The classifier, may be {@code null}.
+     * @param extension The file extension, may be {@code null}.
+     */
+    public Exclusion( String groupId, String artifactId, String classifier, String extension )
+    {
+        this.groupId = ( groupId != null ) ? groupId : "";
+        this.artifactId = ( artifactId != null ) ? artifactId : "";
+        this.classifier = ( classifier != null ) ? classifier : "";
+        this.extension = ( extension != null ) ? extension : "";
+    }
+
+    /**
+     * Gets the group identifier for artifacts to exclude.
+     * 
+     * @return The group identifier, never {@code null}.
+     */
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /**
+     * Gets the artifact identifier for artifacts to exclude.
+     * 
+     * @return The artifact identifier, never {@code null}.
+     */
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    /**
+     * Gets the classifier for artifacts to exclude.
+     * 
+     * @return The classifier, never {@code null}.
+     */
+    public String getClassifier()
+    {
+        return classifier;
+    }
+
+    /**
+     * Gets the file extension for artifacts to exclude.
+     * 
+     * @return The file extension of artifacts to exclude, never {@code null}.
+     */
+    public String getExtension()
+    {
+        return extension;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getGroupId() + ':' + getArtifactId() + ':' + getExtension()
+            + ( getClassifier().length() > 0 ? ':' + getClassifier() : "" );
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+        else if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        Exclusion that = (Exclusion) obj;
+
+        return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId )
+            && extension.equals( that.extension ) && classifier.equals( that.classifier );
+    }
+
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + artifactId.hashCode();
+        hash = hash * 31 + groupId.hashCode();
+        hash = hash * 31 + classifier.hashCode();
+        hash = hash * 31 + extension.hashCode();
+        return hash;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/graph/package-info.java
new file mode 100644 (file)
index 0000000..70879a3
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The representation of a dependency graph by means of connected dependency nodes.
+ */
+package org.eclipse.aether.graph;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallRequest.java
new file mode 100644 (file)
index 0000000..330f85a
--- /dev/null
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.installation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+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.metadata.Metadata;
+
+/**
+ * A request to install artifacts and their accompanying metadata into the local repository.
+ * 
+ * @see RepositorySystem#install(RepositorySystemSession, InstallRequest)
+ */
+public final class InstallRequest
+{
+
+    private Collection<Artifact> artifacts = Collections.emptyList();
+
+    private Collection<Metadata> metadata = Collections.emptyList();
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public InstallRequest()
+    {
+    }
+
+    /**
+     * Gets the artifact to install.
+     * 
+     * @return The artifacts to install, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts to install.
+     * 
+     * @param artifacts The artifacts to install, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public InstallRequest setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts for installation.
+     * 
+     * @param artifact The artifact to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public InstallRequest addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata to install.
+     * 
+     * @return The metadata to install, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to install.
+     * 
+     * @param metadata The metadata to install.
+     * @return This request for chaining, never {@code null}.
+     */
+    public InstallRequest setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata for installation.
+     * 
+     * @param metadata The metadata to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public InstallRequest addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        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 InstallRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallResult.java
new file mode 100644 (file)
index 0000000..fe3ade1
--- /dev/null
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.installation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * The result of installing artifacts and their accompanying metadata into the a remote repository.
+ * 
+ * @see RepositorySystem#install(RepositorySystemSession, InstallRequest)
+ */
+public final class InstallResult
+{
+
+    private final InstallRequest request;
+
+    private Collection<Artifact> artifacts;
+
+    private Collection<Metadata> metadata;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The installation request, must not be {@code null}.
+     */
+    public InstallResult( InstallRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "install request has not been specified" );
+        }
+        this.request = request;
+        artifacts = Collections.emptyList();
+        metadata = Collections.emptyList();
+    }
+
+    /**
+     * Gets the install request that was made.
+     * 
+     * @return The install request, never {@code null}.
+     */
+    public InstallRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the artifacts that got installed.
+     * 
+     * @return The installed artifacts, never {@code null}.
+     */
+    public Collection<Artifact> getArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Sets the artifacts that got installed.
+     * 
+     * @param artifacts The installed artifacts, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public InstallResult setArtifacts( Collection<Artifact> artifacts )
+    {
+        if ( artifacts == null )
+        {
+            this.artifacts = Collections.emptyList();
+        }
+        else
+        {
+            this.artifacts = artifacts;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified artifacts to the result.
+     * 
+     * @param artifact The installed artifact to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public InstallResult addArtifact( Artifact artifact )
+    {
+        if ( artifact != null )
+        {
+            if ( artifacts.isEmpty() )
+            {
+                artifacts = new ArrayList<Artifact>();
+            }
+            artifacts.add( artifact );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the metadata that got installed. Note that due to automatically generated metadata, there might have been
+     * more metadata installed than originally specified in the install request.
+     * 
+     * @return The installed metadata, never {@code null}.
+     */
+    public Collection<Metadata> getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata that got installed.
+     * 
+     * @param metadata The installed metadata, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public InstallResult setMetadata( Collection<Metadata> metadata )
+    {
+        if ( metadata == null )
+        {
+            this.metadata = Collections.emptyList();
+        }
+        else
+        {
+            this.metadata = metadata;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified metadata to this result.
+     * 
+     * @param metadata The installed metadata to add, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public InstallResult addMetadata( Metadata metadata )
+    {
+        if ( metadata != null )
+        {
+            if ( this.metadata.isEmpty() )
+            {
+                this.metadata = new ArrayList<Metadata>();
+            }
+            this.metadata.add( metadata );
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifacts() + ", " + getMetadata();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/InstallationException.java
new file mode 100644 (file)
index 0000000..e976665
--- /dev/null
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.installation;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of an installation error like an IO error.
+ */
+public class InstallationException
+    extends RepositoryException
+{
+
+    /**
+     * Creates a new exception with the specified detail message.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public InstallationException( 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 InstallationException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/installation/package-info.java
new file mode 100644 (file)
index 0000000..35b910b
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The types supporting the publishing of artifacts to a local repository.
+ */
+package org.eclipse.aether.installation;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/AbstractMetadata.java
new file mode 100644 (file)
index 0000000..d95eb54
--- /dev/null
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.metadata;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A skeleton class for metadata.
+ */
+public abstract class AbstractMetadata
+    implements Metadata
+{
+
+    private Metadata newInstance( Map<String, String> properties, File file )
+    {
+        return new DefaultMetadata( getGroupId(), getArtifactId(), getVersion(), getType(), getNature(), file,
+                                    properties );
+    }
+
+    public Metadata setFile( File file )
+    {
+        File current = getFile();
+        if ( ( current == null ) ? file == null : current.equals( file ) )
+        {
+            return this;
+        }
+        return newInstance( getProperties(), file );
+    }
+
+    public Metadata setProperties( Map<String, String> properties )
+    {
+        Map<String, String> current = getProperties();
+        if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) )
+        {
+            return this;
+        }
+        return newInstance( copyProperties( properties ), getFile() );
+    }
+
+    public String getProperty( String key, String defaultValue )
+    {
+        String value = getProperties().get( key );
+        return ( value != null ) ? value : defaultValue;
+    }
+
+    /**
+     * Copies the specified metadata properties. This utility method should be used when creating new metadata 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 );
+        if ( getGroupId().length() > 0 )
+        {
+            buffer.append( getGroupId() );
+        }
+        if ( getArtifactId().length() > 0 )
+        {
+            buffer.append( ':' ).append( getArtifactId() );
+        }
+        if ( getVersion().length() > 0 )
+        {
+            buffer.append( ':' ).append( getVersion() );
+        }
+        buffer.append( '/' ).append( getType() );
+        return buffer.toString();
+    }
+
+    /**
+     * Compares this metadata with the specified object.
+     * 
+     * @param obj The object to compare this metadata against, may be {@code null}.
+     * @return {@code true} if and only if the specified object is another {@link Metadata} with equal coordinates,
+     *         type, nature, properties and file, {@code false} otherwise.
+     */
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( obj == this )
+        {
+            return true;
+        }
+        else if ( !( obj instanceof Metadata ) )
+        {
+            return false;
+        }
+
+        Metadata that = (Metadata) obj;
+
+        return getArtifactId().equals( that.getArtifactId() ) && getGroupId().equals( that.getGroupId() )
+            && getVersion().equals( that.getVersion() ) && getType().equals( that.getType() )
+            && getNature().equals( that.getNature() ) && eq( getFile(), that.getFile() )
+            && eq( getProperties(), 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 metadata.
+     * 
+     * @return A hash code for the metadata.
+     */
+    @Override
+    public int hashCode()
+    {
+        int hash = 17;
+        hash = hash * 31 + getGroupId().hashCode();
+        hash = hash * 31 + getArtifactId().hashCode();
+        hash = hash * 31 + getType().hashCode();
+        hash = hash * 31 + getNature().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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/DefaultMetadata.java
new file mode 100644 (file)
index 0000000..aa9c830
--- /dev/null
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.metadata;
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * A basic metadata instance. <em>Note:</em> Instances of this class are immutable and the exposed mutators return new
+ * objects rather than changing the current instance.
+ */
+public final class DefaultMetadata
+    extends AbstractMetadata
+{
+
+    private final String groupId;
+
+    private final String artifactId;
+
+    private final String version;
+
+    private final String type;
+
+    private final Nature nature;
+
+    private final File file;
+
+    private final Map<String, String> properties;
+
+    /**
+     * Creates a new metadata for the repository root with the specific type and nature.
+     * 
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     */
+    public DefaultMetadata( String type, Nature nature )
+    {
+        this( "", "", "", type, nature, null, (File) null );
+    }
+
+    /**
+     * Creates a new metadata for the groupId level with the specific type and nature.
+     * 
+     * @param groupId The group identifier to which this metadata applies, may be {@code null}.
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     */
+    public DefaultMetadata( String groupId, String type, Nature nature )
+    {
+        this( groupId, "", "", type, nature, null, (File) null );
+    }
+
+    /**
+     * Creates a new metadata for the groupId:artifactId level with the specific type and nature.
+     * 
+     * @param groupId The group identifier to which this metadata applies, may be {@code null}.
+     * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}.
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     */
+    public DefaultMetadata( String groupId, String artifactId, String type, Nature nature )
+    {
+        this( groupId, artifactId, "", type, nature, null, (File) null );
+    }
+
+    /**
+     * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature.
+     * 
+     * @param groupId The group identifier to which this metadata applies, may be {@code null}.
+     * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}.
+     * @param version The version to which this metadata applies, may be {@code null}.
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     */
+    public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature )
+    {
+        this( groupId, artifactId, version, type, nature, null, (File) null );
+    }
+
+    /**
+     * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature.
+     * 
+     * @param groupId The group identifier to which this metadata applies, may be {@code null}.
+     * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}.
+     * @param version The version to which this metadata applies, may be {@code null}.
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     * @param file The resolved file of the metadata, may be {@code null}.
+     */
+    public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature, File file )
+    {
+        this( groupId, artifactId, version, type, nature, null, file );
+    }
+
+    /**
+     * Creates a new metadata for the groupId:artifactId:version level with the specific type and nature.
+     * 
+     * @param groupId The group identifier to which this metadata applies, may be {@code null}.
+     * @param artifactId The artifact identifier to which this metadata applies, may be {@code null}.
+     * @param version The version to which this metadata applies, may be {@code null}.
+     * @param type The type of the metadata, e.g. "maven-metadata.xml", may be {@code null}.
+     * @param nature The nature of the metadata, must not be {@code null}.
+     * @param properties The properties of the metadata, may be {@code null} if none.
+     * @param file The resolved file of the metadata, may be {@code null}.
+     */
+    public DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature,
+                            Map<String, String> properties, File file )
+    {
+        this.groupId = emptify( groupId );
+        this.artifactId = emptify( artifactId );
+        this.version = emptify( version );
+        this.type = emptify( type );
+        if ( nature == null )
+        {
+            throw new IllegalArgumentException( "metadata nature was not specified" );
+        }
+        this.nature = nature;
+        this.file = file;
+        this.properties = copyProperties( properties );
+    }
+
+    DefaultMetadata( String groupId, String artifactId, String version, String type, Nature nature, File file,
+                     Map<String, String> properties )
+    {
+        // NOTE: This constructor assumes immutability of the provided properties, for internal use only
+        this.groupId = emptify( groupId );
+        this.artifactId = emptify( artifactId );
+        this.version = emptify( version );
+        this.type = emptify( type );
+        this.nature = nature;
+        this.file = file;
+        this.properties = properties;
+    }
+
+    private static String emptify( String str )
+    {
+        return ( str == null ) ? "" : str;
+    }
+
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public String getType()
+    {
+        return type;
+    }
+
+    public Nature getNature()
+    {
+        return nature;
+    }
+
+    public File getFile()
+    {
+        return file;
+    }
+
+    public Map<String, String> getProperties()
+    {
+        return properties;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/MergeableMetadata.java
new file mode 100644 (file)
index 0000000..25f15df
--- /dev/null
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.metadata;
+
+import java.io.File;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * A piece of metadata that needs to be merged with any current metadata before installation/deployment.
+ */
+public interface MergeableMetadata
+    extends Metadata
+{
+
+    /**
+     * Merges this metadata into the current metadata (if any). Note that this method will be invoked regardless whether
+     * metadata currently exists or not.
+     * 
+     * @param current The path to the current metadata file, may not exist but must not be {@code null}.
+     * @param result The path to the result file where the merged metadata should be stored, must not be {@code null}.
+     * @throws RepositoryException If the metadata could not be merged.
+     */
+    void merge( File current, File result )
+        throws RepositoryException;
+
+    /**
+     * Indicates whether this metadata has been merged.
+     * 
+     * @return {@code true} if the metadata has been merged, {@code false} otherwise.
+     */
+    boolean isMerged();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/Metadata.java
new file mode 100644 (file)
index 0000000..328544a
--- /dev/null
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.metadata;
+
+import java.io.File;
+import java.util.Map;
+
+/**
+ * A piece of repository metadata, e.g. an index of available versions. In contrast to an artifact, which usually exists
+ * in only one repository, metadata usually exists in multiple repositories and each repository contains a different
+ * copy of the metadata. <em>Note:</em> Metadata instances are supposed to be immutable, e.g. any exposed mutator method
+ * returns a new metadata instance and leaves the original instance unchanged. Implementors are strongly advised to obey
+ * this contract. <em>Note:</em> Implementors are strongly advised to inherit from {@link AbstractMetadata} 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 Metadata
+{
+
+    /**
+     * The nature of the metadata.
+     */
+    enum Nature
+    {
+        /**
+         * The metadata refers to release artifacts only.
+         */
+        RELEASE,
+
+        /**
+         * The metadata refers to snapshot artifacts only.
+         */
+        SNAPSHOT,
+
+        /**
+         * The metadata refers to either release or snapshot artifacts.
+         */
+        RELEASE_OR_SNAPSHOT
+    }
+
+    /**
+     * Gets the group identifier of this metadata.
+     * 
+     * @return The group identifier or an empty string if the metadata applies to the entire repository, never
+     *         {@code null}.
+     */
+    String getGroupId();
+
+    /**
+     * Gets the artifact identifier of this metadata.
+     * 
+     * @return The artifact identifier or an empty string if the metadata applies to the groupId level only, never
+     *         {@code null}.
+     */
+    String getArtifactId();
+
+    /**
+     * Gets the version of this metadata.
+     * 
+     * @return The version or an empty string if the metadata applies to the groupId:artifactId level only, never
+     *         {@code null}.
+     */
+    String getVersion();
+
+    /**
+     * Gets the type of the metadata, e.g. "maven-metadata.xml".
+     * 
+     * @return The type of the metadata, never {@code null}.
+     */
+    String getType();
+
+    /**
+     * Gets the nature of this metadata. The nature indicates to what artifact versions the metadata refers.
+     * 
+     * @return The nature, never {@code null}.
+     */
+    Nature getNature();
+
+    /**
+     * Gets the file of this metadata. Note that only resolved metadata has a file associated with it.
+     * 
+     * @return The file or {@code null} if none.
+     */
+    File getFile();
+
+    /**
+     * Sets the file of the metadata.
+     * 
+     * @param file The file of the metadata, may be {@code null}
+     * @return The new metadata, never {@code null}.
+     */
+    Metadata 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.
+     */
+    String getProperty( String key, String defaultValue );
+
+    /**
+     * Gets the properties of this metadata.
+     * 
+     * @return The (read-only) properties, never {@code null}.
+     */
+    Map<String, String> getProperties();
+
+    /**
+     * Sets the properties for the metadata.
+     * 
+     * @param properties The properties for the metadata, may be {@code null}.
+     * @return The new metadata, never {@code null}.
+     */
+    Metadata setProperties( Map<String, String> properties );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/metadata/package-info.java
new file mode 100644 (file)
index 0000000..141a837
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The definition of metadata, that is an auxiliary entity managed by the repository system to locate artifacts.
+ */
+package org.eclipse.aether.metadata;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/package-info.java
new file mode 100644 (file)
index 0000000..7268b46
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The primary API of the {@link org.eclipse.aether.RepositorySystem} and its functionality.
+ */
+package org.eclipse.aether;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ArtifactRepository.java
new file mode 100644 (file)
index 0000000..2000f8b
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * A repository hosting artifacts.
+ * 
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface ArtifactRepository
+{
+
+    /**
+     * Gets the type of the repository, for example "default".
+     * 
+     * @return The (case-sensitive) type of the repository, never {@code null}.
+     */
+    String getContentType();
+
+    /**
+     * Gets the identifier of this repository.
+     * 
+     * @return The (case-sensitive) identifier, never {@code null}.
+     */
+    String getId();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Authentication.java
new file mode 100644 (file)
index 0000000..c1eaac0
--- /dev/null
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.util.Map;
+
+/**
+ * The authentication to use for accessing a protected resource. This acts basically as an extensible callback mechanism
+ * from which network operations can request authentication data like username and password when needed.
+ */
+public interface Authentication
+{
+
+    /**
+     * Fills the given authentication context with the data from this authentication callback. To do so, implementors
+     * have to call {@link AuthenticationContext#put(String, Object)}. <br>
+     * <br>
+     * The {@code key} parameter supplied to this method acts merely as a hint for interactive callbacks that want to
+     * prompt the user for only that authentication data which is required. Implementations are free to ignore this
+     * parameter and put all the data they have into the authentication context at once.
+     * 
+     * @param context The authentication context to populate, must not be {@code null}.
+     * @param key The key denoting a specific piece of authentication data that is being requested for a network
+     *            operation, may be {@code null}.
+     * @param data Any (read-only) extra data in form of key value pairs that might be useful when getting the
+     *            authentication data, may be {@code null}.
+     */
+    void fill( AuthenticationContext context, String key, Map<String, String> data );
+
+    /**
+     * Updates the given digest with data from this authentication callback. To do so, implementors have to call the
+     * {@code update()} methods in {@link AuthenticationDigest}.
+     * 
+     * @param digest The digest to update, must not be {@code null}.
+     */
+    void digest( AuthenticationDigest digest );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationContext.java
new file mode 100644 (file)
index 0000000..5b1ba2c
--- /dev/null
@@ -0,0 +1,380 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.io.Closeable;
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A glorified map of key value pairs holding (cleartext) authentication data. Authentication contexts are used
+ * internally when network operations need to access secured repositories or proxies. Each authentication context
+ * manages the credentials required to access a single host. Unlike {@link Authentication} callbacks which exist for a
+ * potentially long time like the duration of a repository system session, an authentication context has a supposedly
+ * short lifetime and should be {@link #close() closed} as soon as the corresponding network operation has finished:
+ * 
+ * <pre>
+ * AuthenticationContext context = AuthenticationContext.forRepository( session, repository );
+ * try {
+ *     // get credentials
+ *     char[] password = context.get( AuthenticationContext.PASSWORD, char[].class );
+ *     // perform network operation using retrieved credentials
+ *     ...
+ * } finally {
+ *     // erase confidential authentication data from heap memory
+ *     AuthenticationContext.close( context );
+ * }
+ * </pre>
+ * 
+ * The same authentication data can often be presented using different data types, e.g. a password can be presented
+ * using a character array or (less securely) using a string. For ease of use, an authentication context treats the
+ * following groups of data types as equivalent and converts values automatically during retrieval:
+ * <ul>
+ * <li>{@code String}, {@code char[]}</li>
+ * <li>{@code String}, {@code File}</li>
+ * </ul>
+ * An authentication context is thread-safe.
+ */
+public final class AuthenticationContext
+    implements Closeable
+{
+
+    /**
+     * The key used to store the username. The corresponding authentication data should be of type {@link String}.
+     */
+    public static final String USERNAME = "username";
+
+    /**
+     * The key used to store the password. The corresponding authentication data should be of type {@code char[]} or
+     * {@link String}.
+     */
+    public static final String PASSWORD = "password";
+
+    /**
+     * The key used to store the NTLM domain. The corresponding authentication data should be of type {@link String}.
+     */
+    public static final String NTLM_DOMAIN = "ntlm.domain";
+
+    /**
+     * The key used to store the NTML workstation. The corresponding authentication data should be of type
+     * {@link String}.
+     */
+    public static final String NTLM_WORKSTATION = "ntlm.workstation";
+
+    /**
+     * The key used to store the pathname to a private key file. The corresponding authentication data should be of type
+     * {@link String} or {@link File}.
+     */
+    public static final String PRIVATE_KEY_PATH = "privateKey.path";
+
+    /**
+     * The key used to store the passphrase protecting the private key. The corresponding authentication data should be
+     * of type {@code char[]} or {@link String}.
+     */
+    public static final String PRIVATE_KEY_PASSPHRASE = "privateKey.passphrase";
+
+    /**
+     * The key used to store the acceptance policy for unknown host keys. The corresponding authentication data should
+     * be of type {@link Boolean}. When querying this authentication data, the extra data should provide
+     * {@link #HOST_KEY_REMOTE} and {@link #HOST_KEY_LOCAL}, e.g. to enable a well-founded decision of the user during
+     * an interactive prompt.
+     */
+    public static final String HOST_KEY_ACCEPTANCE = "hostKey.acceptance";
+
+    /**
+     * The key used to store the fingerprint of the public key advertised by remote host. Note that this key is used to
+     * query the extra data passed to {@link #get(String, Map, Class)} when getting {@link #HOST_KEY_ACCEPTANCE}, not
+     * the authentication data in a context.
+     */
+    public static final String HOST_KEY_REMOTE = "hostKey.remote";
+
+    /**
+     * The key used to store the fingerprint of the public key expected from remote host as recorded in a known hosts
+     * database. Note that this key is used to query the extra data passed to {@link #get(String, Map, Class)} when
+     * getting {@link #HOST_KEY_ACCEPTANCE}, not the authentication data in a context.
+     */
+    public static final String HOST_KEY_LOCAL = "hostKey.local";
+
+    /**
+     * The key used to store the SSL context. The corresponding authentication data should be of type
+     * {@link javax.net.ssl.SSLContext}.
+     */
+    public static final String SSL_CONTEXT = "ssl.context";
+
+    /**
+     * The key used to store the SSL hostname verifier. The corresponding authentication data should be of type
+     * {@link javax.net.ssl.HostnameVerifier}.
+     */
+    public static final String SSL_HOSTNAME_VERIFIER = "ssl.hostnameVerifier";
+
+    private final RepositorySystemSession session;
+
+    private final RemoteRepository repository;
+
+    private final Proxy proxy;
+
+    private final Authentication auth;
+
+    private final Map<String, Object> authData;
+
+    private boolean fillingAuthData;
+
+    /**
+     * Gets an authentication context for the specified repository.
+     * 
+     * @param session The repository system session during which the repository is accessed, must not be {@code null}.
+     * @param repository The repository for which to create an authentication context, must not be {@code null}.
+     * @return An authentication context for the repository or {@code null} if no authentication is configured for it.
+     */
+    public static AuthenticationContext forRepository( RepositorySystemSession session, RemoteRepository repository )
+    {
+        return newInstance( session, repository, null, repository.getAuthentication() );
+    }
+
+    /**
+     * Gets an authentication context for the proxy of the specified repository.
+     * 
+     * @param session The repository system session during which the repository is accessed, must not be {@code null}.
+     * @param repository The repository for whose proxy to create an authentication context, must not be {@code null}.
+     * @return An authentication context for the proxy or {@code null} if no proxy is set or no authentication is
+     *         configured for it.
+     */
+    public static AuthenticationContext forProxy( RepositorySystemSession session, RemoteRepository repository )
+    {
+        Proxy proxy = repository.getProxy();
+        return newInstance( session, repository, proxy, ( proxy != null ) ? proxy.getAuthentication() : null );
+    }
+
+    private static AuthenticationContext newInstance( RepositorySystemSession session, RemoteRepository repository,
+                                                      Proxy proxy, Authentication auth )
+    {
+        if ( auth == null )
+        {
+            return null;
+        }
+        return new AuthenticationContext( session, repository, proxy, auth );
+    }
+
+    private AuthenticationContext( RepositorySystemSession session, RemoteRepository repository, Proxy proxy,
+                                   Authentication auth )
+    {
+        if ( session == null )
+        {
+            throw new IllegalArgumentException( "repository system session missing" );
+        }
+        this.session = session;
+        this.repository = repository;
+        this.proxy = proxy;
+        this.auth = auth;
+        authData = new HashMap<String, Object>();
+    }
+
+    /**
+     * Gets the repository system session during which the authentication happens.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    public RepositorySystemSession getSession()
+    {
+        return session;
+    }
+
+    /**
+     * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by
+     * this authentication context does not apply to the repository's host but rather the proxy.
+     * 
+     * @return The repository to be contacted, never {@code null}.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Gets the proxy (if any) to be authenticated with.
+     * 
+     * @return The proxy or {@code null} if authenticating directly with the repository's host.
+     */
+    public Proxy getProxy()
+    {
+        return proxy;
+    }
+
+    /**
+     * Gets the authentication data for the specified key.
+     * 
+     * @param key The key whose authentication data should be retrieved, must not be {@code null}.
+     * @return The requested authentication data or {@code null} if none.
+     */
+    public String get( String key )
+    {
+        return get( key, null, String.class );
+    }
+
+    /**
+     * Gets the authentication data for the specified key.
+     * 
+     * @param <T> The data type of the authentication data.
+     * @param key The key whose authentication data should be retrieved, must not be {@code null}.
+     * @param type The expected type of the authentication data, must not be {@code null}.
+     * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type.
+     */
+    public <T> T get( String key, Class<T> type )
+    {
+        return get( key, null, type );
+    }
+
+    /**
+     * Gets the authentication data for the specified key.
+     * 
+     * @param <T> The data type of the authentication data.
+     * @param key The key whose authentication data should be retrieved, must not be {@code null}.
+     * @param data Any (read-only) extra data in form of key value pairs that might be useful when getting the
+     *            authentication data, may be {@code null}.
+     * @param type The expected type of the authentication data, must not be {@code null}.
+     * @return The requested authentication data or {@code null} if none or if the data doesn't match the expected type.
+     */
+    public <T> T get( String key, Map<String, String> data, Class<T> type )
+    {
+        if ( key == null )
+        {
+            throw new IllegalArgumentException( "authentication data key missing" );
+        }
+        Object value;
+        synchronized ( authData )
+        {
+            value = authData.get( key );
+            if ( value == null && !authData.containsKey( key ) && !fillingAuthData )
+            {
+                if ( auth != null )
+                {
+                    try
+                    {
+                        fillingAuthData = true;
+                        auth.fill( this, key, data );
+                    }
+                    finally
+                    {
+                        fillingAuthData = false;
+                    }
+                    value = authData.get( key );
+                }
+                if ( value == null )
+                {
+                    authData.put( key, value );
+                }
+            }
+        }
+
+        return convert( value, type );
+    }
+
+    private <T> T convert( Object value, Class<T> type )
+    {
+        if ( !type.isInstance( value ) )
+        {
+            if ( String.class.equals( type ) )
+            {
+                if ( value instanceof File )
+                {
+                    value = ( (File) value ).getPath();
+                }
+                else if ( value instanceof char[] )
+                {
+                    value = new String( (char[]) value );
+                }
+            }
+            else if ( File.class.equals( type ) )
+            {
+                if ( value instanceof String )
+                {
+                    value = new File( (String) value );
+                }
+            }
+            else if ( char[].class.equals( type ) )
+            {
+                if ( value instanceof String )
+                {
+                    value = ( (String) value ).toCharArray();
+                }
+            }
+        }
+
+        if ( type.isInstance( value ) )
+        {
+            return type.cast( value );
+        }
+
+        return null;
+    }
+
+    /**
+     * Puts the specified authentication data into this context. This method should only be called from implementors of
+     * {@link Authentication#fill(AuthenticationContext, String, Map)}. Passed in character arrays are not cloned and
+     * become owned by this context, i.e. get erased when the context gets closed.
+     * 
+     * @param key The key to associate the authentication data with, must not be {@code null}.
+     * @param value The (cleartext) authentication data to store, may be {@code null}.
+     */
+    public void put( String key, Object value )
+    {
+        if ( key == null )
+        {
+            throw new IllegalArgumentException( "authentication data key missing" );
+        }
+        synchronized ( authData )
+        {
+            Object oldValue = authData.put( key, value );
+            if ( oldValue instanceof char[] )
+            {
+                Arrays.fill( (char[]) oldValue, '\0' );
+            }
+        }
+    }
+
+    /**
+     * Closes this authentication context and erases sensitive authentication data from heap memory. Closing an already
+     * closed context has no effect.
+     */
+    public void close()
+    {
+        synchronized ( authData )
+        {
+            for ( Object value : authData.values() )
+            {
+                if ( value instanceof char[] )
+                {
+                    Arrays.fill( (char[]) value, '\0' );
+                }
+            }
+            authData.clear();
+        }
+    }
+
+    /**
+     * Closes the specified authentication context. This is a convenience method doing a {@code null} check before
+     * calling {@link #close()} on the given context.
+     * 
+     * @param context The authentication context to close, may be {@code null}.
+     */
+    public static void close( AuthenticationContext context )
+    {
+        if ( context != null )
+        {
+            context.close();
+        }
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationDigest.java
new file mode 100644 (file)
index 0000000..f702b4a
--- /dev/null
@@ -0,0 +1,210 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A helper to calculate a fingerprint/digest for the authentication data of a repository/proxy. Such a fingerprint can
+ * be used to detect changes in the authentication data across JVM restarts without exposing sensitive information.
+ */
+public final class AuthenticationDigest
+{
+
+    private final MessageDigest digest;
+
+    private final RepositorySystemSession session;
+
+    private final RemoteRepository repository;
+
+    private final Proxy proxy;
+
+    /**
+     * Gets the fingerprint for the authentication of the specified repository.
+     * 
+     * @param session The repository system session during which the fingerprint is requested, must not be {@code null}.
+     * @param repository The repository whose authentication is to be fingerprinted, must not be {@code null}.
+     * @return The fingerprint of the repository authentication or an empty string if no authentication is configured,
+     *         never {@code null}.
+     */
+    public static String forRepository( RepositorySystemSession session, RemoteRepository repository )
+    {
+        String digest = "";
+        Authentication auth = repository.getAuthentication();
+        if ( auth != null )
+        {
+            AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, null );
+            auth.digest( authDigest );
+            digest = authDigest.digest();
+        }
+        return digest;
+    }
+
+    /**
+     * Gets the fingerprint for the authentication of the specified repository's proxy.
+     * 
+     * @param session The repository system session during which the fingerprint is requested, must not be {@code null}.
+     * @param repository The repository whose proxy authentication is to be fingerprinted, must not be {@code null}.
+     * @return The fingerprint of the proxy authentication or an empty string if no proxy is present or if no proxy
+     *         authentication is configured, never {@code null}.
+     */
+    public static String forProxy( RepositorySystemSession session, RemoteRepository repository )
+    {
+        String digest = "";
+        Proxy proxy = repository.getProxy();
+        if ( proxy != null )
+        {
+            Authentication auth = proxy.getAuthentication();
+            if ( auth != null )
+            {
+                AuthenticationDigest authDigest = new AuthenticationDigest( session, repository, proxy );
+                auth.digest( authDigest );
+                digest = authDigest.digest();
+            }
+        }
+        return digest;
+    }
+
+    private AuthenticationDigest( RepositorySystemSession session, RemoteRepository repository, Proxy proxy )
+    {
+        this.session = session;
+        this.repository = repository;
+        this.proxy = proxy;
+        digest = newDigest();
+    }
+
+    private static MessageDigest newDigest()
+    {
+        try
+        {
+            return MessageDigest.getInstance( "SHA-1" );
+        }
+        catch ( NoSuchAlgorithmException e )
+        {
+            try
+            {
+                return MessageDigest.getInstance( "MD5" );
+            }
+            catch ( NoSuchAlgorithmException ne )
+            {
+                throw new IllegalStateException( ne );
+            }
+        }
+    }
+
+    /**
+     * Gets the repository system session during which the authentication fingerprint is calculated.
+     * 
+     * @return The repository system session, never {@code null}.
+     */
+    public RepositorySystemSession getSession()
+    {
+        return session;
+    }
+
+    /**
+     * Gets the repository requiring authentication. If {@link #getProxy()} is not {@code null}, the data gathered by
+     * this authentication digest does not apply to the repository's host but rather the proxy.
+     * 
+     * @return The repository to be contacted, never {@code null}.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Gets the proxy (if any) to be authenticated with.
+     * 
+     * @return The proxy or {@code null} if authenticating directly with the repository's host.
+     */
+    public Proxy getProxy()
+    {
+        return proxy;
+    }
+
+    /**
+     * Updates the digest with the specified strings.
+     * 
+     * @param strings The strings to update the digest with, may be {@code null} or contain {@code null} elements.
+     */
+    public void update( String... strings )
+    {
+        if ( strings != null )
+        {
+            for ( String string : strings )
+            {
+                if ( string != null )
+                {
+                    try
+                    {
+                        digest.update( string.getBytes( "UTF-8" ) );
+                    }
+                    catch ( UnsupportedEncodingException e )
+                    {
+                        throw new IllegalStateException( e );
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the digest with the specified characters.
+     * 
+     * @param chars The characters to update the digest with, may be {@code null}.
+     */
+    public void update( char... chars )
+    {
+        if ( chars != null )
+        {
+            for ( char c : chars )
+            {
+                digest.update( (byte) ( c >> 8 ) );
+                digest.update( (byte) ( c & 0xFF ) );
+            }
+        }
+    }
+
+    /**
+     * Updates the digest with the specified bytes.
+     * 
+     * @param bytes The bytes to update the digest with, may be {@code null}.
+     */
+    public void update( byte... bytes )
+    {
+        if ( bytes != null )
+        {
+            digest.update( bytes );
+        }
+    }
+
+    private String digest()
+    {
+        byte[] bytes = digest.digest();
+        StringBuilder buffer = new StringBuilder( bytes.length * 2 );
+        for ( byte aByte : bytes )
+        {
+            int b = aByte & 0xFF;
+            if ( b < 0x10 )
+            {
+                buffer.append( '0' );
+            }
+            buffer.append( Integer.toHexString( b ) );
+        }
+        return buffer.toString();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/AuthenticationSelector.java
new file mode 100644 (file)
index 0000000..46c9bab
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * Selects authentication for a given remote repository.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getAuthenticationSelector()
+ */
+public interface AuthenticationSelector
+{
+
+    /**
+     * Selects authentication for the specified remote repository.
+     * 
+     * @param repository The repository for which to select authentication, must not be {@code null}.
+     * @return The selected authentication or {@code null} if none.
+     */
+    Authentication getAuthentication( RemoteRepository repository );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRegistration.java
new file mode 100644 (file)
index 0000000..af6ea4e
--- /dev/null
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * A request to register an artifact within the local repository. Certain local repository implementations can refuse to
+ * serve physically present artifacts if those haven't been previously registered to them.
+ * 
+ * @see LocalRepositoryManager#add(RepositorySystemSession, LocalArtifactRegistration)
+ */
+public final class LocalArtifactRegistration
+{
+
+    private Artifact artifact;
+
+    private RemoteRepository repository;
+
+    private Collection<String> contexts = Collections.emptyList();
+
+    /**
+     * Creates an uninitialized registration.
+     */
+    public LocalArtifactRegistration()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a registration request for the specified (locally installed) artifact.
+     * 
+     * @param artifact The artifact to register, may be {@code null}.
+     */
+    public LocalArtifactRegistration( Artifact artifact )
+    {
+        setArtifact( artifact );
+    }
+
+    /**
+     * Creates a registration request for the specified artifact.
+     * 
+     * @param artifact The artifact to register, may be {@code null}.
+     * @param repository The remote repository from which the artifact was resolved or {@code null} if the artifact was
+     *            locally installed.
+     * @param contexts The resolution contexts, may be {@code null}.
+     */
+    public LocalArtifactRegistration( Artifact artifact, RemoteRepository repository, Collection<String> contexts )
+    {
+        setArtifact( artifact );
+        setRepository( repository );
+        setContexts( contexts );
+    }
+
+    /**
+     * Gets the artifact to register.
+     * 
+     * @return The artifact or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact to register.
+     * 
+     * @param artifact The artifact, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalArtifactRegistration setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the remote repository from which the artifact was resolved.
+     * 
+     * @return The remote repository or {@code null} if the artifact was locally installed.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the remote repository from which the artifact was resolved.
+     * 
+     * @param repository The remote repository or {@code null} if the artifact was locally installed.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalArtifactRegistration setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    /**
+     * Gets the resolution contexts in which the artifact is available.
+     * 
+     * @return The resolution contexts in which the artifact is available, never {@code null}.
+     */
+    public Collection<String> getContexts()
+    {
+        return contexts;
+    }
+
+    /**
+     * Sets the resolution contexts in which the artifact is available.
+     * 
+     * @param contexts The resolution contexts, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalArtifactRegistration setContexts( Collection<String> contexts )
+    {
+        if ( contexts != null )
+        {
+            this.contexts = contexts;
+        }
+        else
+        {
+            this.contexts = Collections.emptyList();
+        }
+        return this;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactRequest.java
new file mode 100644 (file)
index 0000000..3cc67f8
--- /dev/null
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * A query to the local repository for the existence of an artifact.
+ * 
+ * @see LocalRepositoryManager#find(RepositorySystemSession, LocalArtifactRequest)
+ */
+public final class LocalArtifactRequest
+{
+
+    private Artifact artifact;
+
+    private String context = "";
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    /**
+     * Creates an uninitialized query.
+     */
+    public LocalArtifactRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a query with the specified properties.
+     * 
+     * @param artifact The artifact to query for, may be {@code null}.
+     * @param repositories The remote repositories that should be considered as potential sources for the artifact, may
+     *            be {@code null} or empty to only consider locally installed artifacts.
+     * @param context The resolution context for the artifact, may be {@code null}.
+     */
+    public LocalArtifactRequest( Artifact artifact, List<RemoteRepository> repositories, String context )
+    {
+        setArtifact( artifact );
+        setRepositories( repositories );
+        setContext( context );
+    }
+
+    /**
+     * Gets the artifact to query for.
+     * 
+     * @return The artifact or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact to query for.
+     * 
+     * @param artifact The artifact, may be {@code null}.
+     * @return This query for chaining, never {@code null}.
+     */
+    public LocalArtifactRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the resolution context.
+     * 
+     * @return The resolution context, never {@code null}.
+     */
+    public String getContext()
+    {
+        return context;
+    }
+
+    /**
+     * Sets the resolution context.
+     * 
+     * @param context The resolution context, may be {@code null}.
+     * @return This query for chaining, never {@code null}.
+     */
+    public LocalArtifactRequest setContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    /**
+     * Gets the remote repositories to consider as sources of the artifact.
+     * 
+     * @return The remote repositories, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the remote repositories to consider as sources of the artifact.
+     * 
+     * @param repositories The remote repositories, may be {@code null} or empty to only consider locally installed
+     *            artifacts.
+     * @return This query for chaining, never {@code null}.
+     */
+    public LocalArtifactRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories != null )
+        {
+            this.repositories = repositories;
+        }
+        else
+        {
+            this.repositories = Collections.emptyList();
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " @ " + getRepositories();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalArtifactResult.java
new file mode 100644 (file)
index 0000000..065b823
--- /dev/null
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.io.File;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A result from the local repository about the existence of an artifact.
+ * 
+ * @see LocalRepositoryManager#find(RepositorySystemSession, LocalArtifactRequest)
+ */
+public final class LocalArtifactResult
+{
+
+    private final LocalArtifactRequest request;
+
+    private File file;
+
+    private boolean available;
+
+    private RemoteRepository repository;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The local artifact request, must not be {@code null}.
+     */
+    public LocalArtifactResult( LocalArtifactRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "local artifact request has not been specified" );
+        }
+        this.request = request;
+    }
+
+    /**
+     * Gets the request corresponding to this result.
+     * 
+     * @return The corresponding request, never {@code null}.
+     */
+    public LocalArtifactRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the file to the requested artifact. Note that this file must not be used unless {@link #isAvailable()}
+     * returns {@code true}. An artifact file can be found but considered unavailable if the artifact was cached from a
+     * remote repository that is not part of the list of remote repositories used for the query.
+     * 
+     * @return The file to the requested artifact or {@code null} if the artifact does not exist locally.
+     */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /**
+     * Sets the file to requested artifact.
+     * 
+     * @param file The artifact file, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public LocalArtifactResult setFile( File file )
+    {
+        this.file = file;
+        return this;
+    }
+
+    /**
+     * Indicates whether the requested artifact is available for use. As a minimum, the file needs to be physically
+     * existent in the local repository to be available. Additionally, a local repository manager can consider the list
+     * of supplied remote repositories to determine whether the artifact is logically available and mark an artifact
+     * unavailable (despite its physical existence) if it is not known to be hosted by any of the provided repositories.
+     * 
+     * @return {@code true} if the artifact is available, {@code false} otherwise.
+     * @see LocalArtifactRequest#getRepositories()
+     */
+    public boolean isAvailable()
+    {
+        return available;
+    }
+
+    /**
+     * Sets whether the artifact is available.
+     * 
+     * @param available {@code true} if the artifact is available, {@code false} otherwise.
+     * @return This result for chaining, never {@code null}.
+     */
+    public LocalArtifactResult setAvailable( boolean available )
+    {
+        this.available = available;
+        return this;
+    }
+
+    /**
+     * Gets the (first) remote repository from which the artifact was cached (if any).
+     * 
+     * @return The remote repository from which the artifact was originally retrieved or {@code null} if unknown or if
+     *         the artifact has been locally installed.
+     * @see LocalArtifactRequest#getRepositories()
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the (first) remote repository from which the artifact was cached.
+     * 
+     * @param repository The remote repository from which the artifact was originally retrieved, may be {@code null} if
+     *            unknown or if the artifact has been locally installed.
+     * @return This result for chaining, never {@code null}.
+     */
+    public LocalArtifactResult setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getFile() + " (" + ( isAvailable() ? "available" : "unavailable" ) + ")";
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRegistration.java
new file mode 100644 (file)
index 0000000..a01ba3e
--- /dev/null
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * A request to register metadata within the local repository.
+ * 
+ * @see LocalRepositoryManager#add(RepositorySystemSession, LocalMetadataRegistration)
+ */
+public final class LocalMetadataRegistration
+{
+
+    private Metadata metadata;
+
+    private RemoteRepository repository;
+
+    private Collection<String> contexts = Collections.emptyList();
+
+    /**
+     * Creates an uninitialized registration.
+     */
+    public LocalMetadataRegistration()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a registration request for the specified metadata accompanying a locally installed artifact.
+     * 
+     * @param metadata The metadata to register, may be {@code null}.
+     */
+    public LocalMetadataRegistration( Metadata metadata )
+    {
+        setMetadata( metadata );
+    }
+
+    /**
+     * Creates a registration request for the specified metadata.
+     * 
+     * @param metadata The metadata to register, may be {@code null}.
+     * @param repository The remote repository from which the metadata was resolved or {@code null} if the metadata
+     *            accompanies a locally installed artifact.
+     * @param contexts The resolution contexts, may be {@code null}.
+     */
+    public LocalMetadataRegistration( Metadata metadata, RemoteRepository repository, Collection<String> contexts )
+    {
+        setMetadata( metadata );
+        setRepository( repository );
+        setContexts( contexts );
+    }
+
+    /**
+     * Gets the metadata to register.
+     * 
+     * @return The metadata or {@code null} if not set.
+     */
+    public Metadata getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to register.
+     * 
+     * @param metadata The metadata, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalMetadataRegistration setMetadata( Metadata metadata )
+    {
+        this.metadata = metadata;
+        return this;
+    }
+
+    /**
+     * Gets the remote repository from which the metadata was resolved.
+     * 
+     * @return The remote repository or {@code null} if the metadata was locally installed.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the remote repository from which the metadata was resolved.
+     * 
+     * @param repository The remote repository or {@code null} if the metadata accompanies a locally installed artifact.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalMetadataRegistration setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    /**
+     * Gets the resolution contexts in which the metadata is available.
+     * 
+     * @return The resolution contexts in which the metadata is available, never {@code null}.
+     */
+    public Collection<String> getContexts()
+    {
+        return contexts;
+    }
+
+    /**
+     * Sets the resolution contexts in which the metadata is available.
+     * 
+     * @param contexts The resolution contexts, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public LocalMetadataRegistration setContexts( Collection<String> contexts )
+    {
+        if ( contexts != null )
+        {
+            this.contexts = contexts;
+        }
+        else
+        {
+            this.contexts = Collections.emptyList();
+        }
+        return this;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataRequest.java
new file mode 100644 (file)
index 0000000..0ee4dc5
--- /dev/null
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * A query to the local repository for the existence of metadata.
+ * 
+ * @see LocalRepositoryManager#find(RepositorySystemSession, LocalMetadataRequest)
+ */
+public final class LocalMetadataRequest
+{
+
+    private Metadata metadata;
+
+    private String context = "";
+
+    private RemoteRepository repository = null;
+
+    /**
+     * Creates an uninitialized query.
+     */
+    public LocalMetadataRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a query with the specified properties.
+     * 
+     * @param metadata The metadata to query for, may be {@code null}.
+     * @param repository The source remote repository for the metadata, may be {@code null} for local metadata.
+     * @param context The resolution context for the metadata, may be {@code null}.
+     */
+    public LocalMetadataRequest( Metadata metadata, RemoteRepository repository, String context )
+    {
+        setMetadata( metadata );
+        setRepository( repository );
+        setContext( context );
+    }
+
+    /**
+     * Gets the metadata to query for.
+     * 
+     * @return The metadata or {@code null} if not set.
+     */
+    public Metadata getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to query for.
+     * 
+     * @param metadata The metadata, may be {@code null}.
+     * @return This query for chaining, never {@code null}.
+     */
+    public LocalMetadataRequest setMetadata( Metadata metadata )
+    {
+        this.metadata = metadata;
+        return this;
+    }
+
+    /**
+     * Gets the resolution context.
+     * 
+     * @return The resolution context, never {@code null}.
+     */
+    public String getContext()
+    {
+        return context;
+    }
+
+    /**
+     * Sets the resolution context.
+     * 
+     * @param context The resolution context, may be {@code null}.
+     * @return This query for chaining, never {@code null}.
+     */
+    public LocalMetadataRequest setContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    /**
+     * Gets the remote repository to use as source of the metadata.
+     * 
+     * @return The remote repositories, may be {@code null} for local metadata.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the remote repository to use as sources of the metadata.
+     * 
+     * @param repository The remote repository, may be {@code null}.
+     * @return This query for chaining, may be {@code null} for local metadata.
+     */
+    public LocalMetadataRequest setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getMetadata() + " @ " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalMetadataResult.java
new file mode 100644 (file)
index 0000000..6f3687a
--- /dev/null
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.io.File;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * A result from the local repository about the existence of metadata.
+ * 
+ * @see LocalRepositoryManager#find(RepositorySystemSession, LocalMetadataRequest)
+ */
+public final class LocalMetadataResult
+{
+
+    private final LocalMetadataRequest request;
+
+    private File file;
+
+    private boolean stale;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The local metadata request, must not be {@code null}.
+     */
+    public LocalMetadataResult( LocalMetadataRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "local metadata request has not been specified" );
+        }
+        this.request = request;
+    }
+
+    /**
+     * Gets the request corresponding to this result.
+     * 
+     * @return The corresponding request, never {@code null}.
+     */
+    public LocalMetadataRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the file to the requested metadata if the metadata is available in the local repository.
+     * 
+     * @return The file to the requested metadata or {@code null}.
+     */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /**
+     * Sets the file to requested metadata.
+     * 
+     * @param file The metadata file, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public LocalMetadataResult setFile( File file )
+    {
+        this.file = file;
+        return this;
+    }
+
+    /**
+     * This value indicates whether the metadata is stale and should be updated.
+     * 
+     * @return {@code true} if the metadata is stale and should be updated, {@code false} otherwise.
+     */
+    public boolean isStale()
+    {
+        return stale;
+    }
+
+    /**
+     * Sets whether the metadata is stale.
+     * 
+     * @param stale {@code true} if the metadata is stale and should be updated, {@code false} otherwise.
+     * @return This result for chaining, never {@code null}.
+     */
+    public LocalMetadataResult setStale( boolean stale )
+    {
+        this.stale = stale;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return request.toString() + "(" + getFile() + ")";
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepository.java
new file mode 100644 (file)
index 0000000..91b09d8
--- /dev/null
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+import java.io.File;
+
+/**
+ * A repository on the local file system used to cache contents of remote repositories and to store locally installed
+ * artifacts. Note that this class merely describes such a repository, actual access to the contained artifacts is
+ * handled by a {@link LocalRepositoryManager} which is usually determined from the {@link #getContentType() type} of
+ * the repository.
+ */
+public final class LocalRepository
+    implements ArtifactRepository
+{
+
+    private final File basedir;
+
+    private final String type;
+
+    /**
+     * Creates a new local repository with the specified base directory and unknown type.
+     * 
+     * @param basedir The base directory of the repository, may be {@code null}.
+     */
+    public LocalRepository( String basedir )
+    {
+        this( ( basedir != null ) ? new File( basedir ) : null, "" );
+    }
+
+    /**
+     * Creates a new local repository with the specified base directory and unknown type.
+     * 
+     * @param basedir The base directory of the repository, may be {@code null}.
+     */
+    public LocalRepository( File basedir )
+    {
+        this( basedir, "" );
+    }
+
+    /**
+     * Creates a new local repository with the specified properties.
+     * 
+     * @param basedir The base directory of the repository, may be {@code null}.
+     * @param type The type of the repository, may be {@code null}.
+     */
+    public LocalRepository( File basedir, String type )
+    {
+        this.basedir = basedir;
+        this.type = ( type != null ) ? type : "";
+    }
+
+    public String getContentType()
+    {
+        return type;
+    }
+
+    public String getId()
+    {
+        return "local";
+    }
+
+    /**
+     * Gets the base directory of the repository.
+     * 
+     * @return The base directory or {@code null} if none.
+     */
+    public File getBasedir()
+    {
+        return basedir;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getBasedir() + " (" + getContentType() + ")";
+    }
+
+    @Override
+    public boolean equals( Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null || !getClass().equals( obj.getClass() ) )
+        {
+            return false;
+        }
+
+        LocalRepository that = (LocalRepository) obj;
+
+        return eq( basedir, that.basedir ) && eq( type, that.type );
+    }
+
+    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( basedir );
+        hash = hash * 31 + hash( type );
+        return hash;
+    }
+
+    private static int hash( Object obj )
+    {
+        return obj != null ? obj.hashCode() : 0;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/LocalRepositoryManager.java
new file mode 100644 (file)
index 0000000..d9d8777
--- /dev/null
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/MirrorSelector.java
new file mode 100644 (file)
index 0000000..1614acc
--- /dev/null
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * 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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/NoLocalRepositoryManagerException.java
new file mode 100644 (file)
index 0000000..203ccfb
--- /dev/null
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/Proxy.java
new file mode 100644 (file)
index 0000000..b575bbc
--- /dev/null
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * 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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/ProxySelector.java
new file mode 100644 (file)
index 0000000..680474c
--- /dev/null
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * 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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RemoteRepository.java
new file mode 100644 (file)
index 0000000..aaa9acc
--- /dev/null
@@ -0,0 +1,573 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+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;
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/RepositoryPolicy.java
new file mode 100644 (file)
index 0000000..05224a8
--- /dev/null
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+/**
+ * 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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceReader.java
new file mode 100644 (file)
index 0000000..570f6b6
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/WorkspaceRepository.java
new file mode 100644 (file)
index 0000000..811c589
--- /dev/null
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.repository;
+
+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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/repository/package-info.java
new file mode 100644 (file)
index 0000000..21ab2bc
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The definition of various kinds of repositories that host artifacts.
+ */
+package org.eclipse.aether.repository;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorException.java
new file mode 100644 (file)
index 0000000..7dae7f4
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicy.java
new file mode 100644 (file)
index 0000000..ec519fe
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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 );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorPolicyRequest.java
new file mode 100644 (file)
index 0000000..2edf0c5
--- /dev/null
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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() );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorRequest.java
new file mode 100644 (file)
index 0000000..9a1ba65
--- /dev/null
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactDescriptorResult.java
new file mode 100644 (file)
index 0000000..3de8d5e
--- /dev/null
@@ -0,0 +1,457 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactRequest.java
new file mode 100644 (file)
index 0000000..6076ea5
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to resolve an artifact.
+ * 
+ * @see RepositorySystem#resolveArtifacts(RepositorySystemSession, java.util.Collection)
+ * @see Artifact#getFile()
+ */
+public final class ArtifactRequest
+{
+
+    private Artifact artifact;
+
+    private DependencyNode node;
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public ArtifactRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param artifact The artifact to resolve, may be {@code null}.
+     * @param repositories The repositories to resolve the artifact from, may be {@code null}.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public ArtifactRequest( Artifact artifact, List<RemoteRepository> repositories, String context )
+    {
+        setArtifact( artifact );
+        setRepositories( repositories );
+        setRequestContext( context );
+    }
+
+    /**
+     * Creates a request from the specified dependency node.
+     * 
+     * @param node The dependency node to resolve, may be {@code null}.
+     */
+    public ArtifactRequest( DependencyNode node )
+    {
+        setDependencyNode( node );
+        setRepositories( node.getRepositories() );
+        setRequestContext( node.getRequestContext() );
+    }
+
+    /**
+     * Gets the artifact to resolve.
+     * 
+     * @return The artifact to resolve or {@code null}.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact to resolve.
+     * 
+     * @param artifact The artifact to resolve, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the dependency node (if any) for which to resolve the artifact.
+     * 
+     * @return The dependency node to resolve or {@code null} if unknown.
+     */
+    public DependencyNode getDependencyNode()
+    {
+        return node;
+    }
+
+    /**
+     * Sets the dependency node to resolve.
+     * 
+     * @param node The dependency node to resolve, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactRequest setDependencyNode( DependencyNode node )
+    {
+        this.node = node;
+        if ( node != null )
+        {
+            setArtifact( node.getDependency().getArtifact() );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repositories to resolve the artifact from.
+     * 
+     * @return The repositories, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to resolve the artifact from.
+     * 
+     * @param repositories The repositories, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for the resolution.
+     * 
+     * @param repository The repository to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ArtifactRequest 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 ArtifactRequest 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 ArtifactRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " < " + getRepositories();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResolutionException.java
new file mode 100644 (file)
index 0000000..67d0514
--- /dev/null
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.transfer.ArtifactNotFoundException;
+import org.eclipse.aether.transfer.RepositoryOfflineException;
+
+/**
+ * Thrown in case of a unresolvable artifacts.
+ */
+public class ArtifactResolutionException
+    extends RepositoryException
+{
+
+    private final transient List<ArtifactResult> results;
+
+    /**
+     * Creates a new exception with the specified results.
+     * 
+     * @param results The resolution results at the point the exception occurred, may be {@code null}.
+     */
+    public ArtifactResolutionException( List<ArtifactResult> results )
+    {
+        super( getMessage( results ), getCause( results ) );
+        this.results = ( results != null ) ? results : Collections.<ArtifactResult> emptyList();
+    }
+
+    /**
+     * Creates a new exception with the specified results and detail message.
+     * 
+     * @param results The resolution results at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public ArtifactResolutionException( List<ArtifactResult> results, String message )
+    {
+        super( message, getCause( results ) );
+        this.results = ( results != null ) ? results : Collections.<ArtifactResult> emptyList();
+    }
+
+    /**
+     * Creates a new exception with the specified results, detail message and cause.
+     * 
+     * @param results The resolution results 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 ArtifactResolutionException( List<ArtifactResult> results, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.results = ( results != null ) ? results : Collections.<ArtifactResult> emptyList();
+    }
+
+    /**
+     * Gets the resolution results at the point the exception occurred. Despite being incomplete, callers might want to
+     * use these results to fail gracefully and continue their operation with whatever interim data has been gathered.
+     * 
+     * @return The resolution results or {@code null} if unknown.
+     */
+    public List<ArtifactResult> getResults()
+    {
+        return results;
+    }
+
+    /**
+     * Gets the first result from {@link #getResults()}. This is a convenience method for cases where callers know only
+     * a single result/request is involved.
+     * 
+     * @return The (first) resolution result or {@code null} if none.
+     */
+    public ArtifactResult getResult()
+    {
+        return ( results != null && !results.isEmpty() ) ? results.get( 0 ) : null;
+    }
+
+    private static String getMessage( List<? extends ArtifactResult> results )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+
+        buffer.append( "The following artifacts could not be resolved: " );
+
+        int unresolved = 0;
+
+        String sep = "";
+        for ( ArtifactResult result : results )
+        {
+            if ( !result.isResolved() )
+            {
+                unresolved++;
+
+                buffer.append( sep );
+                buffer.append( result.getRequest().getArtifact() );
+                sep = ", ";
+            }
+        }
+
+        Throwable cause = getCause( results );
+        if ( cause != null )
+        {
+            if ( unresolved == 1 )
+            {
+                buffer.setLength( 0 );
+                buffer.append( cause.getMessage() );
+            }
+            else
+            {
+                buffer.append( ": " ).append( cause.getMessage() );
+            }
+        }
+
+        return buffer.toString();
+    }
+
+    private static Throwable getCause( List<? extends ArtifactResult> results )
+    {
+        for ( ArtifactResult result : results )
+        {
+            if ( !result.isResolved() )
+            {
+                Throwable notFound = null, offline = null;
+                for ( Throwable t : result.getExceptions() )
+                {
+                    if ( t instanceof ArtifactNotFoundException )
+                    {
+                        if ( notFound == null )
+                        {
+                            notFound = t;
+                        }
+                        if ( offline == null && t.getCause() instanceof RepositoryOfflineException )
+                        {
+                            offline = t;
+                        }
+                    }
+                    else
+                    {
+                        return t;
+                    }
+
+                }
+                if ( offline != null )
+                {
+                    return offline;
+                }
+                if ( notFound != null )
+                {
+                    return notFound;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ArtifactResult.java
new file mode 100644 (file)
index 0000000..106ffe0
--- /dev/null
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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.artifact.Artifact;
+import org.eclipse.aether.repository.ArtifactRepository;
+import org.eclipse.aether.transfer.ArtifactNotFoundException;
+
+/**
+ * The result of an artifact resolution request.
+ * 
+ * @see RepositorySystem#resolveArtifacts(RepositorySystemSession, java.util.Collection)
+ * @see Artifact#getFile()
+ */
+public final class ArtifactResult
+{
+
+    private final ArtifactRequest request;
+
+    private List<Exception> exceptions;
+
+    private Artifact artifact;
+
+    private ArtifactRepository repository;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public ArtifactResult( ArtifactRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "resolution request has not been specified" );
+        }
+        this.request = request;
+        exceptions = Collections.emptyList();
+    }
+
+    /**
+     * Gets the resolution request that was made.
+     * 
+     * @return The resolution request, never {@code null}.
+     */
+    public ArtifactRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the resolved artifact (if any). Use {@link #getExceptions()} to query the errors that occurred while trying
+     * to resolve the artifact.
+     * 
+     * @return The resolved artifact or {@code null} if the resolution failed.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the resolved artifact.
+     * 
+     * @param artifact The resolved artifact, may be {@code null} if the resolution failed.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactResult setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the exceptions that occurred while resolving the artifact. Note that this list can be non-empty even if the
+     * artifact was successfully resolved, e.g. when one of the contacted remote repositories didn't contain the
+     * artifact but a later repository eventually contained it.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     * @see #isResolved()
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Records the specified exception while resolving the artifact.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the repository from which the artifact was eventually resolved. Note that successive resolutions of the same
+     * artifact might yield different results if the employed local repository does not track the origin of an artifact.
+     * 
+     * @return The repository from which the artifact was resolved or {@code null} if unknown.
+     */
+    public ArtifactRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository from which the artifact was resolved.
+     * 
+     * @param repository The repository from which the artifact was resolved, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public ArtifactResult setRepository( ArtifactRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    /**
+     * Indicates whether the requested artifact was resolved. Note that the artifact might have been successfully
+     * resolved despite {@link #getExceptions()} indicating transfer errors while trying to fetch the artifact from some
+     * of the specified remote repositories.
+     * 
+     * @return {@code true} if the artifact was resolved, {@code false} otherwise.
+     * @see Artifact#getFile()
+     */
+    public boolean isResolved()
+    {
+        return getArtifact() != null && getArtifact().getFile() != null;
+    }
+
+    /**
+     * Indicates whether the requested artifact is not present in any of the specified repositories.
+     * 
+     * @return {@code true} if the artifact is not present in any repository, {@code false} otherwise.
+     */
+    public boolean isMissing()
+    {
+        for ( Exception e : getExceptions() )
+        {
+            if ( !( e instanceof ArtifactNotFoundException ) )
+            {
+                return false;
+            }
+        }
+        return !isResolved();
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " < " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyRequest.java
new file mode 100644 (file)
index 0000000..f55aff7
--- /dev/null
@@ -0,0 +1,178 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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.collection.CollectRequest;
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * A request to resolve transitive dependencies. This request can either be supplied with a {@link CollectRequest} to
+ * calculate the transitive dependencies or with an already resolved dependency graph.
+ * 
+ * @see RepositorySystem#resolveDependencies(RepositorySystemSession, DependencyRequest)
+ * @see Artifact#getFile()
+ */
+public final class DependencyRequest
+{
+
+    private DependencyNode root;
+
+    private CollectRequest collectRequest;
+
+    private DependencyFilter filter;
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request. Note that either {@link #setRoot(DependencyNode)} or
+     * {@link #setCollectRequest(CollectRequest)} must eventually be called to create a valid request.
+     */
+    public DependencyRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request for the specified dependency graph and with the given resolution filter.
+     * 
+     * @param node The root node of the dependency graph whose artifacts should be resolved, may be {@code null}.
+     * @param filter The resolution filter to use, may be {@code null}.
+     */
+    public DependencyRequest( DependencyNode node, DependencyFilter filter )
+    {
+        setRoot( node );
+        setFilter( filter );
+    }
+
+    /**
+     * Creates a request for the specified collect request and with the given resolution filter.
+     * 
+     * @param request The collect request used to calculate the dependency graph whose artifacts should be resolved, may
+     *            be {@code null}.
+     * @param filter The resolution filter to use, may be {@code null}.
+     */
+    public DependencyRequest( CollectRequest request, DependencyFilter filter )
+    {
+        setCollectRequest( request );
+        setFilter( filter );
+    }
+
+    /**
+     * Gets the root node of the dependency graph whose artifacts should be resolved.
+     * 
+     * @return The root node of the dependency graph or {@code null} if none.
+     */
+    public DependencyNode getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root node of the dependency graph whose artifacts should be resolved. When this request is processed,
+     * the nodes of the given dependency graph will be updated to refer to the resolved artifacts. Eventually, either
+     * {@link #setRoot(DependencyNode)} or {@link #setCollectRequest(CollectRequest)} must be called to create a valid
+     * request.
+     * 
+     * @param root The root node of the dependency graph, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DependencyRequest setRoot( DependencyNode root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    /**
+     * Gets the collect request used to calculate the dependency graph whose artifacts should be resolved.
+     * 
+     * @return The collect request or {@code null} if none.
+     */
+    public CollectRequest getCollectRequest()
+    {
+        return collectRequest;
+    }
+
+    /**
+     * Sets the collect request used to calculate the dependency graph whose artifacts should be resolved. Eventually,
+     * either {@link #setRoot(DependencyNode)} or {@link #setCollectRequest(CollectRequest)} must be called to create a
+     * valid request. If this request is supplied with a dependency node via {@link #setRoot(DependencyNode)}, the
+     * collect request is ignored.
+     * 
+     * @param collectRequest The collect request, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DependencyRequest setCollectRequest( CollectRequest collectRequest )
+    {
+        this.collectRequest = collectRequest;
+        return this;
+    }
+
+    /**
+     * Gets the resolution filter used to select which artifacts of the dependency graph should be resolved.
+     * 
+     * @return The resolution filter or {@code null} to resolve all artifacts of the dependency graph.
+     */
+    public DependencyFilter getFilter()
+    {
+        return filter;
+    }
+
+    /**
+     * Sets the resolution filter used to select which artifacts of the dependency graph should be resolved. For
+     * example, use this filter to restrict resolution to dependencies of a certain scope.
+     * 
+     * @param filter The resolution filter, may be {@code null} to resolve all artifacts of the dependency graph.
+     * @return This request for chaining, never {@code null}.
+     */
+    public DependencyRequest setFilter( DependencyFilter filter )
+    {
+        this.filter = filter;
+        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 DependencyRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        if ( root != null )
+        {
+            return String.valueOf( root );
+        }
+        return String.valueOf( collectRequest );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResolutionException.java
new file mode 100644 (file)
index 0000000..27d9bb2
--- /dev/null
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of a unresolvable dependencies.
+ */
+public class DependencyResolutionException
+    extends RepositoryException
+{
+
+    private final transient DependencyResult result;
+
+    /**
+     * Creates a new exception with the specified result and cause.
+     * 
+     * @param result The dependency result at the point the exception occurred, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public DependencyResolutionException( DependencyResult result, Throwable cause )
+    {
+        super( getMessage( cause ), cause );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result, detail message and cause.
+     * 
+     * @param result The dependency 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 DependencyResolutionException( DependencyResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    private static String getMessage( Throwable cause )
+    {
+        String msg = null;
+        if ( cause != null )
+        {
+            msg = cause.getMessage();
+        }
+        if ( msg == null || msg.length() <= 0 )
+        {
+            msg = "Could not resolve transitive dependencies";
+        }
+        return msg;
+    }
+
+    /**
+     * Gets the dependency 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 dependency result or {@code null} if unknown.
+     */
+    public DependencyResult getResult()
+    {
+        return result;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/DependencyResult.java
new file mode 100644 (file)
index 0000000..3cc8d3a
--- /dev/null
@@ -0,0 +1,186 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.graph.DependencyCycle;
+import org.eclipse.aether.graph.DependencyNode;
+
+/**
+ * The result of a dependency resolution request.
+ * 
+ * @see RepositorySystem#resolveDependencies(RepositorySystemSession, DependencyRequest)
+ */
+public final class DependencyResult
+{
+
+    private final DependencyRequest request;
+
+    private DependencyNode root;
+
+    private List<DependencyCycle> cycles;
+
+    private List<Exception> collectExceptions;
+
+    private List<ArtifactResult> artifactResults;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public DependencyResult( DependencyRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "dependency request has not been specified" );
+        }
+        this.request = request;
+        root = request.getRoot();
+        cycles = Collections.emptyList();
+        collectExceptions = Collections.emptyList();
+        artifactResults = Collections.emptyList();
+    }
+
+    /**
+     * Gets the resolution request that was made.
+     * 
+     * @return The resolution request, never {@code null}.
+     */
+    public DependencyRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the root node of the resolved dependency graph. Note that this dependency graph might be
+     * incomplete/unfinished in case of {@link #getCollectExceptions()} indicating errors during its calculation.
+     * 
+     * @return The root node of the resolved dependency graph or {@code null} if none.
+     */
+    public DependencyNode getRoot()
+    {
+        return root;
+    }
+
+    /**
+     * Sets the root node of the resolved dependency graph.
+     * 
+     * @param root The root node of the resolved dependency graph, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DependencyResult setRoot( DependencyNode root )
+    {
+        this.root = root;
+        return this;
+    }
+
+    /**
+     * Gets the dependency cycles that were encountered while building the dependency graph. Note that dependency cycles
+     * will only be reported here if the underlying request was created from a
+     * {@link org.eclipse.aether.collection.CollectRequest CollectRequest}. If the underlying {@link DependencyRequest}
+     * was created from an existing dependency graph, information about cycles will not be available in this result.
+     * 
+     * @return The dependency cycles in the (raw) graph, never {@code null}.
+     */
+    public List<DependencyCycle> getCycles()
+    {
+        return cycles;
+    }
+
+    /**
+     * Records the specified dependency cycles while building the dependency graph.
+     * 
+     * @param cycles The dependency cycles to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DependencyResult setCycles( List<DependencyCycle> cycles )
+    {
+        if ( cycles == null )
+        {
+            this.cycles = Collections.emptyList();
+        }
+        else
+        {
+            this.cycles = cycles;
+        }
+        return this;
+    }
+
+    /**
+     * Gets the exceptions that occurred while building the dependency graph.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getCollectExceptions()
+    {
+        return collectExceptions;
+    }
+
+    /**
+     * Records the specified exceptions while building the dependency graph.
+     * 
+     * @param exceptions The exceptions to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DependencyResult setCollectExceptions( List<Exception> exceptions )
+    {
+        if ( exceptions == null )
+        {
+            this.collectExceptions = Collections.emptyList();
+        }
+        else
+        {
+            this.collectExceptions = exceptions;
+        }
+        return this;
+    }
+
+    /**
+     * Gets the resolution results for the dependency artifacts that matched {@link DependencyRequest#getFilter()}.
+     * 
+     * @return The resolution results for the dependency artifacts, never {@code null}.
+     */
+    public List<ArtifactResult> getArtifactResults()
+    {
+        return artifactResults;
+    }
+
+    /**
+     * Sets the resolution results for the artifacts that matched {@link DependencyRequest#getFilter()}.
+     * 
+     * @param results The resolution results for the artifacts, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public DependencyResult setArtifactResults( List<ArtifactResult> results )
+    {
+        if ( results == null )
+        {
+            this.artifactResults = Collections.emptyList();
+        }
+        else
+        {
+            this.artifactResults = results;
+        }
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( artifactResults );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataRequest.java
new file mode 100644 (file)
index 0000000..2f6c5f1
--- /dev/null
@@ -0,0 +1,223 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A request to resolve metadata from either a remote repository or the local repository.
+ * 
+ * @see RepositorySystem#resolveMetadata(RepositorySystemSession, java.util.Collection)
+ * @see Metadata#getFile()
+ */
+public final class MetadataRequest
+{
+
+    private Metadata metadata;
+
+    private RemoteRepository repository;
+
+    private String context = "";
+
+    private boolean deleteLocalCopyIfMissing;
+
+    private boolean favorLocalRepository;
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public MetadataRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request to resolve the specified metadata from the local repository.
+     * 
+     * @param metadata The metadata to resolve, may be {@code null}.
+     */
+    public MetadataRequest( Metadata metadata )
+    {
+        setMetadata( metadata );
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param metadata The metadata to resolve, may be {@code null}.
+     * @param repository The repository to resolve the metadata from, may be {@code null} to resolve from the local
+     *            repository.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public MetadataRequest( Metadata metadata, RemoteRepository repository, String context )
+    {
+        setMetadata( metadata );
+        setRepository( repository );
+        setRequestContext( context );
+    }
+
+    /**
+     * Gets the metadata to resolve.
+     * 
+     * @return The metadata or {@code null} if not set.
+     */
+    public Metadata getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the metadata to resolve.
+     * 
+     * @param metadata The metadata, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public MetadataRequest setMetadata( Metadata metadata )
+    {
+        this.metadata = metadata;
+        return this;
+    }
+
+    /**
+     * Gets the repository from which the metadata should be resolved.
+     * 
+     * @return The repository or {@code null} to resolve from the local repository.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository from which the metadata should be resolved.
+     * 
+     * @param repository The repository, may be {@code null} to resolve from the local repository.
+     * @return This request for chaining, never {@code null}.
+     */
+    public MetadataRequest setRepository( RemoteRepository repository )
+    {
+        this.repository = 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 MetadataRequest setRequestContext( String context )
+    {
+        this.context = ( context != null ) ? context : "";
+        return this;
+    }
+
+    /**
+     * Indicates whether the locally cached copy of the metadata should be removed if the corresponding file does not
+     * exist (any more) in the remote repository.
+     * 
+     * @return {@code true} if locally cached metadata should be deleted if no corresponding remote file exists,
+     *         {@code false} to keep the local copy.
+     */
+    public boolean isDeleteLocalCopyIfMissing()
+    {
+        return deleteLocalCopyIfMissing;
+    }
+
+    /**
+     * Controls whether the locally cached copy of the metadata should be removed if the corresponding file does not
+     * exist (any more) in the remote repository.
+     * 
+     * @param deleteLocalCopyIfMissing {@code true} if locally cached metadata should be deleted if no corresponding
+     *            remote file exists, {@code false} to keep the local copy.
+     * @return This request for chaining, never {@code null}.
+     */
+    public MetadataRequest setDeleteLocalCopyIfMissing( boolean deleteLocalCopyIfMissing )
+    {
+        this.deleteLocalCopyIfMissing = deleteLocalCopyIfMissing;
+        return this;
+    }
+
+    /**
+     * Indicates whether the metadata resolution should be suppressed if the corresponding metadata of the local
+     * repository is up-to-date according to the update policy of the remote repository. In this case, the metadata
+     * resolution will even be suppressed if no local copy of the remote metadata exists yet.
+     * 
+     * @return {@code true} to suppress resolution of remote metadata if the corresponding metadata of the local
+     *         repository is up-to-date, {@code false} to resolve the remote metadata normally according to the update
+     *         policy.
+     */
+    public boolean isFavorLocalRepository()
+    {
+        return favorLocalRepository;
+    }
+
+    /**
+     * Controls resolution of remote metadata when already corresponding metadata of the local repository exists. In
+     * cases where the local repository's metadata is sufficient and going to be preferred, resolution of the remote
+     * metadata can be suppressed to avoid unnecessary network access.
+     * 
+     * @param favorLocalRepository {@code true} to suppress resolution of remote metadata if the corresponding metadata
+     *            of the local repository is up-to-date, {@code false} to resolve the remote metadata normally according
+     *            to the update policy.
+     * @return This request for chaining, never {@code null}.
+     */
+    public MetadataRequest setFavorLocalRepository( boolean favorLocalRepository )
+    {
+        this.favorLocalRepository = favorLocalRepository;
+        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 MetadataRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getMetadata() + " < " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/MetadataResult.java
new file mode 100644 (file)
index 0000000..3e5a7b8
--- /dev/null
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.transfer.MetadataNotFoundException;
+
+/**
+ * The result of a metadata resolution request.
+ * 
+ * @see RepositorySystem#resolveMetadata(RepositorySystemSession, java.util.Collection)
+ */
+public final class MetadataResult
+{
+
+    private final MetadataRequest request;
+
+    private Exception exception;
+
+    private boolean updated;
+
+    private Metadata metadata;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public MetadataResult( MetadataRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "metadata request has not been specified" );
+        }
+        this.request = request;
+    }
+
+    /**
+     * Gets the resolution request that was made.
+     * 
+     * @return The resolution request, never {@code null}.
+     */
+    public MetadataRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the resolved metadata (if any).
+     * 
+     * @return The resolved metadata or {@code null} if the resolution failed.
+     */
+    public Metadata getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Sets the resolved metadata.
+     * 
+     * @param metadata The resolved metadata, may be {@code null} if the resolution failed.
+     * @return This result for chaining, never {@code null}.
+     */
+    public MetadataResult setMetadata( Metadata metadata )
+    {
+        this.metadata = metadata;
+        return this;
+    }
+
+    /**
+     * Records the specified exception while resolving the metadata.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public MetadataResult setException( Exception exception )
+    {
+        this.exception = exception;
+        return this;
+    }
+
+    /**
+     * Gets the exception that occurred while resolving the metadata.
+     * 
+     * @return The exception that occurred or {@code null} if none.
+     */
+    public Exception getException()
+    {
+        return exception;
+    }
+
+    /**
+     * Sets the updated flag for the metadata.
+     * 
+     * @param updated {@code true} if the metadata was actually fetched from the remote repository during the
+     *            resolution, {@code false} if the metadata was resolved from a locally cached copy.
+     * @return This result for chaining, never {@code null}.
+     */
+    public MetadataResult setUpdated( boolean updated )
+    {
+        this.updated = updated;
+        return this;
+    }
+
+    /**
+     * Indicates whether the metadata was actually fetched from the remote repository or resolved from the local cache.
+     * If metadata has been locally cached during a previous resolution request and this local copy is still up-to-date
+     * according to the remote repository's update policy, no remote access is made.
+     * 
+     * @return {@code true} if the metadata was actually fetched from the remote repository during the resolution,
+     *         {@code false} if the metadata was resolved from a locally cached copy.
+     */
+    public boolean isUpdated()
+    {
+        return updated;
+    }
+
+    /**
+     * Indicates whether the requested metadata was resolved. Note that the metadata might have been successfully
+     * resolved (from the local cache) despite {@link #getException()} indicating a transfer error while trying to
+     * refetch the metadata from the remote repository.
+     * 
+     * @return {@code true} if the metadata was resolved, {@code false} otherwise.
+     * @see Metadata#getFile()
+     */
+    public boolean isResolved()
+    {
+        return getMetadata() != null && getMetadata().getFile() != null;
+    }
+
+    /**
+     * Indicates whether the requested metadata is not present in the remote repository.
+     * 
+     * @return {@code true} if the metadata is not present in the remote repository, {@code false} otherwise.
+     */
+    public boolean isMissing()
+    {
+        return getException() instanceof MetadataNotFoundException;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getMetadata() + ( isUpdated() ? " (updated)" : " (cached)" );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicy.java
new file mode 100644 (file)
index 0000000..50d1a01
--- /dev/null
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+
+/**
+ * Controls the caching of resolution errors for artifacts/metadata from remote repositories. If caching is enabled for
+ * a given resource, a marker will be set (usually somewhere in the local repository) to suppress repeated resolution
+ * attempts for the broken resource, thereby avoiding expensive but useless network IO. The error marker is considered
+ * stale once the repository's update policy has expired at which point a future resolution attempt will be allowed.
+ * Error caching considers the current network settings such that fixes to the configuration like authentication or
+ * proxy automatically trigger revalidation with the remote side regardless of the time elapsed since the previous
+ * resolution error.
+ * 
+ * @see RepositorySystemSession#getResolutionErrorPolicy()
+ */
+public interface ResolutionErrorPolicy
+{
+
+    /**
+     * Bit mask indicating that resolution errors should not be cached in the local repository. This forces the system
+     * to always query the remote repository for locally missing artifacts/metadata.
+     */
+    int CACHE_DISABLED = 0x00;
+
+    /**
+     * Bit flag indicating whether missing artifacts/metadata should be cached in the local repository. If caching is
+     * enabled, resolution will not be reattempted until the update policy for the affected resource has expired.
+     */
+    int CACHE_NOT_FOUND = 0x01;
+
+    /**
+     * Bit flag indicating whether connectivity/transfer errors (e.g. unreachable host, bad authentication) should be
+     * cached in the local repository. If caching is enabled, resolution will not be reattempted until the update policy
+     * for the affected resource has expired.
+     */
+    int CACHE_TRANSFER_ERROR = 0x02;
+
+    /**
+     * Bit mask indicating that all resolution errors should be cached in the local repository.
+     */
+    int CACHE_ALL = CACHE_NOT_FOUND | CACHE_TRANSFER_ERROR;
+
+    /**
+     * Gets the error policy for an artifact.
+     * 
+     * @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 getArtifactPolicy( RepositorySystemSession session, ResolutionErrorPolicyRequest<Artifact> request );
+
+    /**
+     * Gets the error policy for some metadata.
+     * 
+     * @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 getMetadataPolicy( RepositorySystemSession session, ResolutionErrorPolicyRequest<Metadata> request );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/ResolutionErrorPolicyRequest.java
new file mode 100644 (file)
index 0000000..6d05cf3
--- /dev/null
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * A query for the resolution error policy for a given artifact/metadata.
+ * 
+ * @param <T> The type of the affected repository item (artifact or metadata).
+ * @see ResolutionErrorPolicy
+ */
+public final class ResolutionErrorPolicyRequest<T>
+{
+
+    private T item;
+
+    private RemoteRepository repository;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public ResolutionErrorPolicyRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request for the specified artifact/metadata and remote repository.
+     * 
+     * @param item The artifact/metadata for which to determine the error policy, may be {@code null}.
+     * @param repository The repository from which the resolution is attempted, may be {@code null}.
+     */
+    public ResolutionErrorPolicyRequest( T item, RemoteRepository repository )
+    {
+        setItem( item );
+        setRepository( repository );
+    }
+
+    /**
+     * Gets the artifact/metadata for which to determine the error policy.
+     * 
+     * @return The artifact/metadata for which to determine the error policy or {@code null} if not set.
+     */
+    public T getItem()
+    {
+        return item;
+    }
+
+    /**
+     * Sets the artifact/metadata for which to determine the error policy.
+     * 
+     * @param item The artifact/metadata for which to determine the error policy, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ResolutionErrorPolicyRequest<T> setItem( T item )
+    {
+        this.item = item;
+        return this;
+    }
+
+    /**
+     * Gets the remote repository from which the resolution of the artifact/metadata is attempted.
+     * 
+     * @return The involved remote repository or {@code null} if not set.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the remote repository from which the resolution of the artifact/metadata is attempted.
+     * 
+     * @param repository The repository from which the resolution is attempted, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public ResolutionErrorPolicyRequest<T> setRepository( RemoteRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getItem() + " < " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeRequest.java
new file mode 100644 (file)
index 0000000..b40feb6
--- /dev/null
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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 resolve a version range.
+ * 
+ * @see RepositorySystem#resolveVersionRange(RepositorySystemSession, VersionRangeRequest)
+ */
+public final class VersionRangeRequest
+{
+
+    private Artifact artifact;
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public VersionRangeRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param artifact The artifact whose version range should be resolved, may be {@code null}.
+     * @param repositories The repositories to resolve the version from, may be {@code null}.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public VersionRangeRequest( Artifact artifact, List<RemoteRepository> repositories, String context )
+    {
+        setArtifact( artifact );
+        setRepositories( repositories );
+        setRequestContext( context );
+    }
+
+    /**
+     * Gets the artifact whose version range shall be resolved.
+     * 
+     * @return The artifact or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact whose version range shall be resolved.
+     * 
+     * @param artifact The artifact, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRangeRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the repositories to resolve the version range from.
+     * 
+     * @return The repositories, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to resolve the version range from.
+     * 
+     * @param repositories The repositories, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRangeRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for the resolution.
+     * 
+     * @param repository The repository to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRangeRequest 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 VersionRangeRequest 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 VersionRangeRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " < " + getRepositories();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResolutionException.java
new file mode 100644 (file)
index 0000000..6e62e3f
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of an unparseable or unresolvable version range.
+ */
+public class VersionRangeResolutionException
+    extends RepositoryException
+{
+
+    private final transient VersionRangeResult result;
+
+    /**
+     * Creates a new exception with the specified result.
+     * 
+     * @param result The version range result at the point the exception occurred, may be {@code null}.
+     */
+    public VersionRangeResolutionException( VersionRangeResult result )
+    {
+        super( getMessage( result ), getCause( result ) );
+        this.result = result;
+    }
+
+    private static String getMessage( VersionRangeResult result )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+        buffer.append( "Failed to resolve version range" );
+        if ( result != null )
+        {
+            buffer.append( " for " ).append( result.getRequest().getArtifact() );
+            if ( !result.getExceptions().isEmpty() )
+            {
+                buffer.append( ": " ).append( result.getExceptions().iterator().next().getMessage() );
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static Throwable getCause( VersionRangeResult result )
+    {
+        Throwable cause = null;
+        if ( result != null && !result.getExceptions().isEmpty() )
+        {
+            cause = result.getExceptions().get( 0 );
+        }
+        return cause;
+    }
+
+    /**
+     * Creates a new exception with the specified result and detail message.
+     * 
+     * @param result The version range result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public VersionRangeResolutionException( VersionRangeResult result, String message )
+    {
+        super( message );
+        this.result = result;
+    }
+
+    /**
+     * Creates a new exception with the specified result, detail message and cause.
+     * 
+     * @param result The version range 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 VersionRangeResolutionException( VersionRangeResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    /**
+     * Gets the version range 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 version range result or {@code null} if unknown.
+     */
+    public VersionRangeResult getResult()
+    {
+        return result;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRangeResult.java
new file mode 100644 (file)
index 0000000..fd233f1
--- /dev/null
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.ArtifactRepository;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+
+/**
+ * The result of a version range resolution request.
+ * 
+ * @see RepositorySystem#resolveVersionRange(RepositorySystemSession, VersionRangeRequest)
+ */
+public final class VersionRangeResult
+{
+
+    private final VersionRangeRequest request;
+
+    private List<Exception> exceptions;
+
+    private List<Version> versions;
+
+    private Map<Version, ArtifactRepository> repositories;
+
+    private VersionConstraint versionConstraint;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public VersionRangeResult( VersionRangeRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "version range request has not been specified" );
+        }
+        this.request = request;
+        exceptions = Collections.emptyList();
+        versions = Collections.emptyList();
+        repositories = Collections.emptyMap();
+    }
+
+    /**
+     * Gets the resolution request that was made.
+     * 
+     * @return The resolution request, never {@code null}.
+     */
+    public VersionRangeRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the exceptions that occurred while resolving the version range.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Records the specified exception while resolving the version range.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionRangeResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the versions (in ascending order) that matched the requested range.
+     * 
+     * @return The matching versions (if any), never {@code null}.
+     */
+    public List<Version> getVersions()
+    {
+        return versions;
+    }
+
+    /**
+     * Adds the specified version to the result. Note that versions must be added in ascending order.
+     * 
+     * @param version The version to add, must not be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionRangeResult addVersion( Version version )
+    {
+        if ( versions.isEmpty() )
+        {
+            versions = new ArrayList<Version>();
+        }
+        versions.add( version );
+        return this;
+    }
+
+    /**
+     * Sets the versions (in ascending order) matching the requested range.
+     * 
+     * @param versions The matching versions, may be empty or {@code null} if none.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionRangeResult setVersions( List<Version> versions )
+    {
+        if ( versions == null )
+        {
+            this.versions = Collections.emptyList();
+        }
+        else
+        {
+            this.versions = versions;
+        }
+        return this;
+    }
+
+    /**
+     * Gets the lowest version matching the requested range.
+     * 
+     * @return The lowest matching version or {@code null} if no versions matched the requested range.
+     */
+    public Version getLowestVersion()
+    {
+        if ( versions.isEmpty() )
+        {
+            return null;
+        }
+        return versions.get( 0 );
+    }
+
+    /**
+     * Gets the highest version matching the requested range.
+     * 
+     * @return The highest matching version or {@code null} if no versions matched the requested range.
+     */
+    public Version getHighestVersion()
+    {
+        if ( versions.isEmpty() )
+        {
+            return null;
+        }
+        return versions.get( versions.size() - 1 );
+    }
+
+    /**
+     * Gets the repository from which the specified version was resolved.
+     * 
+     * @param version The version whose source repository should be retrieved, must not be {@code null}.
+     * @return The repository from which the version was resolved or {@code null} if unknown.
+     */
+    public ArtifactRepository getRepository( Version version )
+    {
+        return repositories.get( version );
+    }
+
+    /**
+     * Records the repository from which the specified version was resolved
+     * 
+     * @param version The version whose source repository is to be recorded, must not be {@code null}.
+     * @param repository The repository from which the version was resolved, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionRangeResult setRepository( Version version, ArtifactRepository repository )
+    {
+        if ( repository != null )
+        {
+            if ( repositories.isEmpty() )
+            {
+                repositories = new HashMap<Version, ArtifactRepository>();
+            }
+            repositories.put( version, repository );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the version constraint that was parsed from the artifact's version string.
+     * 
+     * @return The parsed version constraint or {@code null}.
+     */
+    public VersionConstraint getVersionConstraint()
+    {
+        return versionConstraint;
+    }
+
+    /**
+     * Sets the version constraint that was parsed from the artifact's version string.
+     * 
+     * @param versionConstraint The parsed version constraint, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionRangeResult setVersionConstraint( VersionConstraint versionConstraint )
+    {
+        this.versionConstraint = versionConstraint;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.valueOf( repositories );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionRequest.java
new file mode 100644 (file)
index 0000000..e18701b
--- /dev/null
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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 resolve a metaversion.
+ * 
+ * @see RepositorySystem#resolveVersion(RepositorySystemSession, VersionRequest)
+ */
+public final class VersionRequest
+{
+
+    private Artifact artifact;
+
+    private List<RemoteRepository> repositories = Collections.emptyList();
+
+    private String context = "";
+
+    private RequestTrace trace;
+
+    /**
+     * Creates an uninitialized request.
+     */
+    public VersionRequest()
+    {
+        // enables default constructor
+    }
+
+    /**
+     * Creates a request with the specified properties.
+     * 
+     * @param artifact The artifact whose (meta-)version should be resolved, may be {@code null}.
+     * @param repositories The repositories to resolve the version from, may be {@code null}.
+     * @param context The context in which this request is made, may be {@code null}.
+     */
+    public VersionRequest( Artifact artifact, List<RemoteRepository> repositories, String context )
+    {
+        setArtifact( artifact );
+        setRepositories( repositories );
+        setRequestContext( context );
+    }
+
+    /**
+     * Gets the artifact whose (meta-)version shall be resolved.
+     * 
+     * @return The artifact or {@code null} if not set.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Sets the artifact whose (meta-)version shall be resolved.
+     * 
+     * @param artifact The artifact, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRequest setArtifact( Artifact artifact )
+    {
+        this.artifact = artifact;
+        return this;
+    }
+
+    /**
+     * Gets the repositories to resolve the version from.
+     * 
+     * @return The repositories, never {@code null}.
+     */
+    public List<RemoteRepository> getRepositories()
+    {
+        return repositories;
+    }
+
+    /**
+     * Sets the repositories to resolve the version from.
+     * 
+     * @param repositories The repositories, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRequest setRepositories( List<RemoteRepository> repositories )
+    {
+        if ( repositories == null )
+        {
+            this.repositories = Collections.emptyList();
+        }
+        else
+        {
+            this.repositories = repositories;
+        }
+        return this;
+    }
+
+    /**
+     * Adds the specified repository for the resolution.
+     * 
+     * @param repository The repository to add, may be {@code null}.
+     * @return This request for chaining, never {@code null}.
+     */
+    public VersionRequest 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 VersionRequest 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 VersionRequest setTrace( RequestTrace trace )
+    {
+        this.trace = trace;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getArtifact() + " < " + getRepositories();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResolutionException.java
new file mode 100644 (file)
index 0000000..25f381e
--- /dev/null
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of an unresolvable metaversion.
+ */
+public class VersionResolutionException
+    extends RepositoryException
+{
+
+    private final transient VersionResult result;
+
+    /**
+     * Creates a new exception with the specified result.
+     * 
+     * @param result The version result at the point the exception occurred, may be {@code null}.
+     */
+    public VersionResolutionException( VersionResult result )
+    {
+        super( getMessage( result ), getCause( result ) );
+        this.result = result;
+    }
+
+    private static String getMessage( VersionResult result )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+        buffer.append( "Failed to resolve version" );
+        if ( result != null )
+        {
+            buffer.append( " for " ).append( result.getRequest().getArtifact() );
+            if ( !result.getExceptions().isEmpty() )
+            {
+                buffer.append( ": " ).append( result.getExceptions().iterator().next().getMessage() );
+            }
+        }
+        return buffer.toString();
+    }
+
+    private static Throwable getCause( VersionResult result )
+    {
+        Throwable cause = null;
+        if ( result != null && !result.getExceptions().isEmpty() )
+        {
+            cause = result.getExceptions().get( 0 );
+        }
+        return cause;
+    }
+
+    /**
+     * Creates a new exception with the specified result and detail message.
+     * 
+     * @param result The version result at the point the exception occurred, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public VersionResolutionException( VersionResult 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 version 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 VersionResolutionException( VersionResult result, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.result = result;
+    }
+
+    /**
+     * Gets the version 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 version result or {@code null} if unknown.
+     */
+    public VersionResult getResult()
+    {
+        return result;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/VersionResult.java
new file mode 100644 (file)
index 0000000..2e76b1c
--- /dev/null
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.resolution;
+
+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.repository.ArtifactRepository;
+
+/**
+ * The result of a version resolution request.
+ * 
+ * @see RepositorySystem#resolveVersion(RepositorySystemSession, VersionRequest)
+ */
+public final class VersionResult
+{
+
+    private final VersionRequest request;
+
+    private List<Exception> exceptions;
+
+    private String version;
+
+    private ArtifactRepository repository;
+
+    /**
+     * Creates a new result for the specified request.
+     * 
+     * @param request The resolution request, must not be {@code null}.
+     */
+    public VersionResult( VersionRequest request )
+    {
+        if ( request == null )
+        {
+            throw new IllegalArgumentException( "version request has not been specified" );
+        }
+        this.request = request;
+        exceptions = Collections.emptyList();
+    }
+
+    /**
+     * Gets the resolution request that was made.
+     * 
+     * @return The resolution request, never {@code null}.
+     */
+    public VersionRequest getRequest()
+    {
+        return request;
+    }
+
+    /**
+     * Gets the exceptions that occurred while resolving the version.
+     * 
+     * @return The exceptions that occurred, never {@code null}.
+     */
+    public List<Exception> getExceptions()
+    {
+        return exceptions;
+    }
+
+    /**
+     * Records the specified exception while resolving the version.
+     * 
+     * @param exception The exception to record, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionResult addException( Exception exception )
+    {
+        if ( exception != null )
+        {
+            if ( exceptions.isEmpty() )
+            {
+                exceptions = new ArrayList<Exception>();
+            }
+            exceptions.add( exception );
+        }
+        return this;
+    }
+
+    /**
+     * Gets the resolved version.
+     * 
+     * @return The resolved version or {@code null} if the resolution failed.
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+    /**
+     * Sets the resolved version.
+     * 
+     * @param version The resolved version, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionResult setVersion( String version )
+    {
+        this.version = version;
+        return this;
+    }
+
+    /**
+     * Gets the repository from which the version was eventually resolved.
+     * 
+     * @return The repository from which the version was resolved or {@code null} if unknown.
+     */
+    public ArtifactRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Sets the repository from which the version was resolved.
+     * 
+     * @param repository The repository from which the version was resolved, may be {@code null}.
+     * @return This result for chaining, never {@code null}.
+     */
+    public VersionResult setRepository( ArtifactRepository repository )
+    {
+        this.repository = repository;
+        return this;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getVersion() + " @ " + getRepository();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/resolution/package-info.java
new file mode 100644 (file)
index 0000000..84b825b
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The types supporting the resolution of artifacts and metadata from repositories.
+ */
+package org.eclipse.aether.resolution;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/AbstractTransferListener.java
new file mode 100644 (file)
index 0000000..01aff17
--- /dev/null
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+/**
+ * A skeleton implementation for custom transfer listeners. The callback methods in this class do nothing.
+ */
+public abstract class AbstractTransferListener
+    implements TransferListener
+{
+
+    /**
+     * Enables subclassing.
+     */
+    protected AbstractTransferListener()
+    {
+    }
+
+    public void transferInitiated( TransferEvent event )
+        throws TransferCancelledException
+    {
+    }
+
+    public void transferStarted( TransferEvent event )
+        throws TransferCancelledException
+    {
+    }
+
+    public void transferProgressed( TransferEvent event )
+        throws TransferCancelledException
+    {
+    }
+
+    public void transferCorrupted( TransferEvent event )
+        throws TransferCancelledException
+    {
+    }
+
+    public void transferSucceeded( TransferEvent event )
+    {
+    }
+
+    public void transferFailed( TransferEvent event )
+    {
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactNotFoundException.java
new file mode 100644 (file)
index 0000000..3813743
--- /dev/null
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown when an artifact was not found in a particular repository.
+ */
+public class ArtifactNotFoundException
+    extends ArtifactTransferException
+{
+
+    /**
+     * Creates a new exception with the specified artifact and repository.
+     * 
+     * @param artifact The missing artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     */
+    public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository )
+    {
+        super( artifact, repository, getMessage( artifact, repository ) );
+    }
+
+    private static String getMessage( Artifact artifact, RemoteRepository repository )
+    {
+        StringBuilder buffer = new StringBuilder( 256 );
+        buffer.append( "Could not find artifact " ).append( artifact );
+        buffer.append( getString( " in ", repository ) );
+        if ( artifact != null )
+        {
+            String localPath = artifact.getProperty( ArtifactProperties.LOCAL_PATH, null );
+            if ( localPath != null && repository == null )
+            {
+                buffer.append( " at specified path " ).append( localPath );
+            }
+            String downloadUrl = artifact.getProperty( ArtifactProperties.DOWNLOAD_URL, null );
+            if ( downloadUrl != null )
+            {
+                buffer.append( ", try downloading from " ).append( downloadUrl );
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository and detail message.
+     * 
+     * @param artifact The missing artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message )
+    {
+        super( artifact, repository, message );
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository and detail message.
+     * 
+     * @param artifact The missing artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the
+     *            exception actually just occurred.
+     */
+    public ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message, boolean fromCache )
+    {
+        super( artifact, repository, message, fromCache );
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository, detail message and cause.
+     * 
+     * @param artifact The missing artifact, may be {@code null}.
+     * @param repository The involved remote repository, 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 ArtifactNotFoundException( Artifact artifact, RemoteRepository repository, String message, Throwable cause )
+    {
+        super( artifact, repository, message, cause );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ArtifactTransferException.java
new file mode 100644 (file)
index 0000000..5a481ee
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown when an artifact could not be uploaded/downloaded to/from a particular remote repository.
+ */
+public class ArtifactTransferException
+    extends RepositoryException
+{
+
+    private final transient Artifact artifact;
+
+    private final transient RemoteRepository repository;
+
+    private final boolean fromCache;
+
+    static String getString( String prefix, RemoteRepository repository )
+    {
+        if ( repository == null )
+        {
+            return "";
+        }
+        else
+        {
+            return prefix + repository.getId() + " (" + repository.getUrl() + ")";
+        }
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository and detail message.
+     * 
+     * @param artifact The untransferable artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message )
+    {
+        this( artifact, repository, message, false );
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository and detail message.
+     * 
+     * @param artifact The untransferable artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the
+     *            exception actually just occurred.
+     */
+    public ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message, boolean fromCache )
+    {
+        super( message );
+        this.artifact = artifact;
+        this.repository = repository;
+        this.fromCache = fromCache;
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository and cause.
+     * 
+     * @param artifact The untransferable artifact, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public ArtifactTransferException( Artifact artifact, RemoteRepository repository, Throwable cause )
+    {
+        this( artifact, repository, "Could not transfer artifact " + artifact + getString( " from/to ", repository )
+            + getMessage( ": ", cause ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified artifact, repository, detail message and cause.
+     * 
+     * @param artifact The untransferable artifact, may be {@code null}.
+     * @param repository The involved remote repository, 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 ArtifactTransferException( Artifact artifact, RemoteRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.artifact = artifact;
+        this.repository = repository;
+        this.fromCache = false;
+    }
+
+    /**
+     * Gets the artifact that could not be transferred.
+     * 
+     * @return The troublesome artifact or {@code null} if unknown.
+     */
+    public Artifact getArtifact()
+    {
+        return artifact;
+    }
+
+    /**
+     * Gets the remote repository involved in the transfer.
+     * 
+     * @return The involved remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Indicates whether this exception actually just occurred or was played back from the error cache.
+     * 
+     * @return {@code true} if the exception was played back from the error cache, {@code false} if the exception
+     *         actually occurred just now.
+     */
+    public boolean isFromCache()
+    {
+        return fromCache;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/ChecksumFailureException.java
new file mode 100644 (file)
index 0000000..e3f248a
--- /dev/null
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case of a checksum failure during an artifact/metadata download.
+ */
+public class ChecksumFailureException
+    extends RepositoryException
+{
+
+    private final String expected;
+
+    private final String actual;
+
+    private final boolean retryWorthy;
+
+    /**
+     * Creates a new exception with the specified expected and actual checksum. The resulting exception is
+     * {@link #isRetryWorthy() retry-worthy}.
+     * 
+     * @param expected The expected checksum as declared by the hosting repository, may be {@code null}.
+     * @param actual The actual checksum as computed from the local bytes, may be {@code null}.
+     */
+    public ChecksumFailureException( String expected, String actual )
+    {
+        super( "Checksum validation failed, expected " + expected + " but is " + actual );
+        this.expected = expected;
+        this.actual = actual;
+        retryWorthy = true;
+    }
+
+    /**
+     * Creates a new exception with the specified detail message. The resulting exception is not
+     * {@link #isRetryWorthy() retry-worthy}.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public ChecksumFailureException( String message )
+    {
+        this( false, message, null );
+    }
+
+    /**
+     * Creates a new exception with the specified cause. The resulting exception is not {@link #isRetryWorthy()
+     * retry-worthy}.
+     * 
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public ChecksumFailureException( Throwable cause )
+    {
+        this( "Checksum validation failed" + getMessage( ": ", cause ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified detail message and cause. The resulting exception is not
+     * {@link #isRetryWorthy() retry-worthy}.
+     * 
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public ChecksumFailureException( String message, Throwable cause )
+    {
+        this( false, message, cause );
+    }
+
+    /**
+     * Creates a new exception with the specified retry flag, detail message and cause.
+     * 
+     * @param retryWorthy {@code true} if the exception is retry-worthy, {@code false} otherwise.
+     * @param message The detail message, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public ChecksumFailureException( boolean retryWorthy, String message, Throwable cause )
+    {
+        super( message, cause );
+        expected = actual = "";
+        this.retryWorthy = retryWorthy;
+    }
+
+    /**
+     * Gets the expected checksum for the downloaded artifact/metadata.
+     * 
+     * @return The expected checksum as declared by the hosting repository or {@code null} if unknown.
+     */
+    public String getExpected()
+    {
+        return expected;
+    }
+
+    /**
+     * Gets the actual checksum for the downloaded artifact/metadata.
+     * 
+     * @return The actual checksum as computed from the local bytes or {@code null} if unknown.
+     */
+    public String getActual()
+    {
+        return actual;
+    }
+
+    /**
+     * Indicates whether the corresponding download is retry-worthy.
+     * 
+     * @return {@code true} if retrying the download might solve the checksum failure, {@code false} if the checksum
+     *         failure is non-recoverable.
+     */
+    public boolean isRetryWorthy()
+    {
+        return retryWorthy;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataNotFoundException.java
new file mode 100644 (file)
index 0000000..af9a840
--- /dev/null
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown when metadata was not found in a particular repository.
+ */
+public class MetadataNotFoundException
+    extends MetadataTransferException
+{
+
+    /**
+     * Creates a new exception with the specified metadata and local repository.
+     * 
+     * @param metadata The missing metadata, may be {@code null}.
+     * @param repository The involved local repository, may be {@code null}.
+     */
+    public MetadataNotFoundException( Metadata metadata, LocalRepository repository )
+    {
+        super( metadata, null, "Could not find metadata " + metadata + getString( " in ", repository ) );
+    }
+
+    private static String getString( String prefix, LocalRepository repository )
+    {
+        if ( repository == null )
+        {
+            return "";
+        }
+        else
+        {
+            return prefix + repository.getId() + " (" + repository.getBasedir() + ")";
+        }
+    }
+
+    /**
+     * Creates a new exception with the specified metadata and repository.
+     * 
+     * @param metadata The missing metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     */
+    public MetadataNotFoundException( Metadata metadata, RemoteRepository repository )
+    {
+        super( metadata, repository, "Could not find metadata " + metadata + getString( " in ", repository ) );
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository and detail message.
+     * 
+     * @param metadata The missing metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message )
+    {
+        super( metadata, repository, message );
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository and detail message.
+     * 
+     * @param metadata The missing metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the
+     *            exception actually just occurred.
+     */
+    public MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message, boolean fromCache )
+    {
+        super( metadata, repository, message, fromCache );
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository, detail message and cause.
+     * 
+     * @param metadata The missing metadata, may be {@code null}.
+     * @param repository The involved remote repository, 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 MetadataNotFoundException( Metadata metadata, RemoteRepository repository, String message, Throwable cause )
+    {
+        super( metadata, repository, message, cause );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/MetadataTransferException.java
new file mode 100644 (file)
index 0000000..f86b986
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown when metadata could not be uploaded/downloaded to/from a particular remote repository.
+ */
+public class MetadataTransferException
+    extends RepositoryException
+{
+
+    private final transient Metadata metadata;
+
+    private final transient RemoteRepository repository;
+
+    private final boolean fromCache;
+
+    static String getString( String prefix, RemoteRepository repository )
+    {
+        if ( repository == null )
+        {
+            return "";
+        }
+        else
+        {
+            return prefix + repository.getId() + " (" + repository.getUrl() + ")";
+        }
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository and detail message.
+     * 
+     * @param metadata The untransferable metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public MetadataTransferException( Metadata metadata, RemoteRepository repository, String message )
+    {
+        this( metadata, repository, message, false );
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository and detail message.
+     * 
+     * @param metadata The untransferable metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     * @param fromCache {@code true} if the exception was played back from the error cache, {@code false} if the
+     *            exception actually just occurred.
+     */
+    public MetadataTransferException( Metadata metadata, RemoteRepository repository, String message, boolean fromCache )
+    {
+        super( message );
+        this.metadata = metadata;
+        this.repository = repository;
+        this.fromCache = fromCache;
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository and cause.
+     * 
+     * @param metadata The untransferable metadata, may be {@code null}.
+     * @param repository The involved remote repository, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public MetadataTransferException( Metadata metadata, RemoteRepository repository, Throwable cause )
+    {
+        this( metadata, repository, "Could not transfer metadata " + metadata + getString( " from/to ", repository )
+            + getMessage( ": ", cause ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified metadata, repository, detail message and cause.
+     * 
+     * @param metadata The untransferable metadata, may be {@code null}.
+     * @param repository The involved remote repository, 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 MetadataTransferException( Metadata metadata, RemoteRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.metadata = metadata;
+        this.repository = repository;
+        this.fromCache = false;
+    }
+
+    /**
+     * Gets the metadata that could not be transferred.
+     * 
+     * @return The troublesome metadata or {@code null} if unknown.
+     */
+    public Metadata getMetadata()
+    {
+        return metadata;
+    }
+
+    /**
+     * Gets the remote repository involved in the transfer.
+     * 
+     * @return The involved remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+    /**
+     * Indicates whether this exception actually just occurred or was played back from the error cache.
+     * 
+     * @return {@code true} if the exception was played back from the error cache, {@code false} if the exception
+     *         actually occurred just now.
+     */
+    public boolean isFromCache()
+    {
+        return fromCache;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryConnectorException.java
new file mode 100644 (file)
index 0000000..c91be2b
--- /dev/null
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown in case of an unsupported remote repository type.
+ */
+public class NoRepositoryConnectorException
+    extends RepositoryException
+{
+
+    private final transient RemoteRepository repository;
+
+    /**
+     * Creates a new exception with the specified repository.
+     * 
+     * @param repository The remote repository whose content type is not supported, may be {@code null}.
+     */
+    public NoRepositoryConnectorException( RemoteRepository repository )
+    {
+        this( repository, toMessage( repository ) );
+    }
+
+    /**
+     * Creates a new exception with the specified repository and detail message.
+     * 
+     * @param repository The remote repository whose content type is not supported, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public NoRepositoryConnectorException( RemoteRepository repository, String message )
+    {
+        super( message );
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new exception with the specified repository and cause.
+     * 
+     * @param repository The remote repository whose content type is not supported, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public NoRepositoryConnectorException( RemoteRepository repository, Throwable cause )
+    {
+        this( repository, toMessage( repository ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified repository, detail message and cause.
+     * 
+     * @param repository The remote repository whose content type is not supported, 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 NoRepositoryConnectorException( RemoteRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.repository = repository;
+    }
+
+    private static String toMessage( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            return "No connector available to access repository " + repository.getId() + " (" + repository.getUrl()
+                + ") of type " + repository.getContentType();
+        }
+        else
+        {
+            return "No connector available to access repository";
+        }
+    }
+
+    /**
+     * Gets the remote repository whose content type is not supported.
+     * 
+     * @return The unsupported remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoRepositoryLayoutException.java
new file mode 100644 (file)
index 0000000..3176601
--- /dev/null
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown in case of an unsupported repository layout.
+ */
+public class NoRepositoryLayoutException
+    extends RepositoryException
+{
+
+    private final transient RemoteRepository repository;
+
+    /**
+     * Creates a new exception with the specified repository.
+     * 
+     * @param repository The remote repository whose layout is not supported, may be {@code null}.
+     */
+    public NoRepositoryLayoutException( RemoteRepository repository )
+    {
+        this( repository, toMessage( repository ) );
+    }
+
+    /**
+     * Creates a new exception with the specified repository and detail message.
+     * 
+     * @param repository The remote repository whose layout is not supported, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public NoRepositoryLayoutException( RemoteRepository repository, String message )
+    {
+        super( message );
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new exception with the specified repository and cause.
+     * 
+     * @param repository The remote repository whose layout is not supported, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public NoRepositoryLayoutException( RemoteRepository repository, Throwable cause )
+    {
+        this( repository, toMessage( repository ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified repository, detail message and cause.
+     * 
+     * @param repository The remote repository whose layout is not supported, 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 NoRepositoryLayoutException( RemoteRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.repository = repository;
+    }
+
+    private static String toMessage( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            return "Unsupported repository layout " + repository.getContentType();
+        }
+        else
+        {
+            return "Unsupported repository layout";
+        }
+    }
+
+    /**
+     * Gets the remote repository whose layout is not supported.
+     * 
+     * @return The unsupported remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/NoTransporterException.java
new file mode 100644 (file)
index 0000000..895b066
--- /dev/null
@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown in case of an unsupported transport protocol.
+ */
+public class NoTransporterException
+    extends RepositoryException
+{
+
+    private final transient RemoteRepository repository;
+
+    /**
+     * Creates a new exception with the specified repository.
+     * 
+     * @param repository The remote repository whose transport layout is not supported, may be {@code null}.
+     */
+    public NoTransporterException( RemoteRepository repository )
+    {
+        this( repository, toMessage( repository ) );
+    }
+
+    /**
+     * Creates a new exception with the specified repository and detail message.
+     * 
+     * @param repository The remote repository whose transport layout is not supported, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public NoTransporterException( RemoteRepository repository, String message )
+    {
+        super( message );
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new exception with the specified repository and cause.
+     * 
+     * @param repository The remote repository whose transport layout is not supported, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public NoTransporterException( RemoteRepository repository, Throwable cause )
+    {
+        this( repository, toMessage( repository ), cause );
+    }
+
+    /**
+     * Creates a new exception with the specified repository, detail message and cause.
+     * 
+     * @param repository The remote repository whose transport layout is not supported, 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 NoTransporterException( RemoteRepository repository, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.repository = repository;
+    }
+
+    private static String toMessage( RemoteRepository repository )
+    {
+        if ( repository != null )
+        {
+            return "Unsupported transport protocol " + repository.getProtocol();
+        }
+        else
+        {
+            return "Unsupported transport protocol";
+        }
+    }
+
+    /**
+     * Gets the remote repository whose transport protocol is not supported.
+     * 
+     * @return The unsupported remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/RepositoryOfflineException.java
new file mode 100644 (file)
index 0000000..1115054
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * Thrown when a transfer could not be performed because a remote repository is not accessible in offline mode.
+ */
+public class RepositoryOfflineException
+    extends RepositoryException
+{
+
+    private final transient RemoteRepository repository;
+
+    private static String getMessage( RemoteRepository repository )
+    {
+        if ( repository == null )
+        {
+            return "Cannot access remote repositories in offline mode";
+        }
+        else
+        {
+            return "Cannot access " + repository.getId() + " (" + repository.getUrl() + ") in offline mode";
+        }
+    }
+
+    /**
+     * Creates a new exception with the specified repository.
+     * 
+     * @param repository The inaccessible remote repository, may be {@code null}.
+     */
+    public RepositoryOfflineException( RemoteRepository repository )
+    {
+        super( getMessage( repository ) );
+        this.repository = repository;
+    }
+
+    /**
+     * Creates a new exception with the specified repository and detail message.
+     * 
+     * @param repository The inaccessible remote repository, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public RepositoryOfflineException( RemoteRepository repository, String message )
+    {
+        super( message );
+        this.repository = repository;
+    }
+
+    /**
+     * Gets the remote repository that could not be accessed due to offline mode.
+     * 
+     * @return The inaccessible remote repository or {@code null} if unknown.
+     */
+    public RemoteRepository getRepository()
+    {
+        return repository;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferCancelledException.java
new file mode 100644 (file)
index 0000000..5f4ed5b
--- /dev/null
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown in case an upload/download was cancelled (e.g. due to user request).
+ */
+public class TransferCancelledException
+    extends RepositoryException
+{
+
+    /**
+     * Creates a new exception with a stock detail message.
+     */
+    public TransferCancelledException()
+    {
+        super( "The operation was cancelled." );
+    }
+
+    /**
+     * Creates a new exception with the specified detail message.
+     * 
+     * @param message The detail message, may be {@code null}.
+     */
+    public TransferCancelledException( 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 TransferCancelledException( String message, Throwable cause )
+    {
+        super( message, cause );
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferEvent.java
new file mode 100644 (file)
index 0000000..9be298f
--- /dev/null
@@ -0,0 +1,423 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import java.nio.ByteBuffer;
+
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * An event fired to a transfer listener during an artifact/metadata transfer.
+ * 
+ * @see TransferListener
+ * @see TransferEvent.Builder
+ */
+public final class TransferEvent
+{
+
+    /**
+     * The type of the event.
+     */
+    public enum EventType
+    {
+
+        /**
+         * @see TransferListener#transferInitiated(TransferEvent)
+         */
+        INITIATED,
+
+        /**
+         * @see TransferListener#transferStarted(TransferEvent)
+         */
+        STARTED,
+
+        /**
+         * @see TransferListener#transferProgressed(TransferEvent)
+         */
+        PROGRESSED,
+
+        /**
+         * @see TransferListener#transferCorrupted(TransferEvent)
+         */
+        CORRUPTED,
+
+        /**
+         * @see TransferListener#transferSucceeded(TransferEvent)
+         */
+        SUCCEEDED,
+
+        /**
+         * @see TransferListener#transferFailed(TransferEvent)
+         */
+        FAILED
+
+    }
+
+    /**
+     * The type of the request/transfer being performed.
+     */
+    public enum RequestType
+    {
+
+        /**
+         * Download artifact/metadata.
+         */
+        GET,
+
+        /**
+         * Check artifact/metadata existence only.
+         */
+        GET_EXISTENCE,
+
+        /**
+         * Upload artifact/metadata.
+         */
+        PUT,
+
+    }
+
+    private final EventType type;
+
+    private final RequestType requestType;
+
+    private final RepositorySystemSession session;
+
+    private final TransferResource resource;
+
+    private final ByteBuffer dataBuffer;
+
+    private final long transferredBytes;
+
+    private final Exception exception;
+
+    TransferEvent( Builder builder )
+    {
+        type = builder.type;
+        requestType = builder.requestType;
+        session = builder.session;
+        resource = builder.resource;
+        dataBuffer = builder.dataBuffer;
+        transferredBytes = builder.transferredBytes;
+        exception = builder.exception;
+    }
+
+    /**
+     * Gets the type of the event.
+     * 
+     * @return The type of the event, never {@code null}.
+     */
+    public EventType getType()
+    {
+        return type;
+    }
+
+    /**
+     * Gets the type of the request/transfer.
+     * 
+     * @return The type of the request/transfer, never {@code null}.
+     */
+    public RequestType getRequestType()
+    {
+        return requestType;
+    }
+
+    /**
+     * 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 resource that is being transferred.
+     * 
+     * @return The resource being transferred, never {@code null}.
+     */
+    public TransferResource getResource()
+    {
+        return resource;
+    }
+
+    /**
+     * Gets the total number of bytes that have been transferred since the download/upload of the resource was started.
+     * If a download has been resumed, the returned count includes the bytes that were already downloaded during the
+     * previous attempt. In other words, the ratio of transferred bytes to the content length of the resource indicates
+     * the percentage of transfer completion.
+     * 
+     * @return The total number of bytes that have been transferred since the transfer started, never negative.
+     * @see #getDataLength()
+     * @see TransferResource#getResumeOffset()
+     */
+    public long getTransferredBytes()
+    {
+        return transferredBytes;
+    }
+
+    /**
+     * Gets the byte buffer holding the transferred bytes since the last event. A listener must assume this buffer to be
+     * owned by the event source and must not change any byte in this buffer. Also, the buffer is only valid for the
+     * duration of the event callback, i.e. the next event might reuse the same buffer (with updated contents).
+     * Therefore, if the actual event processing is deferred, the byte buffer would have to be cloned to create an
+     * immutable snapshot of its contents.
+     * 
+     * @return The (read-only) byte buffer or {@code null} if not applicable to the event, i.e. if the event type is not
+     *         {@link EventType#PROGRESSED}.
+     */
+    public ByteBuffer getDataBuffer()
+    {
+        return ( dataBuffer != null ) ? dataBuffer.asReadOnlyBuffer() : null;
+    }
+
+    /**
+     * Gets the number of bytes that have been transferred since the last event.
+     * 
+     * @return The number of bytes that have been transferred since the last event, possibly zero but never negative.
+     * @see #getTransferredBytes()
+     */
+    public int getDataLength()
+    {
+        return ( dataBuffer != null ) ? dataBuffer.remaining() : 0;
+    }
+
+    /**
+     * Gets the error that occurred during the transfer.
+     * 
+     * @return The error that occurred or {@code null} if none.
+     */
+    public Exception getException()
+    {
+        return exception;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getRequestType() + " " + getType() + " " + getResource();
+    }
+
+    /**
+     * A builder to create transfer events.
+     */
+    public static final class Builder
+    {
+
+        EventType type;
+
+        RequestType requestType;
+
+        RepositorySystemSession session;
+
+        TransferResource resource;
+
+        ByteBuffer dataBuffer;
+
+        long transferredBytes;
+
+        Exception exception;
+
+        /**
+         * Creates a new transfer event builder for the specified session and the given resource.
+         * 
+         * @param session The repository system session, must not be {@code null}.
+         * @param resource The resource being transferred, must not be {@code null}.
+         */
+        public Builder( RepositorySystemSession session, TransferResource resource )
+        {
+            if ( session == null )
+            {
+                throw new IllegalArgumentException( "session not specified" );
+            }
+            if ( resource == null )
+            {
+                throw new IllegalArgumentException( "transfer resource not specified" );
+            }
+            this.session = session;
+            this.resource = resource;
+            type = EventType.INITIATED;
+            requestType = RequestType.GET;
+        }
+
+        private Builder( Builder prototype )
+        {
+            session = prototype.session;
+            resource = prototype.resource;
+            type = prototype.type;
+            requestType = prototype.requestType;
+            dataBuffer = prototype.dataBuffer;
+            transferredBytes = prototype.transferredBytes;
+            exception = prototype.exception;
+        }
+
+        /**
+         * Creates a new transfer event builder from the current values of this builder. The state of this builder
+         * remains unchanged.
+         * 
+         * @return The new event builder, never {@code null}.
+         */
+        public Builder copy()
+        {
+            return new Builder( this );
+        }
+
+        /**
+         * Sets the type of the event and resets event-specific fields. In more detail, the data buffer and the
+         * exception fields are set to {@code null}. Furthermore, the total number of transferred bytes is set to
+         * {@code 0} if the event type is {@link EventType#STARTED}.
+         * 
+         * @param type The type of the event, must not be {@code null}.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder resetType( EventType type )
+        {
+            if ( type == null )
+            {
+                throw new IllegalArgumentException( "event type not specified" );
+            }
+            this.type = type;
+            dataBuffer = null;
+            exception = null;
+            switch ( type )
+            {
+                case INITIATED:
+                case STARTED:
+                    transferredBytes = 0;
+                default:
+            }
+            return this;
+        }
+
+        /**
+         * Sets the type of the event. When re-using the same builder to generate a sequence of events for one transfer,
+         * {@link #resetType(TransferEvent.EventType)} might be more handy.
+         * 
+         * @param type The type of the event, must not be {@code null}.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder setType( EventType type )
+        {
+            if ( type == null )
+            {
+                throw new IllegalArgumentException( "event type not specified" );
+            }
+            this.type = type;
+            return this;
+        }
+
+        /**
+         * Sets the type of the request/transfer.
+         * 
+         * @param requestType The request/transfer type, must not be {@code null}.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder setRequestType( RequestType requestType )
+        {
+            if ( requestType == null )
+            {
+                throw new IllegalArgumentException( "request type not specified" );
+            }
+            this.requestType = requestType;
+            return this;
+        }
+
+        /**
+         * Sets the total number of bytes that have been transferred so far during the download/upload of the resource.
+         * If a download is being resumed, the count must include the bytes that were already downloaded in the previous
+         * attempt and from which the current transfer started. In this case, the event type {@link EventType#STARTED}
+         * should indicate from what byte the download resumes.
+         * 
+         * @param transferredBytes The total number of bytes that have been transferred so far during the
+         *            download/upload of the resource, must not be negative.
+         * @return This event builder for chaining, never {@code null}.
+         * @see TransferResource#setResumeOffset(long)
+         */
+        public Builder setTransferredBytes( long transferredBytes )
+        {
+            if ( transferredBytes < 0 )
+            {
+                throw new IllegalArgumentException( "number of transferred bytes cannot be negative" );
+            }
+            this.transferredBytes = transferredBytes;
+            return this;
+        }
+
+        /**
+         * Increments the total number of bytes that have been transferred so far during the download/upload.
+         * 
+         * @param transferredBytes The number of bytes that have been transferred since the last event, must not be
+         *            negative.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder addTransferredBytes( long transferredBytes )
+        {
+            if ( transferredBytes < 0 )
+            {
+                throw new IllegalArgumentException( "number of transferred bytes cannot be negative" );
+            }
+            this.transferredBytes += transferredBytes;
+            return this;
+        }
+
+        /**
+         * Sets the byte buffer holding the transferred bytes since the last event.
+         * 
+         * @param buffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if not
+         *            applicable to the event.
+         * @param offset The starting point of valid bytes in the array.
+         * @param length The number of valid bytes, must not be negative.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder setDataBuffer( byte[] buffer, int offset, int length )
+        {
+            return setDataBuffer( ( buffer != null ) ? ByteBuffer.wrap( buffer, offset, length ) : null );
+        }
+
+        /**
+         * Sets the byte buffer holding the transferred bytes since the last event.
+         * 
+         * @param dataBuffer The byte buffer holding the transferred bytes since the last event, may be {@code null} if
+         *            not applicable to the event.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder setDataBuffer( ByteBuffer dataBuffer )
+        {
+            this.dataBuffer = dataBuffer;
+            return this;
+        }
+
+        /**
+         * Sets the error that occurred during the transfer.
+         * 
+         * @param exception The error that occurred during the transfer, may be {@code null} if none.
+         * @return This event builder for chaining, never {@code null}.
+         */
+        public Builder setException( Exception exception )
+        {
+            this.exception = exception;
+            return this;
+        }
+
+        /**
+         * Builds a new transfer event from the current values of this builder. The state of the builder itself remains
+         * unchanged.
+         * 
+         * @return The transfer event, never {@code null}.
+         */
+        public TransferEvent build()
+        {
+            return new TransferEvent( this );
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferListener.java
new file mode 100644 (file)
index 0000000..26c016d
--- /dev/null
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+/**
+ * A listener being notified of artifact/metadata transfers from/to remote repositories. The listener may be called from
+ * an arbitrary thread. Reusing common regular expression syntax, the sequence of events is roughly as follows:
+ * 
+ * <pre>
+ * INITIATED ( STARTED PROGRESSED* CORRUPTED? )* ( SUCCEEDED | FAILED )
+ * </pre>
+ * 
+ * <em>Note:</em> Implementors are strongly advised to inherit from {@link AbstractTransferListener} instead of directly
+ * implementing this interface.
+ * 
+ * @see org.eclipse.aether.RepositorySystemSession#getTransferListener()
+ * @see org.eclipse.aether.RepositoryListener
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @noextend This interface is not intended to be extended by clients.
+ */
+public interface TransferListener
+{
+
+    /**
+     * Notifies the listener about the initiation of a transfer. This event gets fired before any actual network access
+     * to the remote repository and usually indicates some thread is now about to perform the transfer. For a given
+     * transfer request, this event is the first one being fired and it must be emitted exactly once.
+     * 
+     * @param event The event details, must not be {@code null}.
+     * @throws TransferCancelledException If the transfer should be aborted.
+     */
+    void transferInitiated( TransferEvent event )
+        throws TransferCancelledException;
+
+    /**
+     * Notifies the listener about the start of a data transfer. This event indicates a successful connection to the
+     * remote repository. In case of a download, the requested remote resource exists and its size is given by
+     * {@link TransferResource#getContentLength()} if possible. This event may be fired multiple times for given
+     * transfer request if said transfer needs to be repeated (e.g. in response to an authentication challenge).
+     * 
+     * @param event The event details, must not be {@code null}.
+     * @throws TransferCancelledException If the transfer should be aborted.
+     */
+    void transferStarted( TransferEvent event )
+        throws TransferCancelledException;
+
+    /**
+     * Notifies the listener about some progress in the data transfer. This event may even be fired if actually zero
+     * bytes have been transferred since the last event, for instance to enable cancellation.
+     * 
+     * @param event The event details, must not be {@code null}.
+     * @throws TransferCancelledException If the transfer should be aborted.
+     */
+    void transferProgressed( TransferEvent event )
+        throws TransferCancelledException;
+
+    /**
+     * Notifies the listener that a checksum validation failed. {@link TransferEvent#getException()} will be of type
+     * {@link ChecksumFailureException} and can be used to query further details about the expected/actual checksums.
+     * 
+     * @param event The event details, must not be {@code null}.
+     * @throws TransferCancelledException If the transfer should be aborted.
+     */
+    void transferCorrupted( TransferEvent event )
+        throws TransferCancelledException;
+
+    /**
+     * Notifies the listener about the successful completion of a transfer. This event must be fired exactly once for a
+     * given transfer request unless said request failed.
+     * 
+     * @param event The event details, must not be {@code null}.
+     */
+    void transferSucceeded( TransferEvent event );
+
+    /**
+     * Notifies the listener about the unsuccessful termination of a transfer. {@link TransferEvent#getException()} will
+     * provide further information about the failure.
+     * 
+     * @param event The event details, must not be {@code null}.
+     */
+    void transferFailed( TransferEvent event );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/TransferResource.java
new file mode 100644 (file)
index 0000000..b9510fb
--- /dev/null
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2013 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.transfer;
+
+import java.io.File;
+
+import org.eclipse.aether.RequestTrace;
+
+/**
+ * Describes a resource being uploaded or downloaded by the repository system.
+ */
+public final class TransferResource
+{
+
+    private final String repositoryUrl;
+
+    private final String resourceName;
+
+    private final File file;
+
+    private final long startTime;
+
+    private final RequestTrace trace;
+
+    private long contentLength = -1;
+
+    private long resumeOffset;
+
+    /**
+     * Creates a new transfer resource with the specified properties.
+     * 
+     * @param repositoryUrl The base URL of the repository, may be {@code null} or empty if unknown. If not empty, a
+     *            trailing slash will automatically be added if missing.
+     * @param resourceName The relative path to the resource within the repository, may be {@code null}. A leading slash
+     *            (if any) will be automatically removed.
+     * @param file The source/target file involved in the transfer, may be {@code null}.
+     * @param trace The trace information, may be {@code null}.
+     */
+    public TransferResource( String repositoryUrl, String resourceName, File file, RequestTrace trace )
+    {
+        if ( repositoryUrl == null || repositoryUrl.length() <= 0 )
+        {
+            this.repositoryUrl = "";
+        }
+        else if ( repositoryUrl.endsWith( "/" ) )
+        {
+            this.repositoryUrl = repositoryUrl;
+        }
+        else
+        {
+            this.repositoryUrl = repositoryUrl + '/';
+        }
+
+        if ( resourceName == null || resourceName.length() <= 0 )
+        {
+            this.resourceName = "";
+        }
+        else if ( resourceName.startsWith( "/" ) )
+        {
+            this.resourceName = resourceName.substring( 1 );
+        }
+        else
+        {
+            this.resourceName = resourceName;
+        }
+
+        this.file = file;
+
+        this.trace = trace;
+
+        startTime = System.currentTimeMillis();
+    }
+
+    /**
+     * The base URL of the repository, e.g. "http://repo1.maven.org/maven2/". Unless the URL is unknown, it will be
+     * terminated by a trailing slash.
+     * 
+     * @return The base URL of the repository or an empty string if unknown, never {@code null}.
+     */
+    public String getRepositoryUrl()
+    {
+        return repositoryUrl;
+    }
+
+    /**
+     * The path of the resource relative to the repository's base URL, e.g. "org/apache/maven/maven/3.0/maven-3.0.pom".
+     * 
+     * @return The path of the resource, never {@code null}.
+     */
+    public String getResourceName()
+    {
+        return resourceName;
+    }
+
+    /**
+     * Gets the local file being uploaded or downloaded. When the repository system merely checks for the existence of a
+     * remote resource, no local file will be involved in the transfer.
+     * 
+     * @return The source/target file involved in the transfer or {@code null} if none.
+     */
+    public File getFile()
+    {
+        return file;
+    }
+
+    /**
+     * The size of the resource in bytes. Note that the size of a resource during downloads might be unknown to the
+     * client which is usually the case when transfers employ compression like gzip. In general, the content length is
+     * not known until the transfer has {@link TransferListener#transferStarted(TransferEvent) started}.
+     * 
+     * @return The size of the resource in bytes or a negative value if unknown.
+     */
+    public long getContentLength()
+    {
+        return contentLength;
+    }
+
+    /**
+     * Sets the size of the resource in bytes.
+     * 
+     * @param contentLength The size of the resource in bytes or a negative value if unknown.
+     * @return This resource for chaining, never {@code null}.
+     */
+    public TransferResource setContentLength( long contentLength )
+    {
+        this.contentLength = contentLength;
+        return this;
+    }
+
+    /**
+     * Gets the byte offset within the resource from which the download starts. A positive offset indicates a previous
+     * download attempt is being resumed, {@code 0} means the transfer starts at the first byte.
+     * 
+     * @return The zero-based index of the first byte being transferred, never negative.
+     */
+    public long getResumeOffset()
+    {
+        return resumeOffset;
+    }
+
+    /**
+     * Sets the byte offset within the resource at which the download starts.
+     * 
+     * @param resumeOffset The zero-based index of the first byte being transferred, must not be negative.
+     * @return This resource for chaining, never {@code null}.
+     */
+    public TransferResource setResumeOffset( long resumeOffset )
+    {
+        if ( resumeOffset < 0 )
+        {
+            throw new IllegalArgumentException( "resume offset cannot be negative" );
+        }
+        this.resumeOffset = resumeOffset;
+        return this;
+    }
+
+    /**
+     * Gets the timestamp when the transfer of this resource was started.
+     * 
+     * @return The timestamp when the transfer of this resource was started.
+     */
+    public long getTransferStartTime()
+    {
+        return startTime;
+    }
+
+    /**
+     * Gets the trace information that describes the higher level request/operation during which this resource is
+     * transferred.
+     * 
+     * @return The trace information about the higher level operation or {@code null} if none.
+     */
+    public RequestTrace getTrace()
+    {
+        return trace;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getRepositoryUrl() + getResourceName() + " <> " + getFile();
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/transfer/package-info.java
new file mode 100644 (file)
index 0000000..5ce9ff3
--- /dev/null
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * A listener and various exception types dealing with the transfer of a resource between the local system and a remote
+ * repository.
+ */
+package org.eclipse.aether.transfer;
+
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/InvalidVersionSpecificationException.java
new file mode 100644 (file)
index 0000000..b3690c5
--- /dev/null
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.version;
+
+import org.eclipse.aether.RepositoryException;
+
+/**
+ * Thrown when a version or version range could not be parsed.
+ */
+public class InvalidVersionSpecificationException
+    extends RepositoryException
+{
+
+    private final String version;
+
+    /**
+     * Creates a new exception with the specified version and detail message.
+     * 
+     * @param version The invalid version specification, may be {@code null}.
+     * @param message The detail message, may be {@code null}.
+     */
+    public InvalidVersionSpecificationException( String version, String message )
+    {
+        super( message );
+        this.version = version;
+    }
+
+    /**
+     * Creates a new exception with the specified version and cause.
+     * 
+     * @param version The invalid version specification, may be {@code null}.
+     * @param cause The exception that caused this one, may be {@code null}.
+     */
+    public InvalidVersionSpecificationException( String version, Throwable cause )
+    {
+        super( "Could not parse version specification " + version + getMessage( ": ", cause ), cause );
+        this.version = version;
+    }
+
+    /**
+     * Creates a new exception with the specified version, detail message and cause.
+     * 
+     * @param version The invalid version specification, 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 InvalidVersionSpecificationException( String version, String message, Throwable cause )
+    {
+        super( message, cause );
+        this.version = version;
+    }
+
+    /**
+     * Gets the version or version range that could not be parsed.
+     * 
+     * @return The invalid version specification or {@code null} if unknown.
+     */
+    public String getVersion()
+    {
+        return version;
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/Version.java
new file mode 100644 (file)
index 0000000..4aceba6
--- /dev/null
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.version;
+
+/**
+ * A parsed artifact version.
+ */
+public interface Version
+    extends Comparable<Version>
+{
+
+    /**
+     * Gets the original string representation of the version.
+     * 
+     * @return The string representation of the version, never {@code null}.
+     */
+    String toString();
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionConstraint.java
new file mode 100644 (file)
index 0000000..dcb3b68
--- /dev/null
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.version;
+
+/**
+ * A constraint on versions for a dependency. A constraint can either consist of a version range (e.g. "[1, ]") or a
+ * single version (e.g. "1.1"). In the first case, the constraint expresses a hard requirement on a version matching the
+ * range. In the second case, the constraint expresses a soft requirement on a specific version (i.e. a recommendation).
+ */
+public interface VersionConstraint
+{
+
+    /**
+     * Gets the version range of this constraint.
+     * 
+     * @return The version range or {@code null} if none.
+     */
+    VersionRange getRange();
+
+    /**
+     * Gets the version recommended by this constraint.
+     * 
+     * @return The recommended version or {@code null} if none.
+     */
+    Version getVersion();
+
+    /**
+     * Determines whether the specified version satisfies this constraint. In more detail, a version satisfies this
+     * constraint if it matches its version range or if this constraint has no version range and the specified version
+     * equals the version recommended by the constraint.
+     * 
+     * @param version The version to test, must not be {@code null}.
+     * @return {@code true} if the specified version satisfies this constraint, {@code false} otherwise.
+     */
+    boolean containsVersion( Version version );
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionRange.java
new file mode 100644 (file)
index 0000000..cbc2405
--- /dev/null
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2012 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.version;
+
+/**
+ * A range of versions.
+ */
+public interface VersionRange
+{
+
+    /**
+     * Determines whether the specified version is contained within this range.
+     * 
+     * @param version The version to test, must not be {@code null}.
+     * @return {@code true} if this range contains the specified version, {@code false} otherwise.
+     */
+    boolean containsVersion( Version version );
+
+    /**
+     * Gets a lower bound (if any) for this range. If existent, this range does not contain any version smaller than its
+     * lower bound. Note that complex version ranges might exclude some versions even within their bounds.
+     * 
+     * @return A lower bound for this range or {@code null} is there is none.
+     */
+    Bound getLowerBound();
+
+    /**
+     * Gets an upper bound (if any) for this range. If existent, this range does not contain any version greater than
+     * its upper bound. Note that complex version ranges might exclude some versions even within their bounds.
+     * 
+     * @return An upper bound for this range or {@code null} is there is none.
+     */
+    Bound getUpperBound();
+
+    /**
+     * A bound of a version range.
+     */
+    static final class Bound
+    {
+
+        private final Version version;
+
+        private final boolean inclusive;
+
+        /**
+         * Creates a new bound with the specified properties.
+         * 
+         * @param version The bounding version, must not be {@code null}.
+         * @param inclusive A flag whether the specified version is included in the range or not.
+         */
+        public Bound( Version version, boolean inclusive )
+        {
+            if ( version == null )
+            {
+                throw new IllegalArgumentException( "version missing" );
+            }
+            this.version = version;
+            this.inclusive = inclusive;
+        }
+
+        /**
+         * Gets the bounding version.
+         * 
+         * @return The bounding version, never {@code null}.
+         */
+        public Version getVersion()
+        {
+            return version;
+        }
+
+        /**
+         * Indicates whether the bounding version is included in the range or not.
+         * 
+         * @return {@code true} if the bounding version is included in the range, {@code false} if not.
+         */
+        public boolean isInclusive()
+        {
+            return inclusive;
+        }
+
+        @Override
+        public boolean equals( Object obj )
+        {
+            if ( obj == this )
+            {
+                return true;
+            }
+            else if ( obj == null || !getClass().equals( obj.getClass() ) )
+            {
+                return false;
+            }
+
+            Bound that = (Bound) obj;
+            return inclusive == that.inclusive && version.equals( that.version );
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hash = 17;
+            hash = hash * 31 + version.hashCode();
+            hash = hash * 31 + ( inclusive ? 1 : 0 );
+            return hash;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.valueOf( version );
+        }
+
+    }
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/VersionScheme.java
new file mode 100644 (file)
index 0000000..c19177a
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2011 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.aether.version;
+
+/**
+ * A version scheme that handles interpretation of version strings to facilitate their comparison.
+ */
+public interface VersionScheme
+{
+
+    /**
+     * Parses the specified version string, for example "1.0".
+     * 
+     * @param version The version string to parse, must not be {@code null}.
+     * @return The parsed version, never {@code null}.
+     * @throws InvalidVersionSpecificationException If the string violates the syntax rules of this scheme.
+     */
+    Version parseVersion( String version )
+        throws InvalidVersionSpecificationException;
+
+    /**
+     * Parses the specified version range specification, for example "[1.0,2.0)".
+     * 
+     * @param range The range specification to parse, must not be {@code null}.
+     * @return The parsed version range, never {@code null}.
+     * @throws InvalidVersionSpecificationException If the range specification violates the syntax rules of this scheme.
+     */
+    VersionRange parseVersionRange( String range )
+        throws InvalidVersionSpecificationException;
+
+    /**
+     * Parses the specified version constraint specification, for example "1.0" or "[1.0,2.0),(2.0,)".
+     * 
+     * @param constraint The constraint specification to parse, must not be {@code null}.
+     * @return The parsed version constraint, never {@code null}.
+     * @throws InvalidVersionSpecificationException If the constraint specification violates the syntax rules of this
+     *             scheme.
+     */
+    VersionConstraint parseVersionConstraint( final String constraint )
+        throws InvalidVersionSpecificationException;
+
+}
diff --git a/org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java b/org.argeo.slc.repo/src/org/eclipse/aether/version/package-info.java
new file mode 100644 (file)
index 0000000..7ef8c85
--- /dev/null
@@ -0,0 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2014 Sonatype, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+/**
+ * The definition of a version scheme for parsing and comparing versions.
+ */
+package org.eclipse.aether.version;
+
diff --git a/org.argeo.slc.server.repo/META-INF/spring/maven.xml b/org.argeo.slc.server.repo/META-INF/spring/maven.xml
deleted file mode 100644 (file)
index 8836ae4..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
-       xmlns:util="http://www.springframework.org/schema/util"
-       xsi:schemaLocation="
-       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
-       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
-       ">
-
-       <!-- Proxied repositories -->
-       <util:list id="defaultMavenRepositories">
-               <ref local="central" />
-       </util:list>
-
-       <bean id="central" p:url="http://repo1.maven.org/maven2"
-               class="org.argeo.slc.aether.spring.RemoteRepositoryFactory" />
-
-</beans>
\ No newline at end of file
index f0fcaaa4f84b99fec1300aff1d8a0bc45857ae9f..830303ccec94d50f1944c1769d05eb98e1f7698b 100644 (file)
                filter="(cn=docs)" />\r
 \r
        <!-- SERVICES -->\r
-<!--   <service ref="javaRepository" interface="javax.jcr.Repository"> -->\r
-<!--           <service-properties> -->\r
-<!--                   <beans:entry key="cn" value="java" /> -->\r
-<!--           </service-properties> -->\r
-<!--   </service> -->\r
-<!--   <service ref="distRepository" interface="javax.jcr.Repository"> -->\r
-<!--           <service-properties> -->\r
-<!--                   <beans:entry key="cn" value="dist" /> -->\r
-<!--           </service-properties> -->\r
-<!--   </service> -->\r
-<!--   <service ref="rpmRepository" interface="javax.jcr.Repository"> -->\r
-<!--           <service-properties> -->\r
-<!--                   <beans:entry key="cn" value="rpm" /> -->\r
-<!--           </service-properties> -->\r
-<!--   </service> -->\r
-<!--   <service ref="docsRepository" interface="javax.jcr.Repository"> -->\r
-<!--           <service-properties> -->\r
-<!--                   <beans:entry key="cn" value="docs" /> -->\r
-<!--           </service-properties> -->\r
-<!--   </service> -->\r
-\r
        <service ref="slcRepoManager" interface="org.argeo.slc.repo.SlcRepoManager" />\r
 \r
-       <service ref="mavenProxyService" interface="org.argeo.slc.repo.MavenProxyService" />\r
-       <service ref="rpmProxyService" interface="org.argeo.slc.rpmfactory.RpmProxyService" />\r
+<!--   <service ref="mavenProxyService" interface="org.argeo.slc.repo.MavenProxyService" /> -->\r
+<!--   <service ref="rpmProxyService" interface="org.argeo.slc.rpmfactory.RpmProxyService" /> -->\r
 \r
        <!-- LABEL -->\r
        <beans:bean class="org.argeo.cms.spring.osgi.OsgiModuleLabel">\r
index feca34890057c95e6812e9a955f9183df4d8b11c..454009e9d7bc833c8c5145f07f9d83b31548803a 100644 (file)
                <property name="jcrRepository" ref="javaRepository" />
        </bean>
 
-       <bean id="mavenProxyService" class="org.argeo.slc.repo.maven.MavenProxyServiceImpl"
-               init-method="init" destroy-method="destroy" depends-on="ROLE_SLC">
-               <property name="jcrRepository" ref="javaRepository" />
-               <property name="proxyWorkspace" value="${slc.repo.jcr.proxyWorkspace}" />
-               <property name="defaultRepositories" ref="defaultMavenRepositories" />
-       </bean>
+       <!-- <bean id="mavenProxyService" class="org.argeo.slc.repo.maven.MavenProxyServiceImpl" -->
+       <!-- init-method="init" destroy-method="destroy" depends-on="ROLE_SLC"> -->
+       <!-- <property name="jcrRepository" ref="javaRepository" /> -->
+       <!-- <property name="proxyWorkspace" value="${slc.repo.jcr.proxyWorkspace}" 
+               /> -->
+       <!-- <property name="defaultRepositories" ref="defaultMavenRepositories" 
+               /> -->
+       <!-- </bean> -->
 
        <!-- RPM -->
        <bean id="rpmRepoManager" class="org.argeo.slc.repo.core.RpmRepoManagerImpl"
                <property name="jcrRepository" ref="rpmRepository" />
        </bean>
 
-       <bean id="rpmProxyService" class="org.argeo.slc.rpmfactory.core.RpmProxyServiceImpl"
-               init-method="init" destroy-method="destroy" depends-on="ROLE_SLC">
-               <property name="jcrRepository" ref="rpmRepository" />
-               <property name="proxyWorkspace" value="${slc.repo.jcr.proxyWorkspace}" />
-               <property name="defaultRepositories" ref="defaultRpmRepositories" />
-       </bean>
+       <!-- <bean id="rpmProxyService" class="org.argeo.slc.rpmfactory.core.RpmProxyServiceImpl" -->
+       <!-- init-method="init" destroy-method="destroy" depends-on="ROLE_SLC"> -->
+       <!-- <property name="jcrRepository" ref="rpmRepository" /> -->
+       <!-- <property name="proxyWorkspace" value="${slc.repo.jcr.proxyWorkspace}" 
+               /> -->
+       <!-- <property name="defaultRepositories" ref="defaultRpmRepositories" /> -->
+       <!-- </bean> -->
 
-       <!-- Draft to centralize multirepository connection process in an Argeo 
-               environment -->
-       <!-- <bean id="repoService" class="org.argeo.slc.repo.core.RepoServiceImpl" 
-               init-method="init" destroy-method="destroy"> <property name="repositoryFactory" 
-               ref="repositoryFactory" /> <property name="keyring" ref="keyring" /> <property 
-               name="nodeRepository" ref="nodeRepository" /> </bean> -->
 </beans>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-h2.xml b/org.argeo.slc.server.repo/repository-h2.xml
deleted file mode 100644 (file)
index c87f1d4..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- Shared datasource -->
-       <DataSources>
-               <DataSource name="dataSource">
-                       <param name="driver" value="org.h2.Driver" />
-                       <param name="url" value="jdbc:h2:${rep.home}/h2/repository" />
-                       <param name="user" value="${slc.repo.jcr.dbuser}" />
-                       <param name="password" value="${slc.repo.jcr.dbpassword}" />
-                       <param name="databaseType" value="h2" />
-                       <param name="maxPoolSize" value="${slc.repo.jcr.maxPoolSize}" />
-               </DataSource>
-       </DataSources>
-
-       <!-- Repository wide -->
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-               <param name="minRecordLength" value="10240" />
-       </DataStore>
-       <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-               <param name="path" value="${rep.home}/fs" />
-       </FileSystem>
-
-       <!-- Workspaces -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${wsp.home}/fs" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_pm_" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/indexes/workspaces/${wsp.name}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider">
-                               <param name="allow-unknown-principals" value="true" />
-                       </AccessControlProvider>
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${rep.home}/version/fs" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.H2PersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="pm_ver_" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/indexes/repository" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-localfs.xml b/org.argeo.slc.server.repo/repository-localfs.xml
deleted file mode 100644 (file)
index 3ab8a29..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-               <param name="path" value="${rep.home}/repository" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="${argeo.node.repo.defaultWorkspace}" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${wsp.home}" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
-                       <param name="bundleCacheSize" value="${argeo.node.repo.bundleCacheMB}" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${wsp.home}/index" />
-                       <param name="extractorPoolSize" value="${argeo.node.repo.extractorPoolSize}" />
-                       <param name="cacheSize" value="${argeo.node.repo.searchCacheSize}" />
-                       <param name="maxVolatileIndexSize" value="${argeo.node.repo.maxVolatileIndexSize}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider" />
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                       <param name="path" value="${rep.home}/version" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.bundle.BundleFsPersistenceManager">
-                       <param name="bundleCacheSize" value="${argeo.node.repo.bundleCacheMB}" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/index" />
-               <param name="extractorPoolSize" value="${argeo.node.repo.extractorPoolSize}" />
-               <param name="cacheSize" value="${argeo.node.repo.searchCacheSize}" />
-               <param name="maxVolatileIndexSize" value="${argeo.node.repo.maxVolatileIndexSize}" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security" />
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager" />
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-pg-dist.xml b/org.argeo.slc.server.repo/repository-pg-dist.xml
deleted file mode 100644 (file)
index 0e40bc7..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- Shared datasource -->
-       <DataSources>
-               <DataSource name="dataSource">
-                       <param name="driver" value="org.postgresql.Driver" />
-                       <param name="url" value="${slc.repo.jcr.dburl.dist}" />
-                       <param name="user" value="${slc.repo.jcr.dbuser}" />
-                       <param name="password" value="${slc.repo.jcr.dbpassword}" />
-                       <param name="databaseType" value="postgresql" />
-                       <param name="maxPoolSize" value="${slc.repo.jcr.maxPoolSize}" />
-               </DataSource>
-       </DataSources>
-
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-               <param name="dataSourceName" value="dataSource" />
-               <param name="schema" value="postgresql" />
-               <param name="schemaObjectPrefix" value="_fs_" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/indexes/workspaces/${wsp.name}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider">
-                               <param name="allow-unknown-principals" value="true" />
-                       </AccessControlProvider>
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/indexes/repository" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-pg-docs.xml b/org.argeo.slc.server.repo/repository-pg-docs.xml
deleted file mode 100644 (file)
index d67b103..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- Shared datasource -->
-       <DataSources>
-               <DataSource name="dataSource">
-                       <param name="driver" value="org.postgresql.Driver" />
-                       <param name="url" value="${slc.repo.jcr.dburl.docs}" />
-                       <param name="user" value="${slc.repo.jcr.dbuser}" />
-                       <param name="password" value="${slc.repo.jcr.dbpassword}" />
-                       <param name="databaseType" value="postgresql" />
-                       <param name="maxPoolSize" value="${slc.repo.jcr.maxPoolSize}" />
-               </DataSource>
-       </DataSources>
-
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-               <param name="dataSourceName" value="dataSource" />
-               <param name="schema" value="postgresql" />
-               <param name="schemaObjectPrefix" value="_fs_" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/indexes/workspaces/${wsp.name}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider">
-                               <param name="allow-unknown-principals" value="true" />
-                       </AccessControlProvider>
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/indexes/repository" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-pg-java.xml b/org.argeo.slc.server.repo/repository-pg-java.xml
deleted file mode 100644 (file)
index 3832625..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- Shared datasource -->
-       <DataSources>
-               <DataSource name="dataSource">
-                       <param name="driver" value="org.postgresql.Driver" />
-                       <param name="url" value="${slc.repo.jcr.dburl.java}" />
-                       <param name="user" value="${slc.repo.jcr.dbuser}" />
-                       <param name="password" value="${slc.repo.jcr.dbpassword}" />
-                       <param name="databaseType" value="postgresql" />
-                       <param name="maxPoolSize" value="${slc.repo.jcr.maxPoolSize}" />
-               </DataSource>
-       </DataSources>
-
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-               <param name="dataSourceName" value="dataSource" />
-               <param name="schema" value="postgresql" />
-               <param name="schemaObjectPrefix" value="_fs_" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/indexes/workspaces/${wsp.name}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider">
-                               <param name="allow-unknown-principals" value="true" />
-                       </AccessControlProvider>
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/indexes/repository" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.server.repo/repository-pg-rpm.xml b/org.argeo.slc.server.repo/repository-pg-rpm.xml
deleted file mode 100644 (file)
index b35028d..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE Repository PUBLIC "Jackrabbit 2.6" "http://jackrabbit.apache.org/dtd/repository-2.6.dtd">
-<Repository>
-       <!-- Shared datasource -->
-       <DataSources>
-               <DataSource name="dataSource">
-                       <param name="driver" value="org.postgresql.Driver" />
-                       <param name="url" value="${slc.repo.jcr.dburl.rpm}" />
-                       <param name="user" value="${slc.repo.jcr.dbuser}" />
-                       <param name="password" value="${slc.repo.jcr.dbpassword}" />
-                       <param name="databaseType" value="postgresql" />
-                       <param name="maxPoolSize" value="${slc.repo.jcr.maxPoolSize}" />
-               </DataSource>
-       </DataSources>
-
-       <!-- File system and datastore -->
-       <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-               <param name="dataSourceName" value="dataSource" />
-               <param name="schema" value="postgresql" />
-               <param name="schemaObjectPrefix" value="_fs_" />
-       </FileSystem>
-       <DataStore class="org.apache.jackrabbit.core.data.FileDataStore">
-               <param name="path" value="${rep.home}/datastore" />
-       </DataStore>
-
-       <!-- Workspace templates -->
-       <Workspaces rootPath="${rep.home}/workspaces"
-               defaultWorkspace="main" />
-       <Workspace name="${wsp.name}">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="${wsp.name}_" />
-               </PersistenceManager>
-               <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-                       <param name="path" value="${rep.home}/indexes/workspaces/${wsp.name}" />
-               </SearchIndex>
-               <WorkspaceSecurity>
-                       <AccessControlProvider
-                               class="org.argeo.security.jackrabbit.ArgeoAccessControlProvider">
-                               <param name="allow-unknown-principals" value="true" />
-                       </AccessControlProvider>
-               </WorkspaceSecurity>
-       </Workspace>
-
-       <!-- Versioning -->
-       <Versioning rootPath="${rep.home}/version">
-               <FileSystem class="org.apache.jackrabbit.core.fs.db.DbFileSystem">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schema" value="postgresql" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </FileSystem>
-               <PersistenceManager
-                       class="org.apache.jackrabbit.core.persistence.pool.PostgreSQLPersistenceManager">
-                       <param name="dataSourceName" value="dataSource" />
-                       <param name="schemaObjectPrefix" value="_versioning_" />
-               </PersistenceManager>
-       </Versioning>
-
-       <!-- Indexing -->
-       <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-               <param name="path" value="${rep.home}/indexes/repository" />
-       </SearchIndex>
-
-       <!-- Security -->
-       <Security appName="Jackrabbit">
-               <SecurityManager class="org.argeo.security.jackrabbit.ArgeoSecurityManager"
-                       workspaceName="security">
-               </SecurityManager>
-               <AccessManager class="org.argeo.security.jackrabbit.ArgeoAccessManager">
-               </AccessManager>
-       </Security>
-</Repository>
\ No newline at end of file
diff --git a/org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java b/org.argeo.slc.support/ext/test/org/argeo/slc/aether/AetherUtilsTest.java
deleted file mode 100644 (file)
index 6f13701..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import junit.framework.TestCase;
-
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.DefaultArtifact;
-
-public class AetherUtilsTest extends TestCase {
-       public void testConvertPathToArtifact() throws Exception {
-               checkPathConversion("my.group.id:my-artifactId:pom:1.2.3",
-                               "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3.pom");
-               checkPathConversion("my.group.id:my-artifactId:pom:1.2.3-SNAPSHOT",
-                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT.pom");
-               checkPathConversion("my.group.id:my-artifactId:pom:myClassifier:1.2.3",
-                               "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3-myClassifier.pom");
-               checkPathConversion(
-                               "my.group.id:my-artifactId:pom:myClassifier:1.2.3-SNAPSHOT",
-                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT-myClassifier.pom");
-               checkPathConversion(
-                               "my.group.id:my-artifactId:pom:myClassifier:20110828.223836-2",
-                               "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-20110828.223836-2-myClassifier.pom");
-       }
-
-       public void testConvertPathToArtifactRealLife() throws Exception {
-               checkPathConversion(
-                               "org.apache.maven.plugins:maven-antrun-plugin:pom:1.1",
-                               "org/apache/maven/plugins/maven-antrun-plugin/1.1/maven-antrun-plugin-1.1.pom");
-               checkPathConversion(
-                               "org.apache.maven.plugins:maven-plugin-parent:pom:2.0.1",
-                               "org/apache/maven/plugins/maven-plugin-parent/2.0.1/maven-plugin-parent-2.0.1.pom");
-               checkPathConversion(
-                               "org.apache.avalon.framework:avalon-framework-impl:pom:4.3.1",
-                               "org/apache/avalon/framework/avalon-framework-impl/4.3.1/avalon-framework-impl-4.3.1.pom");
-               checkPathConversion(
-                               "org.apache.maven.shared:maven-dependency-tree:pom:1.2",
-                               "org/apache/maven/shared/maven-dependency-tree/1.2/maven-dependency-tree-1.2.pom");
-               checkPathConversion(
-                               "org.argeo.maven.plugins:maven-argeo-osgi-plugin:pom:1.0.33",
-                               "org/argeo/maven/plugins/maven-argeo-osgi-plugin/1.0.33/maven-argeo-osgi-plugin-1.0.33.pom");
-               checkPathConversion(
-                               "org.apache.maven.plugins:maven-clean-plugin:pom:2.4.1",
-                               "org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom");
-       }
-
-       protected void checkPathConversion(String expectedArtifact, String path) {
-               Artifact artifact = AetherUtils.convertPathToArtifact(path, null);
-               if (expectedArtifact == null)
-                       assertNull(artifact);
-               else
-                       assertEquals(new DefaultArtifact(expectedArtifact), artifact);
-       }
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java b/org.argeo.slc.support/src/org/argeo/slc/aether/AetherTemplate.java
deleted file mode 100644 (file)
index a83caa1..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import java.io.File;
-import java.util.List;
-
-import org.argeo.slc.SlcException;
-import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.collection.CollectRequest;
-import org.eclipse.aether.graph.Dependency;
-import org.eclipse.aether.graph.DependencyNode;
-import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.resolution.ArtifactRequest;
-import org.eclipse.aether.resolution.ArtifactResolutionException;
-import org.eclipse.aether.resolution.ArtifactResult;
-
-/** Simplifies access to Aether. */
-public class AetherTemplate {
-       private RepositorySystem repositorySystem;
-       private RepositorySystemSession repositorySystemSession;
-       private List<RemoteRepository> remoteRepositories;
-
-       /** Resolves the artifact in order to give access to its file. */
-       public File getResolvedFile(Artifact artifact) {
-               try {
-                       ArtifactRequest artifactRequest = new ArtifactRequest(artifact,
-                                       remoteRepositories, null);
-                       ArtifactResult result = repositorySystem.resolveArtifact(
-                                       repositorySystemSession, artifactRequest);
-                       return result.getArtifact().getFile();
-               } catch (ArtifactResolutionException e) {
-                       throw new SlcException("Cannot resolve " + artifact, e);
-               }
-       }
-
-       /**
-        * Transitively resolves the dependencies of this artifact (with scope
-        * 'compile')
-        * 
-        * @param artifact
-        *            the artifact to resolve
-        */
-       public DependencyNode resolveDependencies(Artifact artifact) {
-               return resolveDependencies(artifact, "compile");
-       }
-
-       /**
-        * Transitively resolves the dependencies of this artifact.
-        * 
-        * @param artifact
-        *            the artifact to resolve
-        * @param scope
-        *            the scope
-        */
-       public DependencyNode resolveDependencies(Artifact artifact, String scope) {
-               try {
-                       Dependency dependency = new Dependency(artifact, scope);
-                       CollectRequest collectRequest = new CollectRequest();
-                       collectRequest.setRoot(dependency);
-                       for (RemoteRepository remoteRepository : remoteRepositories)
-                               collectRequest.addRepository(remoteRepository);
-                       DependencyNode node = repositorySystem.collectDependencies(
-                                       repositorySystemSession, collectRequest).getRoot();
-
-                       // FIXME adapt to changes in Aether
-                       // repositorySystem.resolveDependencies(repositorySystemSession,
-                       // node,
-                       // null);
-                       return node;
-               } catch (Exception e) {
-                       throw new SlcException("Cannot resolve dependencies of " + artifact
-                                       + " (scope: " + scope + ")", e);
-               }
-       }
-
-       public RepositorySystem getRepositorySystem() {
-               return repositorySystem;
-       }
-
-       public void setRepositorySystem(RepositorySystem repositorySystem) {
-               this.repositorySystem = repositorySystem;
-       }
-
-       public RepositorySystemSession getRepositorySystemSession() {
-               return repositorySystemSession;
-       }
-
-       public void setRepositorySystemSession(
-                       RepositorySystemSession repositorySystemSession) {
-               this.repositorySystemSession = repositorySystemSession;
-       }
-
-       public List<RemoteRepository> getRemoteRepositories() {
-               return remoteRepositories;
-       }
-
-       public void setRemoteRepositories(List<RemoteRepository> remoteRepositories) {
-               this.remoteRepositories = remoteRepositories;
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java b/org.argeo.slc.support/src/org/argeo/slc/aether/AetherUtils.java
deleted file mode 100644 (file)
index 873ddcb..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import java.util.regex.Pattern;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.slc.SlcException;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.graph.DependencyNode;
-
-/** Utilities related to Aether */
-public class AetherUtils {
-       public final static String SNAPSHOT = "SNAPSHOT";
-       // hacked from aether
-       public static final Pattern SNAPSHOT_TIMESTAMP = Pattern
-                       .compile("^(.*-)?([0-9]{8}.[0-9]{6}-[0-9]+)$");
-
-       private final static Log log = LogFactory.getLog(AetherUtils.class);
-
-       /** Logs a dependency node and its transitive dependencies as a tree. */
-       public static void logDependencyNode(int depth,
-                       DependencyNode dependencyNode) {
-               if (!log.isDebugEnabled())
-                       return;
-
-               StringBuffer prefix = new StringBuffer(depth * 2 + 2);
-               // prefix.append("|-");
-               for (int i = 0; i < depth * 2; i++) {
-                       prefix.append(' ');
-               }
-               Artifact artifact = dependencyNode.getDependency().getArtifact();
-               log.debug(prefix + "|-> " + artifact.getArtifactId() + " ["
-                               + artifact.getVersion() + "]"
-                               + (dependencyNode.getDependency().isOptional() ? " ?" : ""));
-               for (DependencyNode child : dependencyNode.getChildren()) {
-                       logDependencyNode(depth + 1, child);
-               }
-       }
-
-       /**
-        * Converts a path (relative to a repository root) to an {@link Artifact}.
-        * 
-        * @param path
-        *            the relative path
-        * @param type
-        *            the layout type, currently ignored because only the 'default'
-        *            Maven 2 layout is currently supported:
-        *            /my/group/id/artifactId/
-        *            version/artifactId-version[-classifier].extension
-        * @return the related artifact or null if the file is not an artifact
-        *         (Maven medata data XML files, check sums, etc.)
-        */
-       public static Artifact convertPathToArtifact(String path, String type) {
-               // TODO rewrite it with regexp (unit tests first!)
-
-               // normalize
-               if (path.startsWith("/"))
-                       path = path.substring(1);
-
-               // parse group id
-               String[] tokensSlash = path.split("/");
-               if (tokensSlash.length < 4)
-                       return null;
-               StringBuffer groupId = new StringBuffer(path.length());
-               for (int i = 0; i < tokensSlash.length - 3; i++) {
-                       if (i != 0)
-                               groupId.append('.');
-                       groupId.append(tokensSlash[i]);
-               }
-               String artifactId = tokensSlash[tokensSlash.length - 3];
-               String baseVersion = tokensSlash[tokensSlash.length - 2];
-               String fileName = tokensSlash[tokensSlash.length - 1];
-
-               if (!fileName.startsWith(artifactId))
-                       return null;
-               // FIXME make it configurable? (via an argument?)
-               if (FilenameUtils.isExtension(fileName, new String[] { "sha1", "md5" }))
-                       return null;
-
-               String extension = FilenameUtils.getExtension(fileName);
-               String baseName = FilenameUtils.getBaseName(fileName);
-
-               // check since we assume hereafter
-               if (!baseName.startsWith(artifactId))
-                       throw new SlcException("Base name '" + baseName
-                                       + " does not start with artifact id '" + artifactId
-                                       + "' in " + path);
-
-               boolean isSnapshot = baseVersion.endsWith("-" + SNAPSHOT);
-               String baseBaseVersion = isSnapshot ? baseVersion.substring(0,
-                               baseVersion.length() - SNAPSHOT.length() - 1) : baseVersion;
-               int artifactAndBaseBaseVersionLength = artifactId.length() + 1
-                               + baseBaseVersion.length() + 1;
-               String classifier = null;
-               if (baseName.length() > artifactAndBaseBaseVersionLength) {
-                       String dashRest = baseName
-                                       .substring(artifactAndBaseBaseVersionLength);
-                       String[] dashes = dashRest.split("-");
-
-                       if (isSnapshot) {
-                               if (dashes[0].equals(SNAPSHOT)) {
-                                       if (dashRest.length() > SNAPSHOT.length() + 1)
-                                               classifier = dashRest.substring(SNAPSHOT.length() + 1);
-
-                               } else {
-                                       if (dashes.length > 2)// assume no '-' in classifier
-                                               classifier = dashes[2];
-                               }
-                       } else {
-                               if (dashes.length > 0)
-                                       classifier = dashes[0];
-                       }
-               }
-
-               // classifier
-               // String classifier = null;
-               // int firstDash = baseName.indexOf('-');
-               // int classifierDash = baseName.lastIndexOf('-');
-               // if (classifierDash > 0 && classifierDash != firstDash) {
-               // classifier = baseName.substring(classifierDash + 1);
-               // }
-               // if (isSnapshot && classifier != null) {
-               // if (classifier.equals(SNAPSHOT))
-               // classifier = null;
-               // else
-               // try {
-               // Long.parseLong(classifier); // build number
-               // // if not failed this is a timestamped version
-               // classifier = null;
-               // } catch (NumberFormatException e) {
-               // // silent
-               // }
-               // }
-
-               // version
-               String version = baseName.substring(artifactId.length() + 1);
-               if (classifier != null)
-                       version = version.substring(0,
-                                       version.length() - classifier.length() - 1);
-
-               // consistency checks
-               if (!isSnapshot && !version.equals(baseVersion))
-                       throw new SlcException("Base version '" + baseVersion
-                                       + "' and version '" + version + "' not in line in " + path);
-               if (!isSnapshot && isSnapshotVersion(version))
-                       throw new SlcException("SNAPSHOT base version '" + baseVersion
-                                       + "' and version '" + version + "' not in line in " + path);
-
-               DefaultArtifact artifact = new DefaultArtifact(groupId.toString(),
-                               artifactId, classifier, extension, version);
-               return artifact;
-       }
-
-       /** Hacked from aether */
-       public static boolean isSnapshotVersion(String version) {
-               return version.endsWith(SNAPSHOT)
-                               || SNAPSHOT_TIMESTAMP.matcher(version).matches();
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java b/org.argeo.slc.support/src/org/argeo/slc/aether/ArtifactIdComparator.java
deleted file mode 100644 (file)
index 6aa0ec6..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import java.util.Comparator;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import org.eclipse.aether.artifact.Artifact;
-
-/**
- * Compare two artifacts, for use in {@link TreeSet} / {@link TreeMap}, consider
- * artifactId first THEN groupId
- */
-public class ArtifactIdComparator implements Comparator<Artifact> {
-       public int compare(Artifact o1, Artifact o2) {
-               if (o1.getArtifactId().equals(o2.getArtifactId()))
-                       return o1.getGroupId().compareTo(o2.getGroupId());
-               return o1.getArtifactId().compareTo(o2.getArtifactId());
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java b/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleRepositoryListener.java
deleted file mode 100644 (file)
index 727c5f3..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.aether.AbstractRepositoryListener;
-import org.eclipse.aether.RepositoryEvent;
-
-public class ConsoleRepositoryListener extends AbstractRepositoryListener {
-
-       private final static Log log = LogFactory
-                       .getLog(ConsoleRepositoryListener.class);
-
-       public void artifactDeployed(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Deployed " + event.getArtifact() + " to "
-                                       + event.getRepository());
-       }
-
-       public void artifactDeploying(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Deploying " + event.getArtifact() + " to "
-                                       + event.getRepository());
-       }
-
-       public void artifactDescriptorInvalid(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.warn("Invalid artifact descriptor for " + event.getArtifact()
-                                       + ": " + event.getException().getMessage());
-       }
-
-       public void artifactDescriptorMissing(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.warn("Missing artifact descriptor for " + event.getArtifact());
-       }
-
-       public void artifactInstalled(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Installed " + event.getArtifact() + " to "
-                                       + event.getFile());
-       }
-
-       public void artifactInstalling(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Installing " + event.getArtifact() + " to "
-                                       + event.getFile());
-       }
-
-       public void artifactResolved(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Resolved artifact " + event.getArtifact() + " from "
-                                       + event.getRepository());
-       }
-
-       public void artifactDownloading(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Downloading artifact " + event.getArtifact() + " from "
-                                       + event.getRepository());
-       }
-
-       public void artifactDownloaded(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Downloaded artifact " + event.getArtifact() + " from "
-                                       + event.getRepository());
-       }
-
-       public void artifactResolving(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Resolving artifact " + event.getArtifact());
-       }
-
-       public void metadataDeployed(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Deployed " + event.getMetadata() + " to "
-                                       + event.getRepository());
-       }
-
-       public void metadataDeploying(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Deploying " + event.getMetadata() + " to "
-                                       + event.getRepository());
-       }
-
-       public void metadataInstalled(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Installed " + event.getMetadata() + " to "
-                                       + event.getFile());
-       }
-
-       public void metadataInstalling(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Installing " + event.getMetadata() + " to "
-                                       + event.getFile());
-       }
-
-       public void metadataInvalid(RepositoryEvent event) {
-               if (log.isDebugEnabled())
-                       log.debug("Invalid metadata " + event.getMetadata());
-       }
-
-       public void metadataResolved(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Resolved metadata " + event.getMetadata() + " from "
-                                       + event.getRepository());
-       }
-
-       public void metadataResolving(RepositoryEvent event) {
-               if (log.isTraceEnabled())
-                       log.trace("Resolving metadata " + event.getMetadata() + " from "
-                                       + event.getRepository());
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java b/org.argeo.slc.support/src/org/argeo/slc/aether/ConsoleTransferListener.java
deleted file mode 100644 (file)
index 3543d68..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import java.io.PrintStream;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.eclipse.aether.transfer.AbstractTransferListener;
-import org.eclipse.aether.transfer.TransferEvent;
-import org.eclipse.aether.transfer.TransferResource;
-
-public class ConsoleTransferListener extends AbstractTransferListener {
-       private final static Log log = LogFactory
-                       .getLog(ConsoleTransferListener.class);
-
-       private PrintStream out;
-
-       private Map<TransferResource, Long> downloads = new ConcurrentHashMap<TransferResource, Long>();
-
-       private int lastLength;
-
-       public ConsoleTransferListener(PrintStream out) {
-               this.out = (out != null) ? out : System.out;
-       }
-
-       @Override
-       public void transferInitiated(TransferEvent event) {
-               String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading"
-                               : "Downloading";
-
-               if (log.isDebugEnabled())
-                       log.debug(message + ": " + event.getResource().getRepositoryUrl()
-                                       + event.getResource().getResourceName());
-       }
-
-       @Override
-       public void transferProgressed(TransferEvent event) {
-               TransferResource resource = event.getResource();
-               downloads.put(resource, Long.valueOf(event.getTransferredBytes()));
-
-               StringBuilder buffer = new StringBuilder(64);
-
-               for (Map.Entry<TransferResource, Long> entry : downloads.entrySet()) {
-                       long total = entry.getKey().getContentLength();
-                       long complete = entry.getValue().longValue();
-
-                       buffer.append(getStatus(complete, total)).append("  ");
-               }
-
-               int pad = lastLength - buffer.length();
-               lastLength = buffer.length();
-               pad(buffer, pad);
-               buffer.append('\r');
-
-               out.print(buffer);
-       }
-
-       private String getStatus(long complete, long total) {
-               if (total >= 1024) {
-                       return toKB(complete) + "/" + toKB(total) + " KB ";
-               } else if (total >= 0) {
-                       return complete + "/" + total + " B ";
-               } else if (complete >= 1024) {
-                       return toKB(complete) + " KB ";
-               } else {
-                       return complete + " B ";
-               }
-       }
-
-       private void pad(StringBuilder buffer, int spaces) {
-               String block = "                                        ";
-               while (spaces > 0) {
-                       int n = Math.min(spaces, block.length());
-                       buffer.append(block, 0, n);
-                       spaces -= n;
-               }
-       }
-
-       @Override
-       public void transferSucceeded(TransferEvent event) {
-               transferCompleted(event);
-
-               TransferResource resource = event.getResource();
-               long contentLength = event.getTransferredBytes();
-               if (contentLength >= 0) {
-                       String type = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded"
-                                       : "Downloaded");
-                       String len = contentLength >= 1024 ? toKB(contentLength) + " KB"
-                                       : contentLength + " B";
-
-                       String throughput = "";
-                       long duration = System.currentTimeMillis()
-                                       - resource.getTransferStartTime();
-                       if (duration > 0) {
-                               DecimalFormat format = new DecimalFormat("0.0",
-                                               new DecimalFormatSymbols(Locale.ENGLISH));
-                               double kbPerSec = (contentLength / 1024.0)
-                                               / (duration / 1000.0);
-                               throughput = " at " + format.format(kbPerSec) + " KB/sec";
-                       }
-
-                       out.println(type + ": " + resource.getRepositoryUrl()
-                                       + resource.getResourceName() + " (" + len + throughput
-                                       + ")");
-               }
-       }
-
-       @Override
-       public void transferFailed(TransferEvent event) {
-               transferCompleted(event);
-
-               log.error(event.getException().getMessage()
-                               + (event.getException().getCause() != null ? " : "
-                                               + event.getException().getCause().getMessage() : ""));
-               // event.getException().printStackTrace( out );
-       }
-
-       private void transferCompleted(TransferEvent event) {
-               downloads.remove(event.getResource());
-
-               StringBuilder buffer = new StringBuilder(64);
-               pad(buffer, lastLength);
-               buffer.append('\r');
-               out.print(buffer);
-       }
-
-       public void transferCorrupted(TransferEvent event) {
-               event.getException().printStackTrace(out);
-       }
-
-       protected long toKB(long bytes) {
-               return (bytes + 1023) / 1024;
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleArtifactDescriptorReader.java
deleted file mode 100644 (file)
index 3aca172..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.impl.ArtifactDescriptorReader;
-import org.eclipse.aether.resolution.ArtifactDescriptorException;
-import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
-import org.eclipse.aether.resolution.ArtifactDescriptorResult;
-
-public class SimpleArtifactDescriptorReader implements ArtifactDescriptorReader {
-
-       public ArtifactDescriptorResult readArtifactDescriptor(
-                       RepositorySystemSession session, ArtifactDescriptorRequest request)
-                       throws ArtifactDescriptorException {
-               ArtifactDescriptorResult result = new ArtifactDescriptorResult(request);
-               return result;
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionRangeResolver.java
deleted file mode 100644 (file)
index b7e7f95..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import org.argeo.slc.aether.osgi.OsgiVersion;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.impl.VersionRangeResolver;
-import org.eclipse.aether.resolution.VersionRangeRequest;
-import org.eclipse.aether.resolution.VersionRangeResolutionException;
-import org.eclipse.aether.resolution.VersionRangeResult;
-import org.eclipse.aether.version.Version;
-
-public class SimpleVersionRangeResolver implements VersionRangeResolver {
-
-       public VersionRangeResult resolveVersionRange(
-                       RepositorySystemSession session, VersionRangeRequest request)
-                       throws VersionRangeResolutionException {
-               VersionRangeResult versionRangeResult = new VersionRangeResult(request);
-               Version version = new OsgiVersion(request.getArtifact()
-                               .getBaseVersion());
-               versionRangeResult.addVersion(version);
-               return null;
-       }
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java b/org.argeo.slc.support/src/org/argeo/slc/aether/SimpleVersionResolver.java
deleted file mode 100644 (file)
index 51a6490..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether;
-
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.impl.VersionResolver;
-import org.eclipse.aether.resolution.VersionRequest;
-import org.eclipse.aether.resolution.VersionResolutionException;
-import org.eclipse.aether.resolution.VersionResult;
-
-public class SimpleVersionResolver implements VersionResolver {
-
-       public VersionResult resolveVersion(RepositorySystemSession session,
-                       VersionRequest request) throws VersionResolutionException {
-               VersionResult versionResult = new VersionResult(request);
-               versionResult.setVersion(request.getArtifact().getBaseVersion());
-               return versionResult;
-       }
-
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java b/org.argeo.slc.support/src/org/argeo/slc/aether/osgi/OsgiVersion.java
deleted file mode 100644 (file)
index 9f35ff9..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether.osgi;
-
-import org.osgi.framework.Version;
-
-/**
- * Wraps an OSGi {@link Version} as an Aether
- * {@link org.eclipse.aether.version.Version}.
- */
-public class OsgiVersion implements org.eclipse.aether.version.Version {
-       final private Version version;
-
-       public OsgiVersion(String str) {
-               version = Version.parseVersion(str);
-       }
-
-       public Version getVersion() {
-               return version;
-       }
-
-       public int compareTo(org.eclipse.aether.version.Version v) {
-               if (!(v instanceof OsgiVersion))
-                       return 0;
-               OsgiVersion ov = (OsgiVersion) v;
-               return version.compareTo(ov.version);
-       }
-}
diff --git a/org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java b/org.argeo.slc.support/src/org/argeo/slc/aether/spring/RemoteRepositoryFactory.java
deleted file mode 100644 (file)
index 7223c78..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2007-2012 Argeo GmbH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *         http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.argeo.slc.aether.spring;
-
-import org.eclipse.aether.repository.RemoteRepository;
-import org.eclipse.aether.util.repository.AuthenticationBuilder;
-import org.springframework.beans.factory.BeanNameAware;
-import org.springframework.beans.factory.FactoryBean;
-
-/** Simplifies the definition of a remote factory using Spring */
-public class RemoteRepositoryFactory implements BeanNameAware,
-               FactoryBean<RemoteRepository> {
-       private String beanName;
-       private String id;
-       private String url;
-       private String type = "default";
-       private String username;
-       private String password;
-
-       public RemoteRepository getObject() throws Exception {
-               RemoteRepository.Builder builder = new RemoteRepository.Builder(
-                               id != null ? id : beanName, type, url);
-               if (username != null) {
-                       AuthenticationBuilder authBuilder = new AuthenticationBuilder();
-                       authBuilder.addUsername(username);
-                       authBuilder.addPassword(password);
-                       builder.setAuthentication(authBuilder.build());
-               }
-               RemoteRepository remoteRepository = builder.build();
-               return remoteRepository;
-       }
-
-       public Class<?> getObjectType() {
-               return RemoteRepository.class;
-       }
-
-       public boolean isSingleton() {
-               return true;
-       }
-
-       public void setBeanName(String name) {
-               this.beanName = name;
-
-       }
-
-       public void setId(String id) {
-               this.id = id;
-       }
-
-       public void setUrl(String url) {
-               this.url = url;
-       }
-
-       public void setType(String type) {
-               this.type = type;
-       }
-
-       public void setUsername(String username) {
-               this.username = username;
-       }
-
-       public void setPassword(String password) {
-               this.password = password;
-       }
-
-}
diff --git a/pom.xml b/pom.xml
index b12659b2db55641c6f7ddb360e2b9cd0931073d7..cf85fe6ac8757ed4c3541611a9321f39a3d1a5d9 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -25,7 +25,7 @@
                <module>org.argeo.slc.core</module>
                <module>org.argeo.slc.unit</module>
                <module>org.argeo.slc.support</module>
-               <module>org.argeo.slc.support.maven</module>
+<!--           <module>org.argeo.slc.support.maven</module> -->
                <module>org.argeo.slc.repo</module>
                <module>org.argeo.slc.factory</module>
                <module>org.argeo.slc.launcher</module>