diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index c4a8c90dd..3dd474f47 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -34,7 +34,13 @@ import java.io.Reader; import java.io.Writer; import java.net.URL; import java.text.SimpleDateFormat; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; import java.util.Date; +import java.util.List; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -419,37 +425,52 @@ public class EnhancedDebugger extends SmackDebugger { // Create a special Reader that wraps the main Reader and logs data to the GUI. ObservableReader debugReader = new ObservableReader(reader); readerListener = new ReaderListener() { - @Override - public void read(final String str) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (EnhancedDebuggerWindow.PERSISTED_DEBUGGER && - !EnhancedDebuggerWindow.getInstance().isVisible()) { - // Do not add content if the parent is not visible - return; - } + private final PriorityBlockingQueue buffer = new PriorityBlockingQueue<>(); - int index = str.lastIndexOf(">"); - if (index != -1) { - if (receivedText.getLineCount() >= EnhancedDebuggerWindow.MAX_TABLE_ROWS) { - try { - receivedText.replaceRange("", 0, receivedText.getLineEndOffset(0)); - } - catch (BadLocationException e) { - LOGGER.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e); - } - } - receivedText.append(str.substring(0, index + 1)); - receivedText.append(NEWLINE); - if (str.length() > index) { - receivedText.append(str.substring(index + 1)); - } + @Override + public void read(final String line) { + + buffer.add(line); + + SwingUtilities.invokeLater(() -> { + List linesToAdd = new ArrayList<>(); + String data; + Instant start = Instant.now(); + try { + // To reduce overhead/increase performance, try to process up to a certain amount of lines at the + // same time, when they arrive in rapid succession. + while (linesToAdd.size() < 50 + && Duration.between(start, Instant.now()).compareTo(Duration.ofMillis(100)) < 0 + && (data = buffer.poll(10, TimeUnit.MILLISECONDS)) != null) { + linesToAdd.add(data); } - else { - receivedText.append(str); + } catch (InterruptedException e) { + // Interrupted wait-for-poll. Process all data now. + } + + if (linesToAdd.isEmpty()) { + return; + } + + if (EnhancedDebuggerWindow.PERSISTED_DEBUGGER && + !EnhancedDebuggerWindow.getInstance().isVisible()) { + // Do not add content if the parent is not visible + return; + } + + // Delete lines from the top, if lines to be added will exceed the maximum. + int linesToDelete = receivedText.getLineCount() + linesToAdd.size() - EnhancedDebuggerWindow.MAX_TABLE_ROWS; + if (linesToDelete > 0) { + try { + receivedText.replaceRange("", 0, receivedText.getLineEndOffset(linesToDelete - 1)); + } + catch (BadLocationException e) { + LOGGER.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e); } } + + // Add the new content. + receivedText.append(String.join(NEWLINE, linesToAdd)); }); } }; @@ -458,34 +479,53 @@ public class EnhancedDebugger extends SmackDebugger { // Create a special Writer that wraps the main Writer and logs data to the GUI. ObservableWriter debugWriter = new ObservableWriter(writer); writerListener = new WriterListener() { + private final PriorityBlockingQueue buffer = new PriorityBlockingQueue<>(); + @Override - public void write(final String str) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - if (EnhancedDebuggerWindow.PERSISTED_DEBUGGER && - !EnhancedDebuggerWindow.getInstance().isVisible()) { - // Do not add content if the parent is not visible - return; - } + public void write(final String line) { - if (sentText.getLineCount() >= EnhancedDebuggerWindow.MAX_TABLE_ROWS) { - try { - sentText.replaceRange("", 0, sentText.getLineEndOffset(0)); - } - catch (BadLocationException e) { - LOGGER.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e); - } - } + buffer.add(line); - sentText.append(str); - if (str.endsWith(">")) { - sentText.append(NEWLINE); + SwingUtilities.invokeLater(() -> { + List linesToAdd = new ArrayList<>(); + String data; + Instant start = Instant.now(); + try { + // To reduce overhead/increase performance, try to process up to a certain amount of lines at the + // same time, when they arrive in rapid succession. + while (linesToAdd.size() < 50 + && Duration.between(start, Instant.now()).compareTo(Duration.ofMillis(100)) < 0 + && (data = buffer.poll(10, TimeUnit.MILLISECONDS)) != null) { + linesToAdd.add(data); + } + } catch (InterruptedException e) { + // Interrupted wait-for-poll. Process all data now. + } + + if (linesToAdd.isEmpty()) { + return; + } + + if (EnhancedDebuggerWindow.PERSISTED_DEBUGGER && + !EnhancedDebuggerWindow.getInstance().isVisible()) { + // Do not add content if the parent is not visible + return; + } + + // Delete lines from the top, if lines to be added will exceed the maximum. + int linesToDelete = sentText.getLineCount() + linesToAdd.size() - EnhancedDebuggerWindow.MAX_TABLE_ROWS; + if (linesToDelete > 0) { + try { + sentText.replaceRange("", 0, sentText.getLineEndOffset(linesToDelete - 1)); + } + catch (BadLocationException e) { + LOGGER.log(Level.SEVERE, "Error with line offset, MAX_TABLE_ROWS is set too low: " + EnhancedDebuggerWindow.MAX_TABLE_ROWS, e); } } + + // Add the new content. + sentText.append(String.join(NEWLINE, linesToAdd)); }); - - } }; debugWriter.addWriterListener(writerListener);