package edu.isi.karma.storm.bolt;
import java.util.Iterator;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import edu.isi.karma.storm.strategy.JoinStrategy;
public class KarmaJoinBolt extends BaseRichBolt {
/**
*
*/
private static final long serialVersionUID = 1L;
private static Logger LOG = LoggerFactory.getLogger(KarmaJoinBolt.class);
private OutputCollector outputCollector;
@SuppressWarnings("rawtypes")
private Map localConfig;
private String atId = "uri";
private String mergePath;
private String joinObjectField;
private JoinStrategy strategy;
public KarmaJoinBolt(@SuppressWarnings("rawtypes") Map localConfig, JoinStrategy joinStrategy)
{
this.localConfig = localConfig;
this.strategy = joinStrategy;
}
@Override
public void execute(Tuple tuple) {
long start = System.currentTimeMillis();
JSONObject objectToJoin = new JSONObject(tuple.getStringByField(joinObjectField));
String[] mergePath = this.mergePath.split(",");
joinJSONObject(objectToJoin, mergePath, 0);
outputCollector.emit(new Values(objectToJoin.getString(atId), objectToJoin.toString()));
outputCollector.ack(tuple);
LOG.debug("id: "+ tuple.getStringByField("id") + " " + (System.currentTimeMillis() - start));
}
private void joinJSONObject(JSONObject obj, String[] mergePath, int level) {
if (obj.has(mergePath[level])) {
Object val = obj.get(mergePath[level]);
if (level == mergePath.length - 1) {
if (val instanceof JSONObject) {
JSONObject target = (JSONObject)val;
JSONObject source = strategy.get(target.get(atId).toString());
if (source != null) {
@SuppressWarnings("rawtypes")
Iterator itr = source.keys();
while (itr.hasNext()) {
String key = itr.next().toString();
Object value = source.get(key);
target.put(key, value);
}
}
}
if (val instanceof String) {
JSONObject source = strategy.get(val.toString());
if (source != null) {
obj.put(mergePath[level], source);
}
}
}
else {
if (val instanceof JSONObject) {
joinJSONObject((JSONObject)val, mergePath, level + 1);
}
if (val instanceof JSONArray) {
JSONArray array = (JSONArray)val;
for (int i = 0; i < array.length(); i++) {
try {
JSONObject object = array.getJSONObject(i);
joinJSONObject(object, mergePath, level + 1);
} catch(Exception e)
{
LOG.error("Unable to join JSON object", e.getMessage());
}
}
}
}
}
}
@Override
public void prepare(@SuppressWarnings("rawtypes") Map globalConfig, TopologyContext arg1, OutputCollector outputCollector) {
this.outputCollector = outputCollector;
atId = localConfig.get("karma.context.atid").toString();
mergePath = localConfig.get("karma.storm.mergepath").toString();
joinObjectField = localConfig.get("karma.storm.join.object.field").toString();
strategy.prepare(localConfig);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFields) {
outputFields.declare(new Fields("id", "json"));
}
}