You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/01/12 15:32:01 UTC
[1/2] camel git commit: [CAMEL-9500] CamelVersionHelper cannot handle
version qualifier
Repository: camel
Updated Branches:
refs/heads/camel-2.16.x 3e0fd2b1c -> 267c297c9
refs/heads/master 659664a45 -> 9ce810f30
[CAMEL-9500] CamelVersionHelper cannot handle version qualifier
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/267c297c
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/267c297c
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/267c297c
Branch: refs/heads/camel-2.16.x
Commit: 267c297c9a631acf124a4dc6bb1216b150940524
Parents: 3e0fd2b
Author: Thomas Diesler <th...@jboss.com>
Authored: Mon Jan 11 13:52:21 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Tue Jan 12 15:27:47 2016 +0100
----------------------------------------------------------------------
.../apache/camel/util/CamelVersionHelper.java | 406 ++++++++++++++++++-
.../camel/util/CamelVersionHelperTest.java | 2 +
2 files changed, 397 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/267c297c/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java b/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
index 5c630b2..4fa7d40 100644
--- a/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
@@ -16,30 +16,414 @@
*/
package org.apache.camel.util;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Stack;
+
/**
* A simple util to test Camel versions.
*/
public final class CamelVersionHelper {
+
private CamelVersionHelper() {
- //utility class, never constructed
+ // utility class, never constructed
}
/**
* Checks whether other >= base
*
- * @param base the base version
+ * @param base the base version
* @param other the other version
* @return <tt>true</tt> if GE, <tt>false</tt> otherwise
*/
public static boolean isGE(String base, String other) {
- String s1 = base.replaceAll("\\.", "");
- String s2 = other.replaceAll("\\.", "");
- // SNAPSHOT as .0
- s1 = s1.replace("-SNAPSHOT", "0");
- s2 = s2.replace("-SNAPSHOT", "0");
- // then use number comparison
- int n1 = Integer.valueOf(s1);
- int n2 = Integer.valueOf(s2);
- return Integer.compare(n2, n1) >= 0;
+ ComparableVersion v1 = new ComparableVersion(base);
+ ComparableVersion v2 = new ComparableVersion(other);
+ return v2.compareTo(v1) >= 0;
+ }
+
+ /**
+ * Generic implementation of version comparison.
+ * https://github.com/apache/maven/blob/master/maven-artifact/src/main/java/
+ * org/apache/maven/artifact/versioning/ComparableVersion.java
+ * <p>
+ * Features:
+ * <ul>
+ * <li>mixing of '<code>-</code>' (hyphen) and '<code>.</code>' (dot)
+ * separators,</li>
+ * <li>transition between characters and digits also constitutes a
+ * separator: <code>1.0alpha1 => [1, 0, alpha, 1]</code></li>
+ * <li>unlimited number of version components,</li>
+ * <li>version components in the text can be digits or strings,</li>
+ * <li>strings are checked for well-known qualifiers and the qualifier
+ * ordering is used for version ordering. Well-known qualifiers (case
+ * insensitive) are:
+ * <ul>
+ * <li><code>alpha</code> or <code>a</code></li>
+ * <li><code>beta</code> or <code>b</code></li>
+ * <li><code>milestone</code> or <code>m</code></li>
+ * <li><code>rc</code> or <code>cr</code></li>
+ * <li><code>snapshot</code></li>
+ * <li><code>(the empty string)</code> or <code>ga</code> or
+ * <code>final</code></li>
+ * <li><code>sp</code></li>
+ * </ul>
+ * Unknown qualifiers are considered after known qualifiers, with lexical
+ * order (always case insensitive),</li>
+ * <li>a hyphen usually precedes a qualifier, and is always less important
+ * than something preceded with a dot.</li>
+ * </ul>
+ * </p>
+ *
+ * @see <a href=
+ * "https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">
+ * "Versioning" on Maven Wiki</a>
+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
+ * @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
+ */
+ private static final class ComparableVersion implements Comparable<ComparableVersion> {
+
+ private String value;
+ private String canonical;
+ private ListItem items;
+
+ private interface Item {
+ int INTEGER_ITEM = 0;
+ int STRING_ITEM = 1;
+ int LIST_ITEM = 2;
+
+ int compareTo(Item item);
+
+ int getType();
+
+ boolean isNull();
+ }
+
+ /**
+ * Represents a numeric item in the version item list.
+ */
+ private static class IntegerItem implements Item {
+
+ private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0");
+ private static final IntegerItem ZERO = new IntegerItem();
+ private final BigInteger value;
+
+ private IntegerItem() {
+ this.value = BIG_INTEGER_ZERO;
+ }
+
+ public IntegerItem(String str) {
+ this.value = new BigInteger(str);
+ }
+
+ public int getType() {
+ return INTEGER_ITEM;
+ }
+
+ public boolean isNull() {
+ return BIG_INTEGER_ZERO.equals(value);
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1,
+ // 1.1 > 1
+ }
+
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return value.compareTo(((IntegerItem)item).value);
+
+ case STRING_ITEM:
+ return 1; // 1.1 > 1-sp
+
+ case LIST_ITEM:
+ return 1; // 1.1 > 1-1
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ return value.toString();
+ }
+ }
+
+ /**
+ * Represents a string in the version item list, usually a qualifier.
+ */
+ private static class StringItem implements Item {
+ private static final String[] QUALIFIERS = {"alpha", "beta", "milestone", "rc", "snapshot", "", "sp"};
+
+ private static final List<String> QUALIFIERS_LIST = Arrays.asList(QUALIFIERS);
+
+ private static final Properties ALIASES = new Properties();
+
+ static {
+ ALIASES.put("ga", "");
+ ALIASES.put("final", "");
+ ALIASES.put("cr", "rc");
+ }
+
+ /**
+ * A comparable value for the empty-string qualifier. This one is
+ * used to determine if a given qualifier makes the version older
+ * than one without a qualifier, or more recent.
+ */
+ private static final String RELEASE_VERSION_INDEX = String.valueOf(QUALIFIERS_LIST.indexOf(""));
+
+ private String value;
+
+ public StringItem(String value, boolean followedByDigit) {
+ if (followedByDigit && value.length() == 1) {
+ // a1 = alpha-1, b1 = beta-1, m1 = milestone-1
+ switch (value.charAt(0)) {
+ case 'a':
+ value = "alpha";
+ break;
+ case 'b':
+ value = "beta";
+ break;
+ case 'm':
+ value = "milestone";
+ break;
+ default:
+ }
+ }
+ this.value = ALIASES.getProperty(value, value);
+ }
+
+ public int getType() {
+ return STRING_ITEM;
+ }
+
+ public boolean isNull() {
+ return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0;
+ }
+
+ /**
+ * Returns a comparable value for a qualifier. This method takes
+ * into account the ordering of known qualifiers then unknown
+ * qualifiers with lexical ordering. just returning an Integer with
+ * the index here is faster, but requires a lot of if/then/else to
+ * check for -1 or QUALIFIERS.size and then resort to lexical
+ * ordering. Most comparisons are decided by the first character, so
+ * this is still fast. If more characters are needed then it
+ * requires a lexical sort anyway.
+ *
+ * @param qualifier
+ * @return an equivalent value that can be used with lexical
+ * comparison
+ */
+ public static String comparableQualifier(String qualifier) {
+ int i = QUALIFIERS_LIST.indexOf(qualifier);
+
+ return i == -1 ? (QUALIFIERS_LIST.size() + "-" + qualifier) : String.valueOf(i);
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ // 1-rc < 1, 1-ga > 1
+ return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX);
+ }
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return -1; // 1.any < 1.1 ?
+
+ case STRING_ITEM:
+ return comparableQualifier(value).compareTo(comparableQualifier(((StringItem)item).value));
+
+ case LIST_ITEM:
+ return -1; // 1.any < 1-1
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ return value;
+ }
+ }
+
+ /**
+ * Represents a version list item. This class is used both for the
+ * global item list and for sub-lists (which start with '-(number)' in
+ * the version specification).
+ */
+ @SuppressWarnings("serial")
+ private static class ListItem extends ArrayList<Item> implements Item {
+ public int getType() {
+ return LIST_ITEM;
+ }
+
+ public boolean isNull() {
+ return size() == 0;
+ }
+
+ void normalize() {
+ for (int i = size() - 1; i >= 0; i--) {
+ Item lastItem = get(i);
+
+ if (lastItem.isNull()) {
+ // remove null trailing items: 0, "", empty list
+ remove(i);
+ } else if (!(lastItem instanceof ListItem)) {
+ break;
+ }
+ }
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ if (size() == 0) {
+ return 0; // 1-0 = 1- (normalize) = 1
+ }
+ Item first = get(0);
+ return first.compareTo(null);
+ }
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return -1; // 1-1 < 1.0.x
+
+ case STRING_ITEM:
+ return 1; // 1-1 > 1-sp
+
+ case LIST_ITEM:
+ Iterator<Item> left = iterator();
+ Iterator<Item> right = ((ListItem)item).iterator();
+
+ while (left.hasNext() || right.hasNext()) {
+ Item l = left.hasNext() ? left.next() : null;
+ Item r = right.hasNext() ? right.next() : null;
+
+ // if this is shorter, then invert the compare and mul
+ // with -1
+ int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);
+
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ return 0;
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ for (Item item : this) {
+ if (buffer.length() > 0) {
+ buffer.append((item instanceof ListItem) ? '-' : '.');
+ }
+ buffer.append(item);
+ }
+ return buffer.toString();
+ }
+ }
+
+ private ComparableVersion(String version) {
+ parseVersion(version);
+ }
+
+ private void parseVersion(String version) {
+ this.value = version;
+
+ items = new ListItem();
+
+ version = version.toLowerCase(Locale.ENGLISH);
+
+ ListItem list = items;
+
+ Stack<Item> stack = new Stack<>();
+ stack.push(list);
+
+ boolean isDigit = false;
+
+ int startIndex = 0;
+
+ for (int i = 0; i < version.length(); i++) {
+ char c = version.charAt(i);
+
+ if (c == '.') {
+ if (i == startIndex) {
+ list.add(IntegerItem.ZERO);
+ } else {
+ list.add(parseItem(isDigit, version.substring(startIndex, i)));
+ }
+ startIndex = i + 1;
+ } else if (c == '-') {
+ if (i == startIndex) {
+ list.add(IntegerItem.ZERO);
+ } else {
+ list.add(parseItem(isDigit, version.substring(startIndex, i)));
+ }
+ startIndex = i + 1;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ } else if (Character.isDigit(c)) {
+ if (!isDigit && i > startIndex) {
+ list.add(new StringItem(version.substring(startIndex, i), true));
+ startIndex = i;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ }
+
+ isDigit = true;
+ } else {
+ if (isDigit && i > startIndex) {
+ list.add(parseItem(true, version.substring(startIndex, i)));
+ startIndex = i;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ }
+
+ isDigit = false;
+ }
+ }
+
+ if (version.length() > startIndex) {
+ list.add(parseItem(isDigit, version.substring(startIndex)));
+ }
+
+ while (!stack.isEmpty()) {
+ list = (ListItem)stack.pop();
+ list.normalize();
+ }
+
+ canonical = items.toString();
+ }
+
+ private static Item parseItem(boolean isDigit, String buf) {
+ return isDigit ? new IntegerItem(buf) : new StringItem(buf, false);
+ }
+
+ public int compareTo(ComparableVersion o) {
+ return items.compareTo(o.items);
+ }
+
+ public String toString() {
+ return value;
+ }
+
+ public boolean equals(Object o) {
+ return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion)o).canonical);
+ }
+
+ public int hashCode() {
+ return canonical.hashCode();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/267c297c/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java b/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
index bf249ba..e2c294d 100644
--- a/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
+++ b/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
@@ -29,10 +29,12 @@ public class CamelVersionHelperTest extends TestCase {
assertTrue(isGE("2.15.0", "2.15.1"));
assertTrue(isGE("2.15.0", "2.16.0"));
assertTrue(isGE("2.15.0", "2.16-SNAPSHOT"));
+ assertTrue(isGE("2.15.0", "2.16-foo"));
assertFalse(isGE("2.15.0", "2.14.3"));
assertFalse(isGE("2.15.0", "2.13.0"));
assertFalse(isGE("2.15.0", "2.13.1"));
assertFalse(isGE("2.15.0", "2.14-SNAPSHOT"));
+ assertFalse(isGE("2.15.0", "2.14-foo"));
}
}
[2/2] camel git commit: [CAMEL-9500] CamelVersionHelper cannot handle
version qualifier
Posted by da...@apache.org.
[CAMEL-9500] CamelVersionHelper cannot handle version qualifier
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/9ce810f3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/9ce810f3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/9ce810f3
Branch: refs/heads/master
Commit: 9ce810f30ebf95e944f44ea03708f0213be9147a
Parents: 659664a
Author: Thomas Diesler <th...@jboss.com>
Authored: Mon Jan 11 13:52:21 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Tue Jan 12 15:28:32 2016 +0100
----------------------------------------------------------------------
.../apache/camel/util/CamelVersionHelper.java | 406 ++++++++++++++++++-
.../camel/util/CamelVersionHelperTest.java | 2 +
2 files changed, 397 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/9ce810f3/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java b/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
index 5c630b2..4fa7d40 100644
--- a/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
+++ b/camel-core/src/main/java/org/apache/camel/util/CamelVersionHelper.java
@@ -16,30 +16,414 @@
*/
package org.apache.camel.util;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Stack;
+
/**
* A simple util to test Camel versions.
*/
public final class CamelVersionHelper {
+
private CamelVersionHelper() {
- //utility class, never constructed
+ // utility class, never constructed
}
/**
* Checks whether other >= base
*
- * @param base the base version
+ * @param base the base version
* @param other the other version
* @return <tt>true</tt> if GE, <tt>false</tt> otherwise
*/
public static boolean isGE(String base, String other) {
- String s1 = base.replaceAll("\\.", "");
- String s2 = other.replaceAll("\\.", "");
- // SNAPSHOT as .0
- s1 = s1.replace("-SNAPSHOT", "0");
- s2 = s2.replace("-SNAPSHOT", "0");
- // then use number comparison
- int n1 = Integer.valueOf(s1);
- int n2 = Integer.valueOf(s2);
- return Integer.compare(n2, n1) >= 0;
+ ComparableVersion v1 = new ComparableVersion(base);
+ ComparableVersion v2 = new ComparableVersion(other);
+ return v2.compareTo(v1) >= 0;
+ }
+
+ /**
+ * Generic implementation of version comparison.
+ * https://github.com/apache/maven/blob/master/maven-artifact/src/main/java/
+ * org/apache/maven/artifact/versioning/ComparableVersion.java
+ * <p>
+ * Features:
+ * <ul>
+ * <li>mixing of '<code>-</code>' (hyphen) and '<code>.</code>' (dot)
+ * separators,</li>
+ * <li>transition between characters and digits also constitutes a
+ * separator: <code>1.0alpha1 => [1, 0, alpha, 1]</code></li>
+ * <li>unlimited number of version components,</li>
+ * <li>version components in the text can be digits or strings,</li>
+ * <li>strings are checked for well-known qualifiers and the qualifier
+ * ordering is used for version ordering. Well-known qualifiers (case
+ * insensitive) are:
+ * <ul>
+ * <li><code>alpha</code> or <code>a</code></li>
+ * <li><code>beta</code> or <code>b</code></li>
+ * <li><code>milestone</code> or <code>m</code></li>
+ * <li><code>rc</code> or <code>cr</code></li>
+ * <li><code>snapshot</code></li>
+ * <li><code>(the empty string)</code> or <code>ga</code> or
+ * <code>final</code></li>
+ * <li><code>sp</code></li>
+ * </ul>
+ * Unknown qualifiers are considered after known qualifiers, with lexical
+ * order (always case insensitive),</li>
+ * <li>a hyphen usually precedes a qualifier, and is always less important
+ * than something preceded with a dot.</li>
+ * </ul>
+ * </p>
+ *
+ * @see <a href=
+ * "https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">
+ * "Versioning" on Maven Wiki</a>
+ * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
+ * @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
+ */
+ private static final class ComparableVersion implements Comparable<ComparableVersion> {
+
+ private String value;
+ private String canonical;
+ private ListItem items;
+
+ private interface Item {
+ int INTEGER_ITEM = 0;
+ int STRING_ITEM = 1;
+ int LIST_ITEM = 2;
+
+ int compareTo(Item item);
+
+ int getType();
+
+ boolean isNull();
+ }
+
+ /**
+ * Represents a numeric item in the version item list.
+ */
+ private static class IntegerItem implements Item {
+
+ private static final BigInteger BIG_INTEGER_ZERO = new BigInteger("0");
+ private static final IntegerItem ZERO = new IntegerItem();
+ private final BigInteger value;
+
+ private IntegerItem() {
+ this.value = BIG_INTEGER_ZERO;
+ }
+
+ public IntegerItem(String str) {
+ this.value = new BigInteger(str);
+ }
+
+ public int getType() {
+ return INTEGER_ITEM;
+ }
+
+ public boolean isNull() {
+ return BIG_INTEGER_ZERO.equals(value);
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ return BIG_INTEGER_ZERO.equals(value) ? 0 : 1; // 1.0 == 1,
+ // 1.1 > 1
+ }
+
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return value.compareTo(((IntegerItem)item).value);
+
+ case STRING_ITEM:
+ return 1; // 1.1 > 1-sp
+
+ case LIST_ITEM:
+ return 1; // 1.1 > 1-1
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ return value.toString();
+ }
+ }
+
+ /**
+ * Represents a string in the version item list, usually a qualifier.
+ */
+ private static class StringItem implements Item {
+ private static final String[] QUALIFIERS = {"alpha", "beta", "milestone", "rc", "snapshot", "", "sp"};
+
+ private static final List<String> QUALIFIERS_LIST = Arrays.asList(QUALIFIERS);
+
+ private static final Properties ALIASES = new Properties();
+
+ static {
+ ALIASES.put("ga", "");
+ ALIASES.put("final", "");
+ ALIASES.put("cr", "rc");
+ }
+
+ /**
+ * A comparable value for the empty-string qualifier. This one is
+ * used to determine if a given qualifier makes the version older
+ * than one without a qualifier, or more recent.
+ */
+ private static final String RELEASE_VERSION_INDEX = String.valueOf(QUALIFIERS_LIST.indexOf(""));
+
+ private String value;
+
+ public StringItem(String value, boolean followedByDigit) {
+ if (followedByDigit && value.length() == 1) {
+ // a1 = alpha-1, b1 = beta-1, m1 = milestone-1
+ switch (value.charAt(0)) {
+ case 'a':
+ value = "alpha";
+ break;
+ case 'b':
+ value = "beta";
+ break;
+ case 'm':
+ value = "milestone";
+ break;
+ default:
+ }
+ }
+ this.value = ALIASES.getProperty(value, value);
+ }
+
+ public int getType() {
+ return STRING_ITEM;
+ }
+
+ public boolean isNull() {
+ return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX) == 0;
+ }
+
+ /**
+ * Returns a comparable value for a qualifier. This method takes
+ * into account the ordering of known qualifiers then unknown
+ * qualifiers with lexical ordering. just returning an Integer with
+ * the index here is faster, but requires a lot of if/then/else to
+ * check for -1 or QUALIFIERS.size and then resort to lexical
+ * ordering. Most comparisons are decided by the first character, so
+ * this is still fast. If more characters are needed then it
+ * requires a lexical sort anyway.
+ *
+ * @param qualifier
+ * @return an equivalent value that can be used with lexical
+ * comparison
+ */
+ public static String comparableQualifier(String qualifier) {
+ int i = QUALIFIERS_LIST.indexOf(qualifier);
+
+ return i == -1 ? (QUALIFIERS_LIST.size() + "-" + qualifier) : String.valueOf(i);
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ // 1-rc < 1, 1-ga > 1
+ return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX);
+ }
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return -1; // 1.any < 1.1 ?
+
+ case STRING_ITEM:
+ return comparableQualifier(value).compareTo(comparableQualifier(((StringItem)item).value));
+
+ case LIST_ITEM:
+ return -1; // 1.any < 1-1
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ return value;
+ }
+ }
+
+ /**
+ * Represents a version list item. This class is used both for the
+ * global item list and for sub-lists (which start with '-(number)' in
+ * the version specification).
+ */
+ @SuppressWarnings("serial")
+ private static class ListItem extends ArrayList<Item> implements Item {
+ public int getType() {
+ return LIST_ITEM;
+ }
+
+ public boolean isNull() {
+ return size() == 0;
+ }
+
+ void normalize() {
+ for (int i = size() - 1; i >= 0; i--) {
+ Item lastItem = get(i);
+
+ if (lastItem.isNull()) {
+ // remove null trailing items: 0, "", empty list
+ remove(i);
+ } else if (!(lastItem instanceof ListItem)) {
+ break;
+ }
+ }
+ }
+
+ public int compareTo(Item item) {
+ if (item == null) {
+ if (size() == 0) {
+ return 0; // 1-0 = 1- (normalize) = 1
+ }
+ Item first = get(0);
+ return first.compareTo(null);
+ }
+ switch (item.getType()) {
+ case INTEGER_ITEM:
+ return -1; // 1-1 < 1.0.x
+
+ case STRING_ITEM:
+ return 1; // 1-1 > 1-sp
+
+ case LIST_ITEM:
+ Iterator<Item> left = iterator();
+ Iterator<Item> right = ((ListItem)item).iterator();
+
+ while (left.hasNext() || right.hasNext()) {
+ Item l = left.hasNext() ? left.next() : null;
+ Item r = right.hasNext() ? right.next() : null;
+
+ // if this is shorter, then invert the compare and mul
+ // with -1
+ int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);
+
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ return 0;
+
+ default:
+ throw new RuntimeException("invalid item: " + item.getClass());
+ }
+ }
+
+ public String toString() {
+ StringBuilder buffer = new StringBuilder();
+ for (Item item : this) {
+ if (buffer.length() > 0) {
+ buffer.append((item instanceof ListItem) ? '-' : '.');
+ }
+ buffer.append(item);
+ }
+ return buffer.toString();
+ }
+ }
+
+ private ComparableVersion(String version) {
+ parseVersion(version);
+ }
+
+ private void parseVersion(String version) {
+ this.value = version;
+
+ items = new ListItem();
+
+ version = version.toLowerCase(Locale.ENGLISH);
+
+ ListItem list = items;
+
+ Stack<Item> stack = new Stack<>();
+ stack.push(list);
+
+ boolean isDigit = false;
+
+ int startIndex = 0;
+
+ for (int i = 0; i < version.length(); i++) {
+ char c = version.charAt(i);
+
+ if (c == '.') {
+ if (i == startIndex) {
+ list.add(IntegerItem.ZERO);
+ } else {
+ list.add(parseItem(isDigit, version.substring(startIndex, i)));
+ }
+ startIndex = i + 1;
+ } else if (c == '-') {
+ if (i == startIndex) {
+ list.add(IntegerItem.ZERO);
+ } else {
+ list.add(parseItem(isDigit, version.substring(startIndex, i)));
+ }
+ startIndex = i + 1;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ } else if (Character.isDigit(c)) {
+ if (!isDigit && i > startIndex) {
+ list.add(new StringItem(version.substring(startIndex, i), true));
+ startIndex = i;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ }
+
+ isDigit = true;
+ } else {
+ if (isDigit && i > startIndex) {
+ list.add(parseItem(true, version.substring(startIndex, i)));
+ startIndex = i;
+
+ list.add(list = new ListItem());
+ stack.push(list);
+ }
+
+ isDigit = false;
+ }
+ }
+
+ if (version.length() > startIndex) {
+ list.add(parseItem(isDigit, version.substring(startIndex)));
+ }
+
+ while (!stack.isEmpty()) {
+ list = (ListItem)stack.pop();
+ list.normalize();
+ }
+
+ canonical = items.toString();
+ }
+
+ private static Item parseItem(boolean isDigit, String buf) {
+ return isDigit ? new IntegerItem(buf) : new StringItem(buf, false);
+ }
+
+ public int compareTo(ComparableVersion o) {
+ return items.compareTo(o.items);
+ }
+
+ public String toString() {
+ return value;
+ }
+
+ public boolean equals(Object o) {
+ return (o instanceof ComparableVersion) && canonical.equals(((ComparableVersion)o).canonical);
+ }
+
+ public int hashCode() {
+ return canonical.hashCode();
+ }
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/9ce810f3/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java b/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
index bf249ba..e2c294d 100644
--- a/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
+++ b/camel-core/src/test/java/org/apache/camel/util/CamelVersionHelperTest.java
@@ -29,10 +29,12 @@ public class CamelVersionHelperTest extends TestCase {
assertTrue(isGE("2.15.0", "2.15.1"));
assertTrue(isGE("2.15.0", "2.16.0"));
assertTrue(isGE("2.15.0", "2.16-SNAPSHOT"));
+ assertTrue(isGE("2.15.0", "2.16-foo"));
assertFalse(isGE("2.15.0", "2.14.3"));
assertFalse(isGE("2.15.0", "2.13.0"));
assertFalse(isGE("2.15.0", "2.13.1"));
assertFalse(isGE("2.15.0", "2.14-SNAPSHOT"));
+ assertFalse(isGE("2.15.0", "2.14-foo"));
}
}