@Override
    public void close() throws IOException {
        State prevState = state;
        if (state == State.CLOSING) return;
        state = State.CLOSING;
        sslEngine.closeOutbound();
        try {
            if (prevState != State.NOT_INITIALIZED && isConnected()) {
                if (!flush(netWriteBuffer)) {
                    throw new IOException("Remaining data in the network buffer, can't send SSL close message.");
                }
                //prep the buffer for the close message
                netWriteBuffer.clear();
                //perform the close, since we called sslEngine.closeOutbound
                SSLEngineResult wrapResult = sslEngine.wrap(ByteUtils.EMPTY_BUF, netWriteBuffer);
                //we should be in a close state
                if (wrapResult.getStatus() != SSLEngineResult.Status.CLOSED) {
                    throw new IOException("Unexpected status returned by SSLEngine.wrap, expected CLOSED, received " +
                            wrapResult.getStatus() + ". Will not send close message to peer.");
                }
                netWriteBuffer.flip();
                flush(netWriteBuffer);
            }
        } catch (IOException ie) {
            log.debug("Failed to send SSL Close message", ie);
        } finally {
            try {
                sslEngine.closeInbound();
            } catch (SSLException e) {
                // This log is for debugging purposes as an exception might occur frequently
                // at this point due to peers not following the TLS specs and failing to send a close_notify alert. 
                // Even if they do, currently, we do not read data from the socket after invoking close().
                log.debug("SSLEngine.closeInBound() raised an exception.", e);
            }
            socketChannel.socket().close();
            socketChannel.close();
            netReadBuffer = null;
            netWriteBuffer = null;
            appReadBuffer = null;
            if (fileChannelBuffer != null) {
                ByteBufferUnmapper.unmap("fileChannelBuffer", fileChannelBuffer);
                fileChannelBuffer = null;
            }
        }
    }
@Test
    public void testSSLEngineCloseInboundInvokedOnClose() throws IOException {
        // Given
        SSLEngine sslEngine = mock(SSLEngine.class);
        Socket socket = mock(Socket.class);
        SocketChannel socketChannel = mock(SocketChannel.class);
        SelectionKey selectionKey = mock(SelectionKey.class);
        when(socketChannel.socket()).thenReturn(socket);
        when(selectionKey.channel()).thenReturn(socketChannel);
        doThrow(new SSLException("Mock exception")).when(sslEngine).closeInbound();
        SslTransportLayer sslTransportLayer = new SslTransportLayer(
                "test-channel",
                selectionKey,
                sslEngine,
                mock(ChannelMetadataRegistry.class)
        );

        // When
        sslTransportLayer.close();

        // Then
        verify(sslEngine, times(1)).closeOutbound();
        verify(sslEngine, times(1)).closeInbound();
        verifyNoMoreInteractions(sslEngine);
    }