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