/*
# Licensed Materials - Property of IBM
# Copyright IBM Corp. 2011, 2014
*/
package com.ibm.streamsx.inet.window;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.ibm.streams.operator.Attribute;
import com.ibm.streams.operator.OperatorContext;
import com.ibm.streams.operator.StreamingInput;
import com.ibm.streams.operator.Tuple;
import com.ibm.streams.operator.window.StreamWindow;
import com.ibm.streams.operator.window.StreamWindowEvent;
import com.ibm.streams.operator.window.StreamWindowListener;
import com.ibm.streams.operator.window.StreamWindowPartitioner;
import com.ibm.streams.operator.window.WindowUtilities;
/**
* Window listener that provides a view of the window's
* contents at the last trigger for sliding windows, or
* eviction for tumbling windows.
*
* @param <T>
*/
public class WindowContentsAtTrigger<T> implements StreamWindowListener<T> {
private final OperatorContext context;
private final StreamingInput<T> input;
private final boolean isSliding;
private final Map<Object,List<T>> windowContents =
Collections.synchronizedMap(new HashMap<Object,List<T>>());
private final List<Attribute> partitionAttributes;
private long lastModified = System.currentTimeMillis();
@SuppressWarnings("unchecked")
public WindowContentsAtTrigger(OperatorContext context, StreamingInput<T> input) {
this.context = context;
this.input = input;
isSliding = StreamWindow.Type.SLIDING.equals(input.getStreamWindow().getType());
List<String> partitionKeys = context.getParameterValues("partitionKey");
if (!partitionKeys.isEmpty()) {
if (!input.getStreamWindow().isPartitioned())
throw new IllegalStateException("Input port " + input.getName() + "is not partitioned");
if (partitionKeys.size() == 1) {
WindowUtilities.registerAttributePartitioner(
(StreamWindow<Tuple>) input.getStreamWindow(),
partitionKeys.toArray(new String[0]));
} else {
// RTC 14070
// Multiple attributes.
final int[] indexes = new int[partitionKeys.size()];
for (int i = 0; i < indexes.length; i++)
indexes[i] = input.getStreamSchema().getAttributeIndex(partitionKeys.get(i));
((StreamWindow<Tuple>) input.getStreamWindow()).registerPartitioner(new StreamWindowPartitioner<Tuple,List<Object>>() {
@Override
public List<Object> getPartition(Tuple tuple) {
final List<Object> attrs = new ArrayList<Object>(indexes.length);
for (int i = 0; i < indexes.length; i++)
attrs.add(tuple.getObject(indexes[i]));
return Collections.unmodifiableList(attrs);
}
});
}
List<Attribute> pa = new ArrayList<Attribute>();
for (String attributeName : partitionKeys)
pa.add(input.getStreamSchema().getAttribute(attributeName));
partitionAttributes = Collections.unmodifiableList(pa);
} else {
if (input.getStreamWindow().isPartitioned())
throw new IllegalStateException("Input port " + input.getName() + "is partitioned but partitionKey parameter is not set.");
partitionAttributes = Collections.emptyList();
}
}
@Override
public synchronized void handleEvent(final StreamWindowEvent<T> event) throws Exception {
final Object partition = event.getPartition();
switch (event.getType()) {
case EVICTION:
if (isSliding)
break;
// fall through for a tumbling window
case TRIGGER:
List<T> tuples = new ArrayList<T>();
for (T tuple : event.getTuples())
tuples.add(tuple);
if (tuples.isEmpty())
windowContents.remove(partition);
else
windowContents.put(partition, tuples);
lastModified = System.currentTimeMillis();
break;
case PARTITION_EVICTION:
windowContents.remove(partition);
lastModified = System.currentTimeMillis();
break;
default:
break;
}
}
public List<T> getWindowContents(Object partition) {
if (partition == null)
return getAllPartitions();
List<T> tuples = windowContents.get(partition);
if (tuples == null)
return Collections.emptyList();
return Collections.unmodifiableList(tuples);
}
private List<T> getAllPartitions() {
List<T> allTuples = new ArrayList<T>();
synchronized (windowContents) {
for (List<T> tuples : windowContents.values()) {
allTuples.addAll(tuples);
}
}
return allTuples;
}
public OperatorContext getContext() {
return context;
}
public StreamingInput<T> getInput() {
return input;
}
public List<Attribute> getPartitionAttributes() {
return partitionAttributes;
}
}