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