Remove atomix.utils.Generics
[controller.git] / third-party / atomix / utils / src / main / java / io / atomix / utils / Version.java
1 /*
2  * Copyright 2018-present Open Networking Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.atomix.utils;
17
18 import com.google.common.collect.ComparisonChain;
19
20 import java.util.Objects;
21
22 import static com.google.common.base.Preconditions.checkArgument;
23 import static java.lang.Integer.parseInt;
24
25 /**
26  * Atomix software version.
27  */
28 public final class Version implements Comparable<Version> {
29
30   /**
31    * Returns a new version from the given version string.
32    *
33    * @param version the version string
34    * @return the version object
35    * @throws IllegalArgumentException if the version string is invalid
36    */
37   public static Version from(String version) {
38     String[] fields = version.split("[.-]", 4);
39     checkArgument(fields.length >= 3, "version number is invalid");
40     return new Version(
41         parseInt(fields[0]),
42         parseInt(fields[1]),
43         parseInt(fields[2]),
44         fields.length == 4 ? fields[3] : null);
45   }
46
47   /**
48    * Returns a new version from the given parts.
49    *
50    * @param major the major version number
51    * @param minor the minor version number
52    * @param patch the patch version number
53    * @param build the build version number
54    * @return the version object
55    */
56   public static Version from(int major, int minor, int patch, String build) {
57     return new Version(major, minor, patch, build);
58   }
59
60   private final int major;
61   private final int minor;
62   private final int patch;
63   private final String build;
64
65   private Version(int major, int minor, int patch, String build) {
66     checkArgument(major >= 0, "major version must be >= 0");
67     checkArgument(minor >= 0, "minor version must be >= 0");
68     checkArgument(patch >= 0, "patch version must be >= 0");
69     this.major = major;
70     this.minor = minor;
71     this.patch = patch;
72     this.build = Build.from(build).toString();
73   }
74
75   /**
76    * Returns the major version number.
77    *
78    * @return the major version number
79    */
80   public int major() {
81     return major;
82   }
83
84   /**
85    * Returns the minor version number.
86    *
87    * @return the minor version number
88    */
89   public int minor() {
90     return minor;
91   }
92
93   /**
94    * Returns the patch version number.
95    *
96    * @return the patch version number
97    */
98   public int patch() {
99     return patch;
100   }
101
102   /**
103    * Returns the build version number.
104    *
105    * @return the build version number
106    */
107   public String build() {
108     return build;
109   }
110
111   @Override
112   public int compareTo(Version that) {
113     return ComparisonChain.start()
114         .compare(this.major, that.major)
115         .compare(this.minor, that.minor)
116         .compare(this.patch, that.patch)
117         .compare(Build.from(this.build), Build.from(that.build))
118         .result();
119   }
120
121   @Override
122   public int hashCode() {
123     return Objects.hash(major, minor, patch, build);
124   }
125
126   @Override
127   public boolean equals(Object object) {
128     if (object == this) {
129       return true;
130     }
131     if (!(object instanceof Version)) {
132       return false;
133     }
134     Version that = (Version) object;
135     return this.major == that.major
136         && this.minor == that.minor
137         && this.patch == that.patch
138         && Objects.equals(this.build, that.build);
139   }
140
141   @Override
142   public String toString() {
143     StringBuilder builder = new StringBuilder()
144         .append(major)
145         .append('.')
146         .append(minor)
147         .append('.')
148         .append(patch);
149     String build = Build.from(this.build).toString();
150     if (build != null) {
151       builder.append('-').append(build);
152     }
153     return builder.toString();
154   }
155
156   /**
157    * Build version.
158    */
159   private static class Build implements Comparable<Build> {
160
161     /**
162      * Creates a new build version from the given string.
163      *
164      * @param build the build version string
165      * @return the build version
166      * @throws IllegalArgumentException if the build version string is invalid
167      */
168     public static Build from(String build) {
169       if (build == null) {
170         return new Build(Type.FINAL, 0);
171       } else if (build.equalsIgnoreCase(Type.SNAPSHOT.name())) {
172         return new Build(Type.SNAPSHOT, 0);
173       }
174
175       for (Type type : Type.values()) {
176         if (type.name != null && build.length() >= type.name.length() && build.substring(0, type.name.length()).equalsIgnoreCase(type.name)) {
177           try {
178             int version = parseInt(build.substring(type.name.length()));
179             return new Build(type, version);
180           } catch (NumberFormatException e) {
181             throw new IllegalArgumentException(build + " is not a valid build version string");
182           }
183         }
184       }
185       throw new IllegalArgumentException(build + " is not a valid build version string");
186     }
187
188     private final Type type;
189     private final int version;
190
191     private Build(Type type, int version) {
192       this.type = type;
193       this.version = version;
194     }
195
196     @Override
197     public int compareTo(Build that) {
198       return ComparisonChain.start()
199           .compare(this.type.ordinal(), that.type.ordinal())
200           .compare(this.version, that.version)
201           .result();
202     }
203
204     @Override
205     public int hashCode() {
206       return Objects.hash(type, version);
207     }
208
209     @Override
210     public boolean equals(Object object) {
211       if (object == this) {
212         return true;
213       }
214       if (!(object instanceof Build)) {
215         return false;
216       }
217       Build that = (Build) object;
218       return Objects.equals(this.type, that.type) && this.version == that.version;
219     }
220
221     @Override
222     public String toString() {
223       return type.format(version);
224     }
225
226     /**
227      * Build type.
228      */
229     private enum Type {
230       SNAPSHOT("snapshot"),
231       ALPHA("alpha"),
232       BETA("beta"),
233       RC("rc"),
234       FINAL(null);
235
236       private final String name;
237
238       Type(String name) {
239         this.name = name;
240       }
241
242       String format(int version) {
243         if (name == null) {
244           return null;
245         } else if ("snapshot".equals(name)) {
246           return "SNAPSHOT";
247         } else {
248           return String.format("%s%d", name, version);
249         }
250       }
251
252       @Override
253       public String toString() {
254         return name;
255       }
256     }
257   }
258 }