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