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