/** A new connection has been opened. */
    public void connectionOpened() {

      preOutput();

      try {
        m_filter.connectionOpened(m_connectionDetails);
      } catch (GrinderException e) {
        e.printStackTrace(getLogger().getErrorLogWriter());
      } finally {
        postOutput();
      }
    }
    /** A connection has been closed. */
    public void connectionClosed() {

      preOutput();

      try {
        m_filter.connectionClosed(m_connectionDetails);
      } catch (GrinderException e) {
        e.printStackTrace(getLogger().getErrorLogWriter());
      } finally {
        postOutput();
      }

      // Close our output stream. This will cause any
      // FilteredStreamThread managing the paired stream to exit.
      Closer.close(m_out);
    }
    /**
     * Handle a message fragment.
     *
     * @param buffer Contains the data.
     * @param bytesRead How many bytes of data in <code>buffer</code>.
     * @exception IOException If an I/O error occurs writing to the output stream.
     */
    public void handle(byte[] buffer, int bytesRead) throws IOException {

      preOutput();

      byte[] newBytes = null;

      try {
        newBytes = m_filter.handle(m_connectionDetails, buffer, bytesRead);
      } catch (GrinderException e) {
        e.printStackTrace(getLogger().getErrorLogWriter());
      } finally {
        postOutput();
      }

      if (newBytes != null) {
        m_out.write(newBytes);
      } else {
        m_out.write(buffer, 0, bytesRead);
      }
    }