1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net;
19
20 import java.net.DatagramSocket;
21 import java.net.InetAddress;
22 import java.net.SocketException;
23 import java.nio.charset.Charset;
24
25 /***
26 * The DatagramSocketClient provides the basic operations that are required
27 * of client objects accessing datagram sockets. It is meant to be
28 * subclassed to avoid having to rewrite the same code over and over again
29 * to open a socket, close a socket, set timeouts, etc. Of special note
30 * is the {@link #setDatagramSocketFactory setDatagramSocketFactory }
31 * method, which allows you to control the type of DatagramSocket the
32 * DatagramSocketClient creates for network communications. This is
33 * especially useful for adding things like proxy support as well as better
34 * support for applets. For
35 * example, you could create a
36 * {@link org.apache.commons.net.DatagramSocketFactory}
37 * that
38 * requests browser security capabilities before creating a socket.
39 * All classes derived from DatagramSocketClient should use the
40 * {@link #_socketFactory_ _socketFactory_ } member variable to
41 * create DatagramSocket instances rather than instantiating
42 * them by directly invoking a constructor. By honoring this contract
43 * you guarantee that a user will always be able to provide his own
44 * Socket implementations by substituting his own SocketFactory.
45 * <p>
46 * <p>
47 * @see DatagramSocketFactory
48 ***/
49
50 public abstract class DatagramSocketClient
51 {
52 /***
53 * The default DatagramSocketFactory shared by all DatagramSocketClient
54 * instances.
55 ***/
56 private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY =
57 new DefaultDatagramSocketFactory();
58
59 /**
60 * Charset to use for byte IO.
61 */
62 private Charset charset = Charset.defaultCharset();
63
64 /*** The timeout to use after opening a socket. ***/
65 protected int _timeout_;
66
67 /*** The datagram socket used for the connection. ***/
68 protected DatagramSocket _socket_;
69
70 /***
71 * A status variable indicating if the client's socket is currently open.
72 ***/
73 protected boolean _isOpen_;
74
75 /*** The datagram socket's DatagramSocketFactory. ***/
76 protected DatagramSocketFactory _socketFactory_;
77
78 /***
79 * Default constructor for DatagramSocketClient. Initializes
80 * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
81 ***/
82 public DatagramSocketClient()
83 {
84 _socket_ = null;
85 _timeout_ = 0;
86 _isOpen_ = false;
87 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
88 }
89
90
91 /***
92 * Opens a DatagramSocket on the local host at the first available port.
93 * Also sets the timeout on the socket to the default timeout set
94 * by {@link #setDefaultTimeout setDefaultTimeout() }.
95 * <p>
96 * _isOpen_ is set to true after calling this method and _socket_
97 * is set to the newly opened socket.
98 * <p>
99 * @exception SocketException If the socket could not be opened or the
100 * timeout could not be set.
101 ***/
102 public void open() throws SocketException
103 {
104 _socket_ = _socketFactory_.createDatagramSocket();
105 _socket_.setSoTimeout(_timeout_);
106 _isOpen_ = true;
107 }
108
109
110 /***
111 * Opens a DatagramSocket on the local host at a specified port.
112 * Also sets the timeout on the socket to the default timeout set
113 * by {@link #setDefaultTimeout setDefaultTimeout() }.
114 * <p>
115 * _isOpen_ is set to true after calling this method and _socket_
116 * is set to the newly opened socket.
117 * <p>
118 * @param port The port to use for the socket.
119 * @exception SocketException If the socket could not be opened or the
120 * timeout could not be set.
121 ***/
122 public void open(int port) throws SocketException
123 {
124 _socket_ = _socketFactory_.createDatagramSocket(port);
125 _socket_.setSoTimeout(_timeout_);
126 _isOpen_ = true;
127 }
128
129
130 /***
131 * Opens a DatagramSocket at the specified address on the local host
132 * at a specified port.
133 * Also sets the timeout on the socket to the default timeout set
134 * by {@link #setDefaultTimeout setDefaultTimeout() }.
135 * <p>
136 * _isOpen_ is set to true after calling this method and _socket_
137 * is set to the newly opened socket.
138 * <p>
139 * @param port The port to use for the socket.
140 * @param laddr The local address to use.
141 * @exception SocketException If the socket could not be opened or the
142 * timeout could not be set.
143 ***/
144 public void open(int port, InetAddress laddr) throws SocketException
145 {
146 _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
147 _socket_.setSoTimeout(_timeout_);
148 _isOpen_ = true;
149 }
150
151
152
153 /***
154 * Closes the DatagramSocket used for the connection.
155 * You should call this method after you've finished using the class
156 * instance and also before you call {@link #open open() }
157 * again. _isOpen_ is set to false and _socket_ is set to null.
158 * If you call this method when the client socket is not open,
159 * a NullPointerException is thrown.
160 ***/
161 public void close()
162 {
163 if (_socket_ != null) {
164 _socket_.close();
165 }
166 _socket_ = null;
167 _isOpen_ = false;
168 }
169
170
171 /***
172 * Returns true if the client has a currently open socket.
173 * <p>
174 * @return True if the client has a curerntly open socket, false otherwise.
175 ***/
176 public boolean isOpen()
177 {
178 return _isOpen_;
179 }
180
181
182 /***
183 * Set the default timeout in milliseconds to use when opening a socket.
184 * After a call to open, the timeout for the socket is set using this value.
185 * This method should be used prior to a call to {@link #open open()}
186 * and should not be confused with {@link #setSoTimeout setSoTimeout()}
187 * which operates on the currently open socket. _timeout_ contains
188 * the new timeout value.
189 * <p>
190 * @param timeout The timeout in milliseconds to use for the datagram socket
191 * connection.
192 ***/
193 public void setDefaultTimeout(int timeout)
194 {
195 _timeout_ = timeout;
196 }
197
198
199 /***
200 * Returns the default timeout in milliseconds that is used when
201 * opening a socket.
202 * <p>
203 * @return The default timeout in milliseconds that is used when
204 * opening a socket.
205 ***/
206 public int getDefaultTimeout()
207 {
208 return _timeout_;
209 }
210
211
212 /***
213 * Set the timeout in milliseconds of a currently open connection.
214 * Only call this method after a connection has been opened
215 * by {@link #open open()}.
216 * <p>
217 * @param timeout The timeout in milliseconds to use for the currently
218 * open datagram socket connection.
219 ***/
220 public void setSoTimeout(int timeout) throws SocketException
221 {
222 _socket_.setSoTimeout(timeout);
223 }
224
225
226 /***
227 * Returns the timeout in milliseconds of the currently opened socket.
228 * If you call this method when the client socket is not open,
229 * a NullPointerException is thrown.
230 * <p>
231 * @return The timeout in milliseconds of the currently opened socket.
232 ***/
233 public int getSoTimeout() throws SocketException
234 {
235 return _socket_.getSoTimeout();
236 }
237
238
239 /***
240 * Returns the port number of the open socket on the local host used
241 * for the connection. If you call this method when the client socket
242 * is not open, a NullPointerException is thrown.
243 * <p>
244 * @return The port number of the open socket on the local host used
245 * for the connection.
246 ***/
247 public int getLocalPort()
248 {
249 return _socket_.getLocalPort();
250 }
251
252
253 /***
254 * Returns the local address to which the client's socket is bound.
255 * If you call this method when the client socket is not open, a
256 * NullPointerException is thrown.
257 * <p>
258 * @return The local address to which the client's socket is bound.
259 ***/
260 public InetAddress getLocalAddress()
261 {
262 return _socket_.getLocalAddress();
263 }
264
265
266 /***
267 * Sets the DatagramSocketFactory used by the DatagramSocketClient
268 * to open DatagramSockets. If the factory value is null, then a default
269 * factory is used (only do this to reset the factory after having
270 * previously altered it).
271 * <p>
272 * @param factory The new DatagramSocketFactory the DatagramSocketClient
273 * should use.
274 ***/
275 public void setDatagramSocketFactory(DatagramSocketFactory factory)
276 {
277 if (factory == null) {
278 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
279 } else {
280 _socketFactory_ = factory;
281 }
282 }
283
284 /**
285 * Gets the charset name.
286 *
287 * @return the charset name.
288 * @since 3.3
289 * TODO Will be deprecated once the code requires Java 1.6 as a mininmum
290 */
291 public String getCharsetName() {
292 return charset.name();
293 }
294
295 /**
296 * Gets the charset.
297 *
298 * @return the charset.
299 * @since 3.3
300 */
301 public Charset getCharset() {
302 return charset;
303 }
304
305 /**
306 * Sets the charset.
307 *
308 * @param charset the charset.
309 * @since 3.3
310 */
311 public void setCharset(Charset charset) {
312 this.charset = charset;
313 }
314 }