1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20 package org.apache.guacamole.protocol; 21 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 /** 26 * Representation of a Guacamole protocol version. Convenience methods are 27 * provided for parsing and comparing versions, as is necessary when 28 * determining the version of the Guacamole protocol common to guacd and a 29 * client. 30 */ 31 public class GuacamoleProtocolVersion { 32 33 /** 34 * Protocol version 1.0.0 and older. Any client that doesn't explicitly 35 * set the protocol version will negotiate down to this protocol version. 36 * This requires that handshake instructions be ordered correctly, and 37 * lacks support for certain protocol-related features introduced in later 38 * versions. 39 */ 40 public static final GuacamoleProtocolVersion VERSION_1_0_0 = new GuacamoleProtocolVersion(1, 0, 0); 41 42 /** 43 * Protocol version 1.1.0, which introduces Client-Server version 44 * detection, arbitrary handshake instruction order, and support 45 * for passing the client timezone to the server during the handshake. 46 */ 47 public static final GuacamoleProtocolVersion VERSION_1_1_0 = new GuacamoleProtocolVersion(1, 1, 0); 48 49 /** 50 * Protocol version 1.3.0, which introduces the "required" instruction 51 * allowing the server to explicitly request connection parameters from the 52 * client. 53 */ 54 public static final GuacamoleProtocolVersion VERSION_1_3_0 = new GuacamoleProtocolVersion(1, 3, 0); 55 56 /** 57 * The most recent version of the Guacamole protocol at the time this 58 * version of GuacamoleProtocolVersion was built. 59 */ 60 public static final GuacamoleProtocolVersion LATEST = VERSION_1_3_0; 61 62 /** 63 * A regular expression that matches the VERSION_X_Y_Z pattern, where 64 * X is the major version component, Y is the minor version component, 65 * and Z is the patch version component. This expression puts each of 66 * the version components in their own group so that they can be easily 67 * used later. 68 */ 69 private static final Pattern VERSION_PATTERN = 70 Pattern.compile("^VERSION_([0-9]+)_([0-9]+)_([0-9]+)$"); 71 72 /** 73 * The major version component of the protocol version. 74 */ 75 private final int major; 76 77 /** 78 * The minor version component of the protocol version. 79 */ 80 private final int minor; 81 82 /** 83 * The patch version component of the protocol version. 84 */ 85 private final int patch; 86 87 /** 88 * Generate a new GuacamoleProtocolVersion object with the given 89 * major version, minor version, and patch version. 90 * 91 * @param major 92 * The integer representation of the major version component. 93 * 94 * @param minor 95 * The integer representation of the minor version component. 96 * 97 * @param patch 98 * The integer representation of the patch version component. 99 */ GuacamoleProtocolVersion(int major, int minor, int patch)100 public GuacamoleProtocolVersion(int major, int minor, int patch) { 101 this.major = major; 102 this.minor = minor; 103 this.patch = patch; 104 } 105 106 /** 107 * Return the major version component of the protocol version. 108 * 109 * @return 110 * The integer major version component. 111 */ getMajor()112 public int getMajor() { 113 return major; 114 } 115 116 /** 117 * Return the minor version component of the protocol version. 118 * 119 * @return 120 * The integer minor version component. 121 */ getMinor()122 public int getMinor() { 123 return minor; 124 } 125 126 /** 127 * Return the patch version component of the protocol version. 128 * 129 * @return 130 * The integer patch version component. 131 */ getPatch()132 public int getPatch() { 133 return patch; 134 } 135 136 /** 137 * Returns whether this GuacamoleProtocolVersion is at least as recent as 138 * (greater than or equal to) the given version. 139 * 140 * @param otherVersion 141 * The version to which this GuacamoleProtocolVersion should be compared. 142 * 143 * @return 144 * true if this object is at least as recent as the given version, 145 * false if the given version is newer. 146 */ atLeast(GuacamoleProtocolVersion otherVersion)147 public boolean atLeast(GuacamoleProtocolVersion otherVersion) { 148 149 // If major is not the same, return inequality 150 if (major != otherVersion.getMajor()) 151 return this.major > otherVersion.getMajor(); 152 153 // Major is the same, but minor is not, return minor inequality 154 if (minor != otherVersion.getMinor()) 155 return this.minor > otherVersion.getMinor(); 156 157 // Major and minor are equal, so return patch inequality 158 return patch >= otherVersion.getPatch(); 159 160 } 161 162 /** 163 * Parse the String format of the version provided and return the 164 * the enum value matching that version. If no value is provided, return 165 * null. 166 * 167 * @param version 168 * The String format of the version to parse. 169 * 170 * @return 171 * The enum value that matches the specified version, VERSION_1_0_0 172 * if no match is found, or null if no comparison version is provided. 173 */ parseVersion(String version)174 public static GuacamoleProtocolVersion parseVersion(String version) { 175 176 // Validate format of version string 177 Matcher versionMatcher = VERSION_PATTERN.matcher(version); 178 if (!versionMatcher.matches()) 179 return null; 180 181 // Parse version number from version string 182 return new GuacamoleProtocolVersion( 183 Integer.parseInt(versionMatcher.group(1)), 184 Integer.parseInt(versionMatcher.group(2)), 185 Integer.parseInt(versionMatcher.group(3)) 186 ); 187 188 } 189 190 @Override hashCode()191 public int hashCode() { 192 int hash = 7; 193 hash = 61 * hash + this.major; 194 hash = 61 * hash + this.minor; 195 hash = 61 * hash + this.patch; 196 return hash; 197 } 198 199 @Override equals(Object obj)200 public boolean equals(Object obj) { 201 202 if (obj == null || !(obj instanceof GuacamoleProtocolVersion)) 203 return false; 204 205 // Versions are equal if all major/minor/patch components are identical 206 final GuacamoleProtocolVersion otherVersion = (GuacamoleProtocolVersion) obj; 207 return this.major == otherVersion.getMajor() 208 && this.minor == otherVersion.getMinor() 209 && this.patch == otherVersion.getPatch(); 210 211 } 212 213 @Override toString()214 public String toString() { 215 return "VERSION_" + getMajor() + "_" + getMinor() + "_" + getPatch(); 216 } 217 218 } 219