Jpos體系結構

一、   ISOComponet

 

 


 

這里ISOFieldISOBitMap都是實現了ISOComponent的葉子節點,ISOMsg則是包含了ISOFieldComposite (組合類):ISOMsg類維護了Hashtable fields,維護了該報文的所有的位元。

 

參考:composite模式

ISOComponent類體系采用composite模式,為的是能夠以統一的方式處理基本元素和復合元素(The Composite Design pattern allows a client object to treat both single components and collections of components identically.   

實現Composite pattern相對比較容易,Composite classes extend a base class that represents primitive objects. Figure 1 shows a class diagram that illustrates the Composite pattern's structure。

Component是一個接口或者抽象類,定義了葉子節點和Composite節點的公共方法;Composite類維護了Component的一個集合,提供了對該集合操作的一些方法,比如addComponent()removeComponent(),同時也包括了葉子節點的操作方法。該模式的

ISOBitMap

封裝了protected BitSet value;并且提供了維護該bitmap的方法

三、   ISOMsg

包括fieldsheaderdirection,消息類型是在第0號位元存放的

 

四、   ISOFieldPackager

ISOFieldPackager抽象了iso8583的位元的封裝方式,定義了位元的抽象特性和一些模版方法,比如packunpack方法

ISOFieldPackager的幾個子類比如ISOStringFieldPackager分別適用于不同的報文的編碼方式,每種不同的編碼方式都包括了三個成員類:Interpreter、paderPrefixer,分別用于負責轉換位元內容、插入填充內容和插入位元長度。

因此通過繼承每一種不同的編碼方式的之類,jpos提供了不同的具體的ISO的數據類型類。Interpreter、Pader、Prefixer接口的具體實現通過構造函數傳入ISO的數據類型類。


五、   Prefixer(域前綴信息)

其中Prefixer指得是ISOField得域長度信息。有兩個主要方法:

void encodeLength(int length, byte[] b) throws ISOException;

int decodeLength(byte[] b, int offset) throws ISOException;

第一個方法是根據length產生長度得編碼信息,存放到byte b[]中,比如encodeLength(21, byte[] b),就是把對21編碼,生成編碼信息存放到b[0]b[1]當中。

Length含義的解釋:代表該域的實際長度,比如某一個域定義的是LL..99,則length可以是0..99之間的任何數。

第二個方法是對第一個方法的逆向操作

參見AsciiPrefixer的源碼

 

六、   InterPreter(翻譯器)

InterPreter接口有下面三個方法:

1void interpret(String data, byte[] b, int offset);

String格式的data轉換成為byte數組

Converts the string data into a different interpretationStandard interpretations are ASCII, EBCDIC, BCD and LITERAL。

2String uninterpret(byte[] rawData, int offset, int length);

Converts the byte array into a String. This reverses the interpret method.

byte數組中的內容轉換回String格式

3int getPackedLength(int nDataUnits);

 

七、   Padder接口(填充器)

An interface for padding and unpadding strings and byte arrays。根據不同情況有多種填充策略,包括LeftPadder,RightPadder,RightTPadder等。

String pad(String data, int maxLength) throws ISOException;  用于填充String或者Byte數組在實際長度和定義的長度之間的空白位

String unpad(String paddedData) throws ISOException;  去除實際長度和定義的長度之間填充的空白

八、   ISOPackager


ISOPackager類為整個iso8583報文,包含了全部128個域的定義。ISO87ApackagerISO93Apackager等類為一些重要和常用的某個具體的協議硬編碼好了完整的位元信息,包括每個位元的代碼,描敘和處理類(FieldPackager)。

在具體使用的時候,可以直接使用這些報文處理類,也可以使用GeneriaPackager類來根據具體讀取報文協議信息,比如config/packager/iso87ascii.xml ,可以很方便地切換協議。

 

九、   ISOFilter

An ISOFilter has the oportunity to modify an incoming or outgoing ISOMsg that is about to go thru an ISOChannel. It also has the chance to Veto by throwing an Exception

ISOFilter除了能夠修改通過ISOChannel接受和發送的ISOMsg以外,還能夠通過拋出異常的方式終止ISOMsg的接受和發送。

public ISOMsg filter (ISOChannel channel, ISOMsg m, LogEvent evt)  throws VetoException;

十、   ISORequest

 

 

十一、      ISOResponse

 

 

 

十二、ISOChannel

Allows the transmision and reception of ISO 8583 Messages,In any case the programmer implementing the high level application logic must not deal with packaging and interchange low level details. The helper class ISOChannel takes care of that.

ISOChannel用來完成底層的packageinterchange,是應用層與底層細節的一個聯系紐帶。這個類負責完成報文的發送和接收,接收的參數包括:ISOPackagerServerSocket或者hostport


 

接口的方法簽名:

public void setPackager(ISOPackager p);

public void connect () throws IOException;

public void disconnect () throws IOException;

public void reconnect() throws IOException;

public boolean isConnected();

public ISOMsg receive() throws IOException, ISOException;

public void send (ISOMsg m) throws IOException, ISOException;

public void setUsable(boolean b);

從上面可以看出,ISOChannel的職責包括:

1)       通過調用相應的Packager完成Fieldpadder、intercpetprefix或者反向操作;

