xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/util/Version.java (revision 5d9f3aa0ca3da3a714233f987fa732f62c0965f6)
1d9038ba8SKryštof Tulinger /*
2d9038ba8SKryštof Tulinger  * CDDL HEADER START
3d9038ba8SKryštof Tulinger  *
4d9038ba8SKryštof Tulinger  * The contents of this file are subject to the terms of the
5d9038ba8SKryštof Tulinger  * Common Development and Distribution License (the "License").
6d9038ba8SKryštof Tulinger  * You may not use this file except in compliance with the License.
7d9038ba8SKryštof Tulinger  *
8d9038ba8SKryštof Tulinger  * See LICENSE.txt included in this distribution for the specific
9d9038ba8SKryštof Tulinger  * language governing permissions and limitations under the License.
10d9038ba8SKryštof Tulinger  *
11d9038ba8SKryštof Tulinger  * When distributing Covered Code, include this CDDL HEADER in each
12d9038ba8SKryštof Tulinger  * file and include the License file at LICENSE.txt.
13d9038ba8SKryštof Tulinger  * If applicable, add the following below this CDDL HEADER, with the
14d9038ba8SKryštof Tulinger  * fields enclosed by brackets "[]" replaced with your own identifying
15d9038ba8SKryštof Tulinger  * information: Portions Copyright [yyyy] [name of copyright owner]
16d9038ba8SKryštof Tulinger  *
17d9038ba8SKryštof Tulinger  * CDDL HEADER END
18d9038ba8SKryštof Tulinger  */
19d9038ba8SKryštof Tulinger 
20d9038ba8SKryštof Tulinger /*
21*5d9f3aa0SAdam Hornáček  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
22d9038ba8SKryštof Tulinger  * Portions Copyright (c) 2019, Krystof Tulinger (tulinkry).
23d9038ba8SKryštof Tulinger  */
24d9038ba8SKryštof Tulinger package org.opengrok.indexer.util;
25d9038ba8SKryštof Tulinger 
26d9038ba8SKryštof Tulinger import java.util.Arrays;
27d9038ba8SKryštof Tulinger import java.util.stream.Stream;
28d9038ba8SKryštof Tulinger 
29d9038ba8SKryštof Tulinger /**
30d9038ba8SKryštof Tulinger  * This class implements portions of semantic versioning from version noted as
31d9038ba8SKryštof Tulinger  * <pre>
32d9038ba8SKryštof Tulinger  *     a.b.c.d.e.f
33d9038ba8SKryštof Tulinger  * </pre>
34d9038ba8SKryštof Tulinger  * where
35d9038ba8SKryštof Tulinger  * <pre>
36d9038ba8SKryštof Tulinger  *     a - major
37d9038ba8SKryštof Tulinger  *     b - minor
38d9038ba8SKryštof Tulinger  *     c - patch
39d9038ba8SKryštof Tulinger  *     d ... - others
40d9038ba8SKryštof Tulinger  * </pre>
41d9038ba8SKryštof Tulinger  *
42d9038ba8SKryštof Tulinger  * @author Krystof Tulinger (tulinkry)
43d9038ba8SKryštof Tulinger  * @see <a href="https://semver.org/">https://semver.org/</a>
44d9038ba8SKryštof Tulinger  */
45d9038ba8SKryštof Tulinger public class Version implements Comparable<Version> {
46d9038ba8SKryštof Tulinger     private final Integer[] versions;
47d9038ba8SKryštof Tulinger 
48d9038ba8SKryštof Tulinger     /**
49d9038ba8SKryštof Tulinger      * Construct the version from integer parts.
50d9038ba8SKryštof Tulinger      * The order is:
51d9038ba8SKryštof Tulinger      * <ol>
52d9038ba8SKryštof Tulinger      * <li>major</li>
53d9038ba8SKryštof Tulinger      * <li>minor</li>
54d9038ba8SKryštof Tulinger      * <li>patch</li>
55d9038ba8SKryštof Tulinger      * <li>... others</li>
56d9038ba8SKryštof Tulinger      * </ol>
57d9038ba8SKryštof Tulinger      *
58d9038ba8SKryštof Tulinger      * @param parts integer values for version partials
59d9038ba8SKryštof Tulinger      */
Version(Integer... parts)60d9038ba8SKryštof Tulinger     public Version(Integer... parts) {
61d9038ba8SKryštof Tulinger         // cut off trailing zeros
62d9038ba8SKryštof Tulinger         int cutOffLength = parts.length;
63d9038ba8SKryštof Tulinger         for (int i = parts.length - 1; i >= 0; i--) {
64d9038ba8SKryštof Tulinger             if (parts[i] != 0) {
65d9038ba8SKryštof Tulinger                 break;
66d9038ba8SKryštof Tulinger             }
67d9038ba8SKryštof Tulinger             cutOffLength--;
68d9038ba8SKryštof Tulinger         }
69d9038ba8SKryštof Tulinger         versions = Arrays.copyOf(parts, cutOffLength);
70d9038ba8SKryštof Tulinger     }
71d9038ba8SKryštof Tulinger 
72d9038ba8SKryštof Tulinger     /**
73d9038ba8SKryštof Tulinger      * Construct the version from a string.
74d9038ba8SKryštof Tulinger      *
75d9038ba8SKryštof Tulinger      * @param string string representing the version (e. g. 1.2.1)
76d9038ba8SKryštof Tulinger      * @return the new instance of version from the string
77d9038ba8SKryštof Tulinger      * @throws NumberFormatException when parts can not be converted to integers
78d9038ba8SKryštof Tulinger      */
from(String string)79d9038ba8SKryštof Tulinger     public static Version from(String string) throws NumberFormatException {
80d9038ba8SKryštof Tulinger         return new Version(
81d9038ba8SKryštof Tulinger                 Stream.of(string.trim().split("\\."))
82d9038ba8SKryštof Tulinger                       .map(String::trim)
83d9038ba8SKryštof Tulinger                       .map(Integer::parseInt)
84d9038ba8SKryštof Tulinger                       .toArray(Integer[]::new)
85d9038ba8SKryštof Tulinger         );
86d9038ba8SKryštof Tulinger     }
87d9038ba8SKryštof Tulinger 
88d9038ba8SKryštof Tulinger     @Override
equals(Object o)89d9038ba8SKryštof Tulinger     public boolean equals(Object o) {
90d9038ba8SKryštof Tulinger         if (this == o) {
91d9038ba8SKryštof Tulinger             return true;
92d9038ba8SKryštof Tulinger         }
93d9038ba8SKryštof Tulinger         if (o == null || getClass() != o.getClass()) {
94d9038ba8SKryštof Tulinger             return false;
95d9038ba8SKryštof Tulinger         }
96d9038ba8SKryštof Tulinger         Version version = (Version) o;
97d9038ba8SKryštof Tulinger         return Arrays.equals(versions, version.versions);
98d9038ba8SKryštof Tulinger     }
99d9038ba8SKryštof Tulinger 
100d9038ba8SKryštof Tulinger     @Override
hashCode()101d9038ba8SKryštof Tulinger     public int hashCode() {
102d9038ba8SKryštof Tulinger         return Arrays.hashCode(versions);
103d9038ba8SKryštof Tulinger     }
104d9038ba8SKryštof Tulinger 
105d9038ba8SKryštof Tulinger     @Override
compareTo(Version o)106d9038ba8SKryštof Tulinger     public int compareTo(Version o) {
107d9038ba8SKryštof Tulinger         if (o == null) {
108d9038ba8SKryštof Tulinger             return 1;
109d9038ba8SKryštof Tulinger         }
110d9038ba8SKryštof Tulinger 
111d9038ba8SKryštof Tulinger         // first different number determines the result
112d9038ba8SKryštof Tulinger         for (int i = 0; i < Math.min(versions.length, o.versions.length); i++) {
113d9038ba8SKryštof Tulinger             if (!versions[i].equals(o.versions[i])) {
114d9038ba8SKryštof Tulinger                 return Integer.compare(versions[i], o.versions[i]);
115d9038ba8SKryštof Tulinger             }
116d9038ba8SKryštof Tulinger         }
117d9038ba8SKryštof Tulinger 
118d9038ba8SKryštof Tulinger         // the comparable parts are the same, the longer has some trailing non-null element which
119d9038ba8SKryštof Tulinger         // makes it greater then the shorter
120d9038ba8SKryštof Tulinger         // e. g. 1.0.0.0.1 vs. 1.0.0
121d9038ba8SKryštof Tulinger         return Integer.compare(versions.length, o.versions.length);
122d9038ba8SKryštof Tulinger     }
123d9038ba8SKryštof Tulinger }
124