1 package com.atlassian.plugins.rest.common.version;
2
3 import com.google.common.base.Function;
4 import org.apache.commons.lang.StringUtils;
5 import org.apache.commons.lang.builder.EqualsBuilder;
6 import org.apache.commons.lang.builder.HashCodeBuilder;
7
8 import javax.annotation.Nullable;
9 import java.util.regex.Matcher;
10 import java.util.regex.Pattern;
11
12
13
14
15
16 public class ApiVersion implements Comparable {
17 public static final String NONE_STRING = "none";
18 public static final ApiVersion NONE = new ApiVersion(NONE_STRING);
19
20 private static final String DOT = ".";
21
22 private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)(?:\\.(\\d+))?(?:\\.(\\d+))?(?:\\.([\\w-]*))?");
23
24 private final Integer major;
25
26 private final Integer minor;
27
28 private final Integer micro;
29
30 private final String classifier;
31
32 private static RuntimeException defaultVersionExceptionMapping(String version) {
33 if (version == null) {
34 throw new NullPointerException();
35 } else {
36 throw new IllegalArgumentException(version);
37 }
38 }
39
40 public ApiVersion(String version) {
41 this(version, new Function<String, RuntimeException>() {
42 @Nullable
43 @Override
44 public RuntimeException apply(String input) {
45 return defaultVersionExceptionMapping(input);
46 }
47 });
48 }
49
50 protected ApiVersion(String version, Function<String, RuntimeException> exceptionMapper) {
51 if (version == null) {
52 throw exceptionMapper.apply(version);
53 }
54
55
56 if (NONE_STRING.equals(version)) {
57 major = minor = micro = null;
58 classifier = null;
59 } else {
60 final Matcher matcher = VERSION_PATTERN.matcher(version);
61 if (!matcher.matches()) {
62 throw exceptionMapper.apply(version);
63 }
64
65 major = Integer.valueOf(matcher.group(1));
66 minor = matcher.group(2) != null ? Integer.valueOf(matcher.group(2)) : null;
67 micro = matcher.group(3) != null ? Integer.valueOf(matcher.group(3)) : null;
68 classifier = matcher.group(4);
69 }
70 }
71
72 public boolean isNone() {
73 return this.equals(NONE);
74 }
75
76 public static boolean isNone(String version) {
77 return NONE_STRING.equals(version);
78 }
79
80 public Integer getMajor() {
81 return major;
82 }
83
84 public Integer getMinor() {
85 return minor;
86 }
87
88 public Integer getMicro() {
89 return micro;
90 }
91
92 public String getClassifier() {
93 return classifier;
94 }
95
96 @Override
97 public boolean equals(Object o) {
98 if (o == null) {
99 return false;
100 }
101 if (o == this) {
102 return true;
103 }
104 if (!(o instanceof ApiVersion)) {
105 return false;
106 }
107
108 final ApiVersion version = (ApiVersion) o;
109 return new EqualsBuilder()
110 .append(this.major, version.major)
111 .append(this.minor, version.minor)
112 .append(this.micro, version.micro)
113 .append(this.classifier, version.classifier).isEquals();
114 }
115
116 @Override
117 public int hashCode() {
118 return new HashCodeBuilder(3, 41).append(major).append(minor).append(micro).append(classifier).toHashCode();
119 }
120
121 public int compareTo(Object o) {
122 if (o == null) {
123 return 1;
124 }
125 if (o == this) {
126 return 0;
127 }
128 if (!(o instanceof ApiVersion)) {
129 return 1;
130 }
131
132 final ApiVersion that = (ApiVersion) o;
133
134 final int majorDifference = compare(this.major, that.major);
135 if (majorDifference != 0) {
136 return majorDifference;
137 }
138 final int minorDifference = compare(this.minor, that.minor);
139 if (minorDifference != 0) {
140 return minorDifference;
141 }
142 final int microDifference = compare(this.micro, that.micro);
143 if (microDifference != 0) {
144 return microDifference;
145 }
146 return compare(this.classifier, that.classifier);
147 }
148
149 private <T extends Comparable<T>> int compare(T n, T m) {
150 if (n == null && m == null) {
151 return 0;
152 }
153 if (n == null) {
154 return -1;
155 }
156 if (m == null) {
157 return +1;
158 }
159 return n.compareTo(m);
160 }
161
162 @Override
163 public String toString() {
164 return isNone()
165 ? NONE_STRING
166 : major
167 + (minor != null ? DOT + minor : "")
168 + (micro != null ? DOT + micro : "")
169 + (StringUtils.isNotBlank(classifier) ? DOT + classifier : "");
170 }
171 }