package com.finance.iso.iso8583.jpos.util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axis2.context.MessageContext;
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.ISOUtil;
import com.finance.iso.iso8583.bean.Transaction;
import com.finance.iso.iso8583.mediator.XLinkAccountInfoWrapper;
import com.finance.iso.iso8583.mediator.XLinkISO8583Util;
import com.finance.iso.iso8583.mediator.XLinkSessionWrapper;
public class XLinkMessageHelper {
private static final String OPERATION_TYPE = "OperationType";
private static final String REVERSAL_PROPERTY = "RevOperationType";
private static final Log log = LogFactory.getLog(XLinkMessageHelper.class);
/**
* @param axis2MsgCtx
* @return
* @throws ISOException
*/
public static ISOMsg createFinacialMessage(MessageContext axis2MsgCtx,org.apache.synapse.MessageContext synCtx,
XLinkAccountInfoWrapper accountInfoWrapper, XLinkSessionWrapper sessionWrapper) throws ISOException {
ISOMsg request = new ISOMsg();
OMElement requestOM = axis2MsgCtx.getEnvelope().getBody()
.getFirstElement();
OMElement operationRequest = requestOM
.getFirstChildWithName((new QName(OPERATION_TYPE)));
// check if the reversal key exists set by the ResponseErrorSequence
String revKey = (String) axis2MsgCtx.getProperty("reversalKey");
if(revKey != null){
log.info("Reversal Key found in MsgCtx: "+revKey);
}
// if above check null, we need to perform with jsonObject tag
if (operationRequest == null) {
log.info("OperationRewquest is null");
OMElement jsonElm = requestOM.getFirstChildWithName((new QName(
"APIRequest")));
if (jsonElm != null) {
log.info("API REquest is not null");
operationRequest = jsonElm.getFirstChildWithName((new QName(
OPERATION_TYPE)));
requestOM = jsonElm;
}
if (axis2MsgCtx.getProperty("FORCE_ERROR_ON_SOURCE_FAULT")!=null){
log.info("Setting Axis2 property");
operationRequest = requestOM.cloneOMElement();
operationRequest.setText("51");
}
}
log.info("Operational REquest: "+operationRequest.getText());
// TODO: Prepare the Reveesal Key here
if (operationRequest != null) {
switch (operationRequest.getText()) {
case "30":
InquiryUtils.createBalanceInquiryMessage(request,requestOM,synCtx, accountInfoWrapper, sessionWrapper);
// createBalanceInquiryMessage(request, requestOM,
// accountInfoWrapper);
break;
case "36":
InquiryUtils.createTransactionHistoryMessage(request,requestOM, synCtx, accountInfoWrapper, sessionWrapper);
// createBalanceInquiryMessage(request, requestOM,
// accountInfoWrapper);
break;
case "37":
InquiryUtils.createInquiryTransferMessage(request,requestOM, synCtx, accountInfoWrapper, sessionWrapper);
// createBalanceInquiryMessage(request, requestOM,
// accountInfoWrapper);
break;
case "38":
InquiryUtils.createInquiryPaymentMessage(request,requestOM, synCtx, accountInfoWrapper, sessionWrapper);
// createBalanceInquiryMessage(request, requestOM,
// accountInfoWrapper);
break;
case "49":
PaymentUtils.createTransferMessage(request, requestOM, accountInfoWrapper, sessionWrapper);
// createPaymentMessage(request, requestOM, accountInfoWrapper);
break;
case "50":
PaymentUtils.createPaymentMessage(request, requestOM, accountInfoWrapper, sessionWrapper);
// createPaymentMessage(request, requestOM, accountInfoWrapper);
break;
case "51":
PaymentUtils.createReversalMessage(request, requestOM, accountInfoWrapper, sessionWrapper, revKey);
// createReversalMessage(request, requestOM, accountInfoWrapper, revKey);
break;
case "56":
PaymentUtils.createTopUpMessage(request, requestOM, accountInfoWrapper, sessionWrapper);
// createPaymentMessage(request, requestOM, accountInfoWrapper);
break;
case "02":
createSignOff(request, requestOM, sessionWrapper);
break;
default:
break;
}
}
log.info("Logging XLink Request");
XLinkISO8583Util.logISOMsg(request);
return request;
}
public static OMElement handleResponse(XLinkSessionWrapper sessionWrapper,
org.apache.axis2.context.MessageContext msgCtx, org.apache.synapse.MessageContext synCtx, ISOMsg m)
throws ISOException, IOException {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMElement apiResponse = fac.createOMElement(new QName("APIResponse"));
String statusCode = (String) m.getValue(39);
String processingCode = (String) m.getValue(3);
msgCtx.setProperty("processingCode", processingCode);
//Failure case
if(statusCode != null && !"00".equals(statusCode) && !"68".equals(statusCode)){
//This code is setting the response to the customer. Before doing this, it needs to generate the proper reversal.
switch (processingCode.substring(0, 2)) {
case "30":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
String revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
OMElement status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
OMElement responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Error occured while trying to query Account Balanace for "+m.getString(102));
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "36":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Error occured while trying to query Account History for "+m.getString(102));
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "37":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Error occured while trying to query Transfer from "+m.getString(102)+" to "+m.getString(103));
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "38":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Payment Inquiry Not Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "49":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Error occured while trying to Transfer "+ m.getString(ISOUtil.unPadLeft(m.getString(4), '0')) +" from "+m.getString(102)+" to "+m.getString(103));
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "50":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Payments Not Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "56":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
revStatusCode = (String) msgCtx.getProperty("RevStatusCode");
status = fac.createOMElement(new QName("StatusCode"));
if(revStatusCode != null){
status.setText(revStatusCode);
}else{
status.setText("1000"+statusCode);
}
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("TopUp Not Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
default:
break;
}
//TODO: Immediately send a REVERSAL. GRAB BIT90 data from RESPONSE
// TODO: FOR SUCCESS CASES, BIT90 sent to client side as reversalKey element and client supposed to send it back to server side.
return apiResponse;
}
// END OF FAILURE
// SUCCESS CASE
if(processingCode == null){
return null;
// Cant return null. Need to return proper response
}
switch (processingCode.substring(0, 2)) {
case "30":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
OMElement status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
OMElement responseData = fac.createOMElement(new QName("ResponseData"));
apiResponse.addChild(responseData);
Map<String, String> decodedBalance = decodeBalance((String)m.getValue(54));
for (Iterator iterator = decodedBalance.entrySet().iterator(); iterator
.hasNext();) {
Entry<String, String> type = (Entry<String, String>) iterator.next();
OMElement balance = fac.createOMElement(new QName(type.getKey()));
balance.setText(type.getValue());
responseData.addChild(balance);
}
if (m.getValue(39).equals("00")) {
String reversalKey = "0200" + m.getValue(11) + m.getValue(7)
+ m.getValue(37);
OMElement revkey = fac
.createOMElement(new QName("ReversalKey"));
revkey.setText(reversalKey);
responseData.addChild(revkey);
// Also add to the messageContext to initiate reversal if the response
// link is down
synCtx.setProperty("reversalKey", reversalKey);
}
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "36":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("ResponseData"));
apiResponse.addChild(responseData);
//Deocing the response.
List<Transaction> decodeTxnHistory = decodeTxnHistory(m.getString(62));
OMElement transactions = fac.createOMElement(new QName("Transactions"));
responseData.addChild(transactions);
for (Transaction transaction : decodeTxnHistory) {
OMElement txn = fac.createOMElement(new QName("Transaction"));
OMElement date = fac.createOMElement(new QName("Date"));
date.setText(transaction.getDate());
OMElement amountT = fac.createOMElement(new QName("Amount"));
amountT.setText(transaction.getAmount());
OMElement currency = fac.createOMElement(new QName("Currency"));
currency.setText(transaction.getCurrency());
OMElement txnType = fac.createOMElement(new QName("TxnType"));
txnType.setText(transaction.getTxnType());
txn.addChild(date);
txn.addChild(amountT);
txn.addChild(currency);
txn.addChild(txnType);
transactions.addChild(txn);
}
// Building the reversalKey
if (m.getValue(39).equals("00")) {
String reversalKey = "0200" + m.getValue(11) + m.getValue(7)
+ m.getValue(37);
OMElement revkey = fac
.createOMElement(new QName("ReversalKey"));
revkey.setText(reversalKey);
responseData.addChild(revkey);
// Also add to the messageContext to initiate reversal if the response
// link is down
synCtx.setProperty("reversalKey", reversalKey);
}
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "37":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("ResponseData"));
apiResponse.addChild(responseData);
OMElement destinationAcct = fac.createOMElement(new QName("DestinationAccountNo"));
destinationAcct.setText(m.getString(103));
responseData.addChild(destinationAcct);
OMElement destinationBankCode = fac.createOMElement(new QName("DestinationBankCode"));
destinationBankCode.setText(m.getString(127));
responseData.addChild(destinationBankCode);
OMElement DestinationAccountType = fac.createOMElement(new QName("DestinationAccountType"));
DestinationAccountType.setText(m.getString(3).substring(4));
responseData.addChild(DestinationAccountType);
Map<String, String> decodeBit61 = decodeBit61(m.getString(61));
if(decodeBit61!=null){
for (Iterator iterator = decodeBit61.entrySet().iterator(); iterator
.hasNext();) {
Entry<String, String> type = (Entry<String, String>) iterator.next();
OMElement balance = fac.createOMElement(new QName(type.getKey()));
balance.setText(type.getValue());
responseData.addChild(balance);
}
}
OMElement inquiryAmount = fac.createOMElement(new QName("InquiryAmount"));
inquiryAmount.setText(ISOUtil.unPadLeft(m.getString(4), '0'));
responseData.addChild(inquiryAmount);
// Building the reversalKey
if (m.getValue(39).equals("00")) {
String reversalKey = "0200" + m.getValue(11) + m.getValue(7)
+ m.getValue(37);
OMElement revkey = fac
.createOMElement(new QName("ReversalKey"));
revkey.setText(reversalKey);
responseData.addChild(revkey);
// Also add to the messageContext to initiate reversal if the response
// link is down
synCtx.setProperty("reversalKey", reversalKey);
}
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "38":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Inquiry Payment Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "49":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("ResponseData"));
apiResponse.addChild(responseData);
destinationAcct = fac.createOMElement(new QName("DestinationAccountNo"));
destinationAcct.setText(m.getString(103));
responseData.addChild(destinationAcct);
destinationBankCode = fac.createOMElement(new QName("DestinationBankCode"));
destinationBankCode.setText(m.getString(127));
responseData.addChild(destinationBankCode);
OMElement messageIdNode = fac.createOMElement(new QName("MessageId"));
messageIdNode.setText(m.getString(37).substring(6));
responseData.addChild(messageIdNode);
decodeBit61 = decodeBit61(m.getString(61));
if(decodeBit61!=null){
for (Iterator iterator = decodeBit61.entrySet().iterator(); iterator
.hasNext();) {
Entry<String, String> type = (Entry<String, String>) iterator.next();
OMElement balance = fac.createOMElement(new QName(type.getKey()));
balance.setText(type.getValue());
responseData.addChild(balance);
}
}
OMElement transferedAmount = fac.createOMElement(new QName("TransferedAmount"));
transferedAmount.setText(ISOUtil.unPadLeft(m.getString(4), '0'));
responseData.addChild(transferedAmount);
// Building the reversalKey
if (m.getValue(39).equals("00")) {
String reversalKey = "0200" + m.getValue(11) + m.getValue(7)
+ m.getValue(37);
OMElement revkey = fac
.createOMElement(new QName("ReversalKey"));
revkey.setText(reversalKey);
responseData.addChild(revkey);
// Also add to the messageContext to initiate reversal if the response
// link is down
synCtx.setProperty("reversalKey", reversalKey);
}
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "50":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("Payment Not Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
case "56":
msgCtx.getEnvelope().getBody().getFirstElement().detach();
status = fac.createOMElement(new QName("StatusCode"));
status.setText("0000"+statusCode);
apiResponse.addChild(status);
responseData = fac.createOMElement(new QName("Reason"));
responseData.setText("TopUp Not Supported for this channel.");
apiResponse.addChild(responseData);
msgCtx.getEnvelope().getBody().addChild(apiResponse);
break;
default:
break;
}
return apiResponse;
}
// private static void createBalanceInquiryMessage(ISOMsg request,
// OMElement requestOM, XLinkAccountInfoWrapper accountInfoWrapper)
// throws ISOException {
//
//
// request.setMTI("0200");
// request.set(2, accountInfoWrapper.getAccountno()); // PAN:123456789
// request.set(3, "300000"); // 300000
// request.set(7, "0421080000");
// request.set(11, NetworkMgtUtil.getRandomNumber());
// request.set(12, "080000");
// request.set(13, "0421");
// request.set(14, "0422");
// request.set(18, "6017");
// request.set(24, "000");
// request.set(32, "950");
// String track2Data = "Hello World!";// TODO: Get proper Track2 data
// request.set(35, track2Data);
// request.set(37, "042112345678"); // TrxId 12345678
// request.set(41, "12345678"); // Needd to know
// request.set(42, "123456789123456"); // Need to know
// request.set(43, "50 AMOY STREET SINGAPORE 069876 SG");
// request.set(49, "IDR");
// char[] array=new char[]{'C','7','4','B','1','D','B','3','2','8','8','A','C','1','5','C'};
// request.set(52,new String(array).getBytes());
// request.set(102, "123456789"); // SAME as PAN
// }
private static void createReversalMessage(ISOMsg request,
OMElement requestOM, XLinkAccountInfoWrapper accountInfoWrapper, String revKey)
throws ISOException {
request.setMTI("0400");
request.set(2, "123456789"); // PAN:123456789
request.set(3, "500100"); // 300100 AccType 01-Savings Account
request.set(4, "1500");
request.set(7, "0421080000");
request.set(11, "000000000083");
request.set(14, "0422");
request.set(18, "6017");
request.set(24, "000");
request.set(32, "950");
request.set(37, "042112345678"); // TrxId 12345678
request.set(41, "12345678"); // Need to know
request.set(42, "123456789123456"); // Need to know
request.set(49, "IDR");
request.set(61, "This is MBSB");
request.set(90, revKey);// From
// prevously
// done Trx
request.set(98, "000000"); // ON US
request.set(100, "950");// Need to know
request.set(102, "123456789"); // SAME as PAN
request.set(103, "123456788"); // REMOTE PAN
request.set(127, "123456799"); // From previous Trx
}
// private static void createPaymentMessage(ISOMsg request,
// OMElement requestOM, XLinkAccountInfoWrapper accountInfoWrapper)
// throws ISOException {
//
// request.setMTI("0200");
// request.set(2, accountInfoWrapper.getAccountno()); // PAN:123456789
// request.set(3, "500100"); // 300100 AccType 01-Savings Account
// request.set(4, requestOM.getFirstChildWithName(new QName("Amount"))
// .getText());
// request.set(7, "0421080000"); // for 90
// request.set(11, NetworkMgtUtil.getRandomNumber()); //for 90
// request.set(12, "080000");
// request.set(13, "0421");
// request.set(14, "0422");
// request.set(18, "6017");
// request.set(24, "000");
// request.set(32, "950");
// String track2Data = ";" + accountInfoWrapper.getAccountno()
// + "=1408900543?";// PAN-123456789 ExpiryDate-14/08
// // SeerviceCode-900 CVC-543
// byte LRC = SecurityUtils.calculateLRC(track2Data.getBytes());
// String LRCChar = new String(new byte[] { LRC });
// request.set(35, track2Data + LRCChar);
// request.set(37, requestOM.getFirstChildWithName(new QName("TrxId"))
// .getText()); // TrxId 12345678 // for 90
// request.set(41, "12345678"); // Needd to know
// request.set(42, "123456789123456"); // Need to know
// request.set(43, "50 AMOY STREET SINGAPORE 069876 SG");
// request.set(49, requestOM.getFirstChildWithName(new QName("Currency"))
// .getText());
// char[] array=new char[]{'C','7','4','B','1','D','B','3','2','8','8','A','C','1','5','C'};
// request.set(52,new String(array).getBytes());
// request.set(61, "This is MBSB");
// request.set(98, "000000"); // ON US
// request.set(102, "123456789"); // SAME as PAN
//
// System.out.println("PAYMENT SENDING");
// XLinkISO8583Util.logISOMsg(request);
// }
private static void createSignOff(ISOMsg request, OMElement requestOM, XLinkSessionWrapper sessionWrapper)
throws ISOException {
// TODO Auto-generated method stub
NetworkMgtUtil.createSignOffMessage(request, sessionWrapper.getNextRequestId());
}
private static Map<String,String> decodeBalance(String originalString){
Map<String,String> hashTable=new java.util.Hashtable<String, String>();
hashTable.put("AccountType", originalString.substring(0,2));
hashTable.put("AmountType", originalString.substring(2,4));
hashTable.put("CurrencyCode", originalString.substring(4,7));
hashTable.put("BalanceType", originalString.substring(7,8));
hashTable.put("BalanceAmount", ISOUtil.unPadLeft(originalString.substring(8,24), '0'));
return hashTable;
}
private static List<Transaction> decodeTxnHistory(String originalString){
String[] transactionArray = originalString.split("(?<=\\G.{28})");
List<Transaction> txnList=null;
if(transactionArray != null){
txnList=new ArrayList<Transaction>();
for (String string : transactionArray) {
String txnDate = string.substring(0, 6).trim();
String[] amountCurArray = string.substring(6, 27).trim().split(" ");
String amount = amountCurArray[0];
String currency = amountCurArray[1];
String txnType = string.substring(27).trim();
Transaction txn=new Transaction(txnDate, amount, currency, txnType);
txnList.add(txn);
}
}
return txnList;
}
private static Map<String,String> decodeBit61(String originalString){
Map<String,String> hashTable=new java.util.Hashtable<String, String>();
try {
hashTable.put("ToAccountName", ISOUtil.unPadRight(originalString.substring(0,30), ' '));
hashTable.put("FromAccountName", ISOUtil.unPadRight(originalString.substring(30,60), ' '));
hashTable.put("RefNumber", ISOUtil.unPadRight(originalString.substring(60,76), ' '));
hashTable.put("ToCurCode", originalString.substring(76,79));
hashTable.put("FromCurCode", originalString.substring(79,82));
hashTable.put("CurRate", ISOUtil.unPadRight(originalString.substring(82), ' '));
} catch (Exception e) {
log.error("Error occured while decoding the BIT 61",e);
}
return hashTable;
}
}