class VirtualConnection extends AbstractConnection
{
    private static final Logger Log = LoggerFactory.getLogger(VirtualConnection.class);

    private final AtomicReference<State> state = new AtomicReference<State>(State.OPEN);

    @Override
    public Certificate[] getLocalCertificates() {
        // Ignore
        return new Certificate[0];
    }

    @Override
    public Certificate[] getPeerCertificates() {
        // Ignore
        return new Certificate[0];
    }

    @Override
    public void setUsingSelfSignedCertificate(boolean isSelfSigned) {
    }

    @Override
    public boolean isUsingSelfSignedCertificate() {
        return false;
    }

    @Override
    public boolean isClosed() {
        return state.get() == State.CLOSED;
    }

    @Override
    public boolean isCompressed() {
        // Return false since compression is not used for virtual connections
        return false;
    }

    @Override
    @Nullable
    public PacketDeliverer getPacketDeliverer() {
        //Ignore
        return null;
    }

    public void startTLS(boolean clientMode, boolean directTLS) throws Exception {
        //Ignore
    }

    public void addCompression() {
        //Ignore
    }

    @Override
    public void startCompression() {
        //Ignore
    }

    @Override
    @Deprecated // Remove in Openfire 4.9 or later.
    public boolean isSecure() {
        return isEncrypted();
    }

    @Override
    public boolean isEncrypted() {
        // Return false since TLS is not used for virtual connections
        return false;
    }

    @Override
    public boolean validate() {
        // Return true since the virtual connection is valid until it no longer exists
        return true;
    }

    @Override
    public boolean isInitialized() {
        return session != null && !isClosed();
    }

    /**
     * Closes the session, the virtual connection and notifies listeners that the connection
     * has been closed.
     *
     * @param error If non-null, the end-stream tag will be preceded with this error.
     */
    @Override
    public void close(@Nullable final StreamError error, final boolean networkInterruption) {<FILL_FUNCTION_BODY>}

    /**
     * Closes the virtual connection. Subclasses should indicate what closing a virtual
     * connection means. At this point the session has a CLOSED state.
     *
     * @param error If non-null, this error will be sent to the peer before the connection is disconnected.
     */
    public abstract void closeVirtualConnection(@Nullable final StreamError error);
}

        if (state.compareAndSet(State.OPEN, State.CLOSED)) {
            
            if (session != null) {
                if (!networkInterruption) {
                    // A 'clean' closure should never be resumed (see #onRemoteDisconnect for handling of unclean disconnects). OF-2752
                    session.getStreamManager().formalClose();
                }
                session.setStatus(Session.Status.CLOSED);
            }

            // See OF-1596
            // The notification will trigger some shutdown procedures that, amongst other things,
            // check what type of session (eg: anonymous) is being closed. This check depends on the
            // session still being available.
            //
            // For that reason, it's important to first notify the listeners, and then close the
            // session - not the other way around.
            //
            // This fixes a very visible bug where MUC users would remain in the MUC room long after
            // their session was closed. Effectively, the bug prevents the MUC room from getting a
            // presence update to notify it that the user logged off.
            notifyCloseListeners();
            closeListeners.clear();

            try {
                closeVirtualConnection(error);
            } catch (Exception e) {
                Log.error(LocaleUtils.getLocalizedString("admin.error.close") + "\n" + toString(), e);
            }
        }
    
<methods>public non-sealed void <init>() ,public Set<Namespace> getAdditionalNamespaces() ,public int getMajorXMPPVersion() ,public int getMinorXMPPVersion() ,public org.jivesoftware.openfire.session.LocalSession getSession() ,public void init(org.jivesoftware.openfire.session.LocalSession) ,public void registerCloseListener(org.jivesoftware.openfire.ConnectionCloseListener, java.lang.Object) ,public void reinit(org.jivesoftware.openfire.session.LocalSession) ,public void removeCloseListener(org.jivesoftware.openfire.ConnectionCloseListener) ,public void setAdditionalNamespaces(Set<Namespace>) ,public void setXMPPVersion(int, int) <variables>private static final Logger Log,private final Set<Namespace> additionalNamespaces,protected final Map<org.jivesoftware.openfire.ConnectionCloseListener,java.lang.Object> closeListeners,private int majorVersion,private int minorVersion,protected org.jivesoftware.openfire.session.LocalSession session