001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008 Sun Microsystems, Inc. 015 * Portions copyright 2013-2016 ForgeRock AS. 016 */ 017package org.opends.server.util; 018 019import static org.opends.messages.ToolMessages.*; 020import static org.opends.server.config.ConfigConstants.*; 021 022import java.io.BufferedReader; 023import java.io.FileNotFoundException; 024import java.io.FileReader; 025import java.io.IOException; 026import java.nio.file.Paths; 027import java.util.Arrays; 028 029import org.forgerock.util.Utils; 030import org.opends.server.core.DirectoryServer; 031import org.opends.server.types.InitializationException; 032 033/** 034 * Represents a particular version of OpenDJ useful for making comparisons 035 * between versions. 036 */ 037@org.opends.server.types.PublicAPI( 038 stability = org.opends.server.types.StabilityLevel.VOLATILE, 039 mayInstantiate = false, mayExtend = false, mayInvoke = true) 040public final class BuildVersion implements Comparable<BuildVersion> 041{ 042 043 private final int major; 044 private final int minor; 045 private final int point; 046 private final String rev; 047 private static final BuildVersion BINARY_VERSION = new BuildVersion( 048 DynamicConstants.MAJOR_VERSION, DynamicConstants.MINOR_VERSION, 049 DynamicConstants.POINT_VERSION, DynamicConstants.REVISION); 050 051 /** 052 * Returns the build version as specified by the dynamic constants. 053 * 054 * @return The build version as specified by the dynamic constants. 055 */ 056 public static BuildVersion binaryVersion() 057 { 058 return BINARY_VERSION; 059 } 060 061 /** 062 * Reads the instance version from config/buildinfo. 063 * 064 * @return The instance version from config/buildinfo. 065 * @throws InitializationException 066 * If an error occurred while reading or parsing the version. 067 */ 068 public static BuildVersion instanceVersion() throws InitializationException 069 { 070 final String buildInfo = Paths.get(DirectoryServer.getInstanceRoot(), CONFIG_DIR_NAME, "buildinfo").toString(); 071 try (final BufferedReader reader = new BufferedReader(new FileReader(buildInfo))) 072 { 073 final String s = reader.readLine(); 074 if (s == null) 075 { 076 throw new InitializationException(ERR_BUILDVERSION_MALFORMED.get(buildInfo)); 077 } 078 return valueOf(s); 079 } 080 catch (FileNotFoundException e) 081 { 082 throw new InitializationException(ERR_INSTANCE_NOT_CONFIGURED.get(), e); 083 } 084 catch (IOException e) 085 { 086 throw new InitializationException(ERR_BUILDVERSION_NOT_FOUND.get(buildInfo)); 087 } 088 catch (final IllegalArgumentException e) 089 { 090 throw new InitializationException(ERR_BUILDVERSION_MALFORMED.get(buildInfo)); 091 } 092 } 093 094 /** 095 * Checks if the binary version is the same than the instance version. 096 * 097 * @throws InitializationException 098 * Sends an exception if the version mismatch. 099 */ 100 public static void checkVersionMismatch() throws InitializationException 101 { 102 if (!BuildVersion.binaryVersion().equals(BuildVersion.instanceVersion())) 103 { 104 throw new InitializationException( 105 ERR_BUILDVERSION_MISMATCH.get(BuildVersion.binaryVersion(), BuildVersion.instanceVersion())); 106 } 107 } 108 109 /** 110 * Parses the string argument as a build version. The string must be of the 111 * form: 112 * 113 * <pre> 114 * major.minor.point[.rev] 115 * </pre> 116 * 117 * @param s 118 * The string to be parsed as a build version. 119 * @return The parsed build version. 120 * @throws IllegalArgumentException 121 * If the string does not contain a parsable build version. 122 */ 123 public static BuildVersion valueOf(final String s) throws IllegalArgumentException 124 { 125 final String[] fields = s.split("\\."); 126 final int nbFields = fields.length; 127 if (!(nbFields == 3 || nbFields == 4)) 128 { 129 throw new IllegalArgumentException("Invalid version string " + s); 130 } 131 final int major = Integer.parseInt(fields[0]); 132 final int minor = Integer.parseInt(fields[1]); 133 final int point = Integer.parseInt(fields[2]); 134 135 if (nbFields == 4) 136 { 137 return new BuildVersion(major, minor, point, fields[3]); 138 } 139 else 140 { 141 return new BuildVersion(major, minor, point); 142 } 143 } 144 145 /** 146 * Creates a new build version using the provided version information. 147 * 148 * @param major 149 * Major release version number. 150 * @param minor 151 * Minor release version number. 152 * @param point 153 * Point release version number. 154 */ 155 private BuildVersion(final int major, final int minor, final int point) 156 { 157 this(major, minor, point, ""); 158 } 159 160 /** 161 * Creates a new build version using the provided version information. 162 * 163 * @param major 164 * Major release version number. 165 * @param minor 166 * Minor release version number. 167 * @param point 168 * Point release version number. 169 * @param rev 170 * VCS revision. 171 */ 172 private BuildVersion(final int major, final int minor, final int point, final String rev) 173 { 174 this.major = major; 175 this.minor = minor; 176 this.point = point; 177 this.rev = rev; 178 } 179 180 @Override 181 public int compareTo(final BuildVersion version) 182 { 183 if (major == version.major) 184 { 185 if (minor == version.minor) 186 { 187 if (point == version.point) 188 { 189 return 0; 190 } 191 else if (point < version.point) 192 { 193 return -1; 194 } 195 } 196 else if (minor < version.minor) 197 { 198 return -1; 199 } 200 } 201 else if (major < version.major) 202 { 203 return -1; 204 } 205 return 1; 206 } 207 208 @Override 209 public boolean equals(final Object obj) 210 { 211 if (this == obj) 212 { 213 return true; 214 } 215 else if (obj instanceof BuildVersion) 216 { 217 final BuildVersion other = (BuildVersion) obj; 218 return major == other.major && minor == other.minor && point == other.point; 219 } 220 else 221 { 222 return false; 223 } 224 } 225 226 /** 227 * Returns the major release version number. 228 * 229 * @return The major release version number. 230 */ 231 public int getMajorVersion() 232 { 233 return major; 234 } 235 236 /** 237 * Returns the minor release version number. 238 * 239 * @return The minor release version number. 240 */ 241 public int getMinorVersion() 242 { 243 return minor; 244 } 245 246 /** 247 * Returns the point release version number. 248 * 249 * @return The point release version number. 250 */ 251 public int getPointVersion() 252 { 253 return point; 254 } 255 256 /** 257 * Returns the VCS revision. 258 * 259 * @return The VCS revision. 260 */ 261 public String getRevision() 262 { 263 return rev; 264 } 265 266 @Override 267 public int hashCode() 268 { 269 return Arrays.hashCode(new int[] { major, minor, point }); 270 } 271 272 @Override 273 public String toString() 274 { 275 if (!rev.isEmpty()) 276 { 277 return Utils.joinAsString(".", major, minor, point, rev); 278 } 279 return Utils.joinAsString(".", major, minor, point); 280 } 281 282 /** 283 * Returns {@code true} if the version is newer than the provided version. 284 * 285 * @param version 286 * The version to be compared 287 * @return {@code true} if the version is newer than the provided version. 288 */ 289 public boolean isNewerThan(final BuildVersion version) 290 { 291 return this.compareTo(version) >= 0; 292 } 293 294 /** 295 * Returns {@code true} if the version is older than the provided version. 296 * 297 * @param version 298 * The version to be compared 299 * @return {@code true} if the version is older than the provided version. 300 */ 301 public boolean isOlderThan(final BuildVersion version) 302 { 303 return this.compareTo(version) <= 0; 304 } 305}