ISO-8583 en Java

Para inaugurar mi blog, hablaré de un proyecto de software libre que tengo: j8583, también conocido como Java-ISO8583. Es una implementación semi-abstracta del protocolo transaccional de comunicación ISO-8583, que puede ser algo complicado y/o tedioso de implementar. UPDATE: Aquí he puesto una breve descripción en español.

ISO8583 es un protocolo transaccional de comunicación, muy utilizado en bancos, también se usa con puntos de venta (las terminales de tarjeta de crédito por ejemplo), y últimamente también se está usando para transaccionar con carriers de telefonía celular. No voy a entrar a detalle en el protocolo como tal. Se puede obtener (pagando) del sitio de ISO.

Para poder utilizar esta librería, se requiere conocer el protocolo en sí. Tiene licencia LGPL, de modo que se puede usar en aplicaciones comerciales cerradas; si hacen una aplicación que se redistribuye (software que venden, etc) solamente deben entregar los fuentes de la librería, junto con cualquier modificación que le hagan.

El paquete incluye ejemplos de una implementación de un cliente que envía y recibe mensajes de ISO8583, así como un server que recibe conexiones y atiende a varios clientes usando ISO8583. Se puede usar de modo binario o ASCII (lo más común).

La página del proyecto es y por supuesto

La documentación y la página las puse en inglés para no excluir a gente de otros países que puedan usar el proyecto. No he tenido tiempo de traducir nada (los javadoc de hecho no sabría cómo generarlos en español, fuera de tomar los HTML generados y traducirlos). La configuración de la fábrica de mensajes (la parte central de la librería) es bastante sencilla, a través de un archivo XML donde se definen plantillas para los tipos de mensaje que se van a crear, así como definiciones de los mensajes que se van a leer, indicando los campos esperados, con su longitud y tipo. De los campos indicados en las definiciones de respuestas, solamente se leen los que se indiquen en el bitmap de una respuesta. De esta manera, leer los mensajes ya es algo automático, todo el código para parseo de respuestas está en la fábrica de mensajes, no es necesario implementar algo adicional.

Los mensajes creados por la fábrica de mensajes son editables, pueden modificarse, agregarse o quitarse campos. La idea es que la fábrica genere nuevos mensajes ya con todos los valores fijos para el tipo de mensaje, y que solamente se tengan que asignar los valores que cambian. Incluso los dos valores que generalmente cambian, los campos 7 (fecha) y 11 (trace), se pueden asignar por la fábrica, poniendo la fecha actual a cada mensaje recién creado y usando un TraceNumberGenerator (una interfaz cuya implementación pueden proveer ustedes) para asignarle un trace en el campo 11 a cada mensaje generado.

Espero les sea de utilidad. Cualquier duda me pueden contactar directamente en SourceForge, registrando cualquier defecto que encuentren y poniendo ahí sus dudas.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Ayuda!!!

Hola ezamudio, mira te pongo en contexto... estamos implementando el estandar iso8583 en un proyecto que estamos desarrollando actualmente, el punto es: Una empresa llamada E-global me va a enviar un String, el cual va a ser parseado por un socket en java y posteriormente esté enviara un Request a un WebService para aplicar ciertas operaciones (pagos, consultas y/o reverso) , el webService me devolvera un Response, el cual va a ser tomado de nueva cuenta por mi Socket y armara un String con la respuesta para que sea enviada de regreso a E-global.

La pregunta es: como E-global va a ser el que inicie las peticiones de los mensajes, es decir, ellos me enviarian el mensaje 0200, 0420 y/o 0800 y yo unicamente voy a devolver un 0210, 0430 y/o 0810 dependiendo del tipo de mensaje, en mi XML donde tengo los template y los parse... como debo armarlo???

Por si no estoy siendo muy claro, debo tener tags template 0200, 0210, 0420, 0430, 0800 y 0810 o simplemente con los 0210, 0430 y/o 0810 es suficiente???

Otra cosa seria, en mi parse 0200 que fields debo tener, los que vengan en la especificación de la petición o de la respuesta

Gracias por tu ayuda.

Imagen de ezamudio

templates

