package com.finance.iso.iso8583.mediator;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOMsg;
import org.jpos.iso.ISOPackager;
import org.jpos.iso.channel.PostChannel;
import com.finance.iso.iso8583.jpos.util.NetworkMgtUtil;
public class XLinkChannel extends PostChannel implements Runnable {
private static final Log log = LogFactory.getLog(XLinkChannel.class);
volatile boolean responseReceived = false;
volatile boolean stopped = false;
volatile ISOMsg response = null;
Thread receiver = null;
private String msisdnKey;
private List<String> expiredListRef;
private Date lastTxTime = null;
private long lastRequestTime = 0;
private boolean isFinMsg=false;
private int DEFAULT_TIMER_RATE= 180;
private static final int TRANSACTION_ECHO_VALIDATE = 180000; //should be 3 min
private static int requestId=0;
private Timer statusTimer;
public XLinkChannel(String host, int port, ISOPackager p) {
super(host, port, p);
//Each X-Link Channel has timer object to check the status of the connectivity
statusTimer = new Timer();
statusTimer.scheduleAtFixedRate(new ChannelStatusCheckTimerHander(this), 0,
DEFAULT_TIMER_RATE * 1000);
}
@Override
public void connect() throws IOException {
super.connect();
receiver = new Thread(this);
receiver.start();
}
@Override
public void disconnect() throws IOException {
super.disconnect();
log.info("Disconnectig Channel");
//Timer should end when the X-link channel disconnect and disposed
statusTimer.cancel();
stopped = true;
if(!expiredListRef.contains(msisdnKey)){
log.info("Adding to expired Session List "+msisdnKey);
expiredListRef.add(msisdnKey);
}
}
public void run() {
while (!stopped) {
try {
ISOMsg message = super.receive();
if (isEchoTest(message)) {
handleEchoTest(message);
} else if (isSignOff(message)) {
synchronized (this) {
responseReceived = true;
notify();
this.disconnect();
}
} else {
// This is a response
synchronized (this) {
response = message;
responseReceived = true;
notify();
}
}
} catch (IOException e) {
try {
this.disconnect();
//expiredListRef.add(msisdnKey);
e.printStackTrace();
log.error("Disconnecting IO Error!!!! @@@");
} catch (IOException e1) {
log.error("Error while terminating XLink channel", e);
expiredListRef.add(msisdnKey);
}
} catch (ISOException e) {
log.error(
"XLink Terminated connector or client has terminated the connection",
e);
try {
this.disconnect();
//expiredListRef.add(msisdnKey);
System.out.println("Disconnecting!!!!");
} catch (IOException e1) {
log.error("Error while terminating XLink channel", e);
}
}
}
log.info("Channel Stopped");
}
private void handleEchoTest(ISOMsg message) throws ISOException,
IOException {
System.out.println("Handling XLink initated EchoTest");
XLinkISO8583Util.logISOMsg(message);
message.set(XLinkISO8583Constant.FIELD_RESPONSE_CODE, XLinkISO8583Constant.RESPONSE_CODE_SUCCESS);
message.setResponseMTI();
XLinkISO8583Util.logISOMsg(message);
super.send(message);
}
private boolean isEchoTest(ISOMsg message) throws ISOException {
String mti = message.getMTI();
if ((mti != null) && mti.equals(XLinkISO8583Constant.NETWORK_REQ_MSG_MTI)) {
String netMgtIdCode = (String) message.getValue(XLinkISO8583Constant.FIELD_NET_MGT_ID_CODE);
if ((netMgtIdCode != null) && netMgtIdCode.equals(XLinkISO8583Constant.NET_MGT_ID_CODE_ECHO_TEST)) {
return true;
}
}
return false;
}
private boolean isSignOff(ISOMsg message) throws ISOException {
String mti = message.getMTI();
XLinkISO8583Util.logISOMsg(message);
if ((mti != null) && mti.equals(XLinkISO8583Constant.NETWORK_RES_MSG_MTI)) {
String netMgtIdCode = (String) message.getValue(XLinkISO8583Constant.FIELD_NET_MGT_ID_CODE);
if ((netMgtIdCode != null) && netMgtIdCode.equals(XLinkISO8583Constant.NET_MGT_ID_CODE_SIGN_OFF)) {
return true;
}
}
return false;
}
@Override
public void send(ISOMsg m) throws IOException, ISOException {
responseReceived = false;
response = null;
if(m.getMTI().equals("0200")){
lastRequestTime=System.currentTimeMillis();
isFinMsg=true;
}else{
isFinMsg=false;
lastRequestTime=0;
}
super.send(m);
}
@Override
public ISOMsg receive() throws IOException, ISOException {
//Is this the culprit
log.info("Trying to Aquire the Channel lock");
synchronized (this) {
log.info("Channel lock aquired");
log.info("Channel waiting for response for 60000 ms");
log.info("Has responseReceived: "+responseReceived);
//Why a while not If?
// while (!responseReceived && !hasTimeedOut) {
try {
log.info("Wait Start Time: "+System.currentTimeMillis());
wait(60000);
log.info("Wait End Time: "+System.currentTimeMillis());
} catch (InterruptedException ignore) {
log.info("Receive Wait INterrupted");
}
// }
log.info("Channel waiting finished for response");
}
log.info("Channel lock released");
return response;
}
public String getMsisdnKey() {
return msisdnKey;
}
public void setMsisdnKey(String msisdnKey) {
this.msisdnKey = msisdnKey;
}
public void setExpiredListRef(List<String> expiredListRef) {
this.expiredListRef = expiredListRef;
}
public List<String> getExpiredListRef() {
return expiredListRef;
}
public Date getLastTxTime() {
return lastTxTime;
}
public void setLastTxTime(Date lastTxTime) {
this.lastTxTime = lastTxTime;
}
public String getNextRequestId(){
return ++requestId+"";
}
private class ChannelStatusCheckTimerHander extends TimerTask {
private XLinkChannel channel;
public ChannelStatusCheckTimerHander(XLinkChannel channel) {
super();
this.channel = channel;
}
@Override
public void run() {
// TODO Auto-generated method stub
if(stopped){
this.cancel();
return;
}
if (lastTxTime != null) {
Date now = Calendar.getInstance().getTime();
// if last transX time - current greater than 20 mins
if ((now.getTime() - lastTxTime.getTime()) >= TRANSACTION_ECHO_VALIDATE) {
ISOMsg request = new ISOMsg();
try {
NetworkMgtUtil.createEchoTestMessage(request, getNextRequestId());
int retryCount = 0;
ISOMsg response = null;
while (retryCount < XLinkISO8583Constant.ECHO_TEST_RETRY_COUNT) {
try {
log.warn("echo test performing for msisdn " +msisdnKey);
channel.send(request);
response = channel.receive();
//TODO: Handle and Validate the ECHO TEST RESPONSE and BREAK the LOOP
break;
} catch (Exception e) {
retryCount++;
}
}
if (retryCount == XLinkISO8583Constant.ECHO_TEST_RETRY_COUNT) {
channel.disconnect();
if (!channel.getExpiredListRef()
.contains(msisdnKey)) {
channel.getExpiredListRef().add(msisdnKey);
}
log.info("### Last Tx exceeds 180seconds and echo failed closing session");
this.cancel();
}
} catch (ISOException e) {
log.error("{Status expiary checking} unexpected error",
e);
} catch (IOException e) {
log.error("{Status expiary checking} unexpected error",
e);
}
}
}
}
}
}