All Downloads are FREE. Search and download functionalities are using the official Maven repository.

co.paralleluniverse.strands.channels.ReducingSendPort Maven / Gradle / Ivy

The newest version!
/*
 * Quasar: lightweight threads and actors for the JVM.
 * Copyright (c) 2013-2015, Parallel Universe Software Co. All rights reserved.
 * 
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *  
 *   or (per the licensee's choosing)
 *  
 * under the terms of the GNU Lesser General Public License version 3.0
 * as published by the Free Software Foundation.
 */
package co.paralleluniverse.strands.channels;

import co.paralleluniverse.common.util.Function2;
import co.paralleluniverse.fibers.DefaultFiberScheduler;
import co.paralleluniverse.fibers.SuspendExecution;
import co.paralleluniverse.strands.StrandFactory;
import co.paralleluniverse.strands.SuspendableRunnable;
import co.paralleluniverse.strands.SuspendableUtils;
import co.paralleluniverse.strands.Timeout;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A transforming {@link SendPort} that will apply a reduction function to values.
 *
 * @author circlespainter
 */
class ReducingSendPort extends SendPortTransformer {
    private static final StrandFactory strandFactoryDefault = DefaultFiberScheduler.getInstance();

    private final Function2 f;
    private final AtomicBoolean closedBeforeFirstSend = new AtomicBoolean(true);
    private final AtomicBoolean closing = new AtomicBoolean(false);
    private final StrandFactory strandFactory;
    private T prev;

    public ReducingSendPort(final SendPort target, final Function2 f, final T init, final StrandFactory strandFactory) {
        super(target);
        this.f = f;
        this.prev = init;
        this.strandFactory = strandFactory;
    }

    public ReducingSendPort(final SendPort target, final Function2 f, final T init) {
        this(target, f, init, strandFactoryDefault);
    }

    @Override
    public void close(final Throwable t) {
        if (!closing.getAndSet(true)) {
            if (closedBeforeFirstSend.get()) {
                strandFactory.newStrand(SuspendableUtils.runnableToCallable(new SuspendableRunnable() {
                    @Override
                    public void run() throws SuspendExecution, InterruptedException {
                        target.send(prev);
                        superClose(t);
                    }
                })).start();
            } else {
                superClose(t);
            }
        }
    }

    private void superClose(final Throwable t) {
        if (t != null)
            super.close(t);
        else
            super.close();
    }
    
    @Override
    public void close() {
        close(null);
    }

    @Override
    public boolean trySend(final S message) {
        closedBeforeFirstSend.set(false);
        return super.trySend(message);
    }

    @Override
    public boolean send(final S message, final Timeout timeout) throws SuspendExecution, InterruptedException {
        closedBeforeFirstSend.set(false);
        return super.send(message, timeout);
    }

    @Override
    public boolean send(final S message, final long timeout, final TimeUnit unit) throws SuspendExecution, InterruptedException {
        closedBeforeFirstSend.set(false);
        return super.send(message, timeout, unit);
    }

    @Override
    public void send(final S message) throws SuspendExecution, InterruptedException {
        closedBeforeFirstSend.set(false);
        super.send(message);
    }

    @Override
    protected T transform(final S m) {
        return (this.prev = reduce(prev, m));
    }

    private T reduce(final T prev, final S m) {
        if (f != null && prev != null)
            return f.apply(prev, m);
        throw new UnsupportedOperationException();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy