1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package org.apache.commons.httpclient.protocol;
31
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.Map;
35
36 import org.apache.commons.httpclient.util.LangUtils;
37
38 /***
39 * A class to encapsulate the specifics of a protocol. This class class also
40 * provides the ability to customize the set and characteristics of the
41 * protocols used.
42 *
43 * <p>One use case for modifying the default set of protocols would be to set a
44 * custom SSL socket factory. This would look something like the following:
45 * <pre>
46 * Protocol myHTTPS = new Protocol( "https", new MySSLSocketFactory(), 443 );
47 *
48 * Protocol.registerProtocol( "https", myHTTPS );
49 * </pre>
50 *
51 * @author Michael Becke
52 * @author Jeff Dever
53 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
54 *
55 * @since 2.0
56 */
57 public class Protocol {
58
59 /*** The available protocols */
60 private static final Map PROTOCOLS = Collections.synchronizedMap(new HashMap());
61
62 /***
63 * Registers a new protocol with the given identifier. If a protocol with
64 * the given ID already exists it will be overridden. This ID is the same
65 * one used to retrieve the protocol from getProtocol(String).
66 *
67 * @param id the identifier for this protocol
68 * @param protocol the protocol to register
69 *
70 * @see #getProtocol(String)
71 */
72 public static void registerProtocol(String id, Protocol protocol) {
73
74 if (id == null) {
75 throw new IllegalArgumentException("id is null");
76 }
77 if (protocol == null) {
78 throw new IllegalArgumentException("protocol is null");
79 }
80
81 PROTOCOLS.put(id, protocol);
82 }
83
84 /***
85 * Unregisters the protocol with the given ID.
86 *
87 * @param id the ID of the protocol to remove
88 */
89 public static void unregisterProtocol(String id) {
90
91 if (id == null) {
92 throw new IllegalArgumentException("id is null");
93 }
94
95 PROTOCOLS.remove(id);
96 }
97
98 /***
99 * Gets the protocol with the given ID.
100 *
101 * @param id the protocol ID
102 *
103 * @return Protocol a protocol
104 *
105 * @throws IllegalStateException if a protocol with the ID cannot be found
106 */
107 public static Protocol getProtocol(String id)
108 throws IllegalStateException {
109
110 if (id == null) {
111 throw new IllegalArgumentException("id is null");
112 }
113
114 Protocol protocol = (Protocol) PROTOCOLS.get(id);
115
116 if (protocol == null) {
117 protocol = lazyRegisterProtocol(id);
118 }
119
120 return protocol;
121 }
122
123 /***
124 * Lazily registers the protocol with the given id.
125 *
126 * @param id the protocol ID
127 *
128 * @return the lazily registered protocol
129 *
130 * @throws IllegalStateException if the protocol with id is not recognized
131 */
132 private static Protocol lazyRegisterProtocol(String id)
133 throws IllegalStateException {
134
135 if ("http".equals(id)) {
136 final Protocol http
137 = new Protocol("http", DefaultProtocolSocketFactory.getSocketFactory(), 80);
138 Protocol.registerProtocol("http", http);
139 return http;
140 }
141
142 if ("https".equals(id)) {
143 final Protocol https
144 = new Protocol("https", SSLProtocolSocketFactory.getSocketFactory(), 443);
145 Protocol.registerProtocol("https", https);
146 return https;
147 }
148
149 throw new IllegalStateException("unsupported protocol: '" + id + "'");
150 }
151
152
153 /*** the scheme of this protocol (e.g. http, https) */
154 private String scheme;
155
156 /*** The socket factory for this protocol */
157 private ProtocolSocketFactory socketFactory;
158
159 /*** The default port for this protocol */
160 private int defaultPort;
161
162 /*** True if this protocol is secure */
163 private boolean secure;
164
165 /***
166 * Constructs a new Protocol. Whether the created protocol is secure depends on
167 * the class of <code>factory</code>.
168 *
169 * @param scheme the scheme (e.g. http, https)
170 * @param factory the factory for creating sockets for communication using
171 * this protocol
172 * @param defaultPort the port this protocol defaults to
173 */
174 public Protocol(String scheme, ProtocolSocketFactory factory, int defaultPort) {
175
176 if (scheme == null) {
177 throw new IllegalArgumentException("scheme is null");
178 }
179 if (factory == null) {
180 throw new IllegalArgumentException("socketFactory is null");
181 }
182 if (defaultPort <= 0) {
183 throw new IllegalArgumentException("port is invalid: " + defaultPort);
184 }
185
186 this.scheme = scheme;
187 this.socketFactory = factory;
188 this.defaultPort = defaultPort;
189 this.secure = (factory instanceof SecureProtocolSocketFactory);
190 }
191
192 /***
193 * Constructs a new Protocol. Whether the created protocol is secure depends on
194 * the class of <code>factory</code>.
195 *
196 * @param scheme the scheme (e.g. http, https)
197 * @param factory the factory for creating sockets for communication using
198 * this protocol
199 * @param defaultPort the port this protocol defaults to
200 * @deprecated Use the constructor that uses ProtocolSocketFactory, this version of
201 * the constructor is only kept for backwards API compatibility.
202 */
203 public Protocol(String scheme,
204 SecureProtocolSocketFactory factory, int defaultPort) {
205 this(scheme, (ProtocolSocketFactory) factory, defaultPort);
206 }
207
208 /***
209 * Returns the defaultPort.
210 * @return int
211 */
212 public int getDefaultPort() {
213 return defaultPort;
214 }
215
216 /***
217 * Returns the socketFactory. If secure the factory is a
218 * SecureProtocolSocketFactory.
219 * @return SocketFactory
220 */
221 public ProtocolSocketFactory getSocketFactory() {
222 return socketFactory;
223 }
224
225 /***
226 * Returns the scheme.
227 * @return The scheme
228 */
229 public String getScheme() {
230 return scheme;
231 }
232
233 /***
234 * Returns true if this protocol is secure
235 * @return true if this protocol is secure
236 */
237 public boolean isSecure() {
238 return secure;
239 }
240
241 /***
242 * Resolves the correct port for this protocol. Returns the given port if
243 * valid or the default port otherwise.
244 *
245 * @param port the port to be resolved
246 *
247 * @return the given port or the defaultPort
248 */
249 public int resolvePort(int port) {
250 return port <= 0 ? getDefaultPort() : port;
251 }
252
253 /***
254 * Return a string representation of this object.
255 * @return a string representation of this object.
256 */
257 public String toString() {
258 return scheme + ":" + defaultPort;
259 }
260
261 /***
262 * Return true if the specified object equals this object.
263 * @param obj The object to compare against.
264 * @return true if the objects are equal.
265 */
266 public boolean equals(Object obj) {
267
268 if (obj instanceof Protocol) {
269
270 Protocol p = (Protocol) obj;
271
272 return (
273 defaultPort == p.getDefaultPort()
274 && scheme.equalsIgnoreCase(p.getScheme())
275 && secure == p.isSecure()
276 && socketFactory.equals(p.getSocketFactory()));
277
278 } else {
279 return false;
280 }
281
282 }
283
284 /***
285 * Return a hash code for this object
286 * @return The hash code.
287 */
288 public int hashCode() {
289 int hash = LangUtils.HASH_SEED;
290 hash = LangUtils.hashCode(hash, this.defaultPort);
291 hash = LangUtils.hashCode(hash, this.scheme.toLowerCase());
292 hash = LangUtils.hashCode(hash, this.secure);
293 hash = LangUtils.hashCode(hash, this.socketFactory);
294 return hash;
295 }
296 }