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=
<name>SLC Distribution</name>
<modules>
<module>slc</module>
- <module>slc-maven</module>
+<!-- <module>slc-maven</module> -->
</modules>
<!-- <profiles> -->
<!-- <profile> -->
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;
<?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>
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,\
--- /dev/null
+additional.bundles = org.junit
--- /dev/null
+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);
+ }
+}
--- /dev/null
+<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 "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.
+]]>
+ </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>
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;
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;
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;
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;
--- /dev/null
+/*
+ * 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();
+ }
+
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
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;
+++ /dev/null
-/*
- * 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;
- }
-
-}
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
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() {
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;
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
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;
--- /dev/null
+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
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 )
+ {
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 -> b -> c -> 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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" ) + ")";
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() + ")";
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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() );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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)" );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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 )
+ {
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
--- /dev/null
+/*******************************************************************************
+ * 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;
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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();
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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 );
+ }
+
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+}
--- /dev/null
+/*******************************************************************************
+ * 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;
+
+++ /dev/null
-<?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
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
<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
+++ /dev/null
-<?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
+++ /dev/null
-<?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
+++ /dev/null
-<?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
+++ /dev/null
-<?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
+++ /dev/null
-<?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
+++ /dev/null
-<?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
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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();
- }
-
-}
+++ /dev/null
-/*
- * 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());
- }
-
-}
+++ /dev/null
-/*
- * 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());
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-
-}
<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>