001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.internal; 014 015import static org.apache.juneau.internal.StringUtils.*; 016 017/** 018 * Represents a version string such as <js>"1.2"</js> or <js>"1.2.3"</js> 019 * 020 * <p> 021 * Used to compare version numbers. 022 */ 023public class Version { 024 025 private int[] parts; 026 027 /** 028 * Constructor 029 * 030 * @param versionString 031 * A string of the form <js>"#.#..."</js> where there can be any number of parts. 032 * <br>Valid values: 033 * <ul> 034 * <li><js>"1.2"</js> 035 * <li><js>"1.2.3"</js> 036 * <li><js>"0.1"</js> 037 * <li><js>".1"</js> 038 * </ul> 039 * Any parts that are not numeric are interpreted as {@link Integer#MAX_VALUE} 040 */ 041 public Version(String versionString) { 042 if (isEmpty(versionString)) 043 versionString = "0"; 044 String[] sParts = split(versionString, '.'); 045 parts = new int[sParts.length]; 046 for (int i = 0; i < sParts.length; i++) { 047 try { 048 parts[i] = sParts[i].isEmpty() ? 0 : Integer.parseInt(sParts[i]); 049 } catch (NumberFormatException e) { 050 parts[i] = Integer.MAX_VALUE; 051 } 052 } 053 } 054 055 /** 056 * Returns <jk>true</jk> if the specified version is at least this version. 057 * 058 * <p> 059 * Note that the following is true: 060 * <p class='bcode'> 061 * boolean b; 062 * b = <jk>new</jk> Version(<js>"1.2"</js>).isAtLeast(<jk>new</jk> Version(<js>"1.2.3"</js>)); <jc>// == true </jc> 063 * b = <jk>new</jk> Version(<js>"1.2.0"</js>).isAtLeast(<jk>new</jk> Version(<js>"1.2.3"</js>)); <jc>// == false</jc> 064 * </p> 065 * 066 * @param v The version to compare to. 067 * @param exclusive Match down-to-version but not including. 068 * @return <jk>true</jk> if the specified version is at least this version. 069 */ 070 public boolean isAtLeast(Version v, boolean exclusive) { 071 for (int i = 0; i < Math.min(parts.length, v.parts.length); i++) { 072 int c = v.parts[i] - parts[i]; 073 if (c > 0) 074 return false; 075 else if (c < 0) 076 return true; 077 } 078 for (int i = parts.length; i < v.parts.length; i++) 079 if (v.parts[i] != 0) 080 return false; 081 return ! exclusive; 082 } 083 084 /** 085 * Returns <jk>true</jk> if the specified version is at most this version. 086 * 087 * <p> 088 * Note that the following is true: 089 * <p class='bcode'> 090 * boolean b; 091 * b = <jk>new</jk> Version(<js>"1.2.3"</js>).isAtMost(<jk>new</jk> Version(<js>"1.2"</js>)); <jc>// == true </jc> 092 * b = <jk>new</jk> Version(<js>"1.2.3"</js>).isAtMost(<jk>new</jk> Version(<js>"1.2.0"</js>)); <jc>// == false</jc> 093 * </p> 094 * 095 * @param v The version to compare to. 096 * @param exclusive Match up-to-version but not including. 097 * @return <jk>true</jk> if the specified version is at most this version. 098 */ 099 public boolean isAtMost(Version v, boolean exclusive) { 100 for (int i = 0; i < Math.min(parts.length, v.parts.length); i++) { 101 int c = parts[i] - v.parts[i]; 102 if (c > 0) 103 return false; 104 else if (c < 0) 105 return true; 106 } 107 for (int i = parts.length; i < v.parts.length; i++) 108 if (v.parts[i] > 0) 109 return false; 110 return ! exclusive; 111 } 112 113 /** 114 * Returns <jk>true</jk> if the specified version is equal to this version. 115 * 116 * <p> 117 * Note that the following is true: 118 * <p class='bcode'> 119 * boolean b; 120 * b = <jk>new</jk> Version(<js>"1.2.3"</js>).equals(<jk>new</jk> Version(<js>"1.2"</js>)); <jc>// == true </jc> 121 * b = <jk>new</jk> Version(<js>"1.2"</js>).equals(<jk>new</jk> Version(<js>"1.2.3"</js>)); <jc>// == true</jc> 122 * </p> 123 * 124 * @param v The version to compare to. 125 * @return <jk>true</jk> if the specified version is equal to this version. 126 */ 127 public boolean isEqualsTo(Version v) { 128 for (int i = 0; i < Math.min(parts.length, v.parts.length); i++) 129 if (v.parts[i] - parts[i] != 0) 130 return false; 131 return true; 132 } 133 134 @Override /* Object */ 135 public String toString() { 136 return join(parts, '.'); 137 } 138}