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