package com.performizeit.plumbing; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; /** * pipe is a class which runs continuously receives msg from producers and transfers them on after processing . */ public class Pipe<S, D> extends Thread { AtomicInteger numProducers = new AtomicInteger(0); BlockingQueue<S> inQueue = new LinkedBlockingQueue<>(); private final PipeHandler<S, D> handler; private Pipe<D, ?> outgoingPipe = null; public Pipe(String name, PipeHandler<S, D> handler) { super(); setName(name); this.handler = handler; } public void send(S e) { inQueue.add(e); } public void setOutgoingPipe(Pipe<D, ?> outgoingPipe) { this.outgoingPipe = outgoingPipe; outgoingPipe.registerProducer(); } public int registerProducer() { return numProducers.incrementAndGet(); } public int producerDone() { int numP = numProducers.decrementAndGet(); if (numP <= 0) { interrupt(); } return numP; } private void handleMsg(S e) { D e1 = handler.handleMsg(e); if (outgoingPipe != null && e1 != null) { outgoingPipe.send(e1); } } @Override public void run() { try { while (numProducers.get() > 0) { try { S a = inQueue.take(); handleMsg(a); } catch (InterruptedException e) { if (numProducers.get() == 0) break; } } // it is stopped get all remaining messages while (true) { S a = inQueue.poll(); if (a == null) break; handleMsg(a); } D e = handler.handleDone(); if (outgoingPipe != null) { if (e != null) outgoingPipe.send(e); } } finally { if (outgoingPipe != null) { outgoingPipe.producerDone(); } } } }