    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;
    023import java.nio.charset.Charset;
    024
    025/**
    026 * The DatagramSocketClient provides the basic operations that are required
    027 * of client objects accessing datagram sockets.  It is meant to be
    028 * subclassed to avoid having to rewrite the same code over and over again
    029 * to open a socket, close a socket, set timeouts, etc.  Of special note
    030 * is the {@link #setDatagramSocketFactory  setDatagramSocketFactory }
    031 * method, which allows you to control the type of DatagramSocket the
    032 * DatagramSocketClient creates for network communications.  This is
    033 * especially useful for adding things like proxy support as well as better
    034 * support for applets.  For
    035 * example, you could create a
    036 * {@link org.apache.commons.net.DatagramSocketFactory}
    037 *  that
    038 * requests browser security capabilities before creating a socket.
    039 * All classes derived from DatagramSocketClient should use the
    040 * {@link #_socketFactory_  _socketFactory_ } member variable to
    041 * create DatagramSocket instances rather than instantiating
    042 * them by directly invoking a constructor.  By honoring this contract
    043 * you guarantee that a user will always be able to provide his own
    044 * Socket implementations by substituting his own SocketFactory.
    045 *
    046 *
    047 * @see DatagramSocketFactory
    048 */
    049
    050public 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    /**
    060     * Charset to use for byte IO.
    061     */
    062    private Charset charset = Charset.defaultCharset();
    063
    064    /** The timeout to use after opening a socket. */
    065    protected int _timeout_;
    066
    067    /** The datagram socket used for the connection. */
    068    protected DatagramSocket _socket_;
    069
    070    /**
    071     * A status variable indicating if the client's socket is currently open.
    072     */
    073    protected boolean _isOpen_;
    074
    075    /** The datagram socket's DatagramSocketFactory. */
    076    protected DatagramSocketFactory _socketFactory_;
    077
    078    /**
    079     * Default constructor for DatagramSocketClient.  Initializes
    080     * _socket_ to null, _timeout_ to 0, and _isOpen_ to false.
    081     */
    082    public DatagramSocketClient()
    083    {
    084        _socket_ = null;
    085        _timeout_ = 0;
    086        _isOpen_ = false;
    087        _socketFactory_ = DEFAULT_SOCKET_FACTORY;
    088    }
    089
    090
    091    /**
    092     * Opens a DatagramSocket on the local host at the first available port.
    093     * Also sets the timeout on the socket to the default timeout set
    094     * by {@link #setDefaultTimeout  setDefaultTimeout() }.
    095     * <p>
    096     * _isOpen_ is set to true after calling this method and _socket_
    097     * is set to the newly opened socket.
    098     *
    099     * @throws SocketException If the socket could not be opened or the
    100     *   timeout could not be set.
    101     */
    102    public void open() throws SocketException
    103    {
    104        _socket_ = _socketFactory_.createDatagramSocket();
    105        _socket_.setSoTimeout(_timeout_);
    106        _isOpen_ = true;
    107    }
    108
    109
    110    /**
    111     * Opens a DatagramSocket on the local host at a specified port.
    112     * Also sets the timeout on the socket to the default timeout set
    113     * by {@link #setDefaultTimeout  setDefaultTimeout() }.
    114     * <p>
    115     * _isOpen_ is set to true after calling this method and _socket_
    116     * is set to the newly opened socket.
    117     *
    118     * @param port The port to use for the socket.
    119     * @throws SocketException If the socket could not be opened or the
    120     *   timeout could not be set.
    121     */
    122    public void open(final int port) throws SocketException
    123    {
    124        _socket_ = _socketFactory_.createDatagramSocket(port);
    125        _socket_.setSoTimeout(_timeout_);
    126        _isOpen_ = true;
    127    }
    128
    129
    130    /**
    131     * Opens a DatagramSocket at the specified address on the local host
    132     * at a specified port.
    133     * Also sets the timeout on the socket to the default timeout set
    134     * by {@link #setDefaultTimeout  setDefaultTimeout() }.
    135     * <p>
    136     * _isOpen_ is set to true after calling this method and _socket_
    137     * is set to the newly opened socket.
    138     *
    139     * @param port The port to use for the socket.
    140     * @param laddr  The local address to use.
    141     * @throws SocketException If the socket could not be opened or the
    142     *   timeout could not be set.
    143     */
    144    public void open(final int port, final InetAddress laddr) throws SocketException
    145    {
    146        _socket_ = _socketFactory_.createDatagramSocket(port, laddr);
    147        _socket_.setSoTimeout(_timeout_);
    148        _isOpen_ = true;
    149    }
    150
    151
    152
    153    /**
    154     * Closes the DatagramSocket used for the connection.
    155     * You should call this method after you've finished using the class
    156     * instance and also before you call {@link #open open() }
    157     * again.   _isOpen_ is set to false and  _socket_ is set to null.
    158     */
    159    public void close()
    160    {
    161        if (_socket_ != null) {
    162            _socket_.close();
    163        }
    164        _socket_ = null;
    165        _isOpen_ = false;
    166    }
    167
    168
    169    /**
    170     * Returns true if the client has a currently open socket.
    171     *
    172     * @return True if the client has a currently open socket, false otherwise.
    173     */
    174    public boolean isOpen()
    175    {
    176        return _isOpen_;
    177    }
    178
    179
    180    /**
    181     * Set the default timeout in milliseconds to use when opening a socket.
    182     * After a call to open, the timeout for the socket is set using this value.
    183     * This method should be used prior to a call to {@link #open open()}
    184     * and should not be confused with {@link #setSoTimeout setSoTimeout()}
    185     * which operates on the currently open socket.  _timeout_ contains
    186     * the new timeout value.
    187     *
    188     * @param timeout  The timeout in milliseconds to use for the datagram socket
    189     *                 connection.
    190     */
    191    public void setDefaultTimeout(final int timeout)
    192    {
    193        _timeout_ = timeout;
    194    }
    195
    196
    197    /**
    198     * Returns the default timeout in milliseconds that is used when
    199     * opening a socket.
    200     *
    201     * @return The default timeout in milliseconds that is used when
    202     *         opening a socket.
    203     */
    204    public int getDefaultTimeout()
    205    {
    206        return _timeout_;
    207    }
    208
    209
    210    /**
    211     * Set the timeout in milliseconds of a currently open connection.
    212     * Only call this method after a connection has been opened
    213     * by {@link #open open()}.
    214     *
    215     * @param timeout  The timeout in milliseconds to use for the currently
    216     *                 open datagram socket connection.
    217     * @throws SocketException if an error setting the timeout
    218     */
    219    public void setSoTimeout(final int timeout) throws SocketException
    220    {
    221        _socket_.setSoTimeout(timeout);
    222    }
    223
    224
    225    /**
    226     * Returns the timeout in milliseconds of the currently opened socket.
    227     * If you call this method when the client socket is not open,
    228     * a NullPointerException is thrown.
    229     *
    230     * @return The timeout in milliseconds of the currently opened socket.
    231     * @throws SocketException if an error getting the timeout
    232     */
    233    public int getSoTimeout() throws SocketException
    234    {
    235        return _socket_.getSoTimeout();
    236    }
    237
    238
    239    /**
    240     * Returns the port number of the open socket on the local host used
    241     * for the connection.  If you call this method when the client socket
    242     * is not open, a NullPointerException is thrown.
    243     *
    244     * @return The port number of the open socket on the local host used
    245     *         for the connection.
    246     */
    247    public int getLocalPort()
    248    {
    249        return _socket_.getLocalPort();
    250    }
    251
    252
    253    /**
    254     * Returns the local address to which the client's socket is bound.
    255     * If you call this method when the client socket is not open, a
    256     * NullPointerException is thrown.
    257     *
    258     * @return The local address to which the client's socket is bound.
    259     */
    260    public InetAddress getLocalAddress()
    261    {
    262        return _socket_.getLocalAddress();
    263    }
    264
    265
    266    /**
    267     * Sets the DatagramSocketFactory used by the DatagramSocketClient
    268     * to open DatagramSockets.  If the factory value is null, then a default
    269     * factory is used (only do this to reset the factory after having
    270     * previously altered it).
    271     *
    272     * @param factory  The new DatagramSocketFactory the DatagramSocketClient
    273     * should use.
    274     */
    275    public void setDatagramSocketFactory(final DatagramSocketFactory factory)
    276    {
    277        if (factory == null) {
    278            _socketFactory_ = DEFAULT_SOCKET_FACTORY;
    279        } else {
    280            _socketFactory_ = factory;
    281        }
    282    }
    283
    284    /**
    285     * Gets the charset name.
    286     *
    287     * @return the charset name.
    288     * @since 3.3
    289     * @deprecated Use {@link #getCharset()} instead
    290     */
    291    @Deprecated
    292    public String getCharsetName() {
    293        return charset.name();
    294    }
    295
    296    /**
    297     * Gets the charset.
    298     *
    299     * @return the charset.
    300     * @since 3.3
    301     */
    302    public Charset getCharset() {
    303        return charset;
    304    }
    305
    306    /**
    307     * Sets the charset.
    308     *
    309     * @param charset the charset.
    310     * @since 3.3
    311     */
    312    public void setCharset(final Charset charset) {
    313        this.charset = charset;
    314    }
    315}