
groovyx.gpars.dataflow.stream.DataflowStreamReadAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gpars Show documentation
Show all versions of gpars Show documentation
The Groovy and Java high-level concurrency library offering actors, dataflow, CSP, agents, parallel collections, fork/join and more
// GPars - Groovy Parallel Systems
//
// Copyright © 2008-2012 The original author or authors
//
// 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 groovyx.gpars.dataflow.stream;
import groovy.lang.Closure;
import groovyx.gpars.actor.impl.MessageStream;
import groovyx.gpars.dataflow.Dataflow;
import groovyx.gpars.dataflow.DataflowChannelListener;
import groovyx.gpars.dataflow.DataflowQueue;
import groovyx.gpars.dataflow.DataflowReadChannel;
import groovyx.gpars.dataflow.DataflowVariable;
import groovyx.gpars.dataflow.DataflowWriteChannel;
import groovyx.gpars.dataflow.Promise;
import groovyx.gpars.dataflow.SyncDataflowVariable;
import groovyx.gpars.dataflow.expression.DataflowExpression;
import groovyx.gpars.dataflow.impl.DataflowChannelEventListenerManager;
import groovyx.gpars.dataflow.impl.DataflowChannelEventOrchestrator;
import groovyx.gpars.dataflow.impl.ThenMessagingRunnable;
import groovyx.gpars.dataflow.operator.BinaryChoiceClosure;
import groovyx.gpars.dataflow.operator.ChainWithClosure;
import groovyx.gpars.dataflow.operator.ChoiceClosure;
import groovyx.gpars.dataflow.operator.CopyChannelsClosure;
import groovyx.gpars.dataflow.operator.FilterClosure;
import groovyx.gpars.dataflow.operator.SeparationClosure;
import groovyx.gpars.group.DefaultPGroup;
import groovyx.gpars.group.PGroup;
import groovyx.gpars.scheduler.Pool;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static java.util.Arrays.asList;
/**
* Adapts a DataflowStream to accommodate for the DataflowReadChannel interface.
* To minimize the overhead and stay in-line with the DataflowStream semantics, the DataflowStreamReadAdapter class is not thread-safe
* and should only be used from within a single thread.
* If multiple threads need to read from a DataflowStream, they should each create their own wrapping DataflowStreamReadAdapter.
*
* @param The type of messages to pass through the stream
* @author Vaclav Pech
*/
@SuppressWarnings({"unchecked"})
public class DataflowStreamReadAdapter implements DataflowReadChannel {
private StreamCore head;
private StreamCore asyncHead;
/**
* Creates a new adapter
*
* @param stream The stream to wrap
*/
public DataflowStreamReadAdapter(final StreamCore stream) {
this.head = stream;
this.asyncHead = head;
this.head.addUpdateListener(new DataflowChannelListener() {
@Override
public void onMessage(final T message) {
fireOnMessage(message);
}
});
}
public Iterator iterator() {
return new FListIterator(head);
}
@SuppressWarnings("ObjectToString")
@Override
public final String toString() {
return head.toString();
}
@Override
public T getVal() throws InterruptedException {
final T first = head.getFirst();
moveHead();
return first;
}
@Override
public T getVal(final long timeout, final TimeUnit units) throws InterruptedException {
final T value = head.getFirstDFV().getVal(timeout, units);
if (value == null) {
if (shouldReportTimeout()) {
return null;
} else {
final T result = head.getFirstDFV().getVal();
moveHead();
return result;
}
} else {
moveHead();
return value;
}
}
private boolean shouldReportTimeout() {
final DataflowVariable firstDFV = head.getFirstDFV();
if (!firstDFV.isBound()) return true;
if (firstDFV instanceof SyncDataflowVariable) {
return ((SyncDataflowVariable) firstDFV).awaitingParties();
}
return false;
}
@Override
public void getValAsync(final MessageStream callback) {
asyncHead.getFirstDFV().getValAsync(callback);
moveAsyncHead();
}
@Override
public void getValAsync(final Object attachment, final MessageStream callback) {
asyncHead.getFirstDFV().getValAsync(attachment, callback);
moveAsyncHead();
}
@Override
public Promise rightShift(final Closure closure) {
return then(closure);
}
@Override
public void whenBound(final Closure closure) {
asyncHead.getFirstDFV().whenBound(closure);
moveAsyncHead();
}
/**
* Schedule closure to be executed by pooled actor after data becomes available.
* It is important to notice that even if the expression is already bound the execution of closure
* will not happen immediately but will be scheduled.
*
* @param pool The thread pool to use for task scheduling for asynchronous message delivery
* @param closure closure to execute when data becomes available. The closure should take at most one argument.
*/
@Override
public void whenBound(final Pool pool, final Closure closure) {
asyncHead.getFirstDFV().whenBound(pool, closure);
moveAsyncHead();
}
@Override
public void whenBound(final PGroup group, final Closure closure) {
asyncHead.getFirstDFV().whenBound(group, closure);
moveAsyncHead();
}
@Override
public void whenBound(final MessageStream stream) {
asyncHead.getFirstDFV().whenBound(stream);
moveAsyncHead();
}
/**
* Schedule closure to be executed after data became available.
* It is important to notice that even if the expression is already bound the execution of closure
* will not happen immediately but will be scheduled
*
* @param closure closure to execute when data becomes available. The closure should take at most one argument.
* @return A promise for the results of the supplied closure. This allows for chaining of then() method calls.
*/
@Override
public final Promise then(final Closure closure) {
final DataflowVariable result = new DataflowVariable();
whenBound(new ThenMessagingRunnable(result, closure));
return result;
}
/**
* Schedule closure to be executed after data becomes available.
* It is important to notice that even if the expression is already bound the execution of closure
* will not happen immediately but will be scheduled.
*
* @param pool The thread pool to use for task scheduling for asynchronous message delivery
* @param closure closure to execute when data becomes available. The closure should take at most one argument.
* @return A promise for the results of the supplied closure. This allows for chaining of then() method calls.
*/
@Override
public Promise then(final Pool pool, final Closure closure) {
final DataflowVariable result = new DataflowVariable();
whenBound(pool, new ThenMessagingRunnable(result, closure));
return result;
}
/**
* Schedule closure to be executed after data becomes available.
* It is important to notice that even if the expression is already bound the execution of closure
* will not happen immediately but will be scheduled.
*
* @param group The PGroup to use for task scheduling for asynchronous message delivery
* @param closure closure to execute when data becomes available. The closure should take at most one argument.
* @return A promise for the results of the supplied closure. This allows for chaining of then() method calls.
*/
@Override
public Promise then(final PGroup group, final Closure closure) {
final DataflowVariable result = new DataflowVariable();
whenBound(group, new ThenMessagingRunnable(result, closure));
return result;
}
@Override
public void wheneverBound(final Closure closure) {
head.wheneverBound(closure);
}
@Override
public void wheneverBound(final MessageStream stream) {
head.wheneverBound(stream);
}
@Override
public final DataflowReadChannel chainWith(final Closure closure) {
return chainWith(Dataflow.retrieveCurrentDFPGroup(), closure);
}
@Override
public final DataflowReadChannel chainWith(final Pool pool, final Closure closure) {
return chainWith(new DefaultPGroup(pool), closure);
}
@Override
public DataflowReadChannel chainWith(final PGroup group, final Closure closure) {
final DataflowQueue result = new DataflowQueue();
group.operator(this, result, new ChainWithClosure(closure));
return result;
}
@Override
public final DataflowReadChannel chainWith(final Map params, final Closure closure) {
return chainWith(Dataflow.retrieveCurrentDFPGroup(), params, closure);
}
@Override
public final DataflowReadChannel chainWith(final Pool pool, final Map params, final Closure closure) {
return chainWith(new DefaultPGroup(pool), params, closure);
}
@Override
public DataflowReadChannel chainWith(final PGroup group, final Map params, final Closure closure) {
final DataflowQueue result = new DataflowQueue();
final Map parameters = new HashMap(params);
parameters.put("inputs", asList(this));
parameters.put("outputs", asList(asList(result)));
group.operator(parameters, new ChainWithClosure(closure));
return result;
}
@Override
public DataflowReadChannel or(final Closure closure) {
return chainWith(closure);
}
@Override
public DataflowReadChannel filter(final Closure closure) {
return chainWith(new FilterClosure(closure));
}
@Override
public DataflowReadChannel filter(final Pool pool, final Closure closure) {
return chainWith(pool, new FilterClosure(closure));
}
@Override
public DataflowReadChannel filter(final PGroup group, final Closure closure) {
return chainWith(group, new FilterClosure(closure));
}
@Override
public DataflowReadChannel filter(final Map params, final Closure closure) {
return chainWith(params, new FilterClosure(closure));
}
@Override
public DataflowReadChannel filter(final Pool pool, final Map params, final Closure closure) {
return chainWith(pool, params, new FilterClosure(closure));
}
@Override
public DataflowReadChannel filter(final PGroup group, final Map params, final Closure closure) {
return chainWith(group, params, new FilterClosure(closure));
}
@Override
public void into(final DataflowWriteChannel target) {
into(Dataflow.retrieveCurrentDFPGroup(), target);
}
@Override
public void into(final Pool pool, final DataflowWriteChannel target) {
into(new DefaultPGroup(pool), target);
}
@Override
public void into(final PGroup group, final DataflowWriteChannel target) {
group.operator(this, target, new ChainWithClosure(new CopyChannelsClosure()));
}
@Override
public void into(final Map params, final DataflowWriteChannel target) {
into(Dataflow.retrieveCurrentDFPGroup(), params, target);
}
@Override
public void into(final Pool pool, final Map params, final DataflowWriteChannel target) {
into(new DefaultPGroup(pool), params, target);
}
@Override
public void into(final PGroup group, final Map params, final DataflowWriteChannel target) {
final Map parameters = new HashMap(params);
parameters.put("inputs", asList(this));
parameters.put("outputs", asList(asList(target)));
group.operator(parameters, new ChainWithClosure(new CopyChannelsClosure()));
}
@Override
public void or(final DataflowWriteChannel target) {
into(target);
}
@Override
public void split(final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(Dataflow.retrieveCurrentDFPGroup(), target1, target2);
}
@Override
public void split(final Pool pool, final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(new DefaultPGroup(pool), target1, target2);
}
@Override
public void split(final PGroup group, final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(group, asList(target1, target2));
}
@Override
public void split(final List> targets) {
split(Dataflow.retrieveCurrentDFPGroup(), targets);
}
@Override
public void split(final Pool pool, final List> targets) {
split(new DefaultPGroup(pool), targets);
}
@Override
public void split(final PGroup group, final List> targets) {
group.operator(asList(this), targets, new ChainWithClosure(new CopyChannelsClosure()));
}
@Override
public void split(final Map params, final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(Dataflow.retrieveCurrentDFPGroup(), params, target1, target2);
}
@Override
public void split(final Pool pool, final Map params, final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(new DefaultPGroup(pool), params, target1, target2);
}
@Override
public void split(final PGroup group, final Map params, final DataflowWriteChannel target1, final DataflowWriteChannel target2) {
split(group, params, asList(target1, target2));
}
@Override
public void split(final Map params, final List> targets) {
split(Dataflow.retrieveCurrentDFPGroup(), params, targets);
}
@Override
public void split(final Pool pool, final Map params, final List> targets) {
split(new DefaultPGroup(pool), params, targets);
}
@Override
public void split(final PGroup group, final Map params, final List> targets) {
final Map parameters = new HashMap(params);
parameters.put("inputs", asList(this));
parameters.put("outputs", asList(asList(targets)));
group.operator(parameters, new ChainWithClosure(new CopyChannelsClosure()));
}
@Override
public DataflowReadChannel tap(final DataflowWriteChannel target) {
return tap(Dataflow.retrieveCurrentDFPGroup(), target);
}
@Override
public DataflowReadChannel tap(final Pool pool, final DataflowWriteChannel target) {
return tap(new DefaultPGroup(pool), target);
}
@Override
public DataflowReadChannel tap(final PGroup group, final DataflowWriteChannel target) {
final DataflowQueue result = new DataflowQueue();
group.operator(asList(this), asList(result, target), new ChainWithClosure(new CopyChannelsClosure()));
return result;
}
@Override
public DataflowReadChannel tap(final Map params, final DataflowWriteChannel target) {
return tap(Dataflow.retrieveCurrentDFPGroup(), params, target);
}
@Override
public DataflowReadChannel tap(final Pool pool, final Map params, final DataflowWriteChannel target) {
return tap(new DefaultPGroup(pool), params, target);
}
@Override
public DataflowReadChannel tap(final PGroup group, final Map params, final DataflowWriteChannel target) {
final DataflowQueue result = new DataflowQueue();
final Map parameters = new HashMap(params);
parameters.put("inputs", asList(this));
parameters.put("outputs", asList(asList(result, target)));
group.operator(parameters, new ChainWithClosure(new CopyChannelsClosure()));
return result;
}
@Override
public DataflowReadChannel merge(final DataflowReadChannel