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    }