/*
* #!
* %
* Copyright (C) 2014 - 2016 Humboldt-Universität zu Berlin
* %
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #_
*/
package de.hub.cs.dbis.lrb.operators;
import java.util.Map;
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 de.hub.cs.dbis.aeolus.utils.TimestampMerger;
import de.hub.cs.dbis.lrb.queries.utils.TopologyControl;
import de.hub.cs.dbis.lrb.types.AbstractLRBTuple;
import de.hub.cs.dbis.lrb.types.AccountBalanceRequest;
import de.hub.cs.dbis.lrb.types.DailyExpenditureRequest;
import de.hub.cs.dbis.lrb.types.PositionReport;
import de.hub.cs.dbis.lrb.types.TravelTimeRequest;
/**
* {@link DispatcherBolt} retrieves a stream of {@code <ts,string>} tuples, parses the second CSV attribute and emits an
* appropriate LRB tuple. The LRB input CSV schema is:
* {@code Type, Time, VID, Spd, XWay, Lane, Dir, Seg, Pos, QID, S_init, S_end, DOW, TOD, Day}<br />
* <br />
* <strong>Output schema:</strong>
* <ul>
* <li>{@link PositionReport} (stream: {@link TopologyControl#POSITION_REPORTS_STREAM_ID})</li>
* <li>{@link AccountBalanceRequest} (stream: {@link TopologyControl#ACCOUNT_BALANCE_REQUESTS_STREAM_ID})</li>
* <li>{@link DailyExpenditureRequest} (stream: {@link TopologyControl#DAILY_EXPEDITURE_REQUESTS_STREAM_ID})</li>
* <li>{@link TravelTimeRequest} (stream: {@link TopologyControl#TRAVEL_TIME_REQUEST_STREAM_ID})</li>
* </ul>
*
* @author mjsax
**/
public class DispatcherBolt extends BaseRichBolt {
private static final long serialVersionUID = 6908631355830501961L;
private static final Logger LOGGER = LoggerFactory.getLogger(DispatcherBolt.class);
/** The storm provided output collector. */
private OutputCollector collector;
@Override
public void prepare(@SuppressWarnings("rawtypes") Map conf, TopologyContext topologyContext, OutputCollector outputCollector) {
this.collector = outputCollector;
}
@Override
public void execute(Tuple input) {
if(input.getSourceStreamId().equals(TimestampMerger.FLUSH_STREAM_ID)) {
this.collector.emit(TimestampMerger.FLUSH_STREAM_ID, new Values((Object)null));
this.collector.ack(input);
return;
}
String raw = null;
try {
raw = input.getString(1);
String[] token = raw.split(",");
// common attributes of all input tuples
short type = Short.parseShort(token[0]);
Short time = new Short(input.getLong(0).shortValue());
Integer vid = new Integer(Integer.parseInt(token[2]));
assert (time.shortValue() == Short.parseShort(token[1]));
if(type == AbstractLRBTuple.position_report) {
this.collector.emit(TopologyControl.POSITION_REPORTS_STREAM_ID, new PositionReport(//
time,//
vid,//
new Integer(Integer.parseInt(token[3])), // speed
new Integer(Integer.parseInt(token[4])), // xway
new Short(Short.parseShort(token[5])), // lane
new Short(Short.parseShort(token[6])), // direction
new Short(Short.parseShort(token[7])), // segment
new Integer(Integer.parseInt(token[8])))); // position
} else {
// common attribute of all requests
Integer qid = new Integer(Integer.parseInt(token[9]));
switch(type) {
case AbstractLRBTuple.account_balance_request:
this.collector.emit(TopologyControl.ACCOUNT_BALANCE_REQUESTS_STREAM_ID, new AccountBalanceRequest(
time, vid, qid));
break;
case AbstractLRBTuple.daily_expenditure_request:
this.collector.emit(TopologyControl.DAILY_EXPEDITURE_REQUESTS_STREAM_ID,
new DailyExpenditureRequest(time, vid,//
new Integer(Integer.parseInt(token[4])), // xway
qid,//
new Short(Short.parseShort(token[14])))); // day
break;
case AbstractLRBTuple.travel_time_request:
this.collector.emit(TopologyControl.TRAVEL_TIME_REQUEST_STREAM_ID, new TravelTimeRequest(time, vid,//
new Integer(Integer.parseInt(token[4])), // xway
qid,//
new Short(Short.parseShort(token[10])), // S_init
new Short(Short.parseShort(token[11])), // S_end
new Short(Short.parseShort(token[12])), // DOW
new Short(Short.parseShort(token[13])))); // TOD
break;
default:
LOGGER.error("Unkown tuple type: {}", new Short(type));
}
}
} catch(Exception e) {
LOGGER.error("Error in line: {}", raw);
LOGGER.error("StackTrace:", e);
}
this.collector.ack(input);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declareStream(TopologyControl.POSITION_REPORTS_STREAM_ID, PositionReport.getSchema());
outputFieldsDeclarer.declareStream(TopologyControl.ACCOUNT_BALANCE_REQUESTS_STREAM_ID,
AccountBalanceRequest.getSchema());
outputFieldsDeclarer.declareStream(TopologyControl.DAILY_EXPEDITURE_REQUESTS_STREAM_ID,
DailyExpenditureRequest.getSchema());
outputFieldsDeclarer
.declareStream(TopologyControl.TRAVEL_TIME_REQUEST_STREAM_ID, TravelTimeRequest.getSchema());
outputFieldsDeclarer.declareStream(TimestampMerger.FLUSH_STREAM_ID, new Fields("ts"));
}
}