You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
11 KiB

package org.leolo.rail;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Vector;
import org.apache.activemq.transport.stomp.StompFrame;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.leolo.rail.util.TUIDDateFormat;
public class TrainMovementProcessor extends Thread{
private Logger log = LogManager.getLogger(TrainMovementProcessor.class);
private final Object SYNC_TOKEN = new Object();
private Queue<StompFrame> procQueue = new LinkedList<>();
private boolean terminated = false;
public void terminate() {
terminated = true;
synchronized(SYNC_TOKEN) {
SYNC_TOKEN.notifyAll();
}
}
public void process(StompFrame data) {
procQueue.add(data);
synchronized(SYNC_TOKEN) {
SYNC_TOKEN.notifyAll();
}
}
@Override
public void run() {
while(true) {
if(terminated) {
return;
}
StompFrame data = procQueue.poll();
if(data==null) {
synchronized(SYNC_TOKEN) {
try {
// log.debug("No more data. Sleep.");
SYNC_TOKEN.wait(1000);
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
}
}
continue;
}
//Actually handle the data
String msgId = data.getHeaders().get("message-id");
log.info("Processing message {}", msgId);
if(Constants.Generic.DEBUG_MODE) {
new File("tmpd").mkdirs();
try(PrintWriter out = new PrintWriter("tmpd/msg_"+msgId.replace(":", "-")+".json")){
out.println(data.getBody());
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
}
}
HashMap<String, ArrayList<JSONObject>> procMap = new HashMap<>();
JSONArray procData = new JSONArray(data.getBody());
log.info("{} entries expected", procData.length());
for(int i=0;i<procData.length();i++) {
JSONObject obj = procData.getJSONObject(i);
String type = obj.getJSONObject("header").getString("msg_type");
if(!procMap.containsKey(type)) {
procMap.put(type, new ArrayList<>());
}
procMap.get(type).add(obj);
}
//[TA]0001: Train Activation
if(procMap.containsKey("0001")) {
ThreadPoolManager.getInstance().execute(()->{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
TUIDDateFormat tdf = new TUIDDateFormat();
int batchSize = 0;
try(
Connection conn = DatabaseManager.getInstance().getConnection();
PreparedStatement pstmtTA = conn.prepareStatement("REPLACE INTO current_train VALUES (?,?,?,?,?,?)");
){
for(JSONObject obj:procMap.get("0001")) {
String trainId = obj.getJSONObject("body").optString("train_id");
String trainUid = obj.getJSONObject("body").optString("train_uid");
Date startDate;
Date endDate;
Date opDate;
try {
startDate = sdf.parse(obj.getJSONObject("body").optString("schedule_start_date"));
endDate = sdf.parse(obj.getJSONObject("body").optString("schedule_end_date"));
opDate = sdf.parse(obj.getJSONObject("body").optString("tp_origin_timestamp"));
}catch(ParseException e) {
log.error(e.getMessage(), e);
continue;
}
String serviceCode = obj.getJSONObject("body").optString("train_service_code");
long activationTime = obj.getJSONObject("body").optLong("creation_timestamp");
String schSrc = obj.getJSONObject("body").optString("schedule_source");
String tuid;
if("C".equals(schSrc)) {
tuid = trainUid + tdf.format(startDate) + tdf.format(endDate) + "0";
}else {
tuid = trainUid + tdf.format(startDate) + tdf.format(endDate) + "V";
}
// log.debug("[TA] {}({}) TSC:{}", trainId, tuid, serviceCode);
pstmtTA.setString(1, trainId);
pstmtTA.setString(2, tuid);
pstmtTA.setDate(3, new java.sql.Date(opDate.getTime()));
pstmtTA.setString(4, serviceCode);
pstmtTA.setTimestamp(5, new Timestamp(activationTime));
pstmtTA.setString(6, CurrentTrainStatus.ACTIVATED.getCode());
pstmtTA.addBatch();
batchSize++;
}
pstmtTA.executeBatch();
conn.commit();
log.info("[TA] Record Count : {}", batchSize);
}catch(SQLException e){
log.error(e.getMessage(), e);
}
});
}//TA
//[TC]0002: Train Cancellation
if(procMap.containsKey("0002")) {
ThreadPoolManager.getInstance().execute(()->{
int batchSize = 0;
try(
Connection conn = DatabaseManager.getInstance().getConnection();
PreparedStatement pstmtTC = conn.prepareStatement("REPLACE train_cancellation VALUES (?,?,?,?,?,?,?)");
PreparedStatement pstmtUTA = conn.prepareStatement("UPDATE current_train SET `status` = ? WHERE train_id = ?");
){
pstmtUTA.setString(1, CurrentTrainStatus.CANCELLED.getCode());
for(JSONObject obj:procMap.get("0002")) {
String train_id = obj.getJSONObject("body").optString("train_id");
String canx_loc = obj.getJSONObject("body").optString("loc_stanox");
String canx_reason = obj.getJSONObject("body").optString("canx_reason_code");
String canx_type = obj.getJSONObject("body").optString("canx_type");
String canx_dev = obj.getJSONObject("header").optString("source_dev_id");
String canx_usr = obj.getJSONObject("header").optString("user_id");
long canx_time = obj.getJSONObject("body").optLong("canx_timestamp");
// log.debug("[TC] {}@{} because {} by {}@{}", train_id, canx_loc, canx_reason, canx_usr, canx_dev);
pstmtTC.setString(1, train_id);
pstmtTC.setString(2, canx_loc);
pstmtTC.setTimestamp(3, new Timestamp(canx_time));
pstmtTC.setString(4, canx_reason);
pstmtTC.setString(5, canx_type);
setString(pstmtTC,6, canx_dev);
setString(pstmtTC,7, canx_usr);
pstmtTC.addBatch();
pstmtUTA.setString(2, train_id);
int rowCount = pstmtUTA.executeUpdate();
Runnable r = new Runnable() {
int runCount = 0;
@Override
public void run() {
runCount++;
try(
Connection conn = DatabaseManager.getInstance().getConnection();
PreparedStatement pstmtUTA = conn.prepareStatement("UPDATE current_train SET `status` = ? WHERE train_id = ?");
){
pstmtUTA.setString(1, CurrentTrainStatus.CANCELLED.getCode());
pstmtUTA.setString(2, train_id);
int rowCount = pstmtUTA.executeUpdate();
if(rowCount==0) {
if(runCount > 5) {
log.warn("[TC] Cannot update {} [LAST]", train_id);
return;
}
log.warn("[TC] Cannot update {} (ROUND {})", train_id, runCount);
ThreadPoolManager.getInstance().schedule(this, System.currentTimeMillis()+(long)(1000*Math.pow(2, runCount)));
}else {
log.info("[TC] Successfully update {} (ROUND {})", train_id, runCount);
}
conn.commit();
}catch(SQLException e) {
log.error(e.getMessage(), e);
}
}
};
if(rowCount==0) {
log.warn("[TC] Cannot update {}", train_id);
ThreadPoolManager.getInstance().schedule(r, System.currentTimeMillis()+1000);
}
batchSize++;
}
pstmtTC.executeBatch();
conn.commit();
log.info("[TC] Record Count : {}", batchSize);
}catch(SQLException e) {
log.error(e.getMessage(), e);
}
});
}//TC
//[TM]0003: Train Movement
if(procMap.containsKey("0003")) {
ThreadPoolManager.getInstance().execute(()->{
try(
Connection conn = DatabaseManager.getInstance().getConnection();
PreparedStatement pstmtTM = conn.prepareStatement("REPLACE INTO current_train_movement VALUES (?,?,?,?,?,?,?,?,?,?,?,?)");
PreparedStatement pstmtUTA = conn.prepareStatement("UPDATE current_train SET `status` = ? WHERE train_id = ?");
){
int batchSize = 0;
for(JSONObject obj:procMap.get("0003")) {
String trainId = obj.getJSONObject("body" ).optString ("train_id");
long movtTime = obj.getJSONObject("body" ).optLong ("actual_timestamp");
long gbttTime = obj.getJSONObject("body" ).optLong ("gbtt_timestamp", -1);
long planTime = obj.getJSONObject("body" ).optLong ("planned_timestamp", -1);
String stanox = obj.getJSONObject("body" ).optString ("loc_stanox");
String eventType = obj.getJSONObject("body" ).optString ("event_type");
boolean correction= obj.getJSONObject("body" ).optBoolean("correction_ind");
String platform = obj.getJSONObject("body" ).optString ("platform");
String line = obj.getJSONObject("body" ).optString ("line_ind");
String route = obj.getJSONObject("body" ).optString ("route");
String dev = obj.getJSONObject("header").optString ("source_dev_id");
String usr = obj.getJSONObject("header").optString ("user_id");
boolean termInd = obj.getJSONObject("body" ).optBoolean("train_terminated", false);
// log.debug("[TM] {}@{} PLAT {}/{}{} by {}@{}{}", trainId, stanox, platform, line, route, usr, dev,termInd?"[T]":"");
pstmtTM.setString(1, trainId);
pstmtTM.setTimestamp(2, new Timestamp(movtTime));
if(gbttTime==-1) {
pstmtTM.setNull(3, Types.TIMESTAMP);
}else {
pstmtTM.setTimestamp(3, new Timestamp(gbttTime));
}
if(planTime==-1) {
pstmtTM.setNull(4, Types.TIMESTAMP);
}else {
pstmtTM.setTimestamp(4, new Timestamp(planTime));
}
pstmtTM.setString(5, stanox);
pstmtTM.setString(6, eventType);
pstmtTM.setString(7, correction?"Y":"N");
setString(pstmtTM,8, platform);
setString(pstmtTM,9, line);
setString(pstmtTM,10, route);
setString(pstmtTM,11, dev);
setString(pstmtTM,12, usr);
pstmtTM.addBatch();
if(termInd) {
pstmtUTA.setString(1, CurrentTrainStatus.TERMINATED.getCode());
pstmtUTA.setString(2, trainId);
pstmtUTA.addBatch();
}
batchSize++;
}
pstmtTM.executeBatch();
pstmtUTA.executeBatch();
conn.commit();
log.info("[TM] Record Count : {}", batchSize);
}catch(SQLException e) {
log.error(e.getMessage(), e);
}
});
}
}
}
protected void setString(PreparedStatement stmt, int col, String val) throws SQLException{
if(val==null||"".equals(val)) {
stmt.setNull(col, Types.CHAR);
}else {
stmt.setString(col, val);
}
}
}