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