Package javaflow.network.impl

Source Code of javaflow.network.impl.NetworkImpl

package javaflow.network.impl;

import javaflow.network.api.*;
import javaflow.network.utils.CombinedPacketListener;
import javaflow.network.utils.ComponentStateListener;
import javaflow.network.utils.PacketCountInComponent;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import javaflow.components.api.Component;
import javaflow.components.api.InputPort;
import javaflow.components.api.InputPorts;
import javaflow.components.api.OutputPort;
import javaflow.components.api.OutputPorts;

final class NetworkImpl implements Network {

    int nextComponentId = 0;
    Map<String, InputPortImpl> inputPorts = new HashMap<>();
    Map<String, OutputPortImpl> outputPorts = new HashMap<>();
    Map<String, InputPortsImpl> inputArrayPorts = new HashMap<>();
    Map<String, OutputPortsImpl> outputArrayPorts = new HashMap<>();
    ArrayList<AbstractRunnableComponent> components = new ArrayList<>();
    AtomicLong alivePacketsCount = new AtomicLong();
    ExecutorService executor;
    AtomicBoolean networkRunning = new AtomicBoolean(false);
    ComponentStateListenerImpl componentStates = new ComponentStateListenerImpl();
    private final CombinedPacketListener packetListeners = new CombinedPacketListener();
    private final FailListener failListener;

    public NetworkImpl() {
        addPacketListener(new PacketListener() {
            @Override
            public void packetCreatedByComponent(long packetId, int componentId) {
                alivePacketsCount.incrementAndGet();
            }

            @Override
            public void packetArrivedAtComponent(long packetId, int componentId) {
            }

            @Override
            public void packetDroppedByComponent(long packetId, int componentId) {
                alivePacketsCount.decrementAndGet();
            }

            @Override
            public void packetLeftComponent(long packetId, int fromComponentId, int towardsComponentId) {
                if (fromComponentId<0){
                    alivePacketsCount.incrementAndGet();
                }
                if (towardsComponentId<0) {
                    alivePacketsCount.decrementAndGet();
                } else {
                    ensureRuns(components.get(towardsComponentId));
                }
            }
        });
        failListener = new FailListener() {
            @Override
            public void componentRaisedError(AbstractRunnableComponent abstractRunnableComponent, Throwable t) {
                NetworkImpl.this.componentRaisedError( abstractRunnableComponent,  t);
            }
        };
    }

    private void componentRaisedError(AbstractRunnableComponent abstractRunnableComponent, Throwable t) {
        System.err.println("Network encountered error from component "+abstractRunnableComponent.componentName());
        t.printStackTrace(System.err);
        shutdownComponents();
    }

