1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.net; 19 20 import java.net.DatagramSocket; 21 import java.net.InetAddress; 22 import java.net.SocketException; 23 import java.nio.charset.Charset; 24 25 /*** 26 * The DatagramSocketClient provides the basic operations that are required 27 * of client objects accessing datagram sockets. It is meant to be 28 * subclassed to avoid having to rewrite the same code over and over again 29 * to open a socket, close a socket, set timeouts, etc. Of special note 30 * is the {@link #setDatagramSocketFactory setDatagramSocketFactory } 31 * method, which allows you to control the type of DatagramSocket the 32 * DatagramSocketClient creates for network communications. This is 33 * especially useful for adding things like proxy support as well as better 34 * support for applets. For 35 * example, you could create a 36 * {@link org.apache.commons.net.DatagramSocketFactory} 37 * that 38 * requests browser security capabilities before creating a socket. 39 * All classes derived from DatagramSocketClient should use the 40 * {@link #_socketFactory_ _socketFactory_ } member variable to 41 * create DatagramSocket instances rather than instantiating 42 * them by directly invoking a constructor. By honoring this contract 43 * you guarantee that a user will always be able to provide his own 44 * Socket implementations by substituting his own SocketFactory. 45 * <p> 46 * <p> 47 * @see DatagramSocketFactory 48 ***/ 49 50 public abstract class DatagramSocketClient 51 { 52 /*** 53 * The default DatagramSocketFactory shared by all DatagramSocketClient 54 * instances. 55 ***/ 56 private static final DatagramSocketFactory __DEFAULT_SOCKET_FACTORY = 57 new DefaultDatagramSocketFactory(); 58 59 /** 60 * Charset to use for byte IO. 61 */ 62 private Charset charset = Charset.defaultCharset(); 63 64 /*** The timeout to use after opening a socket. ***/ 65 protected int _timeout_; 66 67 /*** The datagram socket used for the connection. ***/ 68 protected DatagramSocket _socket_; 69 70 /*** 71 * A status variable indicating if the client's socket is currently open. 72 ***/ 73 protected boolean _isOpen_; 74 75 /*** The datagram socket's DatagramSocketFactory. ***/ 76 protected DatagramSocketFactory _socketFactory_; 77 78 /*** 79 * Default constructor for DatagramSocketClient. Initializes 80 * _socket_ to null, _timeout_ to 0, and _isOpen_ to false. 81 ***/ 82 public DatagramSocketClient() 83 { 84 _socket_ = null; 85 _timeout_ = 0; 86 _isOpen_ = false; 87 _socketFactory_ = __DEFAULT_SOCKET_FACTORY; 88 } 89 90 91 /*** 92 * Opens a DatagramSocket on the local host at the first available port. 93 * Also sets the timeout on the socket to the default timeout set 94 * by {@link #setDefaultTimeout setDefaultTimeout() }. 95 * <p> 96 * _isOpen_ is set to true after calling this method and _socket_ 97 * is set to the newly opened socket. 98 * <p> 99 * @exception 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 * <p> 118 * @param port The port to use for the socket. 119 * @exception SocketException If the socket could not be opened or the 120 * timeout could not be set. 121 ***/ 122 public void open(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 * <p> 139 * @param port The port to use for the socket. 140 * @param laddr The local address to use. 141 * @exception SocketException If the socket could not be opened or the 142 * timeout could not be set. 143 ***/ 144 public void open(int port, 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 * If you call this method when the client socket is not open, 159 * a NullPointerException is thrown. 160 ***/ 161 public void close() 162 { 163 if (_socket_ != null) { 164 _socket_.close(); 165 } 166 _socket_ = null; 167 _isOpen_ = false; 168 } 169 170 171 /*** 172 * Returns true if the client has a currently open socket. 173 * <p> 174 * @return True if the client has a curerntly open socket, false otherwise. 175 ***/ 176 public boolean isOpen() 177 { 178 return _isOpen_; 179 } 180 181 182 /*** 183 * Set the default timeout in milliseconds to use when opening a socket. 184 * After a call to open, the timeout for the socket is set using this value. 185 * This method should be used prior to a call to {@link #open open()} 186 * and should not be confused with {@link #setSoTimeout setSoTimeout()} 187 * which operates on the currently open socket. _timeout_ contains 188 * the new timeout value. 189 * <p> 190 * @param timeout The timeout in milliseconds to use for the datagram socket 191 * connection. 192 ***/ 193 public void setDefaultTimeout(int timeout) 194 { 195 _timeout_ = timeout; 196 } 197 198 199 /*** 200 * Returns the default timeout in milliseconds that is used when 201 * opening a socket. 202 * <p> 203 * @return The default timeout in milliseconds that is used when 204 * opening a socket. 205 ***/ 206 public int getDefaultTimeout() 207 { 208 return _timeout_; 209 } 210 211 212 /*** 213 * Set the timeout in milliseconds of a currently open connection. 214 * Only call this method after a connection has been opened 215 * by {@link #open open()}. 216 * <p> 217 * @param timeout The timeout in milliseconds to use for the currently 218 * open datagram socket connection. 219 ***/ 220 public void setSoTimeout(int timeout) throws SocketException 221 { 222 _socket_.setSoTimeout(timeout); 223 } 224 225 226 /*** 227 * Returns the timeout in milliseconds of the currently opened socket. 228 * If you call this method when the client socket is not open, 229 * a NullPointerException is thrown. 230 * <p> 231 * @return The timeout in milliseconds of the currently opened socket. 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 * <p> 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 * <p> 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 * <p> 272 * @param factory The new DatagramSocketFactory the DatagramSocketClient 273 * should use. 274 ***/ 275 public void setDatagramSocketFactory(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 * TODO Will be deprecated once the code requires Java 1.6 as a mininmum 290 */ 291 public String getCharsetName() { 292 return charset.name(); 293 } 294 295 /** 296 * Gets the charset. 297 * 298 * @return the charset. 299 * @since 3.3 300 */ 301 public Charset getCharset() { 302 return charset; 303 } 304 305 /** 306 * Sets the charset. 307 * 308 * @param charset the charset. 309 * @since 3.3 310 */ 311 public void setCharset(Charset charset) { 312 this.charset = charset; 313 } 314 }