rk.java.compute.cep.ComputeService.java Source code

Java tutorial

Introduction

Here is the source code for rk.java.compute.cep.ComputeService.java

Source

/**
 *    Copyright 2012 RK
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */
package rk.java.compute.cep;

import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.springframework.util.StopWatch;

import rk.java.compute.cep.Compute.IPriceEventSink;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

/**
 * Executor Service for {@link Compute} instances.
 * <P>
 * Subscribes to tick events via {@link #listen(TickEvent)} and dispatches 
 * to appropriate {@link Compute}.
 * <P>
 * {@link Compute} also uses {@link EventBus} as an output sink.
 * 
 * @author RK
 *
 */
public class ComputeService {
    private final BlockingQueue<IPriceTick> feedQueue;
    private final ConcurrentHashMap<String, Compute> handlerCache;
    private final StopWatch stopWatch;
    private ExecutorService executorService;
    private CompletionService<StopWatch> ecs;
    private Future<StopWatch> dispatchTaskFuture;
    private volatile long ticksReceivedCount = 0;
    private volatile long ticksProcessedCount;
    private int shutdownCalls = 0;
    private final int numberOfTickSources;
    private IPriceEventSink eventbus;

    /**
     * @param numberOfTickSources - used to build quorum for shutdown
     * @param eventBus - an {@link EventBus} that's used for the creation of {@link Compute} instances
     */
    public ComputeService(final int numberOfTickSources, IPriceEventSink eventBus) {
        this(new LinkedBlockingQueue<IPriceTick>(), numberOfTickSources, eventBus);
    }

    public ComputeService(final int numberOfTickSources, final int threadPoolSize, IPriceEventSink eventBus) {
        this(new LinkedBlockingQueue<IPriceTick>(), numberOfTickSources, eventBus);
        executorService = Executors.newFixedThreadPool(threadPoolSize);
        ecs = new ExecutorCompletionService<StopWatch>(executorService);
    }

    public ComputeService(BlockingQueue<IPriceTick> queue, final int numberOfTickSources,
            IPriceEventSink eventbus) {
        this.feedQueue = queue;
        this.numberOfTickSources = numberOfTickSources;
        this.eventbus = eventbus;
        this.handlerCache = new ConcurrentHashMap<String, Compute>();
        this.stopWatch = new StopWatch("Dispatcher Task");
        executorService = Executors.newCachedThreadPool();
        ecs = new ExecutorCompletionService<StopWatch>(executorService);
        dispatchTaskFuture = ecs.submit(new Callable<StopWatch>() {
            @Override
            public StopWatch call() throws Exception {
                stopWatch.start();
                run();
                stopWatch.stop();
                return stopWatch;
            }
        });
    }

    private final void run() {
        while (!Thread.currentThread().isInterrupted()) {
            IPriceTick tick = null;
            try {
                tick = feedQueue.take();

                ticksProcessedCount++;
                if (tick == IPriceTick.POISON) {
                    if (++shutdownCalls >= numberOfTickSources) {
                        shutdownHandlers();
                        return;
                    } else {
                        continue;
                    }
                }
                String instrument = tick.getInstrument();
                Compute handler = getOrCreateHandler(instrument);
                handler.add(tick);
            } catch (InterruptedException inte) {
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * @param unit 
     * @param timeout 
     * @param unit 
     * @return {@link #stopWatch} which contains basic runtime stats
     * @throws TimeoutException 
     * @throws ExecutionException 
     * @throws InterruptedException 
      * 
      */
    public StopWatch shutDownAndAwaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException, ExecutionException, TimeoutException {
        StopWatch stopWatch = this.dispatchTaskFuture.get(timeout, unit);
        this.executorService.shutdown();
        this.executorService.awaitTermination(timeout, unit);
        return stopWatch;
    }

    /**
     * Get the handler for this instrument if one exists - if not
     * then create one.
     * If one does exist and it's broken the create and replace it
     * in the cache.
     *  
     * @param instrument
     * @return
     */
    private Compute getOrCreateHandler(String instrument) {
        Compute handler;
        if (!handlerCache.containsKey(instrument)) {
            handler = new Compute(instrument, this.eventbus);
            Compute putIfAbsent = handlerCache.putIfAbsent(instrument, handler);
            if (putIfAbsent != null) {
                handler = putIfAbsent;
            } else {
                this.ecs.submit(handler);
            }
        } else {
            handler = handlerCache.get(instrument);
        }
        return handler;
    }

    private void shutdownHandlers() {
        System.out.println("Shutting down dispatcher. ");
        System.out.println("Dispatcher's HandlerCache size = " + this.handlerCache.size());
        Collection<Compute> values = handlerCache.values();
        for (Compute compute : values) {
            compute.add(IPriceTick.POISON);
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "ComputeService [stopWatch=" + this.stopWatch + ", handlerCache.size()=" + this.handlerCache.size()
                + ", ticksReceivedCount=" + this.ticksReceivedCount + ", ticksProcessedCount="
                + this.ticksProcessedCount + "]";
    }

    /**
     * This is a convention callback for {@link EventBus#register(Object)}
     * <P>
     * Registers with the given bus for {@link TickEvent} via {@link #listen(TickEvent)}
     * @param bus
     */
    public void subscribeToTickEventsFrom(EventBus bus) {
        bus.register(this);
    }

    /**
     * Subscribes to {@link EventBus} for {@link TickEvent}s
     * @param tickEvent
     */
    @Subscribe
    public void listen(IPriceTick tickEvent) {
        this.feedQueue.add(tickEvent);
        this.ticksReceivedCount++;
    }

    /**
     * @return the ticksProcessedCount
     */
    public long getTicksProcessedCount() {
        return this.ticksProcessedCount;
    }

    /**
     * @return the ticksReceivedCount
     */
    public long getTicksReceivedCount() {
        return this.ticksReceivedCount;
    }
}