2)       創建并維護connnection

3)       發送ISOMsg(包括發送請求報文和發送應答報文)

(4)       根據傳輸過來的報文,創建ISOMsg(包括接收請求報文和接收應答報文)

 

大部分的實現邏輯常見org.jpos.BaseChanel.java

public void send(ISOMsg m) throws IOException, ISOException, VetoException

public ISOMsg receive() throws IOException, ISOException

 

public abstract class BaseChannel extends Observable implements

       FilteredChannel, ClientChannel, ServerChannel, FactoryChannel,

       LogSource, ReConfigurable, BaseChannelMBean {

 

詳細見ISOBaseChannelsendreceive方法

 

十三、      ISOMUX

An ISOMUX is a runnable class that asynchronously handles multiplexing and demultiplexing of ISOMsgs over a single ISOChannel.

The multiplexing/demultiplexing is based on the protected function ISOMUX.getKey(). The default implementation returns the concatenated (zero padded) values of fields 41 + field 11 (TerminalID+TraceNumber). You can subclass to provide different behaviour.

ISOMUX allows multiple terminals in a LAN or WAN to asynchronously send and receive messages over a single ISOChannel link. It also automatically handles ISOChannel reconnections.


ISOMUX用來異步地處理某一個特定渠道發來的重發報文。ISOMUX為作為ISOChannel的前端fascade,供發送客戶端調用。 

ISOMUX.getKey()返回報文中的11位元(交易系統生成的流水號)和41位元(終端標識碼)的組合,可以用來唯一識別某比具體的交易。

 

十四、      ISOServer

 

十五、      ServerChannel

服務器方接收接口,使用了java socket編程接口;需要區別于客戶端的接收應答的實現方式

 

public interface ServerChannel extends ISOChannel {

   /**

    * Accepts connection

    * @exception IOException

    */

    public void accept(ServerSocket s) throws IOException;

}

服務器端,實現方法在BaseChannel類中

public void accept(ServerSocket s) throws IOException {

        connect(s.accept());

    }

 

protected void connect(Socket socket) throws IOException, SocketException {

       this.socket = socket;

       applyTimeout();

       setLogger(getLogger(), getOriginalRealm() + "/"

              + socket.getInetAddress().getHostAddress() + ":"

              + socket.getPort());

       serverIn = new DataInputStream(new BufferedInputStream(socket

              .getInputStream()));

       serverOut = new DataOutputStream(new BufferedOutputStream(socket

              .getOutputStream(), 2048));

       usable = true;

       cnt[CONNECT]++;

       setChanged();

       notifyObservers();

    }

 

這樣接收到的數據可以從serverIn中獲取,發送應答可以通過serverOut

 

十六、      協議

發送報文:

m.set(new ISOField(0, "0200"));

m.set(new ISOField(11, "1")); //6位定長數字,前補零

m.set(new ISOField(41, "11"));//8位定長字符,后補空

m.set(new ISOField(44,"nihao")); //25位變長字符

 

發送報文串如下

0200002000000090000000000111      05nihao

報文類型       Bitmap                         消息內容

 

<isomsg direction="incoming">

  <field id="0" value="0200"/>

  <field id="11" value="000001"/>

  <field id="41" value="11      "/>

  <field id="44" value="nihao"/>

</isomsg>

 

響應報文串如下

021000200000029000000000019911      05nihao

<isomsg direction="incoming">

  <field id="0" value="0210"/>

  <field id="11" value="000001"/>

  <field id="39" value="99"/>

  <field id="41" value="11      "/>

  <field id="44" value="nihao"/>

</isomsg>

 

端口監聽獲取的傳輸數據:

發送報文:00410200002000000090000000000111      05nihao

 

響應報文:0043021000200000029000000000019911      05nihao

 

解釋:前4位為報文長度,為十進制,即發送報文長度為41,接收報文長度為43

         第二個4為消息類型MTI

         后面依次為bitmap和消息內容:

1、  bitmap使用16進制表示,002表示第11

2、  000001是因為11位元為6位定長數字,前面補了5個零

3、  1      是因為是8位定長字符,后補7個空格

4、  05nihao 是因為44位元是兩位變長,所以05表示實際長度為5

      

 

十七、      問題

1、  寫日志的方式:

LogEvent evt = new LogEvent (this, "send");

evt.addMessage (m);

這樣在每一個需要寫日志的方法中都要創建對象,好像不妥,不直到是什么原因,不用靜態方法

 

2、  打印報文到標準輸出的方法:xml格式

1ISOmsg.dump(System.out,""); 

輸出結構:

<isomsg direction="incoming">

  <field id="0" value="0200"/>

  <field id="11" value="000001"/>

  <field id="41" value="00000001"/>

</isomsg>

2System.out.println(ISOUtil.hexString(m.pack()));

輸出16進制的報文:

30323030303032303030303030303830303030303030303030313030303030303031

3System.out.println(ISOUtil.dumpString(m.pack()));

輸出二進制的報文:

0200002000000080000000000100000001

 

3、  問題:jpos如何根據bitmap識別報文內容??

答:

 

4、  問題:Jpos如何支持靈活切換多種8583協議?

答:Jpos使用一個通用的packager,這個packager會根據每個協議的配置文件(*.xml,xml格式的配置文件定義了該8583協議的每一個位元的信息(位元號,長度,描敘,處理類),根據這個處理類就可以根據不同的協議以不同的方式使用位元。這樣切換協議的時候,只需要修改下配置文件,或者具體的位元處理類即可,在整體的框架上不需要修改。

 

 

 

 

 

 

 

Does jPOS support ISO8583 - 2003 ?

In ISO8583:2003, for example, the STAN goes from six bytes to 12 bytes in length.

So, the Generic Packager contains this definition to begin with.

  <isofield

      id="11"

      length="6"

      name="SYSTEM TRACE AUDIT NUMBER"

      pad="true"

      class="org.jpos.iso.IFE_NUMERIC"/>

.and you'd change it to look like this:

  <isofield

      id="11"

      length="12"

      name="SYSTEM TRACE AUDIT NUMBER"

      pad="true"

      class="org.jpos.iso.IFE_NUMERIC"/>

Similarly, you'd make a sweep through the entire packager for all 128 fields
(or at least the sub-set "in play" for you).

I'd recommend a 'two-step sweep' exercise:

1. Go through the generic packager XML file provided with the jPOS download and adjust those items like the STAN as indicated.  [You can find a list of these changes in "Annex F" of the ISO8583:2003 spec provided by the International Standards Organization.]  Also - be careful that you incorporate any changes that came with the 1993 revision.  For example, in the Generic Packager, the Action Code (the all-important Field 39) is two positions in length, but in the 1993 standard it went to three positions. [In case you're wondering: the 1987 implementation is still the dominant standard for most implementations worldwide.]

2.Secondly, you'll want to go through the spec provided by the authorizing organization (or gateway) to you (that's assuming, of course, that your exercise is to put in place an ISO implementation created by someone else).  When you get into "private use" fields like 62 and 63, the Standards spec gives you only rough guidelines.  You'll want to see what the authorizer/gateway has done in its implementation.  [Unfortunately, for most of those private use fields, the packager definition will only get you so far.  These private use fields typically have esoteric, proprietary table structures inside of an 'IFE_LLLCHAR' (or similar) construction.  In those cases, you'll need some in-line code to complete the packaging and unpackaging tasks.]