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.io.Closeable; 021import java.io.IOException; 022import java.io.InputStream; 023import java.io.OutputStream; 024import java.net.InetAddress; 025import java.net.InetSocketAddress; 026import java.net.Proxy; 027import java.net.Socket; 028import java.net.SocketException; 029import java.nio.charset.Charset; 030 031import javax.net.ServerSocketFactory; 032import javax.net.SocketFactory; 033 034 035/** 036 * The SocketClient provides the basic operations that are required of 037 * client objects accessing sockets. It is meant to be 038 * subclassed to avoid having to rewrite the same code over and over again 039 * to open a socket, close a socket, set timeouts, etc. Of special note 040 * is the {@link #setSocketFactory setSocketFactory } 041 * method, which allows you to control the type of Socket the SocketClient 042 * creates for initiating network connections. This is especially useful 043 * for adding SSL or proxy support as well as better support for applets. For 044 * example, you could create a 045 * {@link javax.net.SocketFactory} that 046 * requests browser security capabilities before creating a socket. 047 * All classes derived from SocketClient should use the 048 * {@link #_socketFactory_ _socketFactory_ } member variable to 049 * create Socket and ServerSocket instances rather than instantiating 050 * them by directly invoking a constructor. By honoring this contract 051 * you guarantee that a user will always be able to provide his own 052 * Socket implementations by substituting his own SocketFactory. 053 * @see SocketFactory 054 */ 055public abstract class SocketClient 056{ 057 /** 058 * The end of line character sequence used by most IETF protocols. That 059 * is a carriage return followed by a newline: "\r\n" 060 */ 061 public static final String NETASCII_EOL = "\r\n"; 062 063 /** The default SocketFactory shared by all SocketClient instances. */ 064 private static final SocketFactory DEFAULT_SOCKET_FACTORY = 065 SocketFactory.getDefault(); 066 067 /** The default {@link ServerSocketFactory} */ 068 private static final ServerSocketFactory DEFAULT_SERVER_SOCKET_FACTORY = 069 ServerSocketFactory.getDefault(); 070 071 /** 072 * A ProtocolCommandSupport object used to manage the registering of 073 * ProtocolCommandListeners and the firing of ProtocolCommandEvents. 074 */ 075 private ProtocolCommandSupport commandSupport; 076 077 /** The timeout to use after opening a socket. */ 078 protected int _timeout_; 079 080 /** The socket used for the connection. */ 081 protected Socket _socket_; 082 083 /** The hostname used for the connection (null = no hostname supplied). */ 084 protected String _hostname_; 085 086 /** The default port the client should connect to. */ 087 protected int _defaultPort_; 088 089 /** The socket's InputStream. */ 090 protected InputStream _input_; 091 092 /** The socket's OutputStream. */ 093 protected OutputStream _output_; 094 095 /** The socket's SocketFactory. */ 096 protected SocketFactory _socketFactory_; 097 098 /** The socket's ServerSocket Factory. */ 099 protected ServerSocketFactory _serverSocketFactory_; 100 101 /** The socket's connect timeout (0 = infinite timeout) */ 102 private static final int DEFAULT_CONNECT_TIMEOUT = 0; 103 protected int connectTimeout = DEFAULT_CONNECT_TIMEOUT; 104 105 /** Hint for SO_RCVBUF size */ 106 private int receiveBufferSize = -1; 107 108 /** Hint for SO_SNDBUF size */ 109 private int sendBufferSize = -1; 110 111 /** The proxy to use when connecting. */ 112 private Proxy connProxy; 113 114 /** 115 * Charset to use for byte IO. 116 */ 117 private Charset charset = Charset.defaultCharset(); 118 119 /** 120 * Default constructor for SocketClient. Initializes 121 * _socket_ to null, _timeout_ to 0, _defaultPort to 0, 122 * _isConnected_ to false, charset to {@code Charset.defaultCharset()} 123 * and _socketFactory_ to a shared instance of 124 * {@link org.apache.commons.net.DefaultSocketFactory}. 125 */ 126 public SocketClient() 127 { 128 _socket_ = null; 129 _hostname_ = null; 130 _input_ = null; 131 _output_ = null; 132 _timeout_ = 0; 133 _defaultPort_ = 0; 134 _socketFactory_ = DEFAULT_SOCKET_FACTORY; 135 _serverSocketFactory_ = DEFAULT_SERVER_SOCKET_FACTORY; 136 } 137 138 139 /** 140 * Because there are so many connect() methods, the _connectAction_() 141 * method is provided as a means of performing some action immediately 142 * after establishing a connection, rather than reimplementing all 143 * of the connect() methods. The last action performed by every 144 * connect() method after opening a socket is to call this method. 145 * <p> 146 * This method sets the timeout on the just opened socket to the default 147 * timeout set by {@link #setDefaultTimeout setDefaultTimeout() }, 148 * sets _input_ and _output_ to the socket's InputStream and OutputStream 149 * respectively, and sets _isConnected_ to true. 150 * <p> 151 * Subclasses overriding this method should start by calling 152 * <code> super._connectAction_() </code> first to ensure the 153 * initialization of the aforementioned protected variables. 154 * @throws IOException (SocketException) if a problem occurs with the socket 155 */ 156 protected void _connectAction_() throws IOException 157 { 158 _socket_.setSoTimeout(_timeout_); 159 _input_ = _socket_.getInputStream(); 160 _output_ = _socket_.getOutputStream(); 161 } 162 163 164 /** 165 * Opens a Socket connected to a remote host at the specified port and 166 * originating from the current host at a system assigned port. 167 * Before returning, {@link #_connectAction_ _connectAction_() } 168 * is called to perform connection initialization actions. 169 * <p> 170 * @param host The remote host. 171 * @param port The port to connect to on the remote host. 172 * @throws SocketException If the socket timeout could not be set. 173 * @throws IOException If the socket could not be opened. In most 174 * cases you will only want to catch IOException since SocketException is 175 * derived from it. 176 */ 177 public void connect(final InetAddress host, final int port) 178 throws SocketException, IOException 179 { 180 _hostname_ = null; 181 _connect(host, port, null, -1); 182 } 183 184 /** 185 * Opens a Socket connected to a remote host at the specified port and 186 * originating from the current host at a system assigned port. 187 * Before returning, {@link #_connectAction_ _connectAction_() } 188 * is called to perform connection initialization actions. 189 * <p> 190 * @param hostname The name of the remote host. 191 * @param port The port to connect to on the remote host. 192 * @throws SocketException If the socket timeout could not be set. 193 * @throws IOException If the socket could not be opened. In most 194 * cases you will only want to catch IOException since SocketException is 195 * derived from it. 196 * @throws java.net.UnknownHostException If the hostname cannot be resolved. 197 */ 198 public void connect(final String hostname, final int port) 199 throws SocketException, IOException 200 { 201 _hostname_ = hostname; 202 _connect(InetAddress.getByName(hostname), port, null, -1); 203 } 204 205 206 /** 207 * Opens a Socket connected to a remote host at the specified port and 208 * originating from the specified local address and port. 209 * Before returning, {@link #_connectAction_ _connectAction_() } 210 * is called to perform connection initialization actions. 211 * <p> 212 * @param host The remote host. 213 * @param port The port to connect to on the remote host. 214 * @param localAddr The local address to use. 215 * @param localPort The local port to use. 216 * @throws SocketException If the socket timeout could not be set. 217 * @throws IOException If the socket could not be opened. In most 218 * cases you will only want to catch IOException since SocketException is 219 * derived from it. 220 */ 221 public void connect(final InetAddress host, final int port, 222 final InetAddress localAddr, final int localPort) 223 throws SocketException, IOException 224 { 225 _hostname_ = null; 226 _connect(host, port, localAddr, localPort); 227 } 228 229 // helper method to allow code to be shared with connect(String,...) methods 230 private void _connect(final InetAddress host, final int port, final InetAddress localAddr, final int localPort) 231 throws SocketException, IOException 232 { 233 _socket_ = _socketFactory_.createSocket(); 234 if (receiveBufferSize != -1) { 235 _socket_.setReceiveBufferSize(receiveBufferSize); 236 } 237 if (sendBufferSize != -1) { 238 _socket_.setSendBufferSize(sendBufferSize); 239 } 240 if (localAddr != null) { 241 _socket_.bind(new InetSocketAddress(localAddr, localPort)); 242 } 243 _socket_.connect(new InetSocketAddress(host, port), connectTimeout); 244 _connectAction_(); 245 } 246 247 /** 248 * Opens a Socket connected to a remote host at the specified port and 249 * originating from the specified local address and port. 250 * Before returning, {@link #_connectAction_ _connectAction_() } 251 * is called to perform connection initialization actions. 252 * <p> 253 * @param hostname The name of the remote host. 254 * @param port The port to connect to on the remote host. 255 * @param localAddr The local address to use. 256 * @param localPort The local port to use. 257 * @throws SocketException If the socket timeout could not be set. 258 * @throws IOException If the socket could not be opened. In most 259 * cases you will only want to catch IOException since SocketException is 260 * derived from it. 261 * @throws java.net.UnknownHostException If the hostname cannot be resolved. 262 */ 263 public void connect(final String hostname, final int port, 264 final InetAddress localAddr, final int localPort) 265 throws SocketException, IOException 266 { 267 _hostname_ = hostname; 268 _connect(InetAddress.getByName(hostname), port, localAddr, localPort); 269 } 270 271 272 /** 273 * Opens a Socket connected to a remote host at the current default port 274 * and originating from the current host at a system assigned port. 275 * Before returning, {@link #_connectAction_ _connectAction_() } 276 * is called to perform connection initialization actions. 277 * <p> 278 * @param host The remote host. 279 * @throws SocketException If the socket timeout could not be set. 280 * @throws IOException If the socket could not be opened. In most 281 * cases you will only want to catch IOException since SocketException is 282 * derived from it. 283 */ 284 public void connect(final InetAddress host) throws SocketException, IOException 285 { 286 _hostname_ = null; 287 connect(host, _defaultPort_); 288 } 289 290 291 /** 292 * Opens a Socket connected to a remote host at the current default 293 * port and originating from the current host at a system assigned port. 294 * Before returning, {@link #_connectAction_ _connectAction_() } 295 * is called to perform connection initialization actions. 296 * <p> 297 * @param hostname The name of the remote host. 298 * @throws SocketException If the socket timeout could not be set. 299 * @throws IOException If the socket could not be opened. In most 300 * cases you will only want to catch IOException since SocketException is 301 * derived from it. 302 * @throws java.net.UnknownHostException If the hostname cannot be resolved. 303 */ 304 public void connect(final String hostname) throws SocketException, IOException 305 { 306 connect(hostname, _defaultPort_); 307 } 308 309 310 /** 311 * Disconnects the socket connection. 312 * You should call this method after you've finished using the class 313 * instance and also before you call 314 * {@link #connect connect() } 315 * again. _isConnected_ is set to false, _socket_ is set to null, 316 * _input_ is set to null, and _output_ is set to null. 317 * <p> 318 * @throws IOException If there is an error closing the socket. 319 */ 320 public void disconnect() throws IOException 321 { 322 closeQuietly(_socket_); 323 closeQuietly(_input_); 324 closeQuietly(_output_); 325 _socket_ = null; 326 _hostname_ = null; 327 _input_ = null; 328 _output_ = null; 329 } 330 331 private void closeQuietly(final Socket socket) { 332 if (socket != null){ 333 try { 334 socket.close(); 335 } catch (final IOException e) { 336 // Ignored 337 } 338 } 339 } 340 341 private void closeQuietly(final Closeable close){ 342 if (close != null){ 343 try { 344 close.close(); 345 } catch (final IOException e) { 346 // Ignored 347 } 348 } 349 } 350 /** 351 * Returns true if the client is currently connected to a server. 352 * <p> 353 * Delegates to {@link Socket#isConnected()} 354 * @return True if the client is currently connected to a server, 355 * false otherwise. 356 */ 357 public boolean isConnected() 358 { 359 if (_socket_ == null) { 360 return false; 361 } 362 363 return _socket_.isConnected(); 364 } 365 366 /** 367 * Make various checks on the socket to test if it is available for use. 368 * Note that the only sure test is to use it, but these checks may help 369 * in some cases. 370 * @see <a href="https://issues.apache.org/jira/browse/NET-350">NET-350</a> 371 * @return {@code true} if the socket appears to be available for use 372 * @since 3.0 373 */ 374 @SuppressWarnings("resource") 375 public boolean isAvailable(){ 376 if (isConnected()) { 377 try 378 { 379 if (_socket_.getInetAddress() == null) { 380 return false; 381 } 382 if (_socket_.getPort() == 0) { 383 return false; 384 } 385 if (_socket_.getRemoteSocketAddress() == null) { 386 return false; 387 } 388 if (_socket_.isClosed()) { 389 return false; 390 } 391 /* these aren't exact checks (a Socket can be half-open), 392 but since we usually require two-way data transfer, 393 we check these here too: */ 394 if (_socket_.isInputShutdown()) { 395 return false; 396 } 397 if (_socket_.isOutputShutdown()) { 398 return false; 399 } 400 /* ignore the result, catch exceptions: */ 401 // No need to close 402 _socket_.getInputStream(); 403 // No need to close 404 _socket_.getOutputStream(); 405 } 406 catch (final IOException ioex) 407 { 408 return false; 409 } 410 return true; 411 } 412 return false; 413 } 414 415 /** 416 * Sets the default port the SocketClient should connect to when a port 417 * is not specified. The {@link #_defaultPort_ _defaultPort_ } 418 * variable stores this value. If never set, the default port is equal 419 * to zero. 420 * <p> 421 * @param port The default port to set. 422 */ 423 public void setDefaultPort(final int port) 424 { 425 _defaultPort_ = port; 426 } 427 428 /** 429 * Returns the current value of the default port (stored in 430 * {@link #_defaultPort_ _defaultPort_ }). 431 * <p> 432 * @return The current value of the default port. 433 */ 434 public int getDefaultPort() 435 { 436 return _defaultPort_; 437 } 438 439 440 /** 441 * Set the default timeout in milliseconds to use when opening a socket. 442 * This value is only used previous to a call to 443 * {@link #connect connect()} 444 * and should not be confused with {@link #setSoTimeout setSoTimeout()} 445 * which operates on an the currently opened socket. _timeout_ contains 446 * the new timeout value. 447 * <p> 448 * @param timeout The timeout in milliseconds to use for the socket 449 * connection. 450 */ 451 public void setDefaultTimeout(final int timeout) 452 { 453 _timeout_ = timeout; 454 } 455 456 457 /** 458 * Returns the default timeout in milliseconds that is used when 459 * opening a socket. 460 * <p> 461 * @return The default timeout in milliseconds that is used when 462 * opening a socket. 463 */ 464 public int getDefaultTimeout() 465 { 466 return _timeout_; 467 } 468 469 470 /** 471 * Set the timeout in milliseconds of a currently open connection. 472 * Only call this method after a connection has been opened 473 * by {@link #connect connect()}. 474 * <p> 475 * To set the initial timeout, use {@link #setDefaultTimeout(int)} instead. 476 * 477 * @param timeout The timeout in milliseconds to use for the currently 478 * open socket connection. 479 * @throws SocketException If the operation fails. 480 * @throws NullPointerException if the socket is not currently open 481 */ 482 public void setSoTimeout(final int timeout) throws SocketException 483 { 484 _socket_.setSoTimeout(timeout); 485 } 486 487 488 /** 489 * Set the underlying socket send buffer size. 490 * <p> 491 * @param size The size of the buffer in bytes. 492 * @throws SocketException never thrown, but subclasses might want to do so 493 * @since 2.0 494 */ 495 public void setSendBufferSize(final int size) throws SocketException { 496 sendBufferSize = size; 497 } 498 499 /** 500 * Get the current sendBuffer size 501 * @return the size, or -1 if not initialised 502 * @since 3.0 503 */ 504 protected int getSendBufferSize(){ 505 return sendBufferSize; 506 } 507 508 /** 509 * Sets the underlying socket receive buffer size. 510 * <p> 511 * @param size The size of the buffer in bytes. 512 * @throws SocketException never (but subclasses may wish to do so) 513 * @since 2.0 514 */ 515 public void setReceiveBufferSize(final int size) throws SocketException { 516 receiveBufferSize = size; 517 } 518 519 /** 520 * Get the current receivedBuffer size 521 * @return the size, or -1 if not initialised 522 * @since 3.0 523 */ 524 protected int getReceiveBufferSize(){ 525 return receiveBufferSize; 526 } 527 528 /** 529 * Returns the timeout in milliseconds of the currently opened socket. 530 * <p> 531 * @return The timeout in milliseconds of the currently opened socket. 532 * @throws SocketException If the operation fails. 533 * @throws NullPointerException if the socket is not currently open 534 */ 535 public int getSoTimeout() throws SocketException 536 { 537 return _socket_.getSoTimeout(); 538 } 539 540 /** 541 * Enables or disables the Nagle's algorithm (TCP_NODELAY) on the 542 * currently opened socket. 543 * <p> 544 * @param on True if Nagle's algorithm is to be enabled, false if not. 545 * @throws SocketException If the operation fails. 546 * @throws NullPointerException if the socket is not currently open 547 */ 548 public void setTcpNoDelay(final boolean on) throws SocketException 549 { 550 _socket_.setTcpNoDelay(on); 551 } 552 553 554 /** 555 * Returns true if Nagle's algorithm is enabled on the currently opened 556 * socket. 557 * <p> 558 * @return True if Nagle's algorithm is enabled on the currently opened 559 * socket, false otherwise. 560 * @throws SocketException If the operation fails. 561 * @throws NullPointerException if the socket is not currently open 562 */ 563 public boolean getTcpNoDelay() throws SocketException 564 { 565 return _socket_.getTcpNoDelay(); 566 } 567 568 /** 569 * Sets the SO_KEEPALIVE flag on the currently opened socket. 570 * 571 * From the Javadocs, the default keepalive time is 2 hours (although this is 572 * implementation dependent). It looks as though the Windows WSA sockets implementation 573 * allows a specific keepalive value to be set, although this seems not to be the case on 574 * other systems. 575 * @param keepAlive If true, keepAlive is turned on 576 * @throws SocketException if there is a problem with the socket 577 * @throws NullPointerException if the socket is not currently open 578 * @since 2.2 579 */ 580 public void setKeepAlive(final boolean keepAlive) throws SocketException { 581 _socket_.setKeepAlive(keepAlive); 582 } 583 584 /** 585 * Returns the current value of the SO_KEEPALIVE flag on the currently opened socket. 586 * Delegates to {@link Socket#getKeepAlive()} 587 * @return True if SO_KEEPALIVE is enabled. 588 * @throws SocketException if there is a problem with the socket 589 * @throws NullPointerException if the socket is not currently open 590 * @since 2.2 591 */ 592 public boolean getKeepAlive() throws SocketException { 593 return _socket_.getKeepAlive(); 594 } 595 596 /** 597 * Sets the SO_LINGER timeout on the currently opened socket. 598 * <p> 599 * @param on True if linger is to be enabled, false if not. 600 * @param val The linger timeout (in hundredths of a second?) 601 * @throws SocketException If the operation fails. 602 * @throws NullPointerException if the socket is not currently open 603 */ 604 public void setSoLinger(final boolean on, final int val) throws SocketException 605 { 606 _socket_.setSoLinger(on, val); 607 } 608 609 610 /** 611 * Returns the current SO_LINGER timeout of the currently opened socket. 612 * <p> 613 * @return The current SO_LINGER timeout. If SO_LINGER is disabled returns 614 * -1. 615 * @throws SocketException If the operation fails. 616 * @throws NullPointerException if the socket is not currently open 617 */ 618 public int getSoLinger() throws SocketException 619 { 620 return _socket_.getSoLinger(); 621 } 622 623 624 /** 625 * Returns the port number of the open socket on the local host used 626 * for the connection. 627 * Delegates to {@link Socket#getLocalPort()} 628 * <p> 629 * @return The port number of the open socket on the local host used 630 * for the connection. 631 * @throws NullPointerException if the socket is not currently open 632 */ 633 public int getLocalPort() 634 { 635 return _socket_.getLocalPort(); 636 } 637 638 639 /** 640 * Returns the local address to which the client's socket is bound. 641 * Delegates to {@link Socket#getLocalAddress()} 642 * <p> 643 * @return The local address to which the client's socket is bound. 644 * @throws NullPointerException if the socket is not currently open 645 */ 646 public InetAddress getLocalAddress() 647 { 648 return _socket_.getLocalAddress(); 649 } 650 651 /** 652 * Returns the port number of the remote host to which the client is 653 * connected. 654 * Delegates to {@link Socket#getPort()} 655 * <p> 656 * @return The port number of the remote host to which the client is 657 * connected. 658 * @throws NullPointerException if the socket is not currently open 659 */ 660 public int getRemotePort() 661 { 662 return _socket_.getPort(); 663 } 664 665 666 /** 667 * @return The remote address to which the client is connected. 668 * Delegates to {@link Socket#getInetAddress()} 669 * @throws NullPointerException if the socket is not currently open 670 */ 671 public InetAddress getRemoteAddress() 672 { 673 return _socket_.getInetAddress(); 674 } 675 676 677 /** 678 * Verifies that the remote end of the given socket is connected to the 679 * the same host that the SocketClient is currently connected to. This 680 * is useful for doing a quick security check when a client needs to 681 * accept a connection from a server, such as an FTP data connection or 682 * a BSD R command standard error stream. 683 * <p> 684 * @param socket the item to check against 685 * @return True if the remote hosts are the same, false if not. 686 */ 687 public boolean verifyRemote(final Socket socket) 688 { 689 InetAddress host1, host2; 690 691 host1 = socket.getInetAddress(); 692 host2 = getRemoteAddress(); 693 694 return host1.equals(host2); 695 } 696 697 698 /** 699 * Sets the SocketFactory used by the SocketClient to open socket 700 * connections. If the factory value is null, then a default 701 * factory is used (only do this to reset the factory after having 702 * previously altered it). 703 * Any proxy setting is discarded. 704 * <p> 705 * @param factory The new SocketFactory the SocketClient should use. 706 */ 707 public void setSocketFactory(final SocketFactory factory) 708 { 709 if (factory == null) { 710 _socketFactory_ = DEFAULT_SOCKET_FACTORY; 711 } else { 712 _socketFactory_ = factory; 713 } 714 // re-setting the socket factory makes the proxy setting useless, 715 // so set the field to null so that getProxy() doesn't return a 716 // Proxy that we're actually not using. 717 connProxy = null; 718 } 719 720 /** 721 * Sets the ServerSocketFactory used by the SocketClient to open ServerSocket 722 * connections. If the factory value is null, then a default 723 * factory is used (only do this to reset the factory after having 724 * previously altered it). 725 * <p> 726 * @param factory The new ServerSocketFactory the SocketClient should use. 727 * @since 2.0 728 */ 729 public void setServerSocketFactory(final ServerSocketFactory factory) { 730 if (factory == null) { 731 _serverSocketFactory_ = DEFAULT_SERVER_SOCKET_FACTORY; 732 } else { 733 _serverSocketFactory_ = factory; 734 } 735 } 736 737 /** 738 * Sets the connection timeout in milliseconds, which will be passed to the {@link Socket} object's 739 * connect() method. 740 * @param connectTimeout The connection timeout to use (in ms) 741 * @since 2.0 742 */ 743 public void setConnectTimeout(final int connectTimeout) { 744 this.connectTimeout = connectTimeout; 745 } 746 747 /** 748 * Get the underlying socket connection timeout. 749 * @return timeout (in ms) 750 * @since 2.0 751 */ 752 public int getConnectTimeout() { 753 return connectTimeout; 754 } 755 756 /** 757 * Get the underlying {@link ServerSocketFactory} 758 * @return The server socket factory 759 * @since 2.2 760 */ 761 public ServerSocketFactory getServerSocketFactory() { 762 return _serverSocketFactory_; 763 } 764 765 766 /** 767 * Adds a ProtocolCommandListener. 768 * 769 * @param listener The ProtocolCommandListener to add. 770 * @since 3.0 771 */ 772 public void addProtocolCommandListener(final ProtocolCommandListener listener) { 773 getCommandSupport().addProtocolCommandListener(listener); 774 } 775 776 /** 777 * Removes a ProtocolCommandListener. 778 * 779 * @param listener The ProtocolCommandListener to remove. 780 * @since 3.0 781 */ 782 public void removeProtocolCommandListener(final ProtocolCommandListener listener) { 783 getCommandSupport().removeProtocolCommandListener(listener); 784 } 785 786 /** 787 * If there are any listeners, send them the reply details. 788 * 789 * @param replyCode the code extracted from the reply 790 * @param reply the full reply text 791 * @since 3.0 792 */ 793 protected void fireReplyReceived(final int replyCode, final String reply) { 794 if (getCommandSupport().getListenerCount() > 0) { 795 getCommandSupport().fireReplyReceived(replyCode, reply); 796 } 797 } 798 799 /** 800 * If there are any listeners, send them the command details. 801 * 802 * @param command the command name 803 * @param message the complete message, including command name 804 * @since 3.0 805 */ 806 protected void fireCommandSent(final String command, final String message) { 807 if (getCommandSupport().getListenerCount() > 0) { 808 getCommandSupport().fireCommandSent(command, message); 809 } 810 } 811 812 /** 813 * Create the CommandSupport instance if required 814 */ 815 protected void createCommandSupport(){ 816 commandSupport = new ProtocolCommandSupport(this); 817 } 818 819 /** 820 * Subclasses can override this if they need to provide their own 821 * instance field for backwards compatibilty. 822 * 823 * @return the CommandSupport instance, may be {@code null} 824 * @since 3.0 825 */ 826 protected ProtocolCommandSupport getCommandSupport() { 827 return commandSupport; 828 } 829 830 /** 831 * Sets the proxy for use with all the connections. 832 * The proxy is used for connections established after the 833 * call to this method. 834 * 835 * @param proxy the new proxy for connections. 836 * @since 3.2 837 */ 838 public void setProxy(final Proxy proxy) { 839 setSocketFactory(new DefaultSocketFactory(proxy)); 840 connProxy = proxy; 841 } 842 843 /** 844 * Gets the proxy for use with all the connections. 845 * @return the current proxy for connections. 846 */ 847 public Proxy getProxy() { 848 return connProxy; 849 } 850 851 /** 852 * Gets the charset name. 853 * 854 * @return the charset. 855 * @since 3.3 856 * @deprecated Since the code now requires Java 1.6 as a mininmum 857 */ 858 @Deprecated 859 public String getCharsetName() { 860 return charset.name(); 861 } 862 863 /** 864 * Gets the charset. 865 * 866 * @return the charset. 867 * @since 3.3 868 */ 869 public Charset getCharset() { 870 return charset; 871 } 872 873 /** 874 * Sets the charset. 875 * 876 * @param charset the charset. 877 * @since 3.3 878 */ 879 public void setCharset(final Charset charset) { 880 this.charset = charset; 881 } 882 883 /* 884 * N.B. Fields cannot be pulled up into a super-class without breaking binary compatibility, 885 * so the abstract method is needed to pass the instance to the methods which were moved here. 886 */ 887} 888 889