1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.net;
19
20 import java.io.Closeable;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.net.InetAddress;
25 import java.net.InetSocketAddress;
26 import java.net.Proxy;
27 import java.net.Socket;
28 import java.net.SocketException;
29 import java.nio.charset.Charset;
30
31 import javax.net.ServerSocketFactory;
32 import javax.net.SocketFactory;
33
34
35 /**
36 * The SocketClient provides the basic operations that are required of
37 * client objects accessing sockets. It is meant to be
38 * subclassed to avoid having to rewrite the same code over and over again
39 * to open a socket, close a socket, set timeouts, etc. Of special note
40 * is the {@link #setSocketFactory setSocketFactory }
41 * method, which allows you to control the type of Socket the SocketClient
42 * creates for initiating network connections. This is especially useful
43 * for adding SSL or proxy support as well as better support for applets. For
44 * example, you could create a
45 * {@link javax.net.SocketFactory} that
46 * requests browser security capabilities before creating a socket.
47 * All classes derived from SocketClient should use the
48 * {@link #_socketFactory_ _socketFactory_ } member variable to
49 * create Socket and ServerSocket instances rather than instantiating
50 * them by directly invoking a constructor. By honoring this contract
51 * you guarantee that a user will always be able to provide his own
52 * Socket implementations by substituting his own SocketFactory.
53 * @see SocketFactory
54 */
55 public abstract class SocketClient
56 {
57 /**
58 * The end of line character sequence used by most IETF protocols. That
59 * is a carriage return followed by a newline: "\r\n"
60 */
61 public static final String NETASCII_EOL = "\r\n";
62
63 /** The default SocketFactory shared by all SocketClient instances. */
64 private static final SocketFactory __DEFAULT_SOCKET_FACTORY =
65 SocketFactory.getDefault();
66
67 /** The default {@link ServerSocketFactory} */
68 private static final ServerSocketFactory __DEFAULT_SERVER_SOCKET_FACTORY =
69 ServerSocketFactory.getDefault();
70
71 /**
72 * A ProtocolCommandSupport object used to manage the registering of
73 * ProtocolCommandListeners and the firing of ProtocolCommandEvents.
74 */
75 private ProtocolCommandSupport __commandSupport;
76
77 /** The timeout to use after opening a socket. */
78 protected int _timeout_;
79
80 /** The socket used for the connection. */
81 protected Socket _socket_;
82
83 /** The default port the client should connect to. */
84 protected int _defaultPort_;
85
86 /** The socket's InputStream. */
87 protected InputStream _input_;
88
89 /** The socket's OutputStream. */
90 protected OutputStream _output_;
91
92 /** The socket's SocketFactory. */
93 protected SocketFactory _socketFactory_;
94
95 /** The socket's ServerSocket Factory. */
96 protected ServerSocketFactory _serverSocketFactory_;
97
98 /** The socket's connect timeout (0 = infinite timeout) */
99 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