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