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-2015 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 long rev; 057 private static final BuildVersion BINARY_VERSION = new BuildVersion( 058 DynamicConstants.MAJOR_VERSION, DynamicConstants.MINOR_VERSION, 059 DynamicConstants.POINT_VERSION, DynamicConstants.REVISION_NUMBER); 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 if (fields.length != 4) 137 { 138 throw new IllegalArgumentException("Invalid version string " + s); 139 } 140 final int major = Integer.parseInt(fields[0]); 141 final int minor = Integer.parseInt(fields[1]); 142 final int point = Integer.parseInt(fields[2]); 143 final long rev = Long.parseLong(fields[3]); 144 return new BuildVersion(major, minor, point, rev); 145 } 146 147 /** 148 * Creates a new build version using the provided version information. 149 * 150 * @param major 151 * Major release version number. 152 * @param minor 153 * Minor release version number. 154 * @param point 155 * Point release version number. 156 * @param rev 157 * VCS revision number. 158 */ 159 public BuildVersion(final int major, final int minor, final int point, final long rev) 160 { 161 this.major = major; 162 this.minor = minor; 163 this.point = point; 164 this.rev = rev; 165 } 166 167 @Override 168 public int compareTo(final BuildVersion version) 169 { 170 if (major == version.major) 171 { 172 if (minor == version.minor) 173 { 174 if (point == version.point) 175 { 176 if (rev == version.rev) 177 { 178 return 0; 179 } 180 else if (rev < version.rev) 181 { 182 return -1; 183 } 184 } 185 else if (point < version.point) 186 { 187 return -1; 188 } 189 } 190 else if (minor < version.minor) 191 { 192 return -1; 193 } 194 } 195 else if (major < version.major) 196 { 197 return -1; 198 } 199 return 1; 200 } 201 202 @Override 203 public boolean equals(final Object obj) 204 { 205 if (this == obj) 206 { 207 return true; 208 } 209 else if (obj instanceof BuildVersion) 210 { 211 final BuildVersion other = (BuildVersion) obj; 212 return major == other.major && minor == other.minor && point == other.point && rev == other.rev; 213 } 214 else 215 { 216 return false; 217 } 218 } 219 220 /** 221 * Returns the major release version number. 222 * 223 * @return The major release version number. 224 */ 225 public int getMajorVersion() 226 { 227 return major; 228 } 229 230 /** 231 * Returns the minor release version number. 232 * 233 * @return The minor release version number. 234 */ 235 public int getMinorVersion() 236 { 237 return minor; 238 } 239 240 /** 241 * Returns the point release version number. 242 * 243 * @return The point release version number. 244 */ 245 public int getPointVersion() 246 { 247 return point; 248 } 249 250 /** 251 * Returns the VCS revision number. 252 * 253 * @return The VCS revision number. 254 */ 255 public long getRevisionNumber() 256 { 257 return rev; 258 } 259 260 @Override 261 public int hashCode() 262 { 263 return Arrays.hashCode(new int[] { major, minor, point, (int) (rev >>> 32), (int) (rev & 0xFFFFL) }); 264 } 265 266 @Override 267 public String toString() 268 { 269 return Utils.joinAsString(".", major, minor, point, rev); 270 } 271}