diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
index d76efff780..c26cedf9ed 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
@@ -80,7 +80,7 @@ public class DefaultArtifact
this.artifactId = artifactId;
// TODO: this would be where we might have a min/max instead
- this.version = versionRange.getVersion();
+ this.version = versionRange != null ? versionRange.getRecommendedVersion() : null;
this.artifactHandler = artifactHandler;
@@ -188,8 +188,7 @@ public class DefaultArtifact
public String getId()
{
- return getDependencyConflictId() + ( hasClassifier() ? ( ":" + getClassifier() ) : "" ) + ":" +
- getBaseVersion();
+ return getDependencyConflictId() + ( hasClassifier() ? ":" + getClassifier() : "" ) + ":" + getBaseVersion();
}
public String getDependencyConflictId()
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
index f9864e609b..e5f310df55 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
@@ -101,14 +101,10 @@ public class DefaultArtifactFactory
String classifier, String inheritedScope )
{
// TODO: better constructor
- VersionRange versionRange;
+ VersionRange versionRange = null;
if ( version != null )
{
- versionRange = new VersionRange( "[" + version + "]" );
- }
- else
- {
- versionRange = new VersionRange( null );
+ versionRange = VersionRange.createFromVersion( version );
}
return createArtifact( groupId, artifactId, versionRange, scope, type, classifier, inheritedScope );
}
@@ -127,13 +123,11 @@ public class DefaultArtifactFactory
{
return null;
}
-
- // vvv added to retain compile scope. Remove if you want compile inherited as runtime
else if ( Artifact.SCOPE_COMPILE.equals( scope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
{
+ // added to retain compile scope. Remove if you want compile inherited as runtime
desiredScope = Artifact.SCOPE_COMPILE;
}
- // ^^^ added to retain compile scope. Remove if you want compile inherited as runtime
if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
{
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java
new file mode 100644
index 0000000000..1f518da941
--- /dev/null
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java
@@ -0,0 +1,32 @@
+package org.apache.maven.artifact.versioning;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * Occurs when a version is invalid.
+ *
+ * @author Brett Porter
+ * @version $Id$
+ */
+public class InvalidVersionSpecificationException
+ extends Exception
+{
+ public InvalidVersionSpecificationException( String message )
+ {
+ super( message );
+ }
+}
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java
new file mode 100644
index 0000000000..d186e633e8
--- /dev/null
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java
@@ -0,0 +1,62 @@
+package org.apache.maven.artifact.versioning;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+/**
+ * Describes a restriction in versioning.
+ *
+ * @author Brett Porter
+ * @version $Id$
+ */
+public class Restriction
+{
+ private final String lowerBound;
+
+ private final boolean lowerBoundInclusive;
+
+ private final String upperBound;
+
+ private final boolean upperBoundInclusive;
+
+ public Restriction( String lowerBound, boolean lowerBoundInclusive, String upperBound, boolean upperBoundInclusive )
+ {
+ this.lowerBound = lowerBound;
+ this.lowerBoundInclusive = lowerBoundInclusive;
+ this.upperBound = upperBound;
+ this.upperBoundInclusive = upperBoundInclusive;
+ }
+
+ public String getLowerBound()
+ {
+ return lowerBound;
+ }
+
+ public boolean isLowerBoundInclusive()
+ {
+ return lowerBoundInclusive;
+ }
+
+ public String getUpperBound()
+ {
+ return upperBound;
+ }
+
+ public boolean isUpperBoundInclusive()
+ {
+ return upperBoundInclusive;
+ }
+}
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
index 1883dd440e..80363b4ae7 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
@@ -16,6 +16,10 @@ package org.apache.maven.artifact.versioning;
* limitations under the License.
*/
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* Construct a version range from a specification.
*
@@ -24,24 +28,124 @@ package org.apache.maven.artifact.versioning;
*/
public class VersionRange
{
- private String version;
+ private final String recommendedVersion;
- public VersionRange( String spec )
+ private final List restrictions;
+
+ private VersionRange( String recommendedVersion, List restrictions )
{
- if ( spec != null )
+ this.recommendedVersion = recommendedVersion;
+ this.restrictions = restrictions;
+ }
+
+ public String getRecommendedVersion()
+ {
+ return recommendedVersion;
+ }
+
+ public List getRestrictions()
+ {
+ return restrictions;
+ }
+
+ public static VersionRange createFromVersionSpec( String spec )
+ throws InvalidVersionSpecificationException
+ {
+ List exclusions = new ArrayList();
+ String process = spec;
+ String version = null;
+
+ while ( process.startsWith( "[" ) || process.startsWith( "(" ) )
{
- // temporary!
- if ( spec.startsWith( "[" ) )
+ int index1 = process.indexOf( ")" );
+ int index2 = process.indexOf( "]" );
+
+ int index = index2;
+ if ( index2 < 0 || index1 < index2 )
{
- spec = spec.substring( 1, spec.length() - 1 );
+ if ( index1 >= 0 )
+ {
+ index = index1;
+ }
+ }
+
+ if ( index < 0 )
+ {
+ throw new InvalidVersionSpecificationException( "Unbounded range: " + spec );
+ }
+
+ exclusions.add( parseRestriction( process.substring( 0, index + 1 ) ) );
+
+ process = process.substring( index + 1 ).trim();
+
+ if ( process.length() > 0 && process.startsWith( "," ) )
+ {
+ process = process.substring( 1 ).trim();
}
}
- this.version = spec;
+ if ( process.length() > 0 )
+ {
+ if ( exclusions.size() > 0 )
+ {
+ throw new InvalidVersionSpecificationException(
+ "Only fully-qualified sets allowed in multiple set scenario: " + spec );
+ }
+ else
+ {
+ version = process;
+ }
+ }
+
+ return new VersionRange( version, exclusions );
}
- public String getVersion()
+ private static Restriction parseRestriction( String spec )
+ throws InvalidVersionSpecificationException
{
- return version;
+ boolean lowerBoundInclusive = spec.startsWith( "[" );
+ boolean upperBoundInclusive = spec.endsWith( "]" );
+
+ String process = spec.substring( 1, spec.length() - 1 ).trim();
+
+ Restriction restriction;
+
+ int index = process.indexOf( "," );
+
+ if ( index < 0 )
+ {
+ if ( !lowerBoundInclusive || !upperBoundInclusive )
+ {
+ throw new InvalidVersionSpecificationException( "Single version must be surrounded by []: " + spec );
+ }
+ restriction = new Restriction( process, lowerBoundInclusive, process, upperBoundInclusive );
+ }
+ else
+ {
+ String lowerBound = process.substring( 0, index ).trim();
+ String upperBound = process.substring( index + 1 ).trim();
+ if ( lowerBound.equals( upperBound ) )
+ {
+ throw new InvalidVersionSpecificationException( "Range cannot have identical boundaries: " + spec );
+ }
+
+ if ( lowerBound.length() == 0 )
+ {
+ lowerBound = null;
+ }
+ if ( upperBound.length() == 0 )
+ {
+ upperBound = null;
+ }
+
+ restriction = new Restriction( lowerBound, lowerBoundInclusive, upperBound, upperBoundInclusive );
+ }
+
+ return restriction;
+ }
+
+ public static VersionRange createFromVersion( String version )
+ {
+ return new VersionRange( version, Collections.EMPTY_LIST );
}
}
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java
new file mode 100644
index 0000000000..4841098b58
--- /dev/null
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java
@@ -0,0 +1,148 @@
+package org.apache.maven.artifact.versioning;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * 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 java.util.List;
+
+/**
+ * Tests version range construction.
+ *
+ * @author Brett Porter
+ * @version $Id$
+ */
+public class VersionRangeTest
+ extends TestCase
+{
+ private static final String CHECK_NUM_RESTRICTIONS = "check number of restrictions";
+
+ private static final String CHECK_UPPER_BOUND = "check upper bound";
+
+ private static final String CHECK_UPPER_BOUND_INCLUSIVE = "check upper bound is inclusive";
+
+ private static final String CHECK_LOWER_BOUND = "check lower bound";
+
+ private static final String CHECK_LOWER_BOUND_INCLUSIVE = "check lower bound is inclusive";
+
+ private static final String CHECK_VERSION_RECOMMENDATION = "check version recommended";
+
+ public void testRange()
+ throws InvalidVersionSpecificationException
+ {
+ VersionRange range = VersionRange.createFromVersionSpec( "(,1.0]" );
+ List restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 1, restrictions.size() );
+ Restriction restriction = (Restriction) restrictions.get( 0 );
+ assertNull( CHECK_LOWER_BOUND, restriction.getLowerBound() );
+ assertFalse( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertEquals( CHECK_UPPER_BOUND, "1.0", restriction.getUpperBound() );
+ assertTrue( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "1.0" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 0, restrictions.size() );
+ assertEquals( CHECK_VERSION_RECOMMENDATION, "1.0", range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "[1.0]" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 1, restrictions.size() );
+ restriction = (Restriction) restrictions.get( 0 );
+ assertEquals( CHECK_LOWER_BOUND, "1.0", restriction.getLowerBound() );
+ assertTrue( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertEquals( CHECK_UPPER_BOUND, "1.0", restriction.getUpperBound() );
+ assertTrue( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 1, restrictions.size() );
+ restriction = (Restriction) restrictions.get( 0 );
+ assertEquals( CHECK_LOWER_BOUND, "1.2", restriction.getLowerBound() );
+ assertTrue( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertEquals( CHECK_UPPER_BOUND, "1.3", restriction.getUpperBound() );
+ assertTrue( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "[1.0,2.0)" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 1, restrictions.size() );
+ restriction = (Restriction) restrictions.get( 0 );
+ assertEquals( CHECK_LOWER_BOUND, "1.0", restriction.getLowerBound() );
+ assertTrue( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertEquals( CHECK_UPPER_BOUND, "2.0", restriction.getUpperBound() );
+ assertFalse( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "[1.5,)" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 1, restrictions.size() );
+ restriction = (Restriction) restrictions.get( 0 );
+ assertEquals( CHECK_LOWER_BOUND, "1.5", restriction.getLowerBound() );
+ assertTrue( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertNull( CHECK_UPPER_BOUND, restriction.getUpperBound() );
+ assertFalse( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+
+ range = VersionRange.createFromVersionSpec( "(,1.0],[1.2,)" );
+ restrictions = range.getRestrictions();
+ assertEquals( CHECK_NUM_RESTRICTIONS, 2, restrictions.size() );
+ restriction = (Restriction) restrictions.get( 0 );
+ assertNull( CHECK_LOWER_BOUND, restriction.getLowerBound() );
+ assertFalse( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertEquals( CHECK_UPPER_BOUND, "1.0", restriction.getUpperBound() );
+ assertTrue( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+ restriction = (Restriction) restrictions.get( 1 );
+ assertEquals( CHECK_LOWER_BOUND, "1.2", restriction.getLowerBound() );
+ assertTrue( CHECK_LOWER_BOUND_INCLUSIVE, restriction.isLowerBoundInclusive() );
+ assertNull( CHECK_UPPER_BOUND, restriction.getUpperBound() );
+ assertFalse( CHECK_UPPER_BOUND_INCLUSIVE, restriction.isUpperBoundInclusive() );
+ assertNull( CHECK_VERSION_RECOMMENDATION, range.getRecommendedVersion() );
+ }
+
+ public void testInvalidRanges()
+ {
+ checkInvalidRange( "(1.0)" );
+ checkInvalidRange( "[1.0)" );
+ checkInvalidRange( "(1.0]" );
+ checkInvalidRange( "(1.0,1.0]" );
+ checkInvalidRange( "[1.0,1.0)" );
+ checkInvalidRange( "(1.0,1.0)" );
+ checkInvalidRange( "[1.0,1.2),1.3" );
+/* TODO: not testing this presently
+ // overlap
+ checkInvalidRange( "[1.0,1.2),(1.1,1.3]" );
+ // overlap
+ checkInvalidRange( "[1.1,1.3),(1.0,1.2]" );
+*/
+ }
+
+ private void checkInvalidRange( String version )
+ {
+ try
+ {
+ VersionRange.createFromVersionSpec( version );
+ fail( "Version " + version + " should have failed to construct" );
+ }
+ catch ( InvalidVersionSpecificationException expected )
+ {
+ // expected
+ }
+ }
+}