View Javadoc

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