package main.java.bolts;
import static main.java.utils.constants.WorkberchConstants.INDEX_FIELD;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import main.java.utils.ExecutedValue;
import main.java.utils.WorkberchTuple;
import main.java.utils.cartesianindex.CartesianIndex;
import main.java.utils.cartesianindex.CartesianLeaf;
import main.java.utils.cartesianindex.CartesianNode;
import org.apache.commons.lang.StringUtils;
import backtype.storm.topology.BasicOutputCollector;
public class WorkberchCartesianBolt extends WorkberchProvenanceBolt {
private static final long serialVersionUID = 1L;
private final Map<String, List<ExecutedValue>> executedInputs = new HashMap<String, List<ExecutedValue>>();
private boolean uncompleteTuples = true;
public WorkberchCartesianBolt(final String guid, final List<String> outputFields) {
super(guid, outputFields);
for (final String inputField : outputFields) {
if (!inputField.equals(INDEX_FIELD)) {
executedInputs.put(inputField, new ArrayList<ExecutedValue>());
}
}
}
private List<Object> uniteIndexOnCartesianIndex(final List<Object> valuesToEmit) {
final List<Object> realValues = new ArrayList<Object>();
final List<CartesianIndex> indexValues = new ArrayList<CartesianIndex>();
final Iterator<Object> iterValEmit = valuesToEmit.iterator();
final Iterator<String> iterField = getOutputFields().iterator();
String field = StringUtils.EMPTY;
while (iterValEmit.hasNext()) {
final Object value = iterValEmit.next();
field = iterField.hasNext() ? (String) iterField.next() : field;
if (field.startsWith(INDEX_FIELD)) {
indexValues.add(value instanceof CartesianIndex ? (CartesianIndex) value : new CartesianLeaf((Long) value));
} else {
realValues.add(value);
}
}
final CartesianIndex cartesianNode = new CartesianNode(indexValues);
realValues.add(cartesianNode);
return realValues;
}
private void createTuples(final List<String> remainingFields, final WorkberchTuple baseTuple, final List<List<Object>> valuesToEmit) {
if (remainingFields.isEmpty()) {
final List<Object> tupleToEmit = new ArrayList<Object>();
for (final String field : getOutputFields()) {
if (field.startsWith(INDEX_FIELD)) {
for (final String sourceIndex : getRunningNodes()) {
if (baseTuple.getSource().equals(sourceIndex)) {
tupleToEmit.add(baseTuple.getValues().get(INDEX_FIELD));
}
else {
tupleToEmit.add(baseTuple.getValues().get(INDEX_FIELD + sourceIndex));
}
}
} else {
tupleToEmit.add(baseTuple.getValues().get(field));
}
}
valuesToEmit.add(uniteIndexOnCartesianIndex(tupleToEmit));
} else {
final String nextField = remainingFields.get(0);
remainingFields.remove(0);
for (final ExecutedValue value : executedInputs.get(nextField)) {
final Map<String, Object> tupleValues = baseTuple.getValues();
tupleValues.put(nextField, value.getValue());
tupleValues.put(value.getIndexCode(), value.getIndex());
createTuples(remainingFields, baseTuple, valuesToEmit);
}
}
}
private void addExecutedValues(final WorkberchTuple tuple, final List<String> remainingFields) {
for (final String field : tuple.getFields()) {
if (!remainingFields.contains(field) && !field.equals(INDEX_FIELD)) {
final List<ExecutedValue> values = executedInputs.get(field);
if (values != null) {
final ExecutedValue valueExec = new ExecutedValue(tuple.getValues().get(field), INDEX_FIELD + tuple.
getSource(), tuple.getValues().get(INDEX_FIELD));
values.add(valueExec);
}
}
}
}
@Override
public void executeLogic(final WorkberchTuple input, final BasicOutputCollector collector, final boolean lastValues,
final String uuid) {
final List<String> remainingFields = new ArrayList<String>();
remainingFields.addAll(executedInputs.keySet());
remainingFields.removeAll(input.getFields());
addExecutedValues(input, remainingFields);
if (uncompleteTuples) {
boolean notAllValues = false;
for (final String key : executedInputs.keySet()) {
notAllValues |= executedInputs.get(key).isEmpty();
}
uncompleteTuples &= notAllValues;
}
if (!uncompleteTuples) {
final List<List<Object>> valuesToEmit = new ArrayList<List<Object>>();
createTuples(remainingFields, input, valuesToEmit);
final Iterator<List<Object>> iterValue = valuesToEmit.iterator();
while (iterValue.hasNext()) {
emitTuple(iterValue.next(), collector, lastValues && !iterValue.hasNext(), uuid);
}
}
}
}