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: * michael@0: */ michael@0: michael@0: package ch.boye.httpclientandroidlib; michael@0: michael@0: import java.io.Serializable; michael@0: import ch.boye.httpclientandroidlib.util.CharArrayBuffer; michael@0: michael@0: /** michael@0: * Represents a protocol version. The "major.minor" numbering michael@0: * scheme is used to indicate versions of the protocol. 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: *
michael@0: * The default implementation in this class returns 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: }