    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    }