1 package com.atlassian.plugin.util;
2
3 import org.apache.commons.lang.StringUtils;
4
5 import java.util.Comparator;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 public class VersionStringComparator implements Comparator
24 {
25 public static final String DELIMITER_PATTERN = "[\\.,-]";
26 public static final String COMPONENT_PATTERN = "[\\d\\w]+";
27 public static final String VALID_VERSION_PATTERN =
28 COMPONENT_PATTERN + "(" + DELIMITER_PATTERN + COMPONENT_PATTERN + ")*";
29
30 public static boolean isValidVersionString(String version)
31 {
32 return version != null && version.matches(VALID_VERSION_PATTERN);
33 }
34
35
36
37
38
39
40
41
42
43 public int compare(Object o1, Object o2)
44 {
45 if (!(o1 instanceof String)) return 0;
46 if (!(o2 instanceof String)) return 0;
47
48 return compare((String) o1, (String) o2);
49 }
50
51
52
53
54
55
56
57
58
59 public int compare(String version1, String version2)
60 {
61
62 String thisVersion = "0";
63 if (StringUtils.isNotEmpty(version1))
64 {
65 thisVersion = version1.replaceAll(" ", "");
66 }
67 String compareVersion = "0";
68 if (StringUtils.isNotEmpty(version2))
69 {
70 compareVersion = version2.replaceAll(" ", "");
71 }
72
73 if (!thisVersion.matches(VALID_VERSION_PATTERN) || !compareVersion.matches(VALID_VERSION_PATTERN))
74 {
75 throw new IllegalArgumentException(
76 "Version number '" + thisVersion + "' cannot be compared to '" + compareVersion + "'");
77 }
78
79
80 String[] v1 = thisVersion.split(DELIMITER_PATTERN);
81 String[] v2 = compareVersion.split(DELIMITER_PATTERN);
82
83 Comparator componentComparator = new VersionStringComponentComparator();
84
85
86 for (int i = 0; i < (v1.length > v2.length ? v1.length : v2.length); i ++)
87 {
88 String component1 = i >= v1.length ? "0" : v1[i];
89 String component2 = i >= v2.length ? "0" : v2[i];
90
91 if (componentComparator.compare(component1, component2) != 0)
92 return componentComparator.compare(component1, component2);
93 }
94
95 return 0;
96 }
97
98 private class VersionStringComponentComparator implements Comparator
99 {
100 public static final int FIRST_GREATER = 1;
101 public static final int SECOND_GREATER = -1;
102
103 public int compare(Object o1, Object o2)
104 {
105 if (!(o1 instanceof String)) return 0;
106 if (!(o2 instanceof String)) return 0;
107
108 return compare((String) o1, (String) o2);
109 }
110
111 public int compare(String component1, String component2)
112 {
113 if (component1.equalsIgnoreCase(component2)) return 0;
114
115 if (isInteger(component1) && isInteger(component2))
116 {
117
118 if (Integer.parseInt(component1) > Integer.parseInt(component2)) return FIRST_GREATER;
119 if (Integer.parseInt(component2) > Integer.parseInt(component1)) return SECOND_GREATER;
120 return 0;
121 }
122
123
124 if ("0".equals(component1)) return FIRST_GREATER;
125 if ("0".equals(component2)) return SECOND_GREATER;
126
127
128 if (isInteger(component1) && component2.startsWith(component1)) return FIRST_GREATER;
129 if (isInteger(component2) && component1.startsWith(component2)) return SECOND_GREATER;
130
131
132 return component1.compareToIgnoreCase(component2);
133 }
134
135 private boolean isInteger(String string)
136 {
137 return string.matches("\\d+");
138 }
139 }
140 }