Package javaflow.network.impl

Source Code of javaflow.network.impl.InputPortImpl

package javaflow.network.impl;

import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javaflow.components.api.InputPort;
import javaflow.components.api.OutputPort;
import javaflow.components.api.Packet;
import javaflow.network.api.NetworkComponent;
import javaflow.network.api.PortReference;

class InputPortImpl implements InputPort, Port {

    PacketImpl[] queue = new PacketImpl[10];
    int currentRead = 0;
    int currentWrite = 0;
    int count = 0;
    final CopyOnWriteArraySet<OutputPortImpl> connected = new CopyOnWriteArraySet<>();
    private final PortReference portDef;
    private AtomicBoolean closed = new AtomicBoolean(false);
    AbstractRunnableComponent owner;
    AtomicBoolean receiverWaiting = new AtomicBoolean(false);
    Lock lock = new ReentrantLock(false);
    Condition notEmpty = lock.newCondition();
    Condition notFull = lock.newCondition();

    InputPortImpl(PortReference portDef) {
        this.portDef = portDef;
    }

    @Override
    public Packet receive() {
        PacketImpl packet = null;
        lock.lock();
        try {
            waitWhilePortGetsClosedOrThereIsSomethingToBeRead();
            if (count == 0) {
                return null;
            }
            packet = popFromQueue();
        } finally {
            lock.unlock();
        }
        closeIfShouldClose();
        packet.arrivedAtComponent(owner);
        owner.signalPacketConsumed();
        return packet;
    }

    void send(OutputPortImpl sender, PacketImpl p) {
        lock.lock();
        try {
            owner.signalPacketQueued();
            waitUntilThereIsRoomInQueue(sender);
            pushToQueue(p);
        } finally {
            lock.unlock();
        }
    }

    private int inc(int counter) {
        counter++;
        if (counter >= queue.length) {
            counter = 0;
        }
        return counter;
    }

    void addConnection(OutputPortImpl out) {
        connected.add(out);
        signalOutputReconnect();
    }


    boolean hasConnections() {
        for(OutputPort port: connected){
            if (port.isOpen()){
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        return portDef + ": " + count + " messages waiting, " + (hasBeenClosed() ? "port has been closed" : "port is open. Connected from "+ connected);
    }

    public PortReference port(){
        return portDef;
    }

    @Override
    public String toString(int indentation) {
        return Utils.indent(indentation, toString());
    }

    @Override
    public void close() {
        if (closed.compareAndSet(false, true)) {
            lock.lock();
            try {
                if (owner == null) {
                    throw new Error(this + " does not have owner!");
                }
                owner.inputPortClosed();
                receiverWaitEnded();
            } finally {
                lock.unlock();
            }
        }
    }

    @Override
    public boolean isClosed() {
        return closed.get() && !hasPacket();
    }

    protected void closeIfShouldClose() {
        if (!hasConnections()) {
            close();
        }
    }

    @Override
    public boolean hasPacket() {
        lock.lock();
        try {
            return count > 0;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void setOwner(AbstractRunnableComponent component) {
        this.owner = component;
    }

    @Override
    public Object receiveContentAndDrop() {
        Packet receive = receive();
        if (receive == null) {
            return null;
        } else {
            return receive.getContentAndDrop();
        }
    }

    public boolean isOpen() {
        return !isClosed();
    }

    @Override
    public int getOpenPortCount() {
        return isOpen() ? 1 : 0;
    }

    int ownerId() {
        return owner.componentId();
    }

    private void receiverWaitEnded() {
        if (receiverWaiting.compareAndSet(true, false)) {
            owner.receiveReturned();
            notEmpty.signal();
        }
    }

    private void waitingForSomethingToReceive() {
        if (receiverWaiting.compareAndSet(false, true)) {
            owner.waitForReceive();
            notEmpty.awaitUninterruptibly();
            receiverWaitEnded();
        }
    }

    private void markThatSendersAreNotWaiting() {
        for (OutputPortImpl out : connected) {
            out.sendWaitEnded();
        }
    }

    private void markThatReceiverIsNotWaiting() {
        receiverWaitEnded();
    }

    private void waitWhilePortGetsClosedOrThereIsSomethingToBeRead() {
        while (queueSize() == 0 && !closed.get()) {
            markThatSendersAreNotWaiting();
            waitingForSomethingToReceive();
        }
    }

    private PacketImpl popFromQueue() {
        PacketImpl packet;
        count--;
        packet = queue[currentRead];
        currentRead = inc(currentRead);       
        notFull.signalAll();
        markThatSendersAreNotWaiting();
        return packet;
    }

    private void pushToQueue(PacketImpl p) {
        count++;
        queue[currentWrite] = p;
        currentWrite = inc(currentWrite);
        notEmpty.signal();
        receiverWaitEnded();
    }

    private void waitUntilThereIsRoomInQueue(OutputPortImpl sender) {
        while (!(count < queue.length)) {
            markThatReceiverIsNotWaiting();
            if (sender != null) {
                sender.waitForSend();
            }
            notFull.awaitUninterruptibly();
            if (sender != null) {
                sender.sendWaitEnded();
            }
        }
    }

    int queueSize() {
        return count;
    }

    boolean hasBeenClosed() {
        return closed.get();
    }

    @Override
    public void reopen() {
        for(OutputPortImpl out : connected){
            out.reopen();
        }
    }

    @Override
    public NetworkComponent getOwner() {
        return owner;
    }

    public AbstractRunnableComponent owner() {
        return owner;
    }

    public void signalOutputClosed(OutputPortImpl outputPort) {
        closeIfShouldClose();
    }

    public void signalOutputReconnect() {
        if (closed.compareAndSet(true,false)){
            owner.inputPortOpened();
        }
    }
}
TOP

Related Classes of javaflow.network.impl.InputPortImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.