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