001package jmri.util; 002 003import java.io.IOException; 004import java.io.PipedReader; 005import java.util.Arrays; 006import javax.swing.JTextArea; 007 008/** 009 * Small service class to read characters from a pipe and post them to a 010 * JTextArea for display. 011 * 012 * This expects the pipe to remain open, so has no code to handle 013 * a broken pipe gracefully. 014 * 015 * @author Bob Jacobsen Copyright (C) 2004, 2023 016 */ 017public class PipeListener extends Thread { 018 019 private final PipedReader pr; 020 private final JTextArea ta; 021 022 public PipeListener(PipedReader pr, javax.swing.JTextArea ta) { 023 this.pr = pr; 024 this.ta = ta; 025 } 026 027 static final int BUFFER_SIZE = 120; 028 029 @Override 030 public void run() { 031 try { 032 char[] cbuf = new char[BUFFER_SIZE]; 033 while (true) { 034 try { 035 int nRead = pr.read(cbuf, 0, BUFFER_SIZE); // blocking read 036 String content = new String(Arrays.copyOf(cbuf, nRead)); // retain only filled chars 037 038 // The following used to be runOnGui (i.e. not "Eventually") 039 // but that occasionally caused the Swing/AWT thread to block 040 // with very large input strings. Please don't change it back. 041 jmri.util.ThreadingUtil.runOnGUIEventually(() -> { 042 ta.append(content); 043 }); 044 045 } catch (IOException ex) { 046 if ( "Write end dead".equals(ex.getMessage()) || "Pipe broken".equals(ex.getMessage())) { 047 // happens when the writer thread, possibly a script, terminates 048 synchronized (this) { 049 try { 050 wait(500); 051 } catch (InterruptedException exi) { 052 Thread.currentThread().interrupt(); // retain if needed later 053 } 054 } 055 } else { 056 throw ex; 057 } 058 } 059 } 060 } catch (IOException ex) { 061 ta.append("PipeListener Exiting on IOException:" + ex); 062 } 063 } 064}