Untuk memudahkan pembelajaran silahkan diawali melalui link berikut ini terlebih dahulu Bab 1

Thursday, January 30, 2014

Implementasi Menggunakan Java

Implementasi Menggunakan Java


Nah setelah kita mengetahui format message ISO 8583, sekarang bagaimana meng-implementasikan-nya pada bahasa pemrograman Java ? Sebelum kita menulis kode, yang harus kita lakukan pertama kali yaitu adalah menyusun spesifikasi yang akan kita gunakan untuk berkomunikasi. Pada kenyataan-nya, spesifikasi ini sangat penting peranan-nya dan ada kemungkin tiap vendor mempunyai spesifikasi yang berbedaantara satu dengan yang lain. Sebagai catatan, perhatikan betul-betul spesifikasi yang sudah disepakati bersama. Dan sekarang, bagaimanakah cara membuat sebuah spesifikasi untuk message ISO 8583dan implementasi-nya pada bahasa pemrograman Java akan kita bahas pada bab-bab dibawah ini :

  • Pembuatan Spesifikasi Message Network Management
  • Pembuatan Aplikasi Server
  • Pembuatan Aplikasi Client
  • Testing
  • Pembuatan Spesifikasi Message Network Management

    Agar komunikasi antara server dan client dapat berjalan dengan sukses, maka diperlukan sebuah kesepakatan yang harus ditaati oleh kedua belah pihak. Beberapa persyaratan tersebut yaitu mencakup tentang :
    1. Message Protokol, protokol yang akan digunakan dalam contoh kasus ini adalah ISO 8583:1993 yang ditandai dengan angka 1 (satu) pada MTI (Message Type Indicator).
    2. Connection Type, mode koneksi yang akan digunakan adalah mode connection-oriented dimana client membuka koneksi ke server sekali dan mengirimkan banyak message (connect once -> many transaction)
    3. Message System, untuk seluruh message yang dikirimkan ke server harus menggunakan 4 bit header sebagai penanda panjang message yang dikirimkan
    Dan dibawah ini adalah format message Network Management Request/Response :
    1. NETWORK MANAGEMENT REQUEST
      1. Message Type Identifier : 1800
      2. Sender : Client
      3. Purpose : Request network management action to Server
      4. Data ElementNameSubfieldTypeLengthFormatDescription
        MTIN4For request use 1800
        1BitmapH16Use field = 3,7,11,12,13,48 and 70
        3Processing CodeN6Default set to 000001
        7Transmission Date and TimeN8yyyyMMddTransmission Date and Time
        11System Trace Audit NumberN6zero-left-paddingUnique number from client
        12Local time transactionN6HHmmssTransaction time from client
        13Date local transactionN4mmddDate transaction from client
        48Additional Private DataN3zero-left-paddingLenght of Additional Private Data
        48Additional Private DataClientIDN7zero-left-paddingClient identification number
        70Network Information CodeN3001=sign-on, 002=sign-off, 003=echo-test
    2. NETWORK MANAGEMENT RESPONSE
      1. Message Type Identifier : 1810
      2. Sender : Server
      3. Purpose : Response network management action for Client
      4. Data ElementNameSubfieldTypeLengthFormatDescription
        MTIN4For request use 1800
        1BitmapH16Use field = 3,7,11,12,13,39,48 and 70
        3Processing CodeN6Default set to 000001
        7Transmission Date and TimeN8yyyyMMddTransmission Date and Time
        11System Trace Audit NumberN6zero-left-paddingUnique number from client
        12Local time transactionN6HHmmssTransaction time from client
        13Date local transactionN4mmddDate transaction from client
        39Response CodeN3Available Response Code :

        1. 000 = Successfull
        2. 001 = Timeout from Server
        3. 002 = Invalid Network Information Code
        4. 003 = Invalid Processing Code
        48Additional Private DataN3zero-left-paddingLenght of Additional Private Data
        48Additional Private DataClientIDN7zero-left-paddingClient identification number
        70Network Information CodeN3001=sign-on, 002=sign-off, 003=echo-test
    Pembuatan spesifikasi untuk message Network Management sudah selesai, sekarang mari kita implementasikan dengan membuat sebuah aplikasi server-nya dahulu.

    Pembuatan Aplikasi Server

    Sekarang buatlah sebuah project Java biasa pada NetBeans IDE dan berilah nama project tersebut contohnya Implementasi, dan buatlah sebuah package dahulu dengan namaid.web.martinusadyh.iso8583.helper. Didalam package yang telah kita buat, buatlah sebuah helper class dengan nama DecimalHexBinaryConverter.java yang mempunyai fungsi sebagai konverter ketika kita ingin menghitung nilai Bitmap yang kurang lebih seperti kode dibawah ini :
    1. id.web.martinusadyh.iso8583.helper.DecimalHexBinaryConverter.java
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      
      package id.web.martinusadyh.iso8583.helper;
       
      public class DecimalHexBinaryConverter {
       
          public static String decimalToHexa(Integer decimalNumber) {
              return Integer.toHexString(decimalNumber);
          }
       
          public static String decimalToBinary(Integer decimalNumber) {
              StringBuilder binaryNumber = new StringBuilder();
              StringBuilder sbBinary = new StringBuilder();
              String binaryString = Integer.toBinaryString(decimalNumber);
              char[] binary = binaryString.toCharArray();
              int counter = 0;
              // ambil dari index karakter terakhir
              for (int i=binary.length-1; i>=0; i--) {
                  counter++;
                  sbBinary.append(binary[i]);
                  // reset counter ke nol jika berhasil mengambil 4 digit karakter
                  if (counter == 4) counter = 0;
              }
       
              // 4 adalah panjang karakter tiap blok di binary
              // ex: dec [100] == binary [0110 0100]
              for (int i=0; i<4-counter; i++) {
                  if (counter > 0) sbBinary.append("0");
              }
       
              // sekarang dibalik
              for (int i=sbBinary.length()-1; i>=0;i--) {
                  binaryNumber.append(sbBinary.toString().charAt(i));
              }
       
              return binaryNumber.toString();
          }
       
          public static Integer binaryToDecimal(String binaryNumber) {
              return Integer.parseInt(binaryNumber, 2);
          }
       
          public static String binaryToHexa(String binaryNumber) {
              return decimalToHexa(binaryToDecimal(binaryNumber));
          }
       
          public static Integer hexaToDecimal(String hexaNumber) {
              return Integer.parseInt(hexaNumber, 16);
          }
       
          public static String hexaToBinary(String hexaNumber) {
              return decimalToBinary(hexaToDecimal(hexaNumber));
          }
      }
    Setelah selesai membuat konverter dari HexaToBinary dan sebalik-nya, sekarang buatlah sebuah Helper Class lagi yang fungsinya kali ini lebih berkaitan dengan field-field yang terdapat dalam format ISO 8583seperti mencari panjang bitmap yang sebenar-nya, mencari data element yang aktif dalam sebuah message dan lain-lain. Sekarang buatlah sebuah Java Class dengan nama ISOUtil didalam packageid.web.martinusadyh.iso8583.helper yang isinya kurang lebih adalah sebagai berikut :
    1. id.web.martinusadyh.iso8583.helper.ISOUtil.java
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      
      package id.web.martinusadyh.iso8583.helper;
       
      public class ISOUtil {
       
          /** Mencari panjang dari Bitmap 16 karakter atau 32 karakter, jika bit pertama
           * nilai-nya == 1 (active/TRUE) maka secondary bitmap active dan otomatis
           * panjang bitmap menjadi 32 karakter.
           * @param originalMsg message asli ISO beserta dengan MTI-nya
           * @return panjang bitmap yang harus di potong / diambil.
           */
          public static Integer findLengthOfBitmap(String originalMsg) {
              // ambil 1 digit bitmap setelah MTI
              String bitPertama = originalMsg.substring(4,5);
              int panjangBitmap = 0;
              // cek nilai binary-nya
              if (DecimalHexBinaryConverter.hexaToBinary(bitPertama).substring(0, 1).equalsIgnoreCase("1")) {
                  panjangBitmap = 32;
              } else {
                  panjangBitmap = 16;
              }
       
              return panjangBitmap;
          }
       
          public static String getHexaBitmapFromActiveDE(int[] activeDE) {
              StringBuilder finalHexaBitmap = new StringBuilder();
              StringBuilder binaryBitmapForReply = new StringBuilder();
       
              boolean secondarBitmapActive = false;
              int panjangBitmap = 16;
              // pengecekan secondary bitmap
              for (int i=0; i<activeDE.length;i++) {
                  if (activeDE[i] > 64) {
                      secondarBitmapActive = true;
                      panjangBitmap = 32;
                  }
              }
       
              // x4 untuk mendapatkan jumlah seluruh data elemen
              panjangBitmap *= 4;
              int counterBitmap=0;
              String active = "";
              for (int i=0;i<panjangBitmap; i++) {
                  counterBitmap++;
                  active = "0";
                  for (int j=0; j<activeDE.length; j++) {
                      if (counterBitmap == activeDE[j]) active = "1";
                  }
       
                  binaryBitmapForReply.append(active);
              }
       
              // karena secondary bitmap active, bit pertama ganti jadi 1
              if (secondarBitmapActive) {
                  binaryBitmapForReply = new StringBuilder("1"+binaryBitmapForReply.toString().substring(1, binaryBitmapForReply.length()));
              }
       
              char[] binaryBitmapChar = binaryBitmapForReply.toString().toCharArray();
              int counter = 0;
              StringBuilder sb = new StringBuilder();
              for (int i=0;i<binaryBitmapChar.length;i++) {
                  sb.append(binaryBitmapChar[i]);
                  counter++;
       
                  if (counter == 4) {
                      finalHexaBitmap.append(DecimalHexBinaryConverter.binaryToHexa(sb.toString()));
                      sb = new StringBuilder();
                      counter=0;
                  }
              }
       
              return finalHexaBitmap.toString();
          }
       
          public static String findMTI(String originalMsg) {
              return originalMsg.substring(0, 4);
          }
       
          public static String findBinaryBitmapFromHexa(String hexaBitmap) {
              StringBuilder binaryBitmap = new StringBuilder();
              char[] rawBitmap = hexaBitmap.toCharArray();
              for (int i=0; i<rawBitmap.length; i++) {
                  binaryBitmap.append(DecimalHexBinaryConverter.hexaToBinary(String.valueOf(rawBitmap[i])));
              }
       
              return binaryBitmap.toString();
          }
       
          public static String findActiveDE(String binaryBitmap) {
              StringBuilder activeDE = new StringBuilder();
              char[] charBinaryBitmap = binaryBitmap.toCharArray();
              int counter = 0;
              for (int i=0;i<charBinaryBitmap.length;i++) {
                  counter++;
                  if (String.valueOf(charBinaryBitmap[i]).equals("1")) activeDE.append(String.valueOf(counter) + ";");
              }
       
              return activeDE.toString();
          }
      }
    Sampai disini proses pembuatan Helper Class sudah selesai dan siap untuk digunakan, sekarang mari saat-nya kita membuat sebuah implementasi server-nya :) Implementasi server ini akan kita buat dengan menggunakan ServerSocket standart dari Java, jadi kita tidak memerlukan lagi tambahan library lain. Sekarang buatlah sebuah class baru dengan nama ServerISO dan simpanlah pada packageid.web.martinusadyh.iso8583.socket yang isinya kurang lebih seperti kode dibawah ini :
    1. id.web.martinusadyh.iso8583.socket.ServerISO.java
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      175
      176
      177
      178
      179
      180
      181
      182
      183
      184
      185
      186
      187
      188
      189
      190
      191
      192
      193
      194
      195
      196
      197
      198
      199
      200
      201
      202
      203
      204
      205
      206
      207
      
      package id.web.martinusadyh.iso8583.socket;
       
      import id.web.martinusadyh.iso8583.helper.ISOUtil;
      import java.io.IOException;
      import java.io.InputStreamReader;
      import java.io.PrintWriter;
      import java.net.ServerSocket;
      import java.net.Socket;
      import java.util.HashMap;
      import java.util.Map;
       
      /**
       *
       * @author Martinus Ady H <mrt.itnewbies@gmail.com>
       */
      public class ServerISO {
       
          private static final Integer PORT = 12345;
          private static final Map<String, Integer> mappingDENetworkMsg = new HashMap<String, Integer>();
       
          /* Method ini berfungsi untuk menginisialisasi data element dan panjang tiap
           * -tiap data element yang aktif */
          private static void initMappingDENetworkRequest() {
              /* [data-element] [panjang data element] */
              mappingDENetworkMsg.put("3", 6);
              mappingDENetworkMsg.put("7", 8);
              mappingDENetworkMsg.put("11", 6);
              mappingDENetworkMsg.put("12", 6);
              mappingDENetworkMsg.put("13", 4);
              mappingDENetworkMsg.put("39", 3);
              mappingDENetworkMsg.put("48", 999);
              mappingDENetworkMsg.put("70", 3);
          }
       
          /**
           * @param args the command line arguments
           */
          public static void main(String[] args) throws IOException {
              initMappingDENetworkRequest();
              ServerSocket serverSocket = new ServerSocket(PORT);
              System.out.println("Server siap menerima koneksi pada port ["+PORT+"]");
              Socket socket = serverSocket.accept();
              InputStreamReader inStreamReader = new InputStreamReader(socket.getInputStream());
              PrintWriter sendMsg = new PrintWriter(socket.getOutputStream());
       
              int data;
              StringBuffer sb = new StringBuffer();
              int counter = 0;
       
              // tambahan 4 karakter karena msg header adalah 4 digit msg length
              int lengthOfMsg = 4;
              while((data = inStreamReader.read()) != 0) {
                  counter++;
                  sb.append((char) data);
                  if (counter == 4) lengthOfMsg += Integer.valueOf(sb.toString());
       
                  // klo panjang msg dari MTI sampai END OF MSG sama dengan nilai
                  // header maka lanjutkan ke method processingMsg();
                  if (lengthOfMsg == sb.toString().length()) {
                      System.out.println("Rec. Msg ["+sb.toString()+"] len ["+sb.toString().length()+"]");
                      processingMsg(sb.toString(), sendMsg);
                  }
              }
          }
       
          /** Memproses msg yang dikirim oleh client berdasarkan nilai MTI.
           * @param data request msg yang berisi [header 4byte][MTI][BITMAP][DATA ELEMENT]
           * @param sendMsg object printWriter untuk menuliskan msg ke network stream
           */
          private static void processingMsg(String data, PrintWriter sendMsg) {
              // msg.asli tanpa 4 digit msg.header
              String origMsgWithoutMsgHeader = data.substring(4, data.length());
       
              // cek nilai MTI
              if (ISOUtil.findMTI(origMsgWithoutMsgHeader).equalsIgnoreCase("1800")) {
                  handleNetworkMsg(origMsgWithoutMsgHeader, sendMsg);
              }
          }
       
          /** Method ini akan memproses network management request dan akan menambahkan
           * 1 data element yaitu data element 39 (response code) 000 ke client/sender
           * @param networkMsg request msg yang berisi [header 4byte][MTI][BITMAP][DATA ELEMENT]
           * @param sendMsg object printWriter untuk menuliskan msg ke network stream
           */
          private static void handleNetworkMsg(String networkMsg, PrintWriter sendMsg) {
              int panjangBitmap = ISOUtil.findLengthOfBitmap(networkMsg);
              String hexaBitmap = networkMsg.substring(4, 4+panjangBitmap);
       
              // hitung bitmap
              String binaryBitmap = ISOUtil.findBinaryBitmapFromHexa(hexaBitmap);
              String[] activeDE = ISOUtil.findActiveDE(binaryBitmap).split(";");
       
              StringBuilder networkResp = new StringBuilder();
       
              // setting MTI untuk reply network request
              networkResp.append("1810");
       
              // untuk reply, DE yang aktif adalah DE[3,7,11,12,13,39,48 dan 70]
              String bitmapReply = ISOUtil.getHexaBitmapFromActiveDE(new int[] {3,7,11,12,13,39,48, 70});
              networkResp.append(bitmapReply);
       
              // index msg dimulai dr (4 digit MTI+panjang bitmap = index DE ke 3)
              int startIndexMsg = 4+ISOUtil.findLengthOfBitmap(networkMsg);
              int nextIndex = startIndexMsg;
              String sisaDefaultDE = "";
       
              // ambil nilai DE yang sama dulu
              for (int i=0;i<activeDE.length;i++) {
                  // ambil bit ke 3
                  if (activeDE[i].equalsIgnoreCase("3")) {
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      networkResp.append(networkMsg.substring(startIndexMsg, nextIndex));
                      debugMessage(3, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("7")) {
                      startIndexMsg = nextIndex;
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      networkResp.append(networkMsg.substring(startIndexMsg, nextIndex));
                      debugMessage(7, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("11")) {
                      startIndexMsg = nextIndex;
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      networkResp.append(networkMsg.substring(startIndexMsg, nextIndex));
                      debugMessage(11, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("12")) {
                      startIndexMsg = nextIndex;
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      networkResp.append(networkMsg.substring(startIndexMsg, nextIndex));
                      debugMessage(12, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("13")) {
                      startIndexMsg = nextIndex;
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      networkResp.append(networkMsg.substring(startIndexMsg, nextIndex));
                      debugMessage(13, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("48")) {
                      startIndexMsg = nextIndex;
                      // ambil dulu var.len utk DE 48
                      int varLen = Integer.valueOf(networkMsg.substring(startIndexMsg, (startIndexMsg+3)));
                      // 3 digit utk variabel len
                      varLen += 3;
                      nextIndex += varLen;
                      sisaDefaultDE += networkMsg.substring(startIndexMsg, nextIndex);
                      debugMessage(48, networkMsg.substring(startIndexMsg, nextIndex));
                  } else if(activeDE[i].equalsIgnoreCase("70")) {
                      startIndexMsg = nextIndex;
                      nextIndex += mappingDENetworkMsg.get(activeDE[i]);
                      sisaDefaultDE += networkMsg.substring(startIndexMsg, nextIndex);
                      debugMessage(70, networkMsg.substring(startIndexMsg, nextIndex));
                  }
              }
       
              // kasih response kode 39 success
              networkResp.append("000");
              // tambahkan sisa default DE
              networkResp.append(sisaDefaultDE);
       
              // tambahkan length 4 digit utk msg.header
              String msgHeader = "";
              if (networkResp.length() < 10) msgHeader = "000" + networkResp.length();
              if (networkResp.length() < 100 && networkResp.length() >= 10) msgHeader = "00" + networkResp.length();
              if (networkResp.length() < 1000 && networkResp.length() >= 100) msgHeader = "0" + networkResp.length();
              if (networkResp.length() >= 1000) msgHeader = String.valueOf(networkResp.length());
       
              String finalMsg = msgHeader + networkResp.toString();
       
              // send to client
              sendMsg.print(finalMsg);
              sendMsg.flush();
          }
       
          private static void debugMessage(Integer fieldNo, String msg) {
              System.out.println("["+fieldNo+"] ["+msg+"]");
          }
      }
    Sampai disini proses pembuatan implementasi Server ISO 8583 kita sudah selesai, sekarang mari kita lanjutkan dengan membuat implementasi untuk client-nya :)


    No comments:

    Post a Comment