Has anyone played with NIO pipes to filter / intercept System.out?

后端 未结 1 1497
盖世英雄少女心
盖世英雄少女心 2021-01-27 03:53

As suggested here I would like to do that inside the selector loop. What I would really want is to read contents written to system out inside my selector loop.

E

相关标签:
1条回答
  • 2021-01-27 04:11

    One way to do it would be as follows:

    • create a subclass of OutputStream that redirects its output to a Pipe's sink channel
    • redirect System.out using this class: System.setOut(new PrintStream(new MyOutputStream(pipe));
    • register the pipe's source channel with a selector and get whatever was written to System.out in the selector loop, i.e. the source channel's correpsonding SelectionKey is selected as readable()

    The following immplementation is a naive but working implementation, which simply redirects to System.err everything that is written to System.out:

    import java.io.*;
    import java.nio.ByteBuffer;
    import java.nio.channels.*;
    import java.util.Iterator;
    
    public class SystemOutPipe extends Thread {
    
      public static void main(String[] args)
      {
        try {
          SystemOutPipe sop = new SystemOutPipe();
          sop.start();
          System.out.println("This message should be redirected to System.err\nNow waiting 5 seconds ...");
          Thread.sleep(5000L);
          sop.setStopped(true);
          sop.join();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
      private Selector selector;
      private Pipe pipe;
      private boolean stopped = false;
    
      public SystemOutPipe() throws IOException {
        super("SystemOutPipe");
        pipe = Pipe.open();
        System.setOut(new PrintStream(new PipeOutputStream(pipe)));
        selector = Selector.open();
        pipe.source().configureBlocking(false);
        pipe.source().register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
      }
    
      @Override
      public void run() {
        try {
          while (!isStopped()) {
            int n = selector.select(1L);
            if (n > 0) {
              Iterator<SelectionKey> it = selector.selectedKeys().iterator();
              while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();
                if (key.isReadable()) {
                  new ReadHandler(key).run();
                }
              }
            }
          }
        } catch (Exception e) {
          e.printStackTrace(); // writes to System.err !
        }
      }
    
      public synchronized boolean isStopped() {
        return stopped;
      }
    
      public synchronized void setStopped(final boolean stopped) {
        this.stopped = stopped;
      }
    
      public class ReadHandler implements Runnable {
        private final SelectionKey key;
    
        public ReadHandler(final SelectionKey key) {
          this.key = key;
        }
    
        @Override
        public void run() {
          ByteBuffer bbuf = (ByteBuffer) key.attachment();
          ReadableByteChannel channel = (ReadableByteChannel) key.channel();
          try
          {
            int count = 0;
            do {
              bbuf.clear();
              count = channel.read(bbuf);
              if (count > 0) System.err.write(bbuf.array(), 0, count);
            } while(count > 0);
          } catch (IOException e) {
            e.printStackTrace();
            key.cancel();
          }
        }
      }
    
      public class PipeOutputStream extends OutputStream {
        private final Pipe pipe;
    
        public PipeOutputStream(final Pipe pipe) {
          this.pipe = pipe;
        }
    
        @Override
        public void write(final int b) throws IOException {
          write(new byte[] { (byte) b });
        }
    
        @Override
        public void write(final byte[] b) throws IOException {
          write(b, 0, b.length);
        }
    
        @Override
        public void write(final byte[] b, final int off, final int len) throws IOException {
          ByteBuffer bbuf = ByteBuffer.wrap(b, off, len);
          bbuf.position(len);
          bbuf.flip();
          int count = 0;
          while (count < len) {
            int n = pipe.sink().write(bbuf);
            if (n == 0) {
              // let's wait a bit and not consume cpu
              try {
                Thread.sleep(1L);
              } catch (InterruptedException e) {
                throw new IOException(e);
              }
            }
            else count += n;
          }
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题