public Reader newConnectionReader(Reader newReader) {
   ((ObservableReader) reader).removeReaderListener(readerListener);
   ObservableReader debugReader = new ObservableReader(newReader);
   debugReader.addReaderListener(readerListener);
   reader = debugReader;
   return reader;
 }
  /** Creates the debug process, which is a GUI window that displays XML traffic. */
  private void createDebug() {
    frame =
        new JFrame(
            "Smack Debug Window -- " + connection.getServiceName() + ":" + connection.getPort());

    // Add listener for window closing event
    frame.addWindowListener(
        new WindowAdapter() {
          public void windowClosing(WindowEvent evt) {
            rootWindowClosing(evt);
          }
        });

    // We'll arrange the UI into four tabs. The first tab contains all data, the second
    // client generated XML, the third server generated XML, and the fourth is packet
    // data from the server as seen by Smack.
    JTabbedPane tabbedPane = new JTabbedPane();

    JPanel allPane = new JPanel();
    allPane.setLayout(new GridLayout(3, 1));
    tabbedPane.add("All", allPane);

    // Create UI elements for client generated XML traffic.
    final JTextArea sentText1 = new JTextArea();
    final JTextArea sentText2 = new JTextArea();
    sentText1.setEditable(false);
    sentText2.setEditable(false);
    sentText1.setForeground(new Color(112, 3, 3));
    sentText2.setForeground(new Color(112, 3, 3));
    allPane.add(new JScrollPane(sentText1));
    tabbedPane.add("Sent", new JScrollPane(sentText2));

    // Add pop-up menu.
    JPopupMenu menu = new JPopupMenu();
    JMenuItem menuItem1 = new JMenuItem("Copy");
    menuItem1.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // Get the clipboard
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            // Set the sent text as the new content of the clipboard
            clipboard.setContents(new StringSelection(sentText1.getText()), null);
          }
        });

    JMenuItem menuItem2 = new JMenuItem("Clear");
    menuItem2.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            sentText1.setText("");
            sentText2.setText("");
          }
        });

    // Add listener to the text area so the popup menu can come up.
    MouseListener popupListener = new PopupListener(menu);
    sentText1.addMouseListener(popupListener);
    sentText2.addMouseListener(popupListener);
    menu.add(menuItem1);
    menu.add(menuItem2);

    // Create UI elements for server generated XML traffic.
    final JTextArea receivedText1 = new JTextArea();
    final JTextArea receivedText2 = new JTextArea();
    receivedText1.setEditable(false);
    receivedText2.setEditable(false);
    receivedText1.setForeground(new Color(6, 76, 133));
    receivedText2.setForeground(new Color(6, 76, 133));
    allPane.add(new JScrollPane(receivedText1));
    tabbedPane.add("Received", new JScrollPane(receivedText2));

    // Add pop-up menu.
    menu = new JPopupMenu();
    menuItem1 = new JMenuItem("Copy");
    menuItem1.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // Get the clipboard
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            // Set the sent text as the new content of the clipboard
            clipboard.setContents(new StringSelection(receivedText1.getText()), null);
          }
        });

    menuItem2 = new JMenuItem("Clear");
    menuItem2.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            receivedText1.setText("");
            receivedText2.setText("");
          }
        });

    // Add listener to the text area so the popup menu can come up.
    popupListener = new PopupListener(menu);
    receivedText1.addMouseListener(popupListener);
    receivedText2.addMouseListener(popupListener);
    menu.add(menuItem1);
    menu.add(menuItem2);

    // Create UI elements for interpreted XML traffic.
    final JTextArea interpretedText1 = new JTextArea();
    final JTextArea interpretedText2 = new JTextArea();
    interpretedText1.setEditable(false);
    interpretedText2.setEditable(false);
    interpretedText1.setForeground(new Color(1, 94, 35));
    interpretedText2.setForeground(new Color(1, 94, 35));
    allPane.add(new JScrollPane(interpretedText1));
    tabbedPane.add("Interpreted", new JScrollPane(interpretedText2));

    // Add pop-up menu.
    menu = new JPopupMenu();
    menuItem1 = new JMenuItem("Copy");
    menuItem1.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            // Get the clipboard
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            // Set the sent text as the new content of the clipboard
            clipboard.setContents(new StringSelection(interpretedText1.getText()), null);
          }
        });

    menuItem2 = new JMenuItem("Clear");
    menuItem2.addActionListener(
        new ActionListener() {
          public void actionPerformed(ActionEvent e) {
            interpretedText1.setText("");
            interpretedText2.setText("");
          }
        });

    // Add listener to the text area so the popup menu can come up.
    popupListener = new PopupListener(menu);
    interpretedText1.addMouseListener(popupListener);
    interpretedText2.addMouseListener(popupListener);
    menu.add(menuItem1);
    menu.add(menuItem2);

    frame.getContentPane().add(tabbedPane);

    frame.setSize(550, 400);
    frame.setVisible(true);

    // Create a special Reader that wraps the main Reader and logs data to the GUI.
    ObservableReader debugReader = new ObservableReader(reader);
    readerListener =
        new ReaderListener() {
          public void read(String str) {
            int index = str.lastIndexOf(">");
            if (index != -1) {
              receivedText1.append(str.substring(0, index + 1));
              receivedText2.append(str.substring(0, index + 1));
              receivedText1.append(NEWLINE);
              receivedText2.append(NEWLINE);
              if (str.length() > index) {
                receivedText1.append(str.substring(index + 1));
                receivedText2.append(str.substring(index + 1));
              }
            } else {
              receivedText1.append(str);
              receivedText2.append(str);
            }
          }
        };
    debugReader.addReaderListener(readerListener);

    // Create a special Writer that wraps the main Writer and logs data to the GUI.
    ObservableWriter debugWriter = new ObservableWriter(writer);
    writerListener =
        new WriterListener() {
          public void write(String str) {
            sentText1.append(str);
            sentText2.append(str);
            if (str.endsWith(">")) {
              sentText1.append(NEWLINE);
              sentText2.append(NEWLINE);
            }
          }
        };
    debugWriter.addWriterListener(writerListener);

    // Assign the reader/writer objects to use the debug versions. The packet reader
    // and writer will use the debug versions when they are created.
    reader = debugReader;
    writer = debugWriter;

    // Create a thread that will listen for all incoming packets and write them to
    // the GUI. This is what we call "interpreted" packet data, since it's the packet
    // data as Smack sees it and not as it's coming in as raw XML.
    listener =
        new PacketListener() {
          public void processPacket(Packet packet) {
            interpretedText1.append(packet.toXML());
            interpretedText2.append(packet.toXML());
            interpretedText1.append(NEWLINE);
            interpretedText2.append(NEWLINE);
          }
        };
  }