Added javadoc to a couple of MessageFactory methods.

Some more docs have been translated, and the pom now has my name.


git-svn-id: https://j8583.svn.sourceforge.net/svnroot/j8583/j8583@61 db60a039-f72e-0410-b1d2-baa000846441
This commit is contained in:
chochos
2010-12-01 19:45:04 +00:00
parent 4f565129df
commit 04d61220d1
6 changed files with 123 additions and 106 deletions
+4
View File
@@ -37,6 +37,10 @@
<scope>test</scope>
</dependency>
</dependencies>
<organization>
<name>Enrique Zamudio</name>
<url>http://javamexico.org/blogs/ezamudio</url>
</organization>
<developers>
<developer>
<id>chochos</id>
@@ -208,7 +208,7 @@ public class MessageFactory {
* and the rest of the message must come. */
public IsoMessage parseMessage(byte[] buf, int isoHeaderLength) throws ParseException {
IsoMessage m = new IsoMessage(isoHeaderLength > 0 ? new String(buf, 0, isoHeaderLength) : null);
//TODO it only parses ASCII messages for now
//TODO Not really sure if binary support really works, unit tests pending...
int type = 0;
if (useBinary) {
type = ((buf[isoHeaderLength] & 0xff) << 8) | (buf[isoHeaderLength + 1] & 0xff);
@@ -425,6 +425,8 @@ public class MessageFactory {
return typeTemplates.get(type);
}
/** Invoke this method in case you want to freeze the configuration, making message and parsing
* templates, as well as iso headers and custom fields, immutable. */
public void freeze() {
typeTemplates = Collections.unmodifiableMap(typeTemplates);
parseMap = Collections.unmodifiableMap(parseMap);
+2 -2
View File
@@ -29,7 +29,7 @@ Introduction to ISO8583
*--------------*----------------*-----------------+
| 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 |
| Amount | AMOUNT | Currency amount, a positive number expressed in cents, with a fixed width of 12. 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 |
*--------------*----------------*-----------------+
@@ -116,7 +116,7 @@ ISO 8583 types and their corresponding j8583 types
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
to 65535 bytes, and 4 bytes allows for 2.14 billion 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
+14 -13
View File
@@ -1,27 +1,27 @@
-----
Groovy compatibility
Compatibilidad con Groovy
-----
Isn't ANY Java library compatible with Groovy?
¿Qué no cualquier biblioteca de Java es compatible con 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.
Por supuesto. Se puede utilizar j8583 en Groovy al igual que cualquier otra biblioteca de Java. Sin embargo,
algunas clases de j8583 tienen algunos métodos con el expreso propósito de ser utilizados desde Groovy.
* j8583 short-hand in Groovy
* Atajos de j8583 en Groovy
In Java, you can deal with values in an IsoMessage like this:
En Java, se pueden manejar los valores de un IsoMessage en alguna de las siguientes formas:
+-----
message.setValue(32, "Some value", IsoType.LLVAR, 0);
message.setValue(32, "Algun valor", 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
En Groovy se puede hacer lo mismo de esta forma:
+-----
message[32] = IsoType.LLVAR("Some value")
message[32] = IsoType.LLVAR("Algun valor")
message[7] = IsoType.DATE10(new Date())
message[41] = IsoType.ALPHA("Term", 16)
message[11] = IsoType.NUMERIC(123, 6)
@@ -29,7 +29,8 @@ 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.
Esto es posible gracias a que la clase IsoMessage implementa los métodos <<<getAt()>>> y <<<putAt()>>>, que
funcionan de manera similar a <<<getField()>>> y <<<setField()>>>; la clase IsoType tiene dos variantes del
método <<<call()>>>, una con longitud y otra sin longitud, los cuales devuelven instancias de IsoValue con
el valor y longitud apropiados. La variante con longitud debe ser utiliza para crear valores tipo
NUMERIC y ALPHA, mientras que los demás tipos pueden utilizar la variante sin longitud.
+2 -2
View File
@@ -1,8 +1,8 @@
-----
Usage Guide
Guía del usuario
-----
Usage Guide
Guía del usuario
Esta guía explica brevemente cómo configurar y utilizar j8583. Para conocer más acerca del protocolo
ISO8583 como tal, favor de leer la {{{iso8583.html}página correspondiente}}.
+98 -88
View File
@@ -2,143 +2,153 @@
ISO8583
-----
Introduction to ISO8583
Introducción al protocolo 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.
La especificación completa está disponible en el sitio iso.org y es bastante complicada; esta es únicamente
una introducción muy simple a las generalidades del protocolo. Wikipedia tiene un
{{{http://en.wikipedia.org/wiki/ISO_8583}artículo bastante completo}} que abarca la especificación completa
en sus distintas versiones.
* Data types
* Tipos de datos
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 8583 especifica muchos tipos de datos, de los cuales se eligieron los más comunes para ser implementados
en j8583 por medio del enum <<<IsoType>>>. A continuación se presenta una tabla con los tipos ISO más comunes
y su contraparte en j8583:
*--------------*----------------*-----------------+
| <<ISO type>> | <<j8583 type>> | <<Description >> |
| <<Tipo ISO>> | <<Tipo j8583>> | <<Descripción>> |
*--------------*----------------*-----------------+
| Numeric | NUMERIC | Fixed-width numeric values, padded with zeroes to the left.|
| Numérico | NUMERIC | Valores numéricos de longitud fija, rellenos con ceros a la izquierda.
*--------------*----------------*-----------------+
| Alphanumeric | ALPHA | Fixed-width alphanumeric values, padded with spaces to the right.|
| Alfanumérico | ALPHA | Valores alfanuméricos de longitud fija, rellenos con espacios a la derecha.
*--------------*----------------*-----------------+
| Date | DATE10 | Date in format mmddHHMMSS, fixed width of 10. |
| Fecha | DATE10 | Fecha en formato mmddHHMMSS, con longitud fija de 10.
*--------------*----------------*-----------------+
| Date | DATE4 | Date in format mmdd, fixed width of 4. |
| Fecha | DATE4 | Fecha en formato mmdd, con longitud fija de 4.
*--------------*----------------*-----------------+
| Expiration Date | DATE_EXP | Date in format yymm, fixed width of 4. Used for credit card expiration dates. |
| Fecha de expiración | DATE_EXP | Fecha en formato aamm, con longitud fija de 4. Se usa por ejemplo para fechas de expiración de tarjetas de crédito.
*--------------*----------------*-----------------+
| Time | TIME | Time of day in format HHMMSS, fixed width of 6. |
| Hora | TIME | Hora del día en formato HHMMSS, con longitud fija de 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 |
| Monto | AMOUNT | Monto en alguna moneda, expresado en centavos, con una longitud fija de 12. Por ejemplo un dólar se codifica como 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 |
| LLVAR | LLVAR | Valor alfanumérico de longitud variable, hasta 99 caracteres. La longitud del valor se codifica en los dos primeros caracteres del valor; por ejemplo "HOLA" se codifica como 04HOLA
*--------------*----------------*-----------------+
| 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 |
| LLLVAR | LLLVAR | Valor alfanumérico de longitud variable, hasta 999 caracteres. La longitud del valor se codifica en los dos primeros caracteres del valor; por ejemplo "HOLA" se codifica como 004HOLA
*--------------*----------------*-----------------+
ISO 8583 types and their corresponding j8583 types
Tipos de ISO8583 y sus contrapartes en j8583
* Common scenarios
* Escenarios típicos
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.
Las implementaciones de ISO8583 pueden variar mucho dependiendo del proveedor, así como de los productos o
servicios manejados y las transacciones que se van a procesar, pero casi siempre hay ciertos campos que se
utilizan de la misma manera. A continuación se describen estos campos. <<ADVERTENCIA:>> Esto es algo que he
aprendido únicamente por experiencia, la cual ha sido limitada principalmente a proveedores de telefonía celular.
Aquí me enfoco más a describir un campo por su tipo y número, más que el uso que se le pueda dar.
** Message types
** Tipos de mensaje
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.
Estos son algunos de los tipos de mensaje más común. Estos tipos siguen cierta lógica, si se les ve como
valores de 2 bytes; el primer byte indica el tipo de operación: 02 son pagos, 04 son reversos, 08 son pruebas;
el segundo byte indica si es una petición o una respuesta. Y en ocasiones, los reenvíos de peticiones deben
terminar en 1 en vez de 0, por ejemplo un reverso se envía por primera vez como 0400 pero en ocasiones
subsecuentes se debe reenviar como 0401.
*------:--+
| 0200 | A payment or sale request.
| 0200 | Una petición de pago o venta.
*------:--+
| 0210 | A payment or sale response.
| 0210 | Una respuesta de pago o venta.
*------:--+
| 0400 | A reversal request (to undo a previous 0200 operation).
| 0400 | Petición de reverso (para revertir una operación 0200 previa).
*------:--+
| 0410 | A reversal response.
| 0410 | Respuesta de reverso.
*------:--+
| 0600 | A query (to check the status of a previous operation, or check an account's balance, etc).
| 0600 | Una consulta (por ejemplo de saldo o de una operación previa).
*------:--+
| 0610 | A query response.
| 0610 | Respuesta de consulta.
*------:--+
| 0800 | An echo request (just to keep the connection alive and make sure the other side is responsive).
| 0800 | Petición de eco (para mantener viva una conexión y asegurarse que el otro lado de la conexión sigue respondiendo).
*------:--+
| 0810 | An echo response.
| 0810 | Respuesta de eco.
*------:--+
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).
Algunas implementaciones requieren que se envíe 0400 cuando solamente se tiene la petición 0200 sin haber obtenido
respuesta (en caso de expirar el tiempo de espera para el 0210), y enviar 0420 cuando ya se obtuvo respuesta
(en caso de que ocurra algún otro error en el sistema, después de recibir el 0210).
** Common fields
** Campos comunes
[Field 3] Operation code, NUMERIC of length 6.
[Field 3] Código de operación, NUMERIC de longitud 6.
[Field 4] Amount, AMOUNT.
[Field 4] Monto, tipo AMOUNT.
[Field 7] Date, DATE10.
[Field 7] Fecha de la transacción, tipo DATE10.
[Field 11] Trace, NUMERIC of length 6.
[Field 11] Número de trace, NUMERIC de longitud 6.
[Field 17] Transaction date, DATE4.
[Field 17] Fecha de la transacción, tipo DATE4.
[Field 37] Reference number, NUMERIC of length 12.
[Field 37] Número de referencia, NUMERIC de longitud 12.
[Field 38] Confirmation number, NUMERIC of length 6.
[Field 38] Número de confirmación, NUMERIC de longitud 6.
[Field 39] Response code, NUMERIC of length 2.
[Field 39] Código de respuesta, NUMERIC de longitud 2.
[Field 41] Terminal ID, ALPHA of length 8 or 16.
[Field 41] Identificador de la terminal de venta, ALPHA de longitud 8 ó 16.
[Field 49] Currency, NUMERIC of length 3. See the {{{http://en.wikipedia.org/wiki/ISO_4217}ISO 4217}} table of currencies.
[Field 49] Código de moneda, NUMERIC de longitud 3. Ver la tabla de códigos {{{http://es.wikipedia.org/wiki/ISO_4217}ISO 4217}}.
[Field 128] MAC (Message Authentication Code). Usually ALPHA or NUMERIC of length 16.
[Field 128] MAC (Código de autenticación de mensaje). Generalmente ALPHA o NUMERIC de longitud 16.
[]
** Asynchronous transmission and reception
** Transmisión y recepción asíncrona
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.
Cuando se comunican dos sistemas con ISO8583, generalmente la comunicación es asíncrona y todos los mensajes
se manejan por una misma conexión. Entre una terminal y un sistema de mayor tamaño, la comunicación suele ser
síncrona.
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.
En la comunicación asíncrona, el cliente puede enviar cualquier cantidad de peticiones al servidor, y el servidor
puede enviar las respuestas en un orden distinto. Es por esto que el número de traza (campo 11) es tan importante
y no se debe repetir en periodos cortos de tiempo; si el cliente envía peticiones con trazas 123000, 123001 y
123002, el server puede contestar primero la 123001, luego 123002, y finalmente la 123000. El cliente sabrá
a qué petición corresponde cada respuesta por medio del número de traza.
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.
Los mensajes pueden variar en su longitud según el tipo de mensaje y los campos que contenga. El protocolo fue
diseñado de modo que un mensaje se pueda leer en partes; primero el tipo de mensaje, luego el bitmap primario,
y a partir de ahí se leerá cada campo que indique el bitmap, uno por uno. Esto es muy conveniente para
dispositivos pequeños con poca memoria, como terminales de punto de venta, pero no es muy eficiente en sistemas
grandes que procesan un gran volumen de operaciones. En estos casos, generalmente se envía primero un encabezado
de longitud indicando el tamaño del mensaje como un entero sin signo de 2 ó 4 bytes (con el bit más significativo
primero). De esta forma, el receptor siempre lee primero 2 ó 4 bytes, los interpreta como un entero sin signo
y después lee tantos bytes como indique ese encabezado, para convertir esa trama en un IsoMessage. Un encabezado
de 2 bytes permite mensajes hasta de 65535 bytes, mientras que un encabezado de 4 bytes permite mensajes de
2147 millones de bytes, lo cual es más que suficiente, dado que un mensaje puede medir hasta 127290 bytes,
si se codifica en ASCII y tiene 127 campos tipo LLLVAR cada uno con 999 caracteres.
*** Message terminator
*** Terminador de mensaje
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.
El encabezado de longitud que se envía antes de un mensaje es muy útil para separar la operación de lectura
de la operación de procesamiento del mensaje; se puede dedicar un hilo a leer de un socket y encolar esas
tramas para que otro hilo las convierta en IsoMessages. Sin embargo, el encabezado de longitud únicamente indica
cuántos bytes hay que leer, para que el receptor sepa que tiene que recibir al menos ese número de bytes, pero
¿qué pasa si el mensaje en realidad es <más largo> de lo que dice la longitud? Habrá problemas leyendo el
siguiente mensaje. Para evitar este error, algunos sistemas implementa un terminador de mensaje, que es
simplemente un caracter que va al final de cada mensaje. Si los mensajes se codifican como texto, un terminador
común es ASCII 0x03. El terminador puede ser contado como parte del mensaje (incluido en el encabezado de
longitud) o ser contado aparte, depende de la implementación. Se puede especificar el terminador en la propiedad
<<<etx>>> de un IsoMessage, y también en la misma propiedad de la MessageFactory para que todos los mensajes
creados por la fábrica ya contengan el terminador y lo incluyan al generar sus tramas. Para no utilizar un
terminador, se debe indicar -1 en el <<<etx>>> (este es el valor por defecto).
** Binary encoding
** Codificación binaria
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).
Muchas implementaciones de ISO8583 utilizan texto simple para los mensajes (aunque el encabezado de longitud
sea binario). Pero algunas implementaciones codifican sus mensajes en binario. Entre las diferencias
principales tenemos que el tipo de mensaje es de 2 bytes en vez de 4 (la versión ASCII de hecho es una
representación de texto hexadecimal el tipo de mensaje), el bitmap no viene codificado en hexadecimal por lo
que mide sólo 8 bytes; y todos los valores numéricos (incluyendo campos tipo fecha/hora) se codifican usando
{{{http://es.wikipedia.org/wiki/Binary-coded_decimal}BCD}} (incluyendo los encabezados de campos LLVAR y LLLVAR).
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.
Se pueden codificar un mensaje en formato binario activando la propiedad <<<binary>>> de un IsoMessage, o la
propiedad <<<useBinaryMessages>>> de la MessageFactory, para afectar los mensajes creados a partir de ese momento.
Además para poder leer mensajes en formato binario se debe activar la propiedad en la MessageFactory.