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; 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 049public 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}