001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.net;
019
020 import java.net.DatagramSocket;
021 import java.net.InetAddress;
022 import java.net.SocketException;
023
024 /***
025 * The DatagramSocketClient provides the basic operations that are required
026 * of client objects accessing datagram sockets. It is meant to be
027 * subclassed to avoid having to rewrite the same code over and over again
028 * to open a socket, close a socket, set timeouts, etc. Of special note
029 * is the {@link #setDatagramSocketFactory setDatagramSocketFactory }
030 * method, which allows you to control the type of DatagramSocket the
031 * DatagramSocketClient creates for network communications. This is
032 * especially useful for adding things like proxy support as well as better
033 * support for applets. For
034 * example, you could create a
035 * {@link org.apache.commons.net.DatagramSocketFactory}
036 * that
037 * requests browser security capabilities before creating a socket.
038 * All classes derived from DatagramSocketClient should use the
039 * {@link #_socketFactory_ _socketFactory_ } member variable to
040 * create DatagramSocket instances rather than instantiating
041 * them by directly invoking a constructor. By honoring this contract
042 * you guarantee that a user will always be able to provide his own
043 * Socket implementations by substituting his own SocketFactory.
044 * <p>
045 * <p>
046 * @see DatagramSocketFactory
047 ***/
048
049 public abstract class DatagramSocketClient
050 {
051 /***
052 * The default DatagramSocketFactory shared by all DatagramSocketClient
053 * instances.
054 ***/
055 private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY =
056 new DefaultDatagramSocketFactory();
057
058 /*** The timeout to use after opening a socket. ***/
059 protected int _timeout_;
060
061 /*** The datagram socket used for the connection. ***/
062 protected DatagramSocket _socket_;
063
064 /***
065 * A status variable indicating if the client's socket is currently open.
066 ***/
067 protected boolean _isOpen_;
068
069 /*** The datagram socket's DatagramSocketFactory. ***/
070 protected DatagramSocketFactory _socketFactory_;
071
072 /***
073 * Default constructor for DatagramSocketClient. Initializes
074 * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
075 ***/
076 public DatagramSocketClient()
077 {
078 _socket_ = null;
079 _timeout_ = 0;
080 _isOpen_ = false;
081 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
082 }
083
084
085 /***
086 * Opens a DatagramSocket on the local host at the first available port.
087 * Also sets the timeout on the socket to the default timeout set
088 * by {@link #setDefaultTimeout setDefaultTimeout() }.
089 * <p>
090 * _isOpen_ is set to true after calling this method and _socket_
091 * is set to the newly opened socket.
092 * <p>
093 * @exception SocketException If the socket could not be opened or the
094 * timeout could not be set.
095 ***/
096 public void open() throws SocketException
097 {
098 _socket_ = _socketFactory_.createDatagramSocket();
099 _socket_.setSoTimeout(_timeout_);
100 _isOpen_ = true;
101 }
102
103
104 /***
105 * Opens a DatagramSocket on the local host at a specified port.
106 * Also sets the timeout on the socket to the default timeout set
107 * by {@link #setDefaultTimeout setDefaultTimeout() }.
108 * <p>
109 * _isOpen_ is set to true after calling this method and _socket_
110 * is set to the newly opened socket.
111 * <p>
112 * @param port The port to use for the socket.
113 * @exception SocketException If the socket could not be opened or the
114 * timeout could not be set.
115 ***/
116 public void open(int port) throws SocketException
117 {
118 _socket_ = _socketFactory_.createDatagramSocket(port);
119 _socket_.setSoTimeout(_timeout_);
120 _isOpen_ = true;
121 }
122
123
124 /***
125 * Opens a DatagramSocket at the specified address on the local host
126 * at a specified port.
127 * Also sets the timeout on the socket to the default timeout set
128 * by {@link #setDefaultTimeout setDefaultTimeout() }.
129 * <p>
130 * _isOpen_ is set to true after calling this method and _socket_
131 * is set to the newly opened socket.
132 * <p>
133 * @param port The port to use for the socket.
134 * @param laddr The local address to use.
135 * @exception SocketException If the socket could not be opened or the
136 * timeout could not be set.
137 ***/
138 public void open(int port, InetAddress laddr) throws SocketException
139 {
140 _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
141 _socket_.setSoTimeout(_timeout_);
142 _isOpen_ = true;
143 }
144
145
146
147 /***
148 * Closes the DatagramSocket used for the connection.
149 * You should call this method after you've finished using the class
150 * instance and also before you call {@link #open open() }
151 * again. _isOpen_ is set to false and _socket_ is set to null.
152 * If you call this method when the client socket is not open,
153 * a NullPointerException is thrown.
154 ***/
155 public void close()
156 {
157 if (_socket_ != null) {
158 _socket_.close();
159 }
160 _socket_ = null;
161 _isOpen_ = false;
162 }
163
164
165 /***
166 * Returns true if the client has a currently open socket.
167 * <p>
168 * @return True if the client has a curerntly open socket, false otherwise.
169 ***/
170 public boolean isOpen()
171 {
172 return _isOpen_;
173 }
174
175
176 /***
177 * Set the default timeout in milliseconds to use when opening a socket.
178 * After a call to open, the timeout for the socket is set using this value.
179 * This method should be used prior to a call to {@link #open open()}
180 * and should not be confused with {@link #setSoTimeout setSoTimeout()}
181 * which operates on the currently open socket. _timeout_ contains
182 * the new timeout value.
183 * <p>
184 * @param timeout The timeout in milliseconds to use for the datagram socket
185 * connection.
186 ***/
187 public void setDefaultTimeout(int timeout)
188 {
189 _timeout_ = timeout;
190 }
191
192
193 /***
194 * Returns the default timeout in milliseconds that is used when
195 * opening a socket.
196 * <p>
197 * @return The default timeout in milliseconds that is used when
198 * opening a socket.
199 ***/
200 public int getDefaultTimeout()
201 {
202 return _timeout_;
203 }
204
205
206 /***
207 * Set the timeout in milliseconds of a currently open connection.
208 * Only call this method after a connection has been opened
209 * by {@link #open open()}.
210 * <p>
211 * @param timeout The timeout in milliseconds to use for the currently
212 * open datagram socket connection.
213 ***/
214 public void setSoTimeout(int timeout) throws SocketException
215 {
216 _socket_.setSoTimeout(timeout);
217 }
218
219
220 /***
221 * Returns the timeout in milliseconds of the currently opened socket.
222 * If you call this method when the client socket is not open,
223 * a NullPointerException is thrown.
224 * <p>
225 * @return The timeout in milliseconds of the currently opened socket.
226 ***/
227 public int getSoTimeout() throws SocketException
228 {
229 return _socket_.getSoTimeout();
230 }
231
232
233 /***
234 * Returns the port number of the open socket on the local host used
235 * for the connection. If you call this method when the client socket
236 * is not open, a NullPointerException is thrown.
237 * <p>
238 * @return The port number of the open socket on the local host used
239 * for the connection.
240 ***/
241 public int getLocalPort()
242 {
243 return _socket_.getLocalPort();
244 }
245
246
247 /***
248 * Returns the local address to which the client's socket is bound.
249 * If you call this method when the client socket is not open, a
250 * NullPointerException is thrown.
251 * <p>
252 * @return The local address to which the client's socket is bound.
253 ***/
254 public InetAddress getLocalAddress()
255 {
256 return _socket_.getLocalAddress();
257 }
258
259
260 /***
261 * Sets the DatagramSocketFactory used by the DatagramSocketClient
262 * to open DatagramSockets. If the factory value is null, then a default
263 * factory is used (only do this to reset the factory after having
264 * previously altered it).
265 * <p>
266 * @param factory The new DatagramSocketFactory the DatagramSocketClient
267 * should use.
268 ***/
269 public void setDatagramSocketFactory(DatagramSocketFactory factory)
270 {
271 if (factory == null) {
272 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
273 } else {
274 _socketFactory_ = factory;
275 }
276 }
277 }