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 * @author Daniel F. Savarese
047 * @see DatagramSocketFactory
048 ***/
049
050 public abstract class DatagramSocketClient
051 {
052 /***
053 * The default DatagramSocketFactory shared by all DatagramSocketClient
054 * instances.
055 ***/
056 private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY =
057 new DefaultDatagramSocketFactory();
058
059 /*** The timeout to use after opening a socket. ***/
060 protected int _timeout_;
061
062 /*** The datagram socket used for the connection. ***/
063 protected DatagramSocket _socket_;
064
065 /***
066 * A status variable indicating if the client's socket is currently open.
067 ***/
068 protected boolean _isOpen_;
069
070 /*** The datagram socket's DatagramSocketFactory. ***/
071 protected DatagramSocketFactory _socketFactory_;
072
073 /***
074 * Default constructor for DatagramSocketClient. Initializes
075 * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
076 ***/
077 public DatagramSocketClient()
078 {
079 _socket_ = null;
080 _timeout_ = 0;
081 _isOpen_ = false;
082 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
083 }
084
085
086 /***
087 * Opens a DatagramSocket on the local host at the first available port.
088 * Also sets the timeout on the socket to the default timeout set
089 * by {@link #setDefaultTimeout setDefaultTimeout() }.
090 * <p>
091 * _isOpen_ is set to true after calling this method and _socket_
092 * is set to the newly opened socket.
093 * <p>
094 * @exception SocketException If the socket could not be opened or the
095 * timeout could not be set.
096 ***/
097 public void open() throws SocketException
098 {
099 _socket_ = _socketFactory_.createDatagramSocket();
100 _socket_.setSoTimeout(_timeout_);
101 _isOpen_ = true;
102 }
103
104
105 /***
106 * Opens a DatagramSocket on the local host at a specified port.
107 * Also sets the timeout on the socket to the default timeout set
108 * by {@link #setDefaultTimeout setDefaultTimeout() }.
109 * <p>
110 * _isOpen_ is set to true after calling this method and _socket_
111 * is set to the newly opened socket.
112 * <p>
113 * @param port The port to use for the socket.
114 * @exception SocketException If the socket could not be opened or the
115 * timeout could not be set.
116 ***/
117 public void open(int port) throws SocketException
118 {
119 _socket_ = _socketFactory_.createDatagramSocket(port);
120 _socket_.setSoTimeout(_timeout_);
121 _isOpen_ = true;
122 }
123
124
125 /***
126 * Opens a DatagramSocket at the specified address on the local host
127 * at a specified port.
128 * Also sets the timeout on the socket to the default timeout set
129 * by {@link #setDefaultTimeout setDefaultTimeout() }.
130 * <p>
131 * _isOpen_ is set to true after calling this method and _socket_
132 * is set to the newly opened socket.
133 * <p>
134 * @param port The port to use for the socket.
135 * @param laddr The local address to use.
136 * @exception SocketException If the socket could not be opened or the
137 * timeout could not be set.
138 ***/
139 public void open(int port, InetAddress laddr) throws SocketException
140 {
141 _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
142 _socket_.setSoTimeout(_timeout_);
143 _isOpen_ = true;
144 }
145
146
147
148 /***
149 * Closes the DatagramSocket used for the connection.
150 * You should call this method after you've finished using the class
151 * instance and also before you call {@link #open open() }
152 * again. _isOpen_ is set to false and _socket_ is set to null.
153 * If you call this method when the client socket is not open,
154 * a NullPointerException is thrown.
155 ***/
156 public void close()
157 {
158 _socket_.close();
159 _socket_ = null;
160 _isOpen_ = false;
161 }
162
163
164 /***
165 * Returns true if the client has a currently open socket.
166 * <p>
167 * @return True if the client has a curerntly open socket, false otherwise.
168 ***/
169 public boolean isOpen()
170 {
171 return _isOpen_;
172 }
173
174
175 /***
176 * Set the default timeout in milliseconds to use when opening a socket.
177 * After a call to open, the timeout for the socket is set using this value.
178 * This method should be used prior to a call to {@link #open open()}
179 * and should not be confused with {@link #setSoTimeout setSoTimeout()}
180 * which operates on the currently open socket. _timeout_ contains
181 * the new timeout value.
182 * <p>
183 * @param timeout The timeout in milliseconds to use for the datagram socket
184 * connection.
185 ***/
186 public void setDefaultTimeout(int timeout)
187 {
188 _timeout_ = timeout;
189 }
190
191
192 /***
193 * Returns the default timeout in milliseconds that is used when
194 * opening a socket.
195 * <p>
196 * @return The default timeout in milliseconds that is used when
197 * opening a socket.
198 ***/
199 public int getDefaultTimeout()
200 {
201 return _timeout_;
202 }
203
204
205 /***
206 * Set the timeout in milliseconds of a currently open connection.
207 * Only call this method after a connection has been opened
208 * by {@link #open open()}.
209 * <p>
210 * @param timeout The timeout in milliseconds to use for the currently
211 * open datagram socket connection.
212 ***/
213 public void setSoTimeout(int timeout) throws SocketException
214 {
215 _socket_.setSoTimeout(timeout);
216 }
217
218
219 /***
220 * Returns the timeout in milliseconds of the currently opened socket.
221 * If you call this method when the client socket is not open,
222 * a NullPointerException is thrown.
223 * <p>
224 * @return The timeout in milliseconds of the currently opened socket.
225 ***/
226 public int getSoTimeout() throws SocketException
227 {
228 return _socket_.getSoTimeout();
229 }
230
231
232 /***
233 * Returns the port number of the open socket on the local host used
234 * for the connection. If you call this method when the client socket
235 * is not open, a NullPointerException is thrown.
236 * <p>
237 * @return The port number of the open socket on the local host used
238 * for the connection.
239 ***/
240 public int getLocalPort()
241 {
242 return _socket_.getLocalPort();
243 }
244
245
246 /***
247 * Returns the local address to which the client's socket is bound.
248 * If you call this method when the client socket is not open, a
249 * NullPointerException is thrown.
250 * <p>
251 * @return The local address to which the client's socket is bound.
252 ***/
253 public InetAddress getLocalAddress()
254 {
255 return _socket_.getLocalAddress();
256 }
257
258
259 /***
260 * Sets the DatagramSocketFactory used by the DatagramSocketClient
261 * to open DatagramSockets. If the factory value is null, then a default
262 * factory is used (only do this to reset the factory after having
263 * previously altered it).
264 * <p>
265 * @param factory The new DatagramSocketFactory the DatagramSocketClient
266 * should use.
267 ***/
268 public void setDatagramSocketFactory(DatagramSocketFactory factory)
269 {
270 if (factory == null)
271 _socketFactory_ = __DEFAULT_SOCKET_FACTORY;
272 else
273 _socketFactory_ = factory;
274 }
275 }