En tu caso si solamente vas a responder mensajes, puedes no tener templates para crear mensajes, solamente necesitas los templates para parsear las peticiones que te van a enviar. MessageFactory tiene un método para crear una respuesta a un mensaje; si le pasas por ejemplo un IsoMessage tipo 0200, te devuelve un 0210 que trae todos los campos del 0200, ya solamente debes agregarle los que falten, y si sobra alguno pues también quitarlo.

Y obviamente en la guía de parseo de cada tipo de mensaje incluyes los campos que ellos dicen que te van a enviar en el tipo de mensaje que te van a enviar. Ya dijiste que te van a enviar un 0200, porque ellos te envian las peticiones. Entonces necesitas crear una guía de parseo para el 0200 que incluya los campos que dicen que te van a enviar en el 0200.

Persistencia

Hola, tengo una duda en cuanto a la persistencia en JPOS, en el manual vienen algunos ejemplos, pero la verdad son muy burdos y sigo en las mismas,, bueno, el caso es que quiero hacer un objeto a partir de la clase PersistentEngine, pero me pide tres parámetros, la configuración, un log y un realm (tengo entendido que éste es un string), el gran problema es cuando quiero hacer un objeto de la clase Configuration para mandarlo, lo he intentado con el método put, que según yo es ahí dónde mando los datos de la configuración, en la documentación dice que es un string (el nombre de la propiedad) y un object(otro string), pero cuando ejecuto el programa me manda nulos :S ... ya no sé qué hacer.. te dejo el código con el que lo hago, Saludos y espero que puedan ayudarme... plisssssss!!!


Logger l = new Logger();
String p = "prueba";
cfg.put("objeto", "hola");
PersistentEngine e = new PersistentEngine(cfg,l,p);
Error:
Exception in thread "main" java.lang.NullPointerException
at Test.Persistencia1.main(Persistencia1.java:38)

gracias =)

Imagen de ezamudio

no uso jpos

no uso jpos. Este post y discusión es de j8583, no de jpos.

Oooops

Oooops ... en todo caso .. gracias =) seguiré buscando .. sabes de algún lugar donde me puedan ayudar??

Header

Hola de nuevo, oye me surgio una duda con respecto a la composicion del mensaje (HEADER), mira la especificación que me pasaron es la siguiente:

8.1.3 Composición del mensaje.

Cada mensaje de solicitud y respuesta deberá estar formado por un encabezado y un área de datos. El encabezado tendrá una longitud de 2 bytes y contendrá la longitud del área de datos (mensaje ISO) que le sigue. El valor especificado en el encabezado no incluirá la longitud del mismo.

El protocolo TCP/IP podrá incluir dentro de cada paquete tanta información como le sea posible, trayendo como consecuencia que en un mismo paquete pueda viajar un mensaje completo, uno completo y otro incompleto, dos incompletos, etc. De ahí la importancia del correcto uso del encabezado para delimitar los mensajes.

Dentro del jar, no se maneja de esta forma o si???

De antemano gracias. Saludos.

Imagen de ezamudio

incluso hay un método en IsoMessage para escribir un mensaje a un OutputStream, con un encabezado de la longitud que le indiques (entre 2 y 4 bytes). Para leer los mensajes, debes tener un ciclo leyendo de tu InputStream primero 2 bytes, interpretarlos como la longitud del mensaje, crear un buffer de ese tamaño y leerlo; cuando lo hayas leído completo, lo pasas a la MessageFactory para obtener el IsoMessage correspondiente.

Lo que dice de TCP es cierto, pero a nivel aplicativo te afecta principalmente para la lectura (programa tu lectura de datos para que pueda ser en varios pasos, no esperes leer toda la trama de un golpe).

Gracias

Hola de nuevo,

Dentro de los ejemplos que vienen en el proyecto, no viene un ejemplo de como leer los mensajes de este tipo, lo que quiero es saber la longitud del area de datos para así poder determinar si es un string completo, uno completo y uno incompleto y/o dos incompletos...

Si me explico.

Gracias ezamudio.

Imagen de ezamudio

?

no, creo que no te explicaste bien. Pero en fin, la lectura de datos no concierne a j8583, está fuera de su alcance. Pero sí hay ejemplos de eso, en las clases de cliente y servidor, de hecho hay versión con java.io y con java.nio. No lees strings, lees bytes, por fragmentos, como se leen datos de sockets usando cualquier protocolo.

