1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.jpackage.internal; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.Objects; 31 import java.util.regex.Pattern; 32 33 /** 34 * Dotted numeric version string. 35 * E.g.: 1.0.37, 10, 0.5 36 */ 37 class DottedVersion implements Comparable<String> { 38 39 public DottedVersion(String version) { 40 greedy = true; 41 components = parseVersionString(version, greedy); 42 value = version; 43 } 44 45 private DottedVersion(String version, boolean greedy) { 46 this.greedy = greedy; 47 components = parseVersionString(version, greedy); 48 value = version; 49 } 50 51 public static DottedVersion greedy(String version) { 52 return new DottedVersion(version); 53 } 54 55 public static DottedVersion lazy(String version) { 56 return new DottedVersion(version, false); 57 } 58 59 @Override 60 public int compareTo(String o) { 61 int result = 0; 62 int[] otherComponents = parseVersionString(o, greedy); 63 for (int i = 0; i < Math.min(components.length, otherComponents.length) 64 && result == 0; ++i) { 65 result = components[i] - otherComponents[i]; 66 } 67 68 if (result == 0) { 69 result = components.length - otherComponents.length; 70 } 71 72 return result; 73 } 74 75 private static int[] parseVersionString(String version, boolean greedy) { 76 Objects.requireNonNull(version); 77 if (version.isEmpty()) { 78 if (!greedy) { 79 return new int[] {0}; 80 } 81 throw new IllegalArgumentException("Version may not be empty string"); 82 } 83 84 int lastNotZeroIdx = -1; 85 List<Integer> components = new ArrayList<>(); 86 for (var component : version.split("\\.", -1)) { 87 if (component.isEmpty()) { 88 if (!greedy) { 89 break; 90 } 91 92 throw new IllegalArgumentException(String.format( 93 "Version [%s] contains a zero lenght component", version)); 94 } 95 96 if (!DIGITS.matcher(component).matches()) { 97 // Catch "+N" and "-N" cases. 98 if (!greedy) { 99 break; 100 } 101 102 throw new IllegalArgumentException(String.format( 103 "Version [%s] contains invalid component [%s]", version, 104 component)); 105 } 106 107 final int num; 108 try { 109 num = Integer.parseInt(component); 110 } catch (NumberFormatException ex) { 111 if (!greedy) { 112 break; 113 } 114 115 throw ex; 116 } 117 118 if (num != 0) { 119 lastNotZeroIdx = components.size(); 120 } 121 components.add(num); 122 } 123 124 if (lastNotZeroIdx + 1 != components.size()) { 125 // Strip trailing zeros. 126 components = components.subList(0, lastNotZeroIdx + 1); 127 } 128 129 if (components.isEmpty()) { 130 components.add(0); 131 } 132 return components.stream().mapToInt(Integer::intValue).toArray(); 133 } 134 135 @Override 136 public String toString() { 137 return value; 138 } 139 140 final private int[] components; 141 final private String value; 142 final private boolean greedy; 143 144 private static final Pattern DIGITS = Pattern.compile("\\d+"); 145 }