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
018package org.apache.commons.net;
019
020import java.net.DatagramSocket;
021import java.net.InetAddress;
022import 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
049public 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}