/*
# Licensed Materials - Property of IBM
# Copyright IBM Corp. 2015
*/
package com.ibm.streamsx.topology.spl;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.ibm.streams.operator.Attribute;
import com.ibm.streams.operator.OutputTuple;
import com.ibm.streams.operator.StreamSchema;
import com.ibm.streams.operator.Tuple;
import com.ibm.streamsx.topology.TStream;
import com.ibm.streamsx.topology.TWindow;
import com.ibm.streamsx.topology.TopologyElement;
import com.ibm.streamsx.topology.builder.BInputPort;
import com.ibm.streamsx.topology.builder.BOperatorInvocation;
import com.ibm.streamsx.topology.builder.BOutputPort;
import com.ibm.streamsx.topology.function.BiFunction;
import com.ibm.streamsx.topology.function.Function;
import com.ibm.streamsx.topology.internal.core.JavaFunctional;
import com.ibm.streamsx.topology.internal.core.TypeDiscoverer;
import com.ibm.streamsx.topology.internal.functional.ops.FunctionConvertToSPL;
import com.ibm.streamsx.topology.internal.spljava.Schemas;
/**
* Utilities for SPL attribute schema streams.
*
*/
public class SPLStreams {
/**
* Subscribe to an {@link SPLStream} published by topic.
*
* @param te
* Topology the stream will be contained in.
* @param topic
* Topic to subscribe to.
* @param schema
* SPL Schema of the published stream.
* @return Stream containing tuples for the published topic.
*/
public static SPLStream subscribe(TopologyElement te, String topic,
StreamSchema schema) {
Map<String, Object> params = new HashMap<>();
params.put("topic", topic);
params.put("streamType", schema);
SPLStream stream = SPL.invokeSource(te,
"com.ibm.streamsx.topology.topic::Subscribe",
params, schema);
return stream;
}
/**
* Convert a {@code Stream} to an {@code SPLStream}. For each tuple
* {@code t} on {@code stream}, the returned stream will contain a tuple
* that is the result of {@code converter.apply(t, outTuple)} when the
* return is not {@code null}. {@code outTuple} is a newly created, empty,
* {@code OutputTuple}, the {@code converter.apply()} method populates
* {@code outTuple} from {@code t}.
*
* <P>
* Example of converting a stream containing a {@code Sensor} object to an
* SPL schema of {@code tuple<rstring id, float64 reading>}.
*
* <pre>
* <code>
* Stream<Sensor> sensors = ...
* StreamSchema schema = Type.Factory.getStreamSchema("tuple<rstring id, float64 reading>");
* SPLStream splSensors = SPLStreams.convertStream(sensors,
* new BiFunction<Sensor, OutputTuple, OutputTuple>() {
* @Override
* public OutputTuple apply(Sensor sensor, OutputTuple outTuple) {
* outTuple.setString("id", sensor.getId());
* outTuple.setDouble("reading", sensor.getReading());
* return outTuple;
* }}, schema);
* </code>
* </pre>
*
* </P>
*
* @param stream
* Stream to be converted.
* @param converter
* Converter used to populate the SPL tuple.
* @param schema
* Schema of returned SPLStream.
* @return SPLStream containing the converted tuples.
*
* @see SPLStream#convert(com.ibm.streamsx.topology.function.Function)
*/
public static <T> SPLStream convertStream(TStream<T> stream,
BiFunction<T, OutputTuple, OutputTuple> converter,
StreamSchema schema) {
String opName = converter.getClass().getSimpleName();
if (opName.isEmpty()) {
opName = "SPLConvert" + TypeDiscoverer.getTupleName(stream.getTupleType());
}
BOperatorInvocation convOp = JavaFunctional.addFunctionalOperator(
stream, opName, FunctionConvertToSPL.class, converter);
@SuppressWarnings("unused")
BInputPort inputPort = stream.connectTo(convOp, true, null);
BOutputPort convertedTuples = convOp.addOutput(schema);
return new SPLStreamImpl(stream, convertedTuples);
}
/**
* Convert an {@link SPLStream} to a TStream<String>
* by taking its first attribute.
* The returned stream will contain a {@code String} tuple for
* each tuple {@code T} on {@code stream}, the value of the
* {@code String} tuple is {@code T.getString(0)}.
* A runtime error will occur if the first attribute (index 0)
* can not be converted using {@code Tuple.getString(0)}.
* @param stream Stream to be converted to a TStream<String>.
* @return Stream that will contain the first attribute of tuples from {@code stream}
*/
public static TStream<String> toStringStream(SPLStream stream) {
return stream.convert(new Function<Tuple, String>() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String apply(Tuple tuple) {
return tuple.getString(0);
}
});
}
/**
* Convert an {@link SPLStream} to a TStream<String>
* by taking a specific attribute.
* The returned stream will contain a {@code String} tuple for
* each tuple {@code T} on {@code stream}, the value of the
* {@code String} tuple is {@code T.getString(attributeName)}.
* A runtime error will occur if the attribute
* can not be converted using {@code Tuple.getString(attributeName)}.
* @param stream Stream to be converted to a TStream<String>.
* @return Stream that will contain a single attribute of tuples from {@code stream}
*/
public static TStream<String> toStringStream(SPLStream stream, String attributeName) {
Attribute attribute = stream.getSchema().getAttribute(attributeName);
if (attribute == null) {
throw new IllegalArgumentException("Atttribute " + attributeName + " not present in SPL schema "
+ stream.getSchema().getLanguageType());
}
final int attributeIndex = attribute.getIndex();
return stream.convert(new Function<Tuple, String>() {
private static final long serialVersionUID = 1L;
@Override
public String apply(Tuple tuple) {
return tuple.getString(attributeIndex);
}
});
}
/**
* Represent {@code stream} as an {@link SPLStream} with schema
* {@link SPLSchemas#STRING}.
*
* @param stream
* Stream to be represented as an {@code SPLStream}.
* @return {@code SPLStream} representation of {@code stream}.
*/
public static SPLStream stringToSPLStream(TStream<String> stream) {
return convertStream(stream,
new BiFunction<String, OutputTuple, OutputTuple>() {
private static final long serialVersionUID = 1L;
@Override
public OutputTuple apply(String v1, OutputTuple v2) {
v2.setString(0, v1);
return v2;
}
}, Schemas.STRING);
}
/**
* Convert window to an SPL window with a count based trigger policy.
*
* @param window
* Window to be converted.
* @param count
* Count trigger policy value
* @return SPL window with that will trigger every {@code count} tuples.
*/
public static SPLWindow triggerCount(TWindow<Tuple,?> window, int count) {
return new SPLWindowImpl(window, count);
}
/**
* Convert window to an SPL window with a time based trigger policy.
*
* @param window
* Window to be converted.
* @param time
* TIme trigger policy value.
* @param unit
* Unit for {@code time}.
* @return SPL window with that will trigger periodically according to
* {@code time}.
*/
public static SPLWindow triggerTime(TWindow<Tuple,?> window, long time,
TimeUnit unit) {
return new SPLWindowImpl(window, time, unit);
}
}