michael@0: /*
michael@0: * ====================================================================
michael@0: * Licensed to the Apache Software Foundation (ASF) under one
michael@0: * or more contributor license agreements. See the NOTICE file
michael@0: * distributed with this work for additional information
michael@0: * regarding copyright ownership. The ASF licenses this file
michael@0: * to you under the Apache License, Version 2.0 (the
michael@0: * "License"); you may not use this file except in compliance
michael@0: * with the License. You may obtain a copy of the License at
michael@0: *
michael@0: * http://www.apache.org/licenses/LICENSE-2.0
michael@0: *
michael@0: * Unless required by applicable law or agreed to in writing,
michael@0: * software distributed under the License is distributed on an
michael@0: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
michael@0: * KIND, either express or implied. See the License for the
michael@0: * specific language governing permissions and limitations
michael@0: * under the License.
michael@0: * ====================================================================
michael@0: *
michael@0: * This software consists of voluntary contributions made by many
michael@0: * individuals on behalf of the Apache Software Foundation. For more
michael@0: * information on the Apache Software Foundation, please see
michael@0: *
michael@0: * This class defines a protocol version as a combination of michael@0: * protocol name, major version number, and minor version number. michael@0: * Note that {@link #equals} and {@link #hashCode} are defined as michael@0: * final here, they cannot be overridden in derived classes. michael@0: *
michael@0: * michael@0: * @since 4.0 michael@0: */ michael@0: public class ProtocolVersion implements Serializable, Cloneable { michael@0: michael@0: private static final long serialVersionUID = 8950662842175091068L; michael@0: michael@0: michael@0: /** Name of the protocol. */ michael@0: protected final String protocol; michael@0: michael@0: /** Major version number of the protocol */ michael@0: protected final int major; michael@0: michael@0: /** Minor version number of the protocol */ michael@0: protected final int minor; michael@0: michael@0: michael@0: /** michael@0: * Create a protocol version designator. michael@0: * michael@0: * @param protocol the name of the protocol, for example "HTTP" michael@0: * @param major the major version number of the protocol michael@0: * @param minor the minor version number of the protocol michael@0: */ michael@0: public ProtocolVersion(String protocol, int major, int minor) { michael@0: if (protocol == null) { michael@0: throw new IllegalArgumentException michael@0: ("Protocol name must not be null."); michael@0: } michael@0: if (major < 0) { michael@0: throw new IllegalArgumentException michael@0: ("Protocol major version number must not be negative."); michael@0: } michael@0: if (minor < 0) { michael@0: throw new IllegalArgumentException michael@0: ("Protocol minor version number may not be negative"); michael@0: } michael@0: this.protocol = protocol; michael@0: this.major = major; michael@0: this.minor = minor; michael@0: } michael@0: michael@0: /** michael@0: * Returns the name of the protocol. michael@0: * michael@0: * @return the protocol name michael@0: */ michael@0: public final String getProtocol() { michael@0: return protocol; michael@0: } michael@0: michael@0: /** michael@0: * Returns the major version number of the protocol. michael@0: * michael@0: * @return the major version number. michael@0: */ michael@0: public final int getMajor() { michael@0: return major; michael@0: } michael@0: michael@0: /** michael@0: * Returns the minor version number of the HTTP protocol. michael@0: * michael@0: * @return the minor version number. michael@0: */ michael@0: public final int getMinor() { michael@0: return minor; michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Obtains a specific version of this protocol. michael@0: * This can be used by derived classes to instantiate themselves instead michael@0: * of the base class, and to define constants for commonly used versions. michael@0: *this
michael@0: * if the version matches, and creates a new {@link ProtocolVersion}
michael@0: * otherwise.
michael@0: *
michael@0: * @param major the major version
michael@0: * @param minor the minor version
michael@0: *
michael@0: * @return a protocol version with the same protocol name
michael@0: * and the argument version
michael@0: */
michael@0: public ProtocolVersion forVersion(int major, int minor) {
michael@0:
michael@0: if ((major == this.major) && (minor == this.minor)) {
michael@0: return this;
michael@0: }
michael@0:
michael@0: // argument checking is done in the constructor
michael@0: return new ProtocolVersion(this.protocol, major, minor);
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Obtains a hash code consistent with {@link #equals}.
michael@0: *
michael@0: * @return the hashcode of this protocol version
michael@0: */
michael@0: public final int hashCode() {
michael@0: return this.protocol.hashCode() ^ (this.major * 100000) ^ this.minor;
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Checks equality of this protocol version with an object.
michael@0: * The object is equal if it is a protocl version with the same
michael@0: * protocol name, major version number, and minor version number.
michael@0: * The specific class of the object is not relevant,
michael@0: * instances of derived classes with identical attributes are
michael@0: * equal to instances of the base class and vice versa.
michael@0: *
michael@0: * @param obj the object to compare with
michael@0: *
michael@0: * @return true
if the argument is the same protocol version,
michael@0: * false
otherwise
michael@0: */
michael@0: public final boolean equals(Object obj) {
michael@0: if (this == obj) {
michael@0: return true;
michael@0: }
michael@0: if (!(obj instanceof ProtocolVersion)) {
michael@0: return false;
michael@0: }
michael@0: ProtocolVersion that = (ProtocolVersion) obj;
michael@0:
michael@0: return ((this.protocol.equals(that.protocol)) &&
michael@0: (this.major == that.major) &&
michael@0: (this.minor == that.minor));
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Checks whether this protocol can be compared to another one.
michael@0: * Only protocol versions with the same protocol name can be
michael@0: * {@link #compareToVersion compared}.
michael@0: *
michael@0: * @param that the protocol version to consider
michael@0: *
michael@0: * @return true
if {@link #compareToVersion compareToVersion}
michael@0: * can be called with the argument, false
otherwise
michael@0: */
michael@0: public boolean isComparable(ProtocolVersion that) {
michael@0: return (that != null) && this.protocol.equals(that.protocol);
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Compares this protocol version with another one.
michael@0: * Only protocol versions with the same protocol name can be compared.
michael@0: * This method does not define a total ordering, as it would be
michael@0: * required for {@link java.lang.Comparable}.
michael@0: *
michael@0: * @param that the protocl version to compare with
michael@0: *
michael@0: * @return a negative integer, zero, or a positive integer
michael@0: * as this version is less than, equal to, or greater than
michael@0: * the argument version.
michael@0: *
michael@0: * @throws IllegalArgumentException
michael@0: * if the argument has a different protocol name than this object,
michael@0: * or if the argument is null
michael@0: */
michael@0: public int compareToVersion(ProtocolVersion that) {
michael@0: if (that == null) {
michael@0: throw new IllegalArgumentException
michael@0: ("Protocol version must not be null.");
michael@0: }
michael@0: if (!this.protocol.equals(that.protocol)) {
michael@0: throw new IllegalArgumentException
michael@0: ("Versions for different protocols cannot be compared. " +
michael@0: this + " " + that);
michael@0: }
michael@0:
michael@0: int delta = getMajor() - that.getMajor();
michael@0: if (delta == 0) {
michael@0: delta = getMinor() - that.getMinor();
michael@0: }
michael@0: return delta;
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Tests if this protocol version is greater or equal to the given one.
michael@0: *
michael@0: * @param version the version against which to check this version
michael@0: *
michael@0: * @return true
if this protocol version is
michael@0: * {@link #isComparable comparable} to the argument
michael@0: * and {@link #compareToVersion compares} as greater or equal,
michael@0: * false
otherwise
michael@0: */
michael@0: public final boolean greaterEquals(ProtocolVersion version) {
michael@0: return isComparable(version) && (compareToVersion(version) >= 0);
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Tests if this protocol version is less or equal to the given one.
michael@0: *
michael@0: * @param version the version against which to check this version
michael@0: *
michael@0: * @return true
if this protocol version is
michael@0: * {@link #isComparable comparable} to the argument
michael@0: * and {@link #compareToVersion compares} as less or equal,
michael@0: * false
otherwise
michael@0: */
michael@0: public final boolean lessEquals(ProtocolVersion version) {
michael@0: return isComparable(version) && (compareToVersion(version) <= 0);
michael@0: }
michael@0:
michael@0:
michael@0: /**
michael@0: * Converts this protocol version to a string.
michael@0: *
michael@0: * @return a protocol version string, like "HTTP/1.1"
michael@0: */
michael@0: public String toString() {
michael@0: CharArrayBuffer buffer = new CharArrayBuffer(16);
michael@0: buffer.append(this.protocol);
michael@0: buffer.append('/');
michael@0: buffer.append(Integer.toString(this.major));
michael@0: buffer.append('.');
michael@0: buffer.append(Integer.toString(this.minor));
michael@0: return buffer.toString();
michael@0: }
michael@0:
michael@0: public Object clone() throws CloneNotSupportedException {
michael@0: return super.clone();
michael@0: }
michael@0:
michael@0: }