The English version of the new site is ready.

git-svn-id: https://j8583.svn.sourceforge.net/svnroot/j8583/j8583@59 db60a039-f72e-0410-b1d2-baa000846441
This commit is contained in:
chochos
2010-11-30 20:52:55 +00:00
parent 2c501c3f43
commit b016721df9
15 changed files with 882 additions and 10 deletions
-4
View File
@@ -37,10 +37,6 @@
<scope>test</scope>
</dependency>
</dependencies>
<organization>
<name>Java Mexico</name>
<url>http://javamexico.org</url>
</organization>
<developers>
<developer>
<id>chochos</id>
+35
View File
@@ -0,0 +1,35 @@
-----
Groovy compatibility
-----
Isn't ANY Java library compatible with Groovy?
Yes, of course. You can use j8583 in Groovy just as you would use any other Java library. However,
some j8583 classes have certain methods in them written specifically for usage within Groovy.
* j8583 short-hand in Groovy
In Java, you can deal with values in an IsoMessage like this:
+-----
message.setValue(32, "Some value", IsoType.LLVAR, 0);
IsoValue isoValue = message.getField(32);
String value = (String)message.getObjectValue(32);
Object value2 = message.getField(32).getValue();
+-----
In Groovy you can do the same like this
+-----
message[32] = IsoType.LLVAR("Some value")
message[7] = IsoType.DATE10(new Date())
message[41] = IsoType.ALPHA("Term", 16)
message[11] = IsoType.NUMERIC(123, 6)
IsoValue isoValue = message[32]
def value = message[32]?.value
+-----
This is because the IsoMessage class has get <<<getAt()>>> and <<<putAt()>>> methods that work similar
to <<<getField()>>> and <<<setField>>>, and the IsoType class has two <<<call()>>> methods, with and without
length, which return IsoValue instances with the proper type and length. The variant that has a length parameter
must be used with NUMERIC and ALPHA types, and the other types can use the variant without length.
+82
View File
@@ -0,0 +1,82 @@
-----
Usage Guide
-----
Usage Guide
This guide explains how to setup j8583. If you want to know more about the ISO8583 protocol,
please read the {{{iso8583.html}corresponding page}}.
The MessageFactory and IsoMessage classes
These are the two main classes you need to use to work with ISO8583 messages. An IsoMessage can be
encoded into a byte array or a ByteBuffer to be written to an OutputStream, or it can directly write itself
to an OutputStream. You can set and get the values for each field in an IsoMessage, and it will adjust itself
to use a secondary bitmap if necessary. An IsoMessage has settings to encode itself in binary or ASCII,
to use a secondary bitmap even if it's not necessary, and it can have its own ISO header.
However, it can be cumbersome to programmatically create IsoMessages all the time. The MessageFactory is a big aid
in IsoMessages with predefined values; also, it can set the date and the trace number in each new message.
* Configuring the MessageFactory
There are five main things you need to configure in a MessageFactory: ISO headers, message templates,
parsing templates, TraceNumberGenerator, and custom field encoders.
* ISO headers
ISO headers are strings that are associated with a message type. Whenever you ask the message factory
to create an IsoMessage, it will pass the corresponding ISO header (if present) to the new message.
* Message templates
A message template is an IsoMessage itself; the MessageFactory can have a template for each message type
it needs to create. When it creates a message and it has a template for that message type, it copies the
fields from the template to the new message before returning it.
* Parsing templates
A parsing template is a map containing FieldParseInfo objects as values and the field numbers as the keys.
A FieldParseInfo object contains an IsoType and an optional length; with this information and the field number,
the MessageFactory can parse incoming messages, first analyzing the message type and then using the parsing
template for that type; when parsing a message, the MessageFactory only parses the fields that are specified
in the message's bitmap. For example if the bitmap specifies field 4, the factory will get the FieldParseInfo
stored in the map under key 4, and will attempt to parse the field according to the type and length specified
by the FieldParseInfo.
A message does not need to contain all the fields specified in a parsing template, but a parsing template must
contain all the fields specified in the bitmap of a message, or the MessageFactory won't be able to parse it
because it has no way of knowing how it should parse that field (and also all subsequent fields).
* The TraceNumberGenerator
When creating new messages, they usually need to have a unique trace number, contained in field 11. Also, they
usually need to have the date they were created (or the date the transaction was originated) in field 7.
The MessageFactory can automatically set the current date on all new messages, you just need to set the
<<<assignDate>>> property to <<<true>>>. And it can also assign a new trace number to each message it creates,
but for this it needs a TraceNumberGenerator.
The TraceNumberGenerator interface defines a <<<nextTrace()>>> method, which must return a new trace number
between 1 and 999999. It needs to be cyclic, so it returns 1 again after returning 999999. And usually, it
needs to be thread-safe.
j8583 only defines the interface; in production environments you will usually need to implement your own
TraceNumberGenerator, getting the new trace number from a sequence in a database or some similar mechanism.
As an example, the library includes the SimpleTraceGenerator, which simply increments an in-memory value.
* Custom field encoders
Certain implementations of ISO8583 specify fields which contain many subfields. If you only handle strings
in those fields, you'll have to encode all those values before storing them in an IsoMessage, and decode them
when you get them from an IsoMessage.
In these cases you can implement a CustomField, which is an interface that defines two methods, one for encoding
an object into a String and another for decoding an object from a String. You can pass the MessageFactory a
CustomField for every field where you want to store custom values, so that parsed messages will return the
objects decoded by the CustomFields instead of just strings; and when you set a value in an IsoMessage, you
can specify the CustomField to be used to encode the value as a String.
* XML configuration
The easiest way to configure the message templates and parsing templates is by using a
{{{xmlconf.html}XML config file}} and pass it to the MessageFactory.
+46
View File
@@ -0,0 +1,46 @@
-----
Introduction to j8583
-----
What it j8583?
Simply put, j8583 is a Java library to generate and read ISO8583 messages. It does not handle sending or
reading them over a network connection, but it does parse the data you have read and can generate the
data you need to write, or write it directly to an OutputStream.
* What is ISO8583?
ISO8583 is a message format used for credit card transactions, banking and other commercial interaction between
different systems. It has an ASCII variant and a binary one, and it is somewhat convoluted and difficult to
implement.
The main format of the ISO8583 is something like this:
+-----
ISO header (optional)|Message Type|primary bitmap|secondary bitmap (optional)|data fields
+-----
The ISO header is a string containing some code that can vary according to the message type.
The message type is a 4-digit number (or 2 bytes when using binary format).
The bitmap is 64 bits long and it is encoded as 16 hex characters or as 8 bytes when using binary format.
Every bit that is set in the bitmap indicates that the corresponding field is present. If the first bit is set,
then field 1 is present, and so on.
The fields in the message are numbered from 1 to 64. Field 1 is the secondary bitmap, if present. The secondary
bitmap allows for the message to have fields from 65 to 128.
You can {{{iso8583.html}check the ISO8583 guide}} for more information; Wikipedia has
{{{http://en.wikipedia.org/wiki/ISO_8583}a very good article}} on the whole specification.
* How does j8583 work?
j8583 offers a MessageFactory, which once properly configured, can create different message types with
some values predefined, and can also parse a byte array to create a iso message. Messages are represented
by IsoMessage objects, which store IsoValue instances for their data fields. You can work with the IsoValues
or use the convenience methods of IsoMessage to work directly with the stored values.
j8583 can directly handle the basic data types: numeric values, strings, and dates. If you want to encode
a custom object in a field, you can implement a custom field encoder. More information is available in the
{{{guide.html}user's guide}}.
+144
View File
@@ -0,0 +1,144 @@
-----
ISO8583
-----
Introduction to ISO8583
The specification is available at iso.org and it's gotten really complicated; this is just an introduction
to the generalities of the specification. There is actually a
{{{http://en.wikipedia.org/wiki/ISO_8583}really good article}} on Wikipedia covering the whole spec and its
different versions.
* Data types
ISO 8583 specifies a lot of data types, the most common of which are implemented directly in j8583 through
the <<<IsoType>>> enum. Here is a table of the most common ISO types and their j8583 counterpart:
*--------------*----------------*-----------------+
| <<ISO type>> | <<j8583 type>> | <<Description >> |
*--------------*----------------*-----------------+
| Numeric | NUMERIC | Fixed-width numeric values, padded with zeroes to the left.|
*--------------*----------------*-----------------+
| Alphanumeric | ALPHA | Fixed-width alphanumeric values, padded with spaces to the right.|
*--------------*----------------*-----------------+
| Date | DATE10 | Date in format mmddHHMMSS, fixed width of 10. |
*--------------*----------------*-----------------+
| Date | DATE4 | Date in format mmdd, fixed width of 4. |
*--------------*----------------*-----------------+
| Expiration Date | DATE_EXP | Date in format yymm, fixed width of 4. Used for credit card expiration dates. |
*--------------*----------------*-----------------+
| Time | TIME | Time of day in format HHMMSS, fixed width of 6. |
*--------------*----------------*-----------------+
| Amount | AMOUNT | Currency amount, a positive number expressed in cents, with a fixed width of 4. For example one dollar is encoded as 000000000100 |
*--------------*----------------*-----------------+
| LLVAR | LLVAR | Variable-width alphanumeric value, up to 99 characters long. The length of the value is encoded in the first 2 characters of the value, for example "HEY" is encoded as 03HEY |
*--------------*----------------*-----------------+
| LLLVAR | LLLVAR | Variable-width alphanumeric value, up to 999 characters long. The length of the value is encoded in the first 3 characters of the value, for example "HEY" is encoded as 003HEY |
*--------------*----------------*-----------------+
ISO 8583 types and their corresponding j8583 types
* Common scenarios
ISO8583 implementations can vary a lot, depending on the provider, and the type of products and transactions it
is being used for; but there are certain fields which are almost always used in a very similar manner. I will
describe those here. <<DISCLAIMER:>> This is only something I have learned from experience, and I must say
my experience has been rather limited to mobile carrier providers. Here I focus more on the field number and
type, rather on the usage of the field itself.
** Message types
These are some of the most common message types. There is some logic to this, if you look at the message types
as 2-byte hex values: The first byte states the type of operation: 02 are payments, 04 reversals, 08 tests;
the second byte indicates if it's a request or a response. And sometimes repeated requests should end in 1
instead of 0, for example reversals are 0400 the first time but 0401 the next time you send them.
*------:--+
| 0200 | A payment or sale request.
*------:--+
| 0210 | A payment or sale response.
*------:--+
| 0400 | A reversal request (to undo a previous 0200 operation).
*------:--+
| 0410 | A reversal response.
*------:--+
| 0600 | A query (to check the status of a previous operation, or check an account's balance, etc).
*------:--+
| 0610 | A query response.
*------:--+
| 0800 | An echo request (just to keep the connection alive and make sure the other side is responsive).
*------:--+
| 0810 | An echo response.
*------:--+
Some implementations require you to send 0400 for a reversal when you only have the request (so in case of
timeout you use 0400) and 0420 when you did get the response (so in case of some other error in your system).
** Common fields
[Field 3] Operation code, NUMERIC of length 6.
[Field 4] Amount, AMOUNT.
[Field 7] Date, DATE10.
[Field 11] Trace, NUMERIC of length 6.
[Field 17] Transaction date, DATE4.
[Field 37] Reference number, NUMERIC of length 12.
[Field 38] Confirmation number, NUMERIC of length 6.
[Field 39] Response code, NUMERIC of length 2.
[Field 41] Terminal ID, ALPHA of length 8 or 16.
[Field 49] Currency, NUMERIC of length 3. See the {{{http://en.wikipedia.org/wiki/ISO_4217}ISO 4217}} table of currencies.
[Field 128] MAC (Message Authentication Code). Usually ALPHA or NUMERIC of length 16.
[]
** Asynchronous transmission and reception
When communicating two systems with ISO8583, usually the communication is asynchronous and all messages are
handled through a single connection. Between a terminal and a bigger system the communication will be synchronous.
In asynchronous communications, the client can send any number of requests to the server, and the server may
respond to those requests in a different order in which they were sent. This is why the trace number (field 11)
is very important and should not be reused; if the client sends requests with traces 123000, 123001 and 123002,
the server may send back first 123001, then 123002, then 123000. The client will know which response corresponds
to which request by checking the trace of the responses.
The messages can vary in length depending on the message type and the fields it contains. The protocol was
designed so that a message can be read in parts; first the message type, then the primary bitmap, and from there
the rest of the fields (secondary bitmap included) can be read and processed one by one. This is very convenient
for small devices like POS terminals, but is not very efficient in larger systems with a high transaction volume.
In these cases, the sender first encodes the whole message, measures it, and sends the length as a 2- or 4-byte
unsigned integer (most significant bit first). This way the receiver knows to read 2 or 4 bytes, interpret them
as an unsigned integer, and read those many bytes to get an ISO message. Using 2 bytes allows for messages of up
to 65535 bytes, and 4 bytes allows for 2.14 million bytes long, which is a bit of overkill, given that a message
can be as long as 127290 bytes, if it's encoded in ASCII and has 127 LLLVAR fields each with 999 characters.
*** Message terminator
The length header that is sent before a message is very useful to separate the reading operation from the parsing
of the message; you can dedicate a thread to read from a socket, and put those buffers on a queue where another
thread parses them. However, a length header only says how many bytes to read and so the reader must read all
those bytes, but what if the message is invalid because it is <longer> than the length says? To avoid this error,
some systems use a message terminator. This is just a character that must be found at the end of every message.
If messages are encoded as text, a common terminator is ASCII 0x03. The terminator may or may not be counted
as part of the message, that depends on the implementation. You can specify the terminator via the <<<etx>>>
property of an IsoMessage, of preferably in the MessageFactory so that all new messages already will have the
property set. To keep the messages from using a terminator, set <<<etx>>> to -1.
** Binary encoding
Many ISO8583 implementations use plain text for the messages (even if the length header is binary). But some
implementations encode the messages as binary. The main differences are that the message type is only 2 bytes
long instead of 4 (the ASCII version is actually a hex representation of the message type), the bitmap is not
hex-encoded, so it's only 8 bytes long; and all numeric values (including date/time fields) are encoded using
{{{http://en.wikipedia.org/wiki/Binary-coded_decimal}BCD}} (including the headers for LLVAR and LLLVAR fields).
You can encode messages in binary by setting the <<<binary>>> property of IsoMessages, or in the MessageFactory
directly by setting the <<<useBinaryMessages>>> so that it gets set on all new messages. It must be set in
the MessageFactory if you want it to parse binary messages.
+47
View File
@@ -0,0 +1,47 @@
-----
Configuring with Spring
-----
Configuration via Spring
You can configure a MessageFactory as a bean in a Spring ApplicationContext, and inject it into any
other components that need to create or parse IsoMessages.
* Setting up the MessageFactory
The properties that you want to set up in the Spring config are:
*------------+---------------------------------+
| configPath | Specify the path to the XML configuration file with the message and parsing templates.
*------------+---------------------------------+
| customFields | A map with the CustomField implementations that should be used for each field (the keys are the field numbers).
*------------+---------------------------------+
| assignDate | Set it to true to have the MessageFactory set field 7 to a DATE10 with the date the message was created.
*------------+---------------------------------+
| etx | Set it to the numeric value of the message terminator, or -1 if you don't want to use a terminator.
*------------+---------------------------------+
| forceSecondaryBitmap | If true, then the messages will include the secondary bitmap even if they don't contain any fields above 64. Some providers require this.
*------------+---------------------------------+
| ignoreLastMissingField | If true, then the factory only logs a warning when parsing incomplete messages. By default it will throw a ParseException.
*------------+---------------------------------+
| useBinaryMessages | Can be true or false (default false). The factory passes this value to new messages so that they're encoded in binary or ASCII.
*------------+---------------------------------+
| traceNumberGenerator | Set to an implementation of TraceNumberGenerator so that the factory sets a new trace value in field 11 on new messages.
*------------+---------------------------------+
Example:
+-----
<bean id="isoMessageFactory" class="com.solab.iso8583.MessageFactory">
<property name="assignDate" value="true" />
<property name="etx" value="3" />
<property name="ignoreLastMissingField" value="true" />
<property name="customFields"><map>
<entry key="48"><bean class="your.app.DataProductEncoder" /></entry>
<entry key="62"><bean class="your.app.AdditionalDataEncoder" /></entry>
</map></property>
<!-- It is important to set this AFTER the custom fields
if your message templates contain some of those fields -->
<property name="configPath" value="/your-j8583.xml" />
</bean>
+-----
+80
View File
@@ -0,0 +1,80 @@
-----
XML Configuration
-----
XML Configuration
The MessageFactory can read a XML file to setup message templates, ISO headers by type and parsing templates,
which are the most cumbersome parts to configure programmatically.
There are three types of main elements that you need to specify in the config file: <<<header>>>,
<<<template>>>, and <<<parse>>>. All these must be contained in a single <<<j8583-config>>> element.
There is a DTD available at {{{http://j8583.sourceforge.net/j8583.dtd}}}.
* <<<header>>> element
Specify a <<<header>>> element for every type of message that needs an ISO header. Only one per message type:
+-----
<header type="0200">ISO015000050</header>
<header type="0400">ISO015000050</header>
+-----
* <<<template>>> element
Each <<<template>>> element defines a message template, with the message type and the fields that the
template should include. Every new message of that type that the MessageFactory creates will contain those
same values, so this is very useful for defining fixed values, which will be the same in every message.
Only one template per type.
+-----
<template type="0200">
<field num="3" type="NUMERIC" length="6">650000</field>
<field num="32" type="LLVAR">456</field>
<field num="35" type="LLVAR">4591700012340000=</field>
<field num="43" type="ALPHA" length="40">Fixed-width data</field>
<field num="48" type="LLLVAR">Life, the Universe, and Everything|42</field>
<field num="49" type="ALPHA" length="3">840</field>
<field num="60" type="LLLVAR">B456PRO1+000</field>
<field num="61" type="LLLVAR">This field can have a value up to 999 characters long.</field>
<field num="100" type="LLVAR">999</field>
<field num="102" type="LLVAR">ABCD</field>
</template>
+-----
* <<<parse>>> element
Each <<<parse>>> element defines a parsing template for a message type. It must include all the fields that
an incoming message can contain, each field with its type and length (if needed). Only ALPHA and NUMERIC
types need to have a length specified. The other types either have a fixed length, or have their length
specified as part of the field (LLVAR and LLLVAR).
+-----
<parse type="0210">
<field num="3" type="NUMERIC" length="6" />
<field num="4" type="AMOUNT" />
<field num="7" type="DATE10" />
<field num="11" type="NUMERIC" length="6" />
<field num="12" type="TIME" />
<field num="13" type="DATE4" />
<field num="15" type="DATE4" />
<field num="17" type="DATE_EXP" />
<field num="32" type="LLVAR" />
<field num="35" type="LLVAR" />
<field num="37" type="NUMERIC" length="12" />
<field num="38" type="NUMERIC" length="6" />
<field num="39" type="NUMERIC" length="2" />
<field num="41" type="ALPHA" length="16" />
<field num="43" type="ALPHA" length="40" />
<field num="48" type="LLLVAR" />
<field num="49" type="ALPHA" length="3" />
<field num="60" type="LLLVAR" />
<field num="61" type="LLLVAR" />
<field num="70" type="ALPHA" length="3" />
<field num="90" type="ALPHA" length="42" />
<field num="100" type="LLVAR" />
<field num="102" type="LLVAR" />
<field num="126" type="LLLVAR" />
</parse>
+-----
+35
View File
@@ -0,0 +1,35 @@
-----
Groovy compatibility
-----
Isn't ANY Java library compatible with Groovy?
Yes, of course. You can use j8583 in Groovy just as you would use any other Java library. However,
some j8583 classes have certain methods in them written specifically for usage within Groovy.
* j8583 short-hand in Groovy
In Java, you can deal with values in an IsoMessage like this:
+-----
message.setValue(32, "Some value", IsoType.LLVAR, 0);
IsoValue isoValue = message.getField(32);
String value = (String)message.getObjectValue(32);
Object value2 = message.getField(32).getValue();
+-----
In Groovy you can do the same like this
+-----
message[32] = IsoType.LLVAR("Some value")
message[7] = IsoType.DATE10(new Date())
message[41] = IsoType.ALPHA("Term", 16)
message[11] = IsoType.NUMERIC(123, 6)
IsoValue isoValue = message[32]
def value = message[32]?.value
+-----
This is because the IsoMessage class has get <<<getAt()>>> and <<<putAt()>>> methods that work similar
to <<<getField()>>> and <<<setField>>>, and the IsoType class has two <<<call()>>> methods, with and without
length, which return IsoValue instances with the proper type and length. The variant that has a length parameter
must be used with NUMERIC and ALPHA types, and the other types can use the variant without length.
+82
View File
@@ -0,0 +1,82 @@
-----
Usage Guide
-----
Usage Guide
This guide explains how to setup j8583. If you want to know more about the ISO8583 protocol,
please read the {{{iso8583.html}corresponding page}}.
The MessageFactory and IsoMessage classes
These are the two main classes you need to use to work with ISO8583 messages. An IsoMessage can be
encoded into a byte array or a ByteBuffer to be written to an OutputStream, or it can directly write itself
to an OutputStream. You can set and get the values for each field in an IsoMessage, and it will adjust itself
to use a secondary bitmap if necessary. An IsoMessage has settings to encode itself in binary or ASCII,
to use a secondary bitmap even if it's not necessary, and it can have its own ISO header.
However, it can be cumbersome to programmatically create IsoMessages all the time. The MessageFactory is a big aid
in IsoMessages with predefined values; also, it can set the date and the trace number in each new message.
* Configuring the MessageFactory
There are five main things you need to configure in a MessageFactory: ISO headers, message templates,
parsing templates, TraceNumberGenerator, and custom field encoders.
* ISO headers
ISO headers are strings that are associated with a message type. Whenever you ask the message factory
to create an IsoMessage, it will pass the corresponding ISO header (if present) to the new message.
* Message templates
A message template is an IsoMessage itself; the MessageFactory can have a template for each message type
it needs to create. When it creates a message and it has a template for that message type, it copies the
fields from the template to the new message before returning it.
* Parsing templates
A parsing template is a map containing FieldParseInfo objects as values and the field numbers as the keys.
A FieldParseInfo object contains an IsoType and an optional length; with this information and the field number,
the MessageFactory can parse incoming messages, first analyzing the message type and then using the parsing
template for that type; when parsing a message, the MessageFactory only parses the fields that are specified
in the message's bitmap. For example if the bitmap specifies field 4, the factory will get the FieldParseInfo
stored in the map under key 4, and will attempt to parse the field according to the type and length specified
by the FieldParseInfo.
A message does not need to contain all the fields specified in a parsing template, but a parsing template must
contain all the fields specified in the bitmap of a message, or the MessageFactory won't be able to parse it
because it has no way of knowing how it should parse that field (and also all subsequent fields).
* The TraceNumberGenerator
When creating new messages, they usually need to have a unique trace number, contained in field 11. Also, they
usually need to have the date they were created (or the date the transaction was originated) in field 7.
The MessageFactory can automatically set the current date on all new messages, you just need to set the
<<<assignDate>>> property to <<<true>>>. And it can also assign a new trace number to each message it creates,
but for this it needs a TraceNumberGenerator.
The TraceNumberGenerator interface defines a <<<nextTrace()>>> method, which must return a new trace number
between 1 and 999999. It needs to be cyclic, so it returns 1 again after returning 999999. And usually, it
needs to be thread-safe.
j8583 only defines the interface; in production environments you will usually need to implement your own
TraceNumberGenerator, getting the new trace number from a sequence in a database or some similar mechanism.
As an example, the library includes the SimpleTraceGenerator, which simply increments an in-memory value.
* Custom field encoders
Certain implementations of ISO8583 specify fields which contain many subfields. If you only handle strings
in those fields, you'll have to encode all those values before storing them in an IsoMessage, and decode them
when you get them from an IsoMessage.
In these cases you can implement a CustomField, which is an interface that defines two methods, one for encoding
an object into a String and another for decoding an object from a String. You can pass the MessageFactory a
CustomField for every field where you want to store custom values, so that parsed messages will return the
objects decoded by the CustomFields instead of just strings; and when you set a value in an IsoMessage, you
can specify the CustomField to be used to encode the value as a String.
* XML configuration
The easiest way to configure the message templates and parsing templates is by using a
{{{xmlconf.html}XML config file}} and pass it to the MessageFactory.
+46
View File
@@ -0,0 +1,46 @@
-----
Introduction to j8583
-----
What it j8583?
Simply put, j8583 is a Java library to generate and read ISO8583 messages. It does not handle sending or
reading them over a network connection, but it does parse the data you have read and can generate the
data you need to write, or write it directly to an OutputStream.
* What is ISO8583?
ISO8583 is a message format used for credit card transactions, banking and other commercial interaction between
different systems. It has an ASCII variant and a binary one, and it is somewhat convoluted and difficult to
implement.
The main format of the ISO8583 is something like this:
+-----
ISO header (optional)|Message Type|primary bitmap|secondary bitmap (optional)|data fields
+-----
The ISO header is a string containing some code that can vary according to the message type.
The message type is a 4-digit number (or 2 bytes when using binary format).
The bitmap is 64 bits long and it is encoded as 16 hex characters or as 8 bytes when using binary format.
Every bit that is set in the bitmap indicates that the corresponding field is present. If the first bit is set,
then field 1 is present, and so on.
The fields in the message are numbered from 1 to 64. Field 1 is the secondary bitmap, if present. The secondary
bitmap allows for the message to have fields from 65 to 128.
You can {{{iso8583.html}check the ISO8583 guide}} for more information; Wikipedia has
{{{http://en.wikipedia.org/wiki/ISO_8583}a very good article}} on the whole specification.
* How does j8583 work?
j8583 offers a MessageFactory, which once properly configured, can create different message types with
some values predefined, and can also parse a byte array to create a iso message. Messages are represented
by IsoMessage objects, which store IsoValue instances for their data fields. You can work with the IsoValues
or use the convenience methods of IsoMessage to work directly with the stored values.
j8583 can directly handle the basic data types: numeric values, strings, and dates. If you want to encode
a custom object in a field, you can implement a custom field encoder. More information is available in the
{{{guide.html}user's guide}}.
+144
View File
@@ -0,0 +1,144 @@
-----
ISO8583
-----
Introduction to ISO8583
The specification is available at iso.org and it's gotten really complicated; this is just an introduction
to the generalities of the specification. There is actually a
{{{http://en.wikipedia.org/wiki/ISO_8583}really good article}} on Wikipedia covering the whole spec and its
different versions.
* Data types
ISO 8583 specifies a lot of data types, the most common of which are implemented directly in j8583 through
the <<<IsoType>>> enum. Here is a table of the most common ISO types and their j8583 counterpart:
*--------------*----------------*-----------------+
| <<ISO type>> | <<j8583 type>> | <<Description >> |
*--------------*----------------*-----------------+
| Numeric | NUMERIC | Fixed-width numeric values, padded with zeroes to the left.|
*--------------*----------------*-----------------+
| Alphanumeric | ALPHA | Fixed-width alphanumeric values, padded with spaces to the right.|
*--------------*----------------*-----------------+
| Date | DATE10 | Date in format mmddHHMMSS, fixed width of 10. |
*--------------*----------------*-----------------+
| Date | DATE4 | Date in format mmdd, fixed width of 4. |
*--------------*----------------*-----------------+
| Expiration Date | DATE_EXP | Date in format yymm, fixed width of 4. Used for credit card expiration dates. |
*--------------*----------------*-----------------+
| Time | TIME | Time of day in format HHMMSS, fixed width of 6. |
*--------------*----------------*-----------------+
| Amount | AMOUNT | Currency amount, a positive number expressed in cents, with a fixed width of 4. For example one dollar is encoded as 000000000100 |
*--------------*----------------*-----------------+
| LLVAR | LLVAR | Variable-width alphanumeric value, up to 99 characters long. The length of the value is encoded in the first 2 characters of the value, for example "HEY" is encoded as 03HEY |
*--------------*----------------*-----------------+
| LLLVAR | LLLVAR | Variable-width alphanumeric value, up to 999 characters long. The length of the value is encoded in the first 3 characters of the value, for example "HEY" is encoded as 003HEY |
*--------------*----------------*-----------------+
ISO 8583 types and their corresponding j8583 types
* Common scenarios
ISO8583 implementations can vary a lot, depending on the provider, and the type of products and transactions it
is being used for; but there are certain fields which are almost always used in a very similar manner. I will
describe those here. <<DISCLAIMER:>> This is only something I have learned from experience, and I must say
my experience has been rather limited to mobile carrier providers. Here I focus more on the field number and
type, rather on the usage of the field itself.
** Message types
These are some of the most common message types. There is some logic to this, if you look at the message types
as 2-byte hex values: The first byte states the type of operation: 02 are payments, 04 reversals, 08 tests;
the second byte indicates if it's a request or a response. And sometimes repeated requests should end in 1
instead of 0, for example reversals are 0400 the first time but 0401 the next time you send them.
*------:--+
| 0200 | A payment or sale request.
*------:--+
| 0210 | A payment or sale response.
*------:--+
| 0400 | A reversal request (to undo a previous 0200 operation).
*------:--+
| 0410 | A reversal response.
*------:--+
| 0600 | A query (to check the status of a previous operation, or check an account's balance, etc).
*------:--+
| 0610 | A query response.
*------:--+
| 0800 | An echo request (just to keep the connection alive and make sure the other side is responsive).
*------:--+
| 0810 | An echo response.
*------:--+
Some implementations require you to send 0400 for a reversal when you only have the request (so in case of
timeout you use 0400) and 0420 when you did get the response (so in case of some other error in your system).
** Common fields
[Field 3] Operation code, NUMERIC of length 6.
[Field 4] Amount, AMOUNT.
[Field 7] Date, DATE10.
[Field 11] Trace, NUMERIC of length 6.
[Field 17] Transaction date, DATE4.
[Field 37] Reference number, NUMERIC of length 12.
[Field 38] Confirmation number, NUMERIC of length 6.
[Field 39] Response code, NUMERIC of length 2.
[Field 41] Terminal ID, ALPHA of length 8 or 16.
[Field 49] Currency, NUMERIC of length 3. See the {{{http://en.wikipedia.org/wiki/ISO_4217}ISO 4217}} table of currencies.
[Field 128] MAC (Message Authentication Code). Usually ALPHA or NUMERIC of length 16.
[]
** Asynchronous transmission and reception
When communicating two systems with ISO8583, usually the communication is asynchronous and all messages are
handled through a single connection. Between a terminal and a bigger system the communication will be synchronous.
In asynchronous communications, the client can send any number of requests to the server, and the server may
respond to those requests in a different order in which they were sent. This is why the trace number (field 11)
is very important and should not be reused; if the client sends requests with traces 123000, 123001 and 123002,
the server may send back first 123001, then 123002, then 123000. The client will know which response corresponds
to which request by checking the trace of the responses.
The messages can vary in length depending on the message type and the fields it contains. The protocol was
designed so that a message can be read in parts; first the message type, then the primary bitmap, and from there
the rest of the fields (secondary bitmap included) can be read and processed one by one. This is very convenient
for small devices like POS terminals, but is not very efficient in larger systems with a high transaction volume.
In these cases, the sender first encodes the whole message, measures it, and sends the length as a 2- or 4-byte
unsigned integer (most significant bit first). This way the receiver knows to read 2 or 4 bytes, interpret them
as an unsigned integer, and read those many bytes to get an ISO message. Using 2 bytes allows for messages of up
to 65535 bytes, and 4 bytes allows for 2.14 million bytes long, which is a bit of overkill, given that a message
can be as long as 127290 bytes, if it's encoded in ASCII and has 127 LLLVAR fields each with 999 characters.
*** Message terminator
The length header that is sent before a message is very useful to separate the reading operation from the parsing
of the message; you can dedicate a thread to read from a socket, and put those buffers on a queue where another
thread parses them. However, a length header only says how many bytes to read and so the reader must read all
those bytes, but what if the message is invalid because it is <longer> than the length says? To avoid this error,
some systems use a message terminator. This is just a character that must be found at the end of every message.
If messages are encoded as text, a common terminator is ASCII 0x03. The terminator may or may not be counted
as part of the message, that depends on the implementation. You can specify the terminator via the <<<etx>>>
property of an IsoMessage, of preferably in the MessageFactory so that all new messages already will have the
property set. To keep the messages from using a terminator, set <<<etx>>> to -1.
** Binary encoding
Many ISO8583 implementations use plain text for the messages (even if the length header is binary). But some
implementations encode the messages as binary. The main differences are that the message type is only 2 bytes
long instead of 4 (the ASCII version is actually a hex representation of the message type), the bitmap is not
hex-encoded, so it's only 8 bytes long; and all numeric values (including date/time fields) are encoded using
{{{http://en.wikipedia.org/wiki/Binary-coded_decimal}BCD}} (including the headers for LLVAR and LLLVAR fields).
You can encode messages in binary by setting the <<<binary>>> property of IsoMessages, or in the MessageFactory
directly by setting the <<<useBinaryMessages>>> so that it gets set on all new messages. It must be set in
the MessageFactory if you want it to parse binary messages.
+47
View File
@@ -0,0 +1,47 @@
-----
Configuring with Spring
-----
Configuration via Spring
You can configure a MessageFactory as a bean in a Spring ApplicationContext, and inject it into any
other components that need to create or parse IsoMessages.
* Setting up the MessageFactory
The properties that you want to set up in the Spring config are:
*------------+---------------------------------+
| configPath | Specify the path to the XML configuration file with the message and parsing templates.
*------------+---------------------------------+
| customFields | A map with the CustomField implementations that should be used for each field (the keys are the field numbers).
*------------+---------------------------------+
| assignDate | Set it to true to have the MessageFactory set field 7 to a DATE10 with the date the message was created.
*------------+---------------------------------+
| etx | Set it to the numeric value of the message terminator, or -1 if you don't want to use a terminator.
*------------+---------------------------------+
| forceSecondaryBitmap | If true, then the messages will include the secondary bitmap even if they don't contain any fields above 64. Some providers require this.
*------------+---------------------------------+
| ignoreLastMissingField | If true, then the factory only logs a warning when parsing incomplete messages. By default it will throw a ParseException.
*------------+---------------------------------+
| useBinaryMessages | Can be true or false (default false). The factory passes this value to new messages so that they're encoded in binary or ASCII.
*------------+---------------------------------+
| traceNumberGenerator | Set to an implementation of TraceNumberGenerator so that the factory sets a new trace value in field 11 on new messages.
*------------+---------------------------------+
Example:
+-----
<bean id="isoMessageFactory" class="com.solab.iso8583.MessageFactory">
<property name="assignDate" value="true" />
<property name="etx" value="3" />
<property name="ignoreLastMissingField" value="true" />
<property name="customFields"><map>
<entry key="48"><bean class="your.app.DataProductEncoder" /></entry>
<entry key="62"><bean class="your.app.AdditionalDataEncoder" /></entry>
</map></property>
<!-- It is important to set this AFTER the custom fields
if your message templates contain some of those fields -->
<property name="configPath" value="/your-j8583.xml" />
</bean>
+-----
+80
View File
@@ -0,0 +1,80 @@
-----
XML Configuration
-----
XML Configuration
The MessageFactory can read a XML file to setup message templates, ISO headers by type and parsing templates,
which are the most cumbersome parts to configure programmatically.
There are three types of main elements that you need to specify in the config file: <<<header>>>,
<<<template>>>, and <<<parse>>>. All these must be contained in a single <<<j8583-config>>> element.
There is a DTD available at {{{http://j8583.sourceforge.net/j8583.dtd}}}.
* <<<header>>> element
Specify a <<<header>>> element for every type of message that needs an ISO header. Only one per message type:
+-----
<header type="0200">ISO015000050</header>
<header type="0400">ISO015000050</header>
+-----
* <<<template>>> element
Each <<<template>>> element defines a message template, with the message type and the fields that the
template should include. Every new message of that type that the MessageFactory creates will contain those
same values, so this is very useful for defining fixed values, which will be the same in every message.
Only one template per type.
+-----
<template type="0200">
<field num="3" type="NUMERIC" length="6">650000</field>
<field num="32" type="LLVAR">456</field>
<field num="35" type="LLVAR">4591700012340000=</field>
<field num="43" type="ALPHA" length="40">Fixed-width data</field>
<field num="48" type="LLLVAR">Life, the Universe, and Everything|42</field>
<field num="49" type="ALPHA" length="3">840</field>
<field num="60" type="LLLVAR">B456PRO1+000</field>
<field num="61" type="LLLVAR">This field can have a value up to 999 characters long.</field>
<field num="100" type="LLVAR">999</field>
<field num="102" type="LLVAR">ABCD</field>
</template>
+-----
* <<<parse>>> element
Each <<<parse>>> element defines a parsing template for a message type. It must include all the fields that
an incoming message can contain, each field with its type and length (if needed). Only ALPHA and NUMERIC
types need to have a length specified. The other types either have a fixed length, or have their length
specified as part of the field (LLVAR and LLLVAR).
+-----
<parse type="0210">
<field num="3" type="NUMERIC" length="6" />
<field num="4" type="AMOUNT" />
<field num="7" type="DATE10" />
<field num="11" type="NUMERIC" length="6" />
<field num="12" type="TIME" />
<field num="13" type="DATE4" />
<field num="15" type="DATE4" />
<field num="17" type="DATE_EXP" />
<field num="32" type="LLVAR" />
<field num="35" type="LLVAR" />
<field num="37" type="NUMERIC" length="12" />
<field num="38" type="NUMERIC" length="6" />
<field num="39" type="NUMERIC" length="2" />
<field num="41" type="ALPHA" length="16" />
<field num="43" type="ALPHA" length="40" />
<field num="48" type="LLLVAR" />
<field num="49" type="ALPHA" length="3" />
<field num="60" type="LLLVAR" />
<field num="61" type="LLLVAR" />
<field num="70" type="ALPHA" length="3" />
<field num="90" type="ALPHA" length="42" />
<field num="100" type="LLVAR" />
<field num="102" type="LLVAR" />
<field num="126" type="LLLVAR" />
</parse>
+-----
+7 -3
View File
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="j8583">
<bannerLeft>
<name>j8583</name>
<src>http://sflogo.sourceforge.net/sflogo.php?group_id=194767&type=7</src>
<href>http://j8583.sourceforge.net/</href>
<name>j8583</name>
<href>http://j8583.sourceforge.net/</href>
</bannerLeft>
<bannerRight>
<name>j8583</name>
<src>http://sflogo.sourceforge.net/sflogo.php?group_id=194767&amp;type=7</src>
<href>http://j8583.sourceforge.net/</href>
</bannerRight>
<body>
<links>
@@ -17,6 +19,8 @@
<item name="Introduction" href="index.html"/>
<item name="API docs" href="apidocs/index.html" />
<item name="Beginner's Guide" href="guide.html"/>
<item name="ISO8583" href="iso8583.html" />
<item name="XML config" href="xmlconf.html" />
<item name="Spring Example" href="spring.html"/>
<item name="Groovy Compatibility" href="groovy.html" />
<item name="Download" href="http://sourceforge.net/projects/j8583/files/j8583/" />
+7 -3
View File
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="j8583">
<bannerLeft>
<name>j8583</name>
<src>http://sflogo.sourceforge.net/sflogo.php?group_id=194767&type=7</src>
<href>http://j8583.sourceforge.net/</href>
<name>j8583</name>
<href>http://j8583.sourceforge.net/</href>
</bannerLeft>
<bannerRight>
<name>j8583</name>
<src>http://sflogo.sourceforge.net/sflogo.php?group_id=194767&amp;type=7</src>
<href>http://j8583.sourceforge.net/</href>
</bannerRight>
<body>
<links>
@@ -17,6 +19,8 @@
<item name="Introducción" href="index.html"/>
<item name="Documentación API" href="../apidocs/index.html" />
<item name="Guía de inicio" href="guide.html"/>
<item name="ISO8583" href="iso8583.html" />
<item name="XML config" href="xmlconf.html" />
<item name="Ejemplo con Spring" href="spring.html"/>
<item name="Compatibilidad con Groovy" href="groovy.html" />
<item name="Descargar" href="http://sourceforge.net/projects/j8583/files/j8583/" />