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    }