Package com.espertech.esper.dataflow.core

Source Code of com.espertech.esper.dataflow.core.EPDataFlowInstanceImpl

/*
* *************************************************************************************
*  Copyright (C) 2008 EsperTech, Inc. All rights reserved.                            *
*  http://esper.codehaus.org                                                          *
*  http://www.espertech.com                                                           *
*  ---------------------------------------------------------------------------------- *
*  The software in this package is published under the terms of the GPL license       *
*  a copy of which has been included with this distribution in the license.txt file.  *
* *************************************************************************************
*/

package com.espertech.esper.dataflow.core;

import com.espertech.esper.client.dataflow.*;
import com.espertech.esper.dataflow.interfaces.DataFlowOpCloseContext;
import com.espertech.esper.dataflow.interfaces.DataFlowOpLifecycle;
import com.espertech.esper.dataflow.interfaces.DataFlowOpOpenContext;
import com.espertech.esper.dataflow.ops.Emitter;
import com.espertech.esper.dataflow.runnables.CompletionListener;
import com.espertech.esper.dataflow.runnables.GraphSourceRunnable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class EPDataFlowInstanceImpl implements EPDataFlowInstance, CompletionListener {
    private static final Log log = LogFactory.getLog(EPDataFlowInstanceImpl.class);

    private final String dataFlowName;
    private final Object userObject;
    private final String instanceId;
    private volatile EPDataFlowState state;
    private final List<GraphSourceRunnable> sourceRunnables;
    private final Map<Integer, Object> operators;
    private final Set<Integer> operatorBuildOrder;
    private final EPDataFlowInstanceStatistics statisticsProvider;

    private List<CountDownLatch> joinedThreadLatches;
    private List<Thread> threads;
    private Thread runCurrentThread;

    public EPDataFlowInstanceImpl(String dataFlowName, Object userObject, String instanceId, EPDataFlowState state, List<GraphSourceRunnable> sourceRunnables, Map<Integer, Object> operators, Set<Integer> operatorBuildOrder, EPDataFlowInstanceStatistics statisticsProvider) {
        this.dataFlowName = dataFlowName;
        this.userObject = userObject;
        this.instanceId = instanceId;
        this.state = state;
        this.sourceRunnables = sourceRunnables;
        this.operators = operators;
        this.operatorBuildOrder = operatorBuildOrder;
        this.statisticsProvider = statisticsProvider;
    }

    public String getDataFlowName() {
        return dataFlowName;
    }

    public EPDataFlowState getState() {
        return state;
    }

    public Object getUserObject() {
        return userObject;
    }

    public String getInstanceId() {
        return instanceId;
    }

    public synchronized EPDataFlowInstanceCaptive startCaptive() {
        checkExecCompleteState();
        checkExecCancelledState();
        checkExecRunningState();
        state = EPDataFlowState.RUNNING;

        callOperatorOpen();

        Map<String, Emitter> emitters = new HashMap<String, Emitter>();
        for (Object operator : operators.values()) {
            if (operator instanceof Emitter) {
                Emitter emitter = (Emitter) operator;
                emitters.put(emitter.getName(), emitter);
            }
        }
       
        return new EPDataFlowInstanceCaptive(emitters, sourceRunnables);
    }

    public synchronized void run() {
        checkExecCompleteState();
        checkExecCancelledState();
        checkExecRunningState();

        if (sourceRunnables.size() != 1) {
            throw new UnsupportedOperationException("The data flow '" + dataFlowName + "' has zero or multiple sources and requires the use of the start method instead");
        }

        callOperatorOpen();
       
        GraphSourceRunnable sourceRunnable = sourceRunnables.get(0);
        state = EPDataFlowState.RUNNING;
        runCurrentThread = Thread.currentThread();
        try {
            sourceRunnable.runSync();
        }
        catch (InterruptedException ex) {
            callOperatorClose();
            state = EPDataFlowState.CANCELLED;
            throw new EPDataFlowCancellationException("Data flow '" + dataFlowName + "' execution was cancelled", dataFlowName);
        }
        catch (Throwable t) {
            callOperatorClose();
            state = EPDataFlowState.COMPLETE;
            throw new EPDataFlowExecutionException("Exception encountered running data flow '" + dataFlowName + "': " + t.getMessage(), t, dataFlowName);
        }
        callOperatorClose();
        if (state != EPDataFlowState.CANCELLED) {
            state = EPDataFlowState.COMPLETE;
        }
    }

    public synchronized void start() {
        checkExecCompleteState();
        checkExecCancelledState();
        checkExecRunningState();

        callOperatorOpen();

        final AtomicInteger countdown = new AtomicInteger(sourceRunnables.size());
        threads = new ArrayList<Thread>();
        for (int i = 0; i < sourceRunnables.size(); i++) {
            GraphSourceRunnable runnable = sourceRunnables.get(i);
            String threadName = "esper." + dataFlowName + "-" + i;
            Thread thread = new Thread(runnable, threadName);
            thread.setContextClassLoader(Thread.currentThread().getContextClassLoader());
            thread.setDaemon(true);
            runnable.addCompletionListener(new CompletionListener() {
                public void completed() {
                    int remaining = countdown.decrementAndGet();
                    if (remaining == 0) {
                        EPDataFlowInstanceImpl.this.completed();
                    }
                }
            });
            state = EPDataFlowState.RUNNING;
            threads.add(thread);
            thread.start();
        }
    }

    public void join() throws InterruptedException {
        if (state == EPDataFlowState.INSTANTIATED) {
            throw new IllegalStateException("Data flow '" + dataFlowName + "' instance has not been executed, please use join after start or run");
        }
        if (state == EPDataFlowState.CANCELLED) {
            throw new IllegalStateException("Data flow '" + dataFlowName + "' instance has been cancelled and cannot be joined");
        }

        // latch used for non-blocking start
        if (threads != null) {
            for (Thread thread : threads) {
                thread.join();
            }
        }
        else {
            CountDownLatch latch = new CountDownLatch(1);
            synchronized (this) {
                if (joinedThreadLatches == null) {
                    joinedThreadLatches = new ArrayList<CountDownLatch>();
                }
                joinedThreadLatches.add(latch);
            }
            if (state != EPDataFlowState.COMPLETE) {
                latch.await();
            }
        }
    }

    public void cancel() {
        if (state == EPDataFlowState.COMPLETE || state == EPDataFlowState.CANCELLED) {
            return;
        }
        if (state == EPDataFlowState.INSTANTIATED) {
            state = EPDataFlowState.CANCELLED;
            sourceRunnables.clear();
            callOperatorClose();
            return;
        }

        // handle async start
        if (threads != null) {
            for (GraphSourceRunnable runnable : sourceRunnables) {
                runnable.shutdown();
            }
            for (Thread thread : threads) {
                if (thread.isAlive() && !thread.isInterrupted()) {
                    thread.interrupt();
                }
            }
        }
        // handle run
        else {
            if (runCurrentThread != null) {
                runCurrentThread.interrupt();
            }
            runCurrentThread = null;
        }

        callOperatorClose();

        state = EPDataFlowState.CANCELLED;
        sourceRunnables.clear();
    }

    public synchronized void completed() {
        if (state != EPDataFlowState.CANCELLED) {
            state = EPDataFlowState.COMPLETE;
        }

        callOperatorClose();

        if (joinedThreadLatches != null) {
            for (CountDownLatch joinedThread : joinedThreadLatches) {
                joinedThread.countDown();
            }
        }
    }

    public EPDataFlowInstanceStatistics getStatistics() {
        return statisticsProvider;
    }

    private void checkExecCompleteState() {
        if (state == EPDataFlowState.COMPLETE) {
            throw new IllegalStateException("Data flow '" + dataFlowName + "' instance has already completed, please use instantiate to run the data flow again");
        }
    }

    private void checkExecRunningState() {
        if (state == EPDataFlowState.RUNNING) {
            throw new IllegalStateException("Data flow '" + dataFlowName + "' instance is already running");
        }
    }

    private void checkExecCancelledState() {
        if (state == EPDataFlowState.CANCELLED) {
            throw new IllegalStateException("Data flow '" + dataFlowName + "' instance has been cancelled and cannot be run or started");
        }
    }

    private void callOperatorClose() {
        for (Integer opNum : operatorBuildOrder) {
            Object operator = operators.get(opNum);
            if (operator instanceof DataFlowOpLifecycle) {
                try {
                    DataFlowOpLifecycle lf = (DataFlowOpLifecycle) operator;
                    lf.close(new DataFlowOpCloseContext());
                }
                catch (RuntimeException ex) {
                    log.error("Exception encountered closing data flow '" + dataFlowName + "': " + ex.getMessage(), ex);
                }
            }
        }
    }

    private void callOperatorOpen() {
        for (Integer opNum : operatorBuildOrder) {
            Object operator = operators.get(opNum);
            if (operator instanceof DataFlowOpLifecycle) {
                try {
                    DataFlowOpLifecycle lf = (DataFlowOpLifecycle) operator;
                    lf.open(new DataFlowOpOpenContext());
                }
                catch (RuntimeException ex) {
                    throw new EPDataFlowExecutionException("Exception encountered opening data flow 'FlowOne' in operator " + operator.getClass().getSimpleName() + ": " + ex.getMessage(), ex, dataFlowName);
                }
            }
        }
    }
}
TOP

Related Classes of com.espertech.esper.dataflow.core.EPDataFlowInstanceImpl

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.