    @Override
    public void runInCurrentThread() {
        if (networkRunning.compareAndSet(false, true)) {
            try {
                executor = Executors.newCachedThreadPool();
                closeAllUnconnectedInputs();
                final int componentsCount = components.size();
                PacketCountInComponent packetCounter = new PacketCountInComponent(componentsCount);
                addPacketListener(packetCounter);
                for (AbstractRunnableComponent r : components) {
                    if (shouldRun(r)) {
                        startComponent(r);
                    }
                }
                componentStates.waitForComponentsStop();
                if (alivePacketsCount.get() > 0) {
                    StringBuilder builder = new StringBuilder();
                    builder.append("There are " + alivePacketsCount.get() + " packets left and no components are running.\n");
                    builder.append("Components failed due error:\n");
                    for (int i = 0; i < componentsCount; i++) {
                        final AbstractRunnableComponent component = components.get(i);
                        if (component.getError()     != null){
                            Throwable t = component.getError();
                            builder.append("    ");
                            builder.append(component.componentName() + ": ");
                            ByteArrayOutputStream bout = new ByteArrayOutputStream();
                            PrintStream print = new PrintStream(bout);
                            t.printStackTrace(print);
                            builder.append(new String(bout.toByteArray()));
                            builder.append("\n");
                        }
                    }
                    builder.append("Components suspended or messages inside:\n");
                    for (int i = 0; i < componentsCount; i++) {
                        final AbstractRunnableComponent component = components.get(i);
                        if (component.state() == 0 && packetCounter.getCount(i) == 0) {
                            continue;
                        }
                        String state = component.getStateString();
                        final int count = packetCounter.getCount(i);
                        builder.append("    ");
                        builder.append(component.componentName() + " (" + state + ")" + ": " + count + " in component\n");
                    }
                    builder.append("\nPorts with messages:\n");
                    for (int i = 0; i < componentsCount; i++) {
                        final AbstractRunnableComponent component = components.get(i);
                        if (!component.hasInputPacketsWaiting()) {
                            continue;
                        }
                        for (Port p : component.inputs()) {
                            builder.append("    ");
                            builder.append(p.toString(4));
                            builder.append("\n");
                        }
                    }
                    throw new Error(builder.toString());
                }
                // } catch (InterruptedException ex) {
                //     throw new Error(ex);
            } finally {
                shutdownComponents();
                executor.shutdown();
                try {
                    executor.awaitTermination(10, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                executor = null;
                networkRunning.set(false);
            }
        }
    }

    void reopenAllPorts() {
        for(OutputPortsImpl ports : this.outputArrayPorts.values()){
            ports.reopen();
        };
        for(OutputPortImpl port : this.outputPorts.values()){
            port.reopen();
        };

    }

    private void shutdownComponents() {
        for (AbstractRunnableComponent component : components) {
            component.onNetworkShutdown();
        }
    }

    void addComponent(AbstractRunnableComponent component) {
        component.addListener(getPacketListeners());
        component.addListener(getComponentStateListener());
        component.setComponentId(components.size());
        component.setFailListener(failListener);
        components.add(component);
    }
    void addComponent(String name, Component component) {
        try {
            List<Port> iPorts = new ArrayList<>();
            List<Port> oPorts = new ArrayList<>();
            Class componentClass = component.getClass();
            while (componentClass != null) {
                for (Field field : componentClass.getDeclaredFields()) {
                    if (field.getType().equals(InputPort.class)) {
                        PortReference portDef = createReference(name, field);
                        InputPortImpl in = new InputPortImpl(portDef);
                        addInputPort(portDef.toString(), in);
                        field.setAccessible(true);
                        field.set(component, in);
                        iPorts.add(in);
                    }
                    if (field.getType().equals(OutputPort.class)) {
                        PortReference portDef = createReference(name, field);
                        OutputPortImpl out = new OutputPortImpl(portDef);
                        addOutputPort(portDef.toString(), out);
                        field.setAccessible(true);
                        field.set(component, out);
                        oPorts.add(out);
                    }
                    if (field.getType().equals(InputPorts.class)) {
                        PortReference portDef = createReference(name, field);
                        InputPortsImpl ins = new InputPortsImpl(portDef);
                        inputArrayPorts.put(portDef.toString(), ins);
                        field.setAccessible(true);
                        field.set(component, ins);
                        iPorts.add(ins);
                    }
                    if (field.getType().equals(OutputPorts.class)) {
                        PortReference portDef = createReference(name, field);
                        OutputPortsImpl outs = new OutputPortsImpl(portDef);
                        outputArrayPorts.put(portDef.toString(), outs);
                        field.setAccessible(true);
                        field.set(component, outs);
                        oPorts.add(outs);
                    }
                }
                componentClass = componentClass.getSuperclass();
            }
            addComponent(new RunnableComponent(name, component, iPorts, oPorts));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    private PortReference createReference(String name, Field field) {
        return new PortReference(name, NetworkApiUtil.portNameForField(field));
    }


    void addOutputPort(String name, OutputPortImpl out) {
        outputPorts.put(name, out);
    }

    void addInputPort(String name, InputPortImpl in) {
        inputPorts.put(name, in);
    }

    PacketListener getPacketListeners(){
        return packetListeners;
    }

    PacketImpl createPacket(final Object content, final OutputPortImpl creatorPort) {
        try {
            return new PacketImpl(content, creatorPort);
        } finally {
            alivePacketsCount.incrementAndGet();
        }
    }

    InputPortImpl getInput(String portName) {
        InputPortImpl port = inputPorts.get(portName);
        if (port == null) {
            PortReference ref = PortReference.parse(portName);
            if (ref.isArrayPort()) {
                port = createArrayInputPort(ref);
            } else {
                throw new Error("Could not find input port " + portName + ". These port are available: " + inputPorts
                        .keySet().toString());
            }
        }
        return port;
    }

    OutputPortImpl getOutput(String portName) {
        OutputPortImpl port = outputPorts.get(portName);
        if (port == null) {
            PortReference ref = PortReference.parse(portName);
            if (ref.isArrayPort()) {
                port = createArrayOutputPort(ref);
            } else {
                throw new Error("Could not find output port " + portName + ". These port are available: " + outputPorts
                        .keySet().toString());
            }
        }
        return port;
    }

    void ensureRuns(AbstractRunnableComponent component) {
        if (networkRunning.get()) {
            startComponent(component);
        }
    }

    private void startComponent(AbstractRunnableComponent r) {
        if (r.signalStarting()) {
            componentStates.componentStarting(r.componentId());
            executor.execute(r);
        }
    }

    ComponentStateListener getComponentStateListener(){
        return componentStates;
    }

    private OutputPortImpl createArrayOutputPort(PortReference ref) {
        OutputPortsImpl outputArray = outputArrayPorts.get(ref.componentAndPortName());



        if (outputArray == null) {
            throw new Error(
                    "Could not find array output port for " + ref + ". These are available " + outputArrayPorts
                    .keySet());
        }
        OutputPortImpl out = outputArray.get(ref.portIndex());
        return out;
    }

    private InputPortImpl createArrayInputPort(PortReference ref) {
        int i = ref.portIndex();
        InputPortsImpl inputArray = inputArrayPorts.get(ref.componentAndPortName());
        if (inputArray == null) {
            throw new Error(
                    "Could not find array input port for " + ref + ". These are available " + inputArrayPorts
                    .keySet());
        }
        InputPortImpl in = inputArray.get(ref.portIndex());
        return in;
    }

    private void closeAllUnconnectedInputs() {
        for (InputPortImpl in : inputPorts.values()) {
            if (!in.hasConnections()) {
                in.close();
            }
        }
    }

    PacketImpl createPacket(Object content) {
        return createPacket(content, null);
    }

    @Override
    public final void addPacketListener(PacketListener listener) {
        packetListeners.add(listener);
    }

    @Override
    public Collection<NetworkComponent> components() {
        return (Collection) Collections.unmodifiableCollection(components);
    }

    private boolean shouldRun(AbstractRunnableComponent r) {
        return r.hasInputPacketsWaiting() || r.hasNoInputs() || r.mustRun();
    }

    @Override
    public void close() {
        for (OutputPort<?> port : outputPorts.values()) {
            port.close();
        }

        for (InputPort<?> port : inputPorts.values()) {
            port.close();
        }

        for (InputPorts<?> port : inputArrayPorts.values()) {
            port.closeAll();
        }

        for (OutputPorts<?> port : outputArrayPorts.values()) {
            port.closeAll();
        }

    }
}
TOP

Related Classes of javaflow.network.impl.NetworkImpl

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.