diff --git a/pom.xml b/pom.xml index c4a4970..a6e9c5b 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,10 @@ test + + Enrique Zamudio + http://javamexico.org/blogs/ezamudio + chochos diff --git a/src/main/java/com/solab/iso8583/MessageFactory.java b/src/main/java/com/solab/iso8583/MessageFactory.java index c3bdc0d..40ca272 100644 --- a/src/main/java/com/solab/iso8583/MessageFactory.java +++ b/src/main/java/com/solab/iso8583/MessageFactory.java @@ -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); diff --git a/src/site/apt/iso8583.apt b/src/site/apt/iso8583.apt index 51e518d..b395113 100644 --- a/src/site/apt/iso8583.apt +++ b/src/site/apt/iso8583.apt @@ -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 diff --git a/src/site/es/apt/groovy.apt b/src/site/es/apt/groovy.apt index 3f691f2..a0c4607 100644 --- a/src/site/es/apt/groovy.apt +++ b/src/site/es/apt/groovy.apt @@ -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 <<>> and <<>> methods that work similar - to <<>> and <<>>, and the IsoType class has two <<>> 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 <<>> y <<>>, que + funcionan de manera similar a <<>> y <<>>; la clase IsoType tiene dos variantes del + método <<>>, 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. diff --git a/src/site/es/apt/guide.apt b/src/site/es/apt/guide.apt index 1bc1f65..b8f0878 100644 --- a/src/site/es/apt/guide.apt +++ b/src/site/es/apt/guide.apt @@ -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}}. diff --git a/src/site/es/apt/iso8583.apt b/src/site/es/apt/iso8583.apt index 51e518d..c8a5832 100644 --- a/src/site/es/apt/iso8583.apt +++ b/src/site/es/apt/iso8583.apt @@ -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 <<>> 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 <<>>. A continuación se presenta una tabla con los tipos ISO más comunes + y su contraparte en j8583: *--------------*----------------*-----------------+ -| <> | <> | <> | +| <> | <> | <> | *--------------*----------------*-----------------+ -| 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. <> 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. <> 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 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 <<>> - 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 <<>> 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 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 + <<>> 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 <<>> (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 <<>> property of IsoMessages, or in the MessageFactory - directly by setting the <<>> 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 <<>> de un IsoMessage, o la + propiedad <<>> 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.