/* # Licensed Materials - Property of IBM # Copyright IBM Corp. 2015 */ package com.ibm.streamsx.topology.spl; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import com.ibm.streams.operator.Operator; import com.ibm.streams.operator.StreamSchema; import com.ibm.streams.operator.model.PrimitiveOperator; import com.ibm.streamsx.topology.TSink; import com.ibm.streamsx.topology.Topology; import com.ibm.streamsx.topology.TopologyElement; import com.ibm.streamsx.topology.builder.BOperatorInvocation; import com.ibm.streamsx.topology.internal.core.SourceInfo; import com.ibm.streamsx.topology.internal.core.TSinkImpl; /** * Integration between Java topologies and SPL Java primitive operators. * <p> * In addition to the usual Java types used for operator parameter values, * a {@code Supplier<T>} parameter value may be specified. * Submission time parameters are passed in this manner. * See {@link Topology#createSubmissionParameter(String, Class)}. * For example: * <pre>{@code * Map<String,Object> params = ... * params.put("aLong", topology.createSubmissionParameter(..., Long.class); * params.put("aShort", topology.createSubmissionParameter(..., (short)13); * ... = JavaPrimitive.invokeJavaPrimitive(..., params); * }</pre> */ public class JavaPrimitive { /** * Create an SPLStream from the invocation of an SPL Java primitive * operator with a single input port & output port. * The Java class {@code opClass} must be annotated with {@code PrimitiveOperator}. * * @param opClass * Class of the operator to be invoked. * @param input * Stream that will be connected to the only input port of the * operator * @param outputSchema * SPL schema of the operator's only output port. * @param params * Parameters for the SPL Java Primitive operator, ignored if {@code null}. * @return SPLStream the represents the output of the operator. */ public static SPLStream invokeJavaPrimitive( Class<? extends Operator> opClass, SPLInput input, StreamSchema outputSchema, Map<String, ? extends Object> params) { BOperatorInvocation op = input.builder().addOperator( getInvocationName(opClass), opClass, params); SourceInfo.setSourceInfo(op, JavaPrimitive.class); SPL.connectInputToOperator(input, op); return new SPLStreamImpl(input, op.addOutput(outputSchema)); } /** * Invoke an SPL Java primitive operator with an arbitrary number * of input and output ports. * <BR> * Each input stream or window in {@code inputs} results in * a input port for the operator with the input port index * matching the position of the input in {@code inputs}. * If {@code inputs} is {@code null} or empty then the operator will not * have any input ports. * <BR> * Each SPL schema in {@code outputSchemas} an output port * for the operator with the output port index * matching the position of the schema in {@code outputSchemas}. * If {@code outputSchemas} is {@code null} or empty then the operator will not * have any output ports. * * @param te Reference to Topology the operator will be in. * @param opClass Class of the operator to be invoked. * @param inputs Input streams to be connected to the operator. May be {@code null} if no input streams are required. * @param outputSchemas Schemas of the output streams. May be {@code null} if no output streams are required. * @param params * Parameters for the SPL Java Primitive operator, ignored if {@code null}. * @return List of {@code SPLStream} instances that represent the outputs of the operator. */ public static List<SPLStream> invokeJavaPrimitive( TopologyElement te, Class<? extends Operator> opClass, List<? extends SPLInput> inputs, List<StreamSchema> outputSchemas, Map<String, ? extends Object> params) { BOperatorInvocation op = te.builder().addOperator( getInvocationName(opClass), opClass, params); SourceInfo.setSourceInfo(op, JavaPrimitive.class); if (inputs != null && !inputs.isEmpty()) { for (SPLInput input : inputs) SPL.connectInputToOperator(input, op); } if (outputSchemas == null || outputSchemas.isEmpty()) return Collections.emptyList(); List<SPLStream> streams = new ArrayList<>(outputSchemas.size()); for (StreamSchema outputSchema : outputSchemas) streams.add(new SPLStreamImpl(te, op.addOutput(outputSchema))); return streams; } /** * Invocation of a Java primitive operator that consumes a Stream. * * @param opClass * Class of the operator to be invoked * @param input * Stream that will be connected to the only input port of the * operator * @param params * Parameters for the SPL Java Primitive operator, ignored if {@code null}. */ public static TSink invokeJavaPrimitiveSink( Class<? extends Operator> opClass, SPLInput input, Map<String, ? extends Object> params) { BOperatorInvocation sink = input.builder().addOperator( getInvocationName(opClass), opClass, params); SourceInfo.setSourceInfo(sink, JavaPrimitive.class); SPL.connectInputToOperator(input, sink); return new TSinkImpl(input.topology(), sink); } /** * Invocation of a Java primitive source operator to produce a SPL Stream. * * @param te * Reference to Topology the operator will be in. * @param opClass * Class of the operator to be invoked. * @param schema * Schema of the output port. * @param params * Parameters for the SPL Java Primitive operator, ignored if {@code null}. * @return SPLStream the represents the output of the operator. */ public static SPLStream invokeJavaPrimitiveSource(TopologyElement te, Class<? extends Operator> opClass, StreamSchema schema, Map<String, ? extends Object> params) { BOperatorInvocation source = te.builder().addOperator( getInvocationName(opClass), opClass, params); SourceInfo.setSourceInfo(source, JavaPrimitive.class); return new SPLStreamImpl(te, source.addOutput(schema)); } private static String getInvocationName(Class<? extends Operator> opClass) { PrimitiveOperator po = opClass.getAnnotation(PrimitiveOperator.class); if (po == null) throw new IllegalStateException("Missing @PrimitiveOperator for: " + opClass.getName()); String opName = po.name(); if (opName.isEmpty()) { opName = opClass.getSimpleName(); } return opName; } }