/**
   * Launch a pair of threads to handle bi-directional stream communication.
   *
   * @param localSocket Local socket.
   * @param remoteEndPoint ConnectionDetails. The remote <code>EndPoint</code> to forward output to.
   *     This is also used in the logging and filter output.
   * @param clientEndPoint The <code>EndPoint</code> to be used in the logging and filter output.
   *     This may well differ from the <code>localSocket</code> binding.
   * @param isSecure Whether the connection is secure.
   * @exception IOException If an I/O error occurs.
   */
  protected final void launchThreadPair(
      Socket localSocket, EndPoint remoteEndPoint, EndPoint clientEndPoint, boolean isSecure)
      throws IOException {

    final Socket remoteSocket = m_socketFactory.createClientSocket(remoteEndPoint);

    final ConnectionDetails connectionDetails =
        new ConnectionDetails(clientEndPoint, remoteEndPoint, isSecure);

    new FilteredStreamThread(
        localSocket.getInputStream(),
        new OutputStreamFilterTee(
            connectionDetails, remoteSocket.getOutputStream(), m_requestFilter, m_requestColour));

    new FilteredStreamThread(
        remoteSocket.getInputStream(),
        new OutputStreamFilterTee(
            connectionDetails.getOtherEnd(),
            localSocket.getOutputStream(),
            m_responseFilter,
            m_responseColour));
  }