View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.http;
29  
30  import java.io.Serializable;
31  
32  import org.apache.http.annotation.Immutable;
33  
34  /**
35   * Represents a protocol version. The "major.minor" numbering
36   * scheme is used to indicate versions of the protocol.
37   * <p>
38   * This class defines a protocol version as a combination of
39   * protocol name, major version number, and minor version number.
40   * Note that {@link #equals} and {@link #hashCode} are defined as
41   * final here, they cannot be overridden in derived classes.
42   * </p>
43   *
44   * @since 4.0
45   */
46  @Immutable
47  public class ProtocolVersion implements Serializable, Cloneable {
48  
49      private static final long serialVersionUID = 8950662842175091068L;
50  
51  
52      /** Name of the protocol. */
53      protected final String protocol;
54  
55      /** Major version number of the protocol */
56      protected final int major;
57  
58      /** Minor version number of the protocol */
59      protected final int minor;
60  
61  
62      /**
63       * Create a protocol version designator.
64       *
65       * @param protocol   the name of the protocol, for example "HTTP"
66       * @param major      the major version number of the protocol
67       * @param minor      the minor version number of the protocol
68       */
69      public ProtocolVersion(String protocol, int major, int minor) {
70          if (protocol == null) {
71              throw new IllegalArgumentException
72                  ("Protocol name must not be null.");
73          }
74          if (major < 0) {
75              throw new IllegalArgumentException
76                  ("Protocol major version number must not be negative.");
77          }
78          if (minor < 0) {
79              throw new IllegalArgumentException
80                  ("Protocol minor version number may not be negative");
81          }
82          this.protocol = protocol;
83          this.major = major;
84          this.minor = minor;
85      }
86  
87      /**
88       * Returns the name of the protocol.
89       *
90       * @return the protocol name
91       */
92      public final String getProtocol() {
93          return protocol;
94      }
95  
96      /**
97       * Returns the major version number of the protocol.
98       *
99       * @return the major version number.
100      */
101     public final int getMajor() {
102         return major;
103     }
104 
105     /**
106      * Returns the minor version number of the HTTP protocol.
107      *
108      * @return the minor version number.
109      */
110     public final int getMinor() {
111         return minor;
112     }
113 
114 
115     /**
116      * Obtains a specific version of this protocol.
117      * This can be used by derived classes to instantiate themselves instead
118      * of the base class, and to define constants for commonly used versions.
119      * <br/>
120      * The default implementation in this class returns <code>this</code>
121      * if the version matches, and creates a new {@link ProtocolVersion}
122      * otherwise.
123      *
124      * @param major     the major version
125      * @param minor     the minor version
126      *
127      * @return  a protocol version with the same protocol name
128      *          and the argument version
129      */
130     public ProtocolVersion forVersion(int major, int minor) {
131 
132         if ((major == this.major) && (minor == this.minor)) {
133             return this;
134         }
135 
136         // argument checking is done in the constructor
137         return new ProtocolVersion(this.protocol, major, minor);
138     }
139 
140 
141     /**
142      * Obtains a hash code consistent with {@link #equals}.
143      *
144      * @return  the hashcode of this protocol version
145      */
146     @Override
147     public final int hashCode() {
148         return this.protocol.hashCode() ^ (this.major * 100000) ^ this.minor;
149     }
150 
151 
152     /**
153      * Checks equality of this protocol version with an object.
154      * The object is equal if it is a protocl version with the same
155      * protocol name, major version number, and minor version number.
156      * The specific class of the object is <i>not</i> relevant,
157      * instances of derived classes with identical attributes are
158      * equal to instances of the base class and vice versa.
159      *
160      * @param obj       the object to compare with
161      *
162      * @return  <code>true</code> if the argument is the same protocol version,
163      *          <code>false</code> otherwise
164      */
165     @Override
166     public final boolean equals(Object obj) {
167         if (this == obj) {
168             return true;
169         }
170         if (!(obj instanceof ProtocolVersion)) {
171             return false;
172         }
173         ProtocolVersion that = (ProtocolVersion) obj;
174 
175         return ((this.protocol.equals(that.protocol)) &&
176                 (this.major == that.major) &&
177                 (this.minor == that.minor));
178     }
179 
180 
181     /**
182      * Checks whether this protocol can be compared to another one.
183      * Only protocol versions with the same protocol name can be
184      * {@link #compareToVersion compared}.
185      *
186      * @param that      the protocol version to consider
187      *
188      * @return  <code>true</code> if {@link #compareToVersion compareToVersion}
189      *          can be called with the argument, <code>false</code> otherwise
190      */
191     public boolean isComparable(ProtocolVersion that) {
192         return (that != null) && this.protocol.equals(that.protocol);
193     }
194 
195 
196     /**
197      * Compares this protocol version with another one.
198      * Only protocol versions with the same protocol name can be compared.
199      * This method does <i>not</i> define a total ordering, as it would be
200      * required for {@link java.lang.Comparable}.
201      *
202      * @param that      the protocl version to compare with
203      *
204      * @return   a negative integer, zero, or a positive integer
205      *           as this version is less than, equal to, or greater than
206      *           the argument version.
207      *
208      * @throws IllegalArgumentException
209      *         if the argument has a different protocol name than this object,
210      *         or if the argument is <code>null</code>
211      */
212     public int compareToVersion(ProtocolVersion that) {
213         if (that == null) {
214             throw new IllegalArgumentException
215                 ("Protocol version must not be null.");
216         }
217         if (!this.protocol.equals(that.protocol)) {
218             throw new IllegalArgumentException
219                 ("Versions for different protocols cannot be compared. " +
220                  this + " " + that);
221         }
222 
223         int delta = getMajor() - that.getMajor();
224         if (delta == 0) {
225             delta = getMinor() - that.getMinor();
226         }
227         return delta;
228     }
229 
230 
231     /**
232      * Tests if this protocol version is greater or equal to the given one.
233      *
234      * @param version   the version against which to check this version
235      *
236      * @return  <code>true</code> if this protocol version is
237      *          {@link #isComparable comparable} to the argument
238      *          and {@link #compareToVersion compares} as greater or equal,
239      *          <code>false</code> otherwise
240      */
241     public final boolean greaterEquals(ProtocolVersion version) {
242         return isComparable(version) && (compareToVersion(version) >= 0);
243     }
244 
245 
246     /**
247      * Tests if this protocol version is less or equal to the given one.
248      *
249      * @param version   the version against which to check this version
250      *
251      * @return  <code>true</code> if this protocol version is
252      *          {@link #isComparable comparable} to the argument
253      *          and {@link #compareToVersion compares} as less or equal,
254      *          <code>false</code> otherwise
255      */
256     public final boolean lessEquals(ProtocolVersion version) {
257         return isComparable(version) && (compareToVersion(version) <= 0);
258     }
259 
260 
261     /**
262      * Converts this protocol version to a string.
263      *
264      * @return  a protocol version string, like "HTTP/1.1"
265      */
266     @Override
267     public String toString() {
268         StringBuilder buffer = new StringBuilder();
269         buffer.append(this.protocol);
270         buffer.append('/');
271         buffer.append(Integer.toString(this.major));
272         buffer.append('.');
273         buffer.append(Integer.toString(this.minor));
274         return buffer.toString();
275     }
276 
277     @Override
278     public Object clone() throws CloneNotSupportedException {
279         return super.clone();
280     }
281 
282 }