Es simple:

- Lees 2 bytes
- Interpretas esos 2 bytes como un entero sin signo
- Creas un buffer (byte[]) del tamaño que obtuviste en el paso anterior
- Lees bytes del socket hasta llenar ese buffer

Code

Se realiza con estas lineas, verdad???

while (socket != null && socket.isConnected() && Thread.currentThread().isAlive() && !Thread.currentThread().isInterrupted()) {

int count = 0;
byte[] lenbuf = new byte[2];

if (socket.getInputStream().read(lenbuf) == 2) {
int size = ((lenbuf[0] & 0xff) << 8) | (lenbuf[1] & 0xff);
byte[] buf = new byte[size];

socket.getInputStream().read(buf);
count++;

new Thread(new Processor(buf, socket, 400), "resp").start();
}
}

Imagen de ezamudio

más o menos

ese código va en contra de lo que te mencionaron de que el mensaje puede llegar en una sola lectura o en varias. Ese código hace una sola lectura del buffer (se supone que intenta llenarlo, pero nunca se sabe). Es un poco más elaborado pero como dije desde el principio, nada tiene que ver con j8583.

Ejemplo de BitMap

Mira es que no entiendo como se debe hacer, te pongo un ejemplo del bitmap que necesito parsear:

0000 | 49534F30 31353030 30303537 30323030 42323341 38303031 32384131 39303138

| ISO0150000570200B23A800128A19018 |

0020 | 30303030 30303030 31303030 30313030 35303939 30303030 30303030 30303335

| 00000000100001005099000000000035 |

0040 | 30303031 30363138 30323532 31383331 30333138 30323532 30313036 30313036

| 00010618025218310318025201060106 |

0060 | 30313036 30323132 32313938 30303031 30303030 30313030 30313D34 38313231

| 01060212219800010000010001=48121 |

0080 | 32303130 36313833 31303345 4D303820 20202020 20202020 20202020 20202020

| 20106183103EM08 |

00A0 | 20202020 20202020 20202020 20202020 20202020 20202020 20202020 20202020

| |

00C0 | 20202030 34345052 55454241 434F424C 494E4541 32312020 20202B31 38333130

| 044PRUEBACOBLINEA21 +18310 |

00E0 | 32372020 30313030 30303037 37373939 34203438 34202020 20202020 20202020

| 27 0100000777994 484 |

0100 | 20202020 20303131 42303132 43454C2B 43494530 31332020 20202020 20202020

| 011B012CEL+CIE013 |

0120 | 20202030 36303030 30303130 30324D58

| 06000001002MX

Y honestamente no termino de entender como lo tengo que programar, tú me comentas que eso no es de ISO8583, me podrias recomendar algunoas articulos o paginas en donde me pueda dar una idea de como hacer eso???

Gracias

Imagen de ezamudio

formato

Medio raro ese formato pero en fin.

Lo primero parece el encabezado ISO (los primeros 12 chars ISO015000057) y luego un mensaje tipo 0200, luego el bitmap B23A800128A19018.

Necesitas una spec para saber qué campos estás esperando y de qué tipo es cada uno. El bitmap solamente indica qué campos hay, pero no de qué tipo son. Este bitmap indica que la trama trae campos 1, 3, 4, 7, 11, 12, 13, 15, 17, 32, 35, 37, 41, 43, 48, 49, 52, 60 y 62.

Con esa spec puedes crear un archivo de configuración para tu MessageFactory, indicando la guía de parseo para los mensajes 0200 (si es que estás esperando recibir mensajes 0200) y/o una plantilla para los mensajes 0200 (si es que vas a crear y enviar mensajes 0200). En j8583.sourceforge.net está toda la info acerca de dicho archivo.

???

Como le hiciste para saber que el bitmap B23A800128A19018, esta indicando que los campos que traé son 1, 3, 4, 7, 11, 12, 13, 15, 17, 32, 35, 37, 41, 43, 48, 49, 52, 60 y 62.

=@ =O, estoy intentando deducirlo pero no le encuentro la lógica....

Imagen de ezamudio

jej

es que tú ves puros códigos hexadecimales... yo ya veo rubias, morenas, pelirrojas...

ya en serio, sí tengo ojo para medio parsear tramas de ISO8583 después de varios años de estar trabajando con varias implementaciones.

Para saber que el bitmap indica esos campos, solamente debes interpretarlo como una cadena hexadecimal de 64 bits. B2 por ejemplo: B es 11, 2 es 2, 11 en binario es 1011 y 2 es 0010 por lo tanto el primer byte es 10100010; los bits encendidos son 1, 3, 4 y 7. El siguiente byte es 3A; 3 es 3 y A es 10; en binario, 3 es 0011 y 10 es 1010 por lo tanto el segundo byte es 00111010 pero como ahora empiezas a contar del noveno bit, tienes los bits 11, 12, 13 y 15. Y así con los demás (obvio no hago esto a mano, tengo ya un programita que me dice qué bits están encendidos y la verdad ahora que lo pienso, no sería mala idea meterlo a j8583 como herramientas adicionales).

Bug de la trama LLLVAR

Hola buenas tardes, creo que hay un bug con el campo LLLVAR, me doy cuenta que cada vez que es necesario convertir una trama desde bytes la cual contiene como último campo un LLLVAR sin datos (es decir solo lleva dos bytes nulos al final) la librería no lo puede convertir y lanza una excepción "Insufficient data for LLLVAR" o algo así, me doy cuenta que solo pasa cuando el campo esta al final, si un campo LLLVAR sin datos va en la mitad de la trama la librería funciona correctamente.

por ejemplo la trama:

00 00 00 00 00 08 10 30 38 00 00 02 90 00 08 40 03 00 00 00 87 82 67 10 00 00 01 22 30 37 06 25 30 30 30 30 30 30 30 34 32 37 00 00 05 31 32 33 34 35

y el código:

map.put(3,new NumericParseInfo(6));
map.put(4,new NumericParseInfo(12));
map.put(11,new NumericParseInfo(6));
map.put(12,new NumericParseInfo(6));
map.put(13,new NumericParseInfo(4));
map.put(37,new AlphaParseInfo(12));
map.put(39,new AlphaParseInfo(2));
map.put(41,new AlphaParseInfo(8));
map.put(44,new LlvarParseInfo());
map.put(48,new LlvarParseInfo());
map.put(60,new LllbinParseInfo());
map.put(61,new LllvarParseInfo());
map.put(62,new LllbinParseInfo());
map.put(63,new LllbinParseInfo());

(No recuerdo que campos específicos se usan en esta trama en particular, por eso puse todos los que uso)

IsoMessage msg=factory.parseMessage(data,5);
IsoValue val=msg.getField(61);
System.out.println("CAMPO 61: " + val.getValue());

da como resultado: CAMPO 61:12345

pero la trama:
00 00 00 00 00 08 10 30 38 00 00 02 90 00 08 40 03 00 00 00 87 82 67 10 00 00 01 22 30 37 06 25 30 30 30 30 30 30 30 34 32 37 00 00 00

y el mismo código tira la excepción:

"java.text.ParseException: Insufficient data for bin LLLVAR header, field 61 pos 43"

De antemano, gracias por la atención a este mensaje si se le puede dar solución.

Imagen de ezamudio

github

Por favor registra el bug en github para resolverlo en el siguiente release

duda sombre los campos

Que tal un saludo!

Tengo una duda en el envío de la información, a ver si alguien sabe porqué.

cuál es el criterio para decidir qué campos se envía?
por ejemplo:
se envía los campos

4 - monto (en centavos, 12 posiciones fijo)
7 - fecha y hora del mensaje (10 posiciones en formato MMddHHMMSS)
11 - trace (6 dígitos)

porque utilizan el 4, 7 y 11 para el envío y no utilizan el 2,3,4 en forma consecutiva?

Imagen de ezamudio

estándar

Eso está descrito en el estándar de ISO8583. Búscalo en Google, hay una página en wikipedia que describe bastante bien esto porque el documento oficial está en IEEE y cuesta una lana.

Problema al Mapear

Que buen aporte hiciste @ezamudio y me da gusto que la gente apoye a los desarrolladores, pero bueno siguiendo tu ejemplo he notado que varios errores son porque no saben mapear correctamente el ISO 8583 o ignoran si están bien formados, así que les voy a proporcionar una hoja de calculo que diseñe en excel, la cual te permite ver todos los campos y valores que tenga un ISO simplemente tienen que pegar el ISO (sin los 2 bytes de longitud) en la celda de color verde y automáticamente van a poder ver todos los campos.

Excel ISO8583

Saludos y espero que esto les sirva.

PD. Una vez que hayan pegado el ISO y solo les interesa ver los campos que están viajando, seleccionen la columna Longitud y filtren todos los campos que tengan el valor "0" de esa manera solo aparecerán los campos que están viajando.

Hola, gracias por el aporte.

Hola, gracias por el aporte. Estuve probrando en el excel una trama, la cual el cliente tiene problemas para parsear y me di cuenta que estas definiendo el element 41 con un tamaño de 16 cuando la especificación indica que deber ser de 8.
Saludos.

Problemas con Trama ISO8583 y header Custom.

Hola. Quería ver si me podían ayudar a validar la siguiente trama. Cabe destacar que para nosotros la trama es correcta pero al cliente le llegan los datos cortados a partir de las primeras posiciones del elemento 63.

A continuación la trama:

00160|0123456789|154|01|092|SPO|0205A2200000A08000020000000010000000930000310717060212345604960015123456789012002CAIXAURA030000200000000000000000000000000040104

Análisis de trama desde el servicio que origina la transacción:

4500 00d4 a6e3 4000 4006 12dc ac10 0801 E.....@.@.......
ac14 203f bc10 2710 da94 6c84 c8cd 55f3 ...?..'...l...U.
8018 002e 812b 0000 0101 080a 9bdb ca92 .....+..........
0000 0000 3030 3136 307c 3031 3233 3435 ....00160|012345
3637 3839 7c31 3534 7c30 317c 3039 327c 6789|154|01|092|
5350 4f7c 3032 3035 4132 3230 3030 3030 SPO|0205A2200000
4130 3830 3030 3032 3030 3030 3030 3030 A080000200000000
3130 3030 3030 3030 3933 3030 3030 3331 1000000093000031
3037 3137 3036 3032 3132 3334 3536 3034 0717060212345604
3936 3030 3135 3132 3334 3536 3738 3930 9600151234567890
3132 3030 3243 4149 5841 5552 4130 3330 12002CAIXAURA030
3030 3032 3030 3030 3030 3030 3030 3030 0002000000000000
3030 3030 3030 3030 3030 3030 3030 3034 0000000000000004
3031 3034 0104

Se corta a partir de aqui: 00160|0123456789|154|01|092|SPO|0205A2200000A08000020000000010000000930000310717060212345604960015123456789012002CAIXAURA03000020....

Importante: Esta trama tiene un header custom del cliente.
Muchas gracias.

Hacer cliente para ISO 8583

Hola ezamudi, estoy intentando hacer un cliente pero no tengo mucha nocion sobre el ISO 8583, tu me puedes ayudar?

saludos.

Imagen de ezamudio

pues...

Si no sabes qué es ISO8583 lo mejor es que leas la página de wikipedia o consigas algún documento que te lo explique. Sin ese conocimiento, no te va a servir de mucho j8583.

No puedo parsear mensajes iso8583

Antes que nada buenas noches sr. Zamudio, agradezco que te tomaras el tiempo y conocimientos para subir este tipo de aportes,
te cuento brevemente el motivo por el cual consulto, he estado probando j8583 en una aplicación que estoy desarrollando, y me he topado con un detalle al momento de pasear los mensajes iso8583
he probado con las clases de ejemplo que aportaste y me pasa el mismo detalle, simplemente no parsea el mensaje al ejecutar la linea:

IsoMessage msgParseado = mfact.createResponse(incoming);

ni me arroja excepción alguna en pasar por dicha linea, en mi aplicacion y al correr tus ejemplos siempre el objeto msgParseado es igual null

mfact fue ya seteado de la siguiente manera:

mfact = ConfigParser.createFromClasspathConfig(/probarj8583/configj8583.xml");

creo que el detalle esta a la hora de ir por el archivo, te comento que he probado en poner toda la ruta en donde se encuentra el xml, también solamente el nombre sin diagonal y con diagonal, etc, pero nunca arroja excepción si el error se genera en este punto.

Por favor pido tu apoyo con algún comentario o idea que te venga a la mente de por que no puedo parsear los menajes, mi ambiente de desarrollo es en netbeans y trabajo con una distribución linux fedora

la librería j8583 que utilizo es: j8583-1.11.0
y adicionalmente para poder compilar los paquetes: slf4j-1.7.9 y slf4j-nop-1.7.9

mi xml de pruebas es:
 

pero también he probado con tu xml de ejemplo en mi código, y obviamente con tus clases.

por favor si requieres mas información indícame para proporcionarla.

Desde ya te agradezco.

Saludos.

Imagen de ezamudio

log4j

Habilita logging a nivel bajo (debug o incluso trace) para que puedas ver los mensajes de la MessageFactory, que imprime varios cuando se configura a partir del XML.

logging en nivel "FINEST"

Buenas tardes Enrique, gracias por el tip, el error que tenia era que no estaba ingresando un path correcto, pero como no tiraba excepción y SI me generaba un mensaje ISO8583 pues simplemente no lo note antes, con tus clases ejemplo era algo así "carpeta/config.xml"
sigo teniendo problemas a la hora de pasarlo a mi aplicación, estoy trabajando con una Java Enterprise Application, probé con un path similar, quitando y poniendo carpetas en el path, incluso la ruta completa y no logro hacer que funcione,
en estos momentos lo he solucionado con la función alternativa createFromUrl que incluiste en ConfigParser, me he propuesto avanzar de esta manera y mas adelante veo que sucede pues me encuentro muy atrasado con este desarrollo.

Si tienes alguna experiencia implementando j8583 en una Enterprise Application (la del triangulito con sus modulos ejb y web) o sabes como se comporta el classpath en este tipo de aplicaciones nuevamente agradeceré me compartas tu experiencia que sin duda me servirá.

Nuevamente muchas gracias.

Imagen de ezamudio

class loaders

Tu problema seguramente está relacionado con class loaders. El método   tiene dos variantes; la que recibe un ClassLoader es la que debes usar en ambientes JEE para que le pases un ClassLoader de tu aplicación y con eso encuentre el XML que le indicas, porque de lo contrario, va a usar el ClassLoader de la clase MessageFactory, que en un ambiente JEE es otro separado que va a buscar dentro del jar de j8583 nada más o en todo caso dentro del directorio lib, pero no tiene acceso al classpath de tu aplicación.

createFromClasspathConfig con ClassLoader para JEE

Excelente!! ya pude implementarlo gracias a tu ayuda,
perdona la demora en contestar, me enfoque en avanzar ya que estaba algo atrasado.

Saludos.

Iso 8583 diferente

como estas primero agredecerte por que me a servido demasiado tu libreria pero tengo un problema una institucion n me esta enviando los datos segun ellos en la iso 8583 pero analizando la trama que me envian no contiene el bitmap ahora mi pregunta va a lo siguiente como puedo hacer para que la libreria no tome en cuenta el bitmap o en su defecto yo partir de la cadena de texto que tengo poder generar el bitmap y enviarlo a si ala alibreria gracias

Imagen de ezamudio

no es ISO

Si no trae bitmap pues realmente no es ISO. No entiendo cómo pretenden que sepas qué campos enviaron si no trae un bitmap, a menos que realmente SIEMPRE el mensaje traiga los mismos campos. En ese caso tendrás que leerlo a bajo nivel, avanzando por campo, leyendo cada uno directamente con el FieldParseInfo correspondiente.

La otra opción, como bien dices, es que si siempre te envían los mismos campos, pues generes un bitmap en texto para representar esos campos, y lo uses siempre para parsear mensajes entrantes.

Iso

Serías tan amable de enviarme el java aplicacion ISO 8583 mi email es : negrod27@gmail.com

Imagen de ezamudio

Bájala

Está en maven central, en github.com/chochos/j8583 y en j8583.sourceforge.net