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.
- ezamudio's blog
- Inicie sesión o regístrese para enviar comentarios
RE:
bastante interesante, aunque no vendría mal una pequeña introducción sobre ISO 8583 para los que no sabemos bien que onda.
de cualquier manera ya me puse a investigar un poco, buen proyecto!
El protocolo como tal
Agregué un pequeño párrafo explicando algo en general del protocolo. El problema es que el documento que lo explica es muy largo, y no he encontrado una página donde se explique a detalle; solamente se puede bajar el PDF del sitio de ISO pero pagando una buena lana, lo que me hace pensar que la especificación en sí no es pública (lo cual es un poco ridículo siendo un estándar). No sé si al difundir los detalles del protocolo se infringe algun copyright o algo asi (no debería).
No estaría mal tener una página explicando el protocolo en español, eh?
JCAPS - ISO8583 - XML - HELP PLEASE!!!
Que tal amigos! les tengo una pregunta a ver si pueden ayudarme. El tema es asi: Estoy en un proyecto en el que vamos a recibir mensajes en formato ISO8583, estamos utilizando JCAPS para este proyecto, el tema es si saben si agregando JPOS a JavaCAPS, se pueden tomar los mensajes ISO8583 y transformarlos a XML?????
Desde ya muchisimas gracias!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Slds
Alexis.-
niso8583
Hola Enrique, encontre tu version para dot net "niso8583", me gustaria hacerte algunas preguntas ya que estoy tratando de utilizar las librerias.
1. He intentado eliminar el Header del mensaje, para cumplir con la especificacion que necesito " Message length, Message type identifier,One or two bitmaps,Series of data elements" eliminandolo del archivo de configuracion xml pero no lo he logrado, de igual forma he hecho estos intentos para declararlo con valor nulo pero ninguno ha funcionado.
null
NULL
saludos cordiales
PN
niso8583
Que raro, las pruebas que tengo en niso8583 son iguales a las de j8583, pero no recuerdo si hay una prueba de enviar mensajes sin header... la cosa es que j8583 si lo he usado en produccion pero niso8583 no, de hecho no esta terminado todavia. Pero pues para quitar el header de ISO simplemente podrias dejarlo en blanco en el XML, como una cadena vacia y eso deberia funcionar, no?
Given the choice of dancing pigs and security, users will choose dancing pigs, every single time.
Steve Riley
interesante
Hola que tal es muy interesante el proyecto espero puedas subir mas documentacion sobre la norma
Explicacion del protocolo
A petición popular, aquí está la descripción (breve) del protocolo ISO8583, en español.
Given the choice of dancing pigs and security, users will choose dancing pigs, every single time. - Steve Riley
Consulta sobre campo de Tipo LLLVAR
Hola que tal Enrique, esta muy interesante el framework.
Te explico, estoy revisando el framework y evaluando si es compatible con las tramas que tengo que generar y parsear, pero me manda un error.
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 411
at java.lang.String.checkBounds(Unknown Source)
at java.lang.String.(Unknown Source)
at com.solab.iso8583.parse.FieldParseInfo.parseBinary(FieldParseInfo.java:164)
at com.solab.iso8583.MessageFactory.parseMessage(MessageFactory.java:212)
at j8583.example.Example.main(Example.java:87)
He descargado las fuentes del ejemplo y he llegado a la conclusion que el error es cuando trato de poner una cantidad alta de caracteres en un campo LLLVAR,supuestamente deberia aceptar hasta 999 segun la norma, yo quiero poner 255 caracteres en un campo y me manda error en el parse.
Incluso he utilizado las fuentes y el ejemplo que mencionas alli , le he puesto un campo mas grande al que tienes de ejemplo y me manda el error mencionado.
field num="61" type="LLLVAR" (puse 255 caracteres y error ) OJO: el campo es LLLVAR
Por otro lado he estabo probando poner menor cantidad de caracteres y al poner mas de 80 caracteres me manda el siguiente error,
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 16
at com.solab.iso8583.MessageFactory.parseMessage(MessageFactory.java:167)
at j8583.example.Example.main(Example.java:87)
SI pongo menos cantidad todo sale OK, peor si aumento la cantidad de caracteres en los demas campos me manda el mismo error.
Hay alguna restriccion en cuanto al tamaño total de la trama ? o el tamaño de los campos ? me estoy guiando de la documentacion ISO8583 en español sobre los campos.
La generacion de la trama es correcta, pero como te indico el error me sale a la hora de hacerle "parse" a la trama generada para obtener el mensaje.
Seria de mucho aprecio tu ayuda debido a que si no me llega a parsear esa trama no podria utilizar el framework =( .
Espero tu pronta respuesta.
Campos anteriores
Sospecho que tu problema no es con el campo 61 sino con algún campo anterior. Seguramente quieres parsear un mensaje mal formado, que en el bitmap indica tener algún campo que realmente no viene en el mensaje. Recuerda que se leen de manera secuencial; si el bitmap dice que vienen los campos 3, 4, 7, 11, 37, 41 y 61 por ejemplo, y todos tienen longitudes fijas excepto el 61, entonces el parser va tomando los datos que encuentra y los convierte en los campos definidos por el bitmap. Por ejemplo los primeros 6 bytes los toma para el campo 3, los siguientes 12 para el 4, los siguientes 10 para 7, los siguientes 6 para el 11, los siguientes 12 para el 37 y los siguientes 16 para el 41, entonces ya leyó 62 bytes. De ahí espera leer 3 bytes que va a interpretar como la longitud del LLLVAR para saber cuánto mide ese campo (porque es de longitud variable).
El error que te está saliendo es por una de dos razones:
1. El bitmap indica un campo que realmente no viene, o tiene una longitud distinta de la especificada para el parser (si indicas que el campo 41 mide 16 bytes y nada más vienen 8, el parser se va a comer 8 bytes de los siguientes campos y ya de ahí queda mal sincronizado)
2. El campo 61 no trae encabezado de longitud. Los primeros 3 bytes del campo 61 indican la longitud. Por ejemplo si el contenido del campo es "hola" entonces el campo completo debe verse en la trama como "004hola".
Las tramas que estás parseando las generaste tú, o vienen de algun sistema externo?
Revision de Campos
Las tramas las estoy generando con el j8583, la generacion de las tramas funciona a la perfeccion, genera los 3 bytes antecesores a los campos LLLVAR y todo correctamente.
Lo que hice para descartar dudas de campos antecesores como me mencionaste fue ejecutar los ejemplos que vienen con las fuentes de J8583 .Al correrlo todo funciona a la perfeccion pero cuando intento poner un texto de mas de 90 digitos en el campo que menciono abajo me mando error.
field num="61" type="LLLVAR" => 1234P
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 16
at com.solab.iso8583.MessageFactory.parseMessage(MessageFactory.java:167)
at j8583.example.Example.main(Example.java:87)
En ese campo que supuestamente es LLLVAR le he puesto una cadena de 255 caracteres para hacer la prueba y me manda el siguiente error
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 417
at java.lang.String.checkBounds(Unknown Source)
at java.lang.String.(Unknown Source)
at com.solab.iso8583.parse.FieldParseInfo.parseBinary(FieldParseInfo.java:164)
at com.solab.iso8583.MessageFactory.parseMessage(MessageFactory.java:212)
at j8583.example.Example.main(Example.java:87)
Agradeceria tu apoyo y pronta respuesta
Saludos,
Johann
Configuracion
La otra posibilidad es que estés generando tramas con campos que no están indicados en la configuración del parser. Por lo tanto aunque venga en el bitmap, el parser no sabe qué hacer con dicho campo porque no lo tiene en su configuración.
Revision de Configuracion
Como te mencione en el mensaje anterior lo que hice fue ejecutar el ejemplo que viene con las fuentes de j8583 y en el campo
field num="61" type="LLLVAR" => 1234P del archivo de configuracion config.xml , al ponerle mas de 90 campos me salen los errores mencionados anteriormente..
config
Y no moviste NADA de la configuración? Cuál es la que usaste para las pruebas, la que esta en subversion en la ultima revisión? voy a ver esa a ver si tiene algun problema.
config
Lo unico q movi de la configuracion es el valor del campo osea en vez de 1234P le puse una cadena mas larga.
La version que descargue es la 1.2 que es la unica que vi en la pagina del proyecto
Espero tus respuestas de la revision enrique.
Saludos y gracias.
config
OK creo que el problema que mencionas no es con los ejemplos de sockets sino con el que lee de un archivo. El problema está en el método main de la clase Ejemplo, cuando se va a parsear el archivo con el mensaje binario:
debe ser realmente
Gracias por encontrar este error, subiré la corrección al repositorio cuanto antes y voy a revisar el release para que al menos el ejemplo ya no tenga este problema, que causaba que no se leyera el archivo completo y por eso ocurre el problema que mencionas.
niso8583 Processor.Respond
Saludo, Estoy realizando pruebas con el niso 8583 y tengo algunas dudas quisiera saber si alguno me puede ayudar.
IsoMessage incoming = mfact.ParseMessage(msg, 12);
Esta llamada envía el arreglo de bytes recibido y el tamaño del header.
Para hacer pruebas estoy usando el VTS3 y este software que emula el vap me envía una cabecera que es de 12 campos pero que contiene 22 bytes (en realida son 44 bytes fixed).
Creo que se debe cambiar en esta línea el 12 por un 22.
Gracias desde ya por su ayuda.
ok
creo que ya te preguntaste y respondiste. Si no funciona con 12, prueba con 22 y si no con 44. No entendi el resto de lo que dijiste.
ni8583 Alguien lo a probado
Saludos, Gracias por tu ayuda.
No estoy muy seguro de que el software niso8583 que se puede bajar de subversion, en realidad funcione.
Lo estoy pegando al VTS3 y no funciona el decoding de los bytes me parece que no es el adecuado.
Alguien me puede dar una luz.
Gracias desde ya por su ayuda.
niso8583
niso8583 es la versión en .NET de j8583, es un port que estoy haciendo pero la verdad no lo he usado en producción, no uso .NET actualmente y por lo tanto no está tan actualizado como j8583 que sí lo tengo funcionando en producción.
No sé qué es VTS3. Si me dejas en la página de niso8583 el reporte del problema indicando la excepción que obtienes o el error que obtienes (un resultado inválido cuando sabes que debería haber otro resultado), la manera de reproducirlo, cuando tenga un rato lo veo.
niso8583
VTS es Visa Test System, es el sistema que entrega la marca Visa de tarjetas de crédito para realizar certificaciones imitando lo que sucede en producción. En este sistema existen tramas visa, mastercard y amex.
Voy a revisar el codigo java, para llevar el concepto a .net, y te envío los cambios que realice.
Gracias por tu ayuda.
Iso8583 ver 2003
Hola que tal, estoy realizando pruebas con J8583 y me parece muy util, pero me entro una y al revisar el código crecieron más. Esta libreria esta desarrollada para la version más antigua de la ISO, creo que para la de 1987. ¿Estoy en lo correcto?. Bueno, estuve realizando cambios en la libreria, y me topé con el inconveniente de que no se contempló el uso de DataElements compuestos, como el DataElement 6 "Amount cardholder billing" que consta de 3 campos. Bueno ese fue mi problema, me gustaria saber si en el desarrollo que realizaste contemplaste este tipo de dificultades, o si existe una versión más actualizada de esta libreria. Finalmente muchas gracias por esta contribución que me ha ayudado bastante en el aprendizaje de este protocolo ISO8583.
No
La versión en la que me basé es una especificación que recibí una vez para realizar un desarrollo similar, por encargo, y me parece que era de finales de los 90's. El problema con ISO8583 es que cada quien hace su implementación como le da la gana. Actualmente sólo se manejan valores de tipo numérico, alfanumérico, montos y fechas en los campos. El tipo de dato que mencionas finalmente se va a codificar como texto para su inclusión en una trama y se debe parsear dicho texto para su lectura de dicha trama. En mi experiencia estos campos vienen al final como LLVAR o LLLVAR o un ALPHA y ya dentro del texto traen sus delimitadores o lo que sea para separar los sub-campos. Esto se puede manejar por fuera de la librería, es decir, codificas tus datos como el texto que debe ir en el campo correspondiente y lo metes a un mensaje, y la parte inversa es que obtienes el texto del campo correspondiente y parseas los datos para obtener tus sub-campos.
Tengo planeado incluir algún tipo de dato CUSTOM en la siguiente versión, pero estoy evaluando la mejor manera de hacer esto, que sea simple para el usuario pero tenga buen performance. Lo más probable es que defina una interfaz con un método para codificar tu propio objeto y otro para parsearlo, para que implementes esa interfaz y de algún modo indiques al MessageFactory que debe usarse tu componente para el campo X, de modo que primero se invoque tu componente y el texto resultante ya se codifique en la trama, y en la operación inversa se parsee el texto de acuerdo al tipo estándar de ISO8583 y posteriormente tu componente parsee el dato y devuelva un objeto, el cual se incluye ya en el mensaje resultante. Pero hoy en día no existe tal funcionalidad.
Problema al recibir respuesta
Hola que tal, tengo un tiempo tratando de utilizar J8583, pero a la hora de enviar el mensaje, me dice que no estoy enviando el Header, ni la longitud del mensaje, como puedo lograr esto al enviar el mensaje? Por otra parte que puedo hacer para darme cuenta de que estoy enviando la trama de forma correcta? Que no me falta nada? No se si ese sea el problema por el cual la respuesta del socket es null.
La vida nos da sorpresas xD
Gracias por la pronta respuesta, verás yo estoy haciendo eso mismo, y me parece gracioso, pues creo que manejarlo por medio de una interfaz en los más apropiado, aca me tiraban golpes por no darles las cosas de forma sencilla >.<. El problema reside en mi inexperiencia en el uso de este tipo de protocolo y la falta de ejemplos de implementación o de mensajes. Actualmente, ya elabore una forma de parsear este tipo de cadenas para los DataElements CONSTRUCTED que se refieran a monstos ya sea Data Elemente 6, 30, etc.
Bueno muchas gracias, a cambiando de tema, ¿cuanto tiempo te tomo elaborar esta libreria entre analisis, diseño y desarrollo? para tener un alcance medio de cuanto me tomara a mi actualizarla xD.
Nuevamente gracias he aprendido bastante leyendo la libreria.
más info
vsuarez3, no entendi bien tu problema. La clase Message tiene un método para escribir a un OutputStream; si le pasas System.out como parámetro verás el mensaje en la salida estándar de tu programa.
Normalmente la comunicación de tramas ISO8583 se lleva a cabo por medio de un socket de manera asincrónica, y se transmite primero un encabezado de 2 o 4 bytes indicando la longitud de la trama, seguido de la trama. La librería j8583 ya viene preparada para esto, simplemente le indicas al mensaje cuántos bytes quieres utilizar para el encabezado de longitud. Y para leerlos de un socket necesitas leer 2 bytes (o 3 o 4), interpretarlos como la longitud de mensaje, y leer tantos bytes como te indiquen; eso lo pasas al MessageFactory para que te genere una instancia de Message. Fijate en los ejemplos de Client, Server y ChannelServer.
Tiempo
Flamel, escribir versión inicial de la librería completa me tomó aproximadamente una semana, pero esto porque era como la tercera vez que tenía que implementar algo así y decidí que en vez de hacerlo otra vez desde cero (porque no podía reutilizar código de las implementaciones previas porque es propiedad de otros clientes), valía más la pena hacer la librería externa y poderla utilizar en cualquier proyecto. Así que la experiencia de las implementaciones previas me dio mucha idea de cómo escribir esta versión, lo más simple posible y que permita bastante flexibilidad. Conforme he necesitado más funcionalidad se la he ido agregando. Si suficientes usuarios me piden alguna característica es posible que la implemente; si un usuario necesita una característica de manera urgente, podemos ya verlo como un proyecto pagado y así me comprometo a entregarlo en cierto tiempo y dar soporte ya por un canal más directo.
Nuevamente
Lo que pregunto es exactamanet lo que explicas, pero la respuesta que pido es en código: Cómo envio el encabezado y la longitud de la trama?
Lo que sucede es que me estoy conectando a una terminal remota y cuando envio la trama me dice que no tiene el encabezado ni l alongitud de la trama.
Además me dicen que la longitud del mensaje debe ser de 6 bits y la estoy enviando de dos.
Que debo hacer?
bits != bytes
6 bits? pero supongo que leen un byte completo... envia la longitud como un solo byte entonces...
CustomField en repositorio
Flamel: me puse a ver qué necesitaba para manejar otros datos aparte de String/Date/BigDecimal/Number en la librería y terminé haciendo los cambios necesarios. Hay una nueva interfaz CustomField que debes implementar para convertir tu propio objeto en un String y también crear uno de tus objetos a partir de un String; con esto puede meter un objeto tuyo a un campo LLVAR por ejemplo, y si le pasas tu implementación de CustomField al MessageFactory, lo va a usar para decodificar los objetos al parsear mensajes, de modo que cuando pides el valor del campo que sabes que trae tu objeto, nada más lo debes castear a tu clase.
Modifiqué el ejemplo Client.java para que se use esto en el campo 48. Haré el release 1.3 de la librería tal vez hoy mismo o la próxima semana pero mientras tanto puedes bajar estos cambios directo del repositorio. Nada más están en la versión para Java 5, después haré los cambios para 1.4.
Gracias.
Gracias, ya habia creado una solución para los DataElement 4 - 6 que son de tipo Amount, pero igualmente revisare la tuya, mas ahora me nacieron muchas otras dudas sobre la utilización de la norma. Por ejemplo: 1) ¿Se puede aplicar esta norma entre una entidad bancaria y homebanking?, hasta donde yo se es una norma para ATM, 2) esta norma, soporta estructuras complejas? es decir, listas o DTO's, dado que por ahi una persona me mencionó que si lo hacia, de hacerlo ¿como se hace?, 3) Si realizo un request asi: Consulta de tus ultimos movimientos, cuantas tramas de respuesta se generan o es solo una que implementa un tipo de dato complejo??
Disculpa si te molesto con mis dudas, pero me hacen volar ultimamente.
Muchas Gracias.
no se...
muchas preguntas. Si por "norma" te refieres al protocolo ISO8583, pues no veo por qué no se pueda aplicar entre una entidad bancaria y homebanking (sea lo que sea que entiendas por "homebanking"). Yo lo he visto en uso hasta para venta de tiempo aire celular. Se usa para transacciones monetarias, no solamente con bancos pero sí es lo más común. Los cajeros y las terminales de tarjeta de crédito también usan este protocolo.
Que yo sepa no se soportan estructuras complejas porque solamente es para datos alfanuméricos, pero pues dentro de un campo LLVAR o LLLVAR puedes almacenar cualquier cadena que puede ser una estructura compleja codificada... aunque ya sería una extensión y por lo tanto no es estrictamente parte del protocolo.
Lo que preguntas de consultar últimos movimientos, te lo tiene que contestar quien te vaya a mandar esa respuesta. ISO8583 a pesar de ser un estándar, varia mucho en cada implementación.
Problema con la Librería.
Se supone que la clase IsoMessage envía automáticamente estos datos antes del mensaje:
- Caracteres de inicio del mensaje (ej. 0000)
- Longitud del mensaje (ej. 0061)
- Tipo de mensaje (ej. 0200)
Qué puede estar sucediendo que no están llegando estos datos a quien le envío? Solo llega el mensaje y nada más.
Puede haber algún problema con la librería? O que crees que puede ser?
Otra cosa es: Los encabezados (del config.xml) pueden variar o son estándares.
no se
no me das info, no te puedo responder. Pero no es problema con la libreria, porque simplemente con que uses los ejemplos verás que funciona. La tengo funcionando además en algunos sistemas y no tiene problemas comunicándose con otros sistemas que no sé ni en qué estan hechos. Pero lo que envia antes del mensaje siempre es primero la longitud, luego si hay un encabezado ISO lo envia y finalmente el mensaje (incluyendo el tipo). Para ello debes usar el método IsoMessage.write(OutputStream,int) indicándole cuántos bytes debe usar para escribir la longitud (por lo general son 2, pero he visto casos en que piden 4). No veo cómo puede estarles llegando el puro mensaje.
Buenas, queria acotar algo
Buenas, queria acotar algo sobre el tema de la cabecera, esa cabecera no esta contemplada dentro de la ISO8583 ver 2003, basicamente ISO consta de 3 partes: MTI, BitMap, DataElements. Cuando yo use la J8583 por primera vez, me generaba la cabecera, ya metiendo mano pude eliminar que se requiera esa cabecera. También vi que cuando le pones tamaño 0 a la función IsoMessage.write(OutputStream,int), deberia obviar la parte esta de crearla, que por algun extraño motivo a mi no me funcionaba.
Cambiando de Tema, Enrique disculpa, me preguntaba si haz visto la implementación de este protocolo para Banca en Linea, en el caso de que el sitema de banca en linea se encuentre en el mismo servidor , ¿es necsario usar ISO ahi?.
Gracias.
Detalles
Sigo teniendo el mismo problema, me informan que no estan llegando los Caracteres de inicio del mensaje (ej. 0000), la Longitud del mensaje (ej. 0061) ni el Tipo de mensaje (ej. 0200), aqui te doy detalles, por favor ayudame con este problema.
Estoy utlizando tu librería, la ultima versión.
Lo primero que hago es coenctarme mediante socket. Hasta aquí todo bien.
Una vez conectado envío una operación como la siguiente:
this.isomsg = this.messageFact.newMessage(0x200);
msg.setBinary(true); //Tambien lo envio como asccii probando pro tampoco
msg.setValue(2, getNumero(), IsoType.LLVAR, 0); //Primary Account Number
msg.setValue(3, "00000", IsoType.NUMERIC, 6); //Processing Code
msg.setValue(4, new BigDecimal(getAmount()), IsoType.AMOUNT, 0); //Transaction Amount
msg.setValue(11, getSecuencia(), IsoType.NUMERIC, 6); //System Trace number
msg.setValue(12, fecha.substring(8), IsoType.TIME, 0); //Transaction Time
msg.setValue(13, fecha.substring(4, 8), IsoType.DATE4, 0); //Transaction Date
msg.setValue(14, getVence(), IsoType.DATE_EXP, 0); //Transaction Expiration Date
msg.setValue(22, "011", IsoType.NUMERIC, 3);
msg.setValue(35, getBanda(), IsoType.LLVAR, 0);
msg.setValue(25, "00", IsoType.NUMERIC, 2); //POS Condition code
msg.setValue(41, getTerminalId(), IsoType.ALPHA, 8); //Terminal Id
msg.setValue(42, getMerchantId(), IsoType.ALPHA, 15); //Merchant Id
msg.setValue(49, this.currecyCode, IsoType.NUMERIC, 3); //Currency Code
msg.setValue(52, this.decimalToBinary(Long.parseLong(getPin()), 64), IsoType.LLVAR, 0); //Cardholder PIN Block
msg.setValue(62, getIdLote(), IsoType.LLVAR, 0); //Invoice Number
return "0";
Estos campos son alimentados de una base datos.
Esa es la operación que envío, devuelvo 0, porque la tomo en otro sitio para procesarla, una vez la proceso, la imprimo y la envío.
logger.info("Voy enviar");
msg.write(output, 2);
this.write(fout, 2); //Escribo a un archivo
logger.info("Recibí la respuesta.");
tranRespuesta = read(input); //Lo que hago aqui es leer el socket pero me devulve null
logger.info("Respuesta: " + tranRespuesta); // tranRespuesta = a lo que exista en el socket
SImpre me devuelve null, no se si estoy perdiendo algun paso o que será...
Se supone que la clase IsoMessage envía automáticamente estos datos antes del mensaje:
- Caracteres de inicio del mensaje (ej. 0000)
- Longitud del mensaje (ej. 0061)
- Tipo de mensaje (ej. 0200)
Qué puede estar sucediendo que no están llegando estos datos a quien le envío? Solo llega el mensaje y nada más.
Que debo hacer para lograr obtener el mensaje completo?
Cuando hablo de operacion me refiero al tipo de mensaje.
Por favor, AYUDAME! con esto.
no se a que te refieres con
no se a que te refieres con caracteres de inicio de mensaje 0000. Revisa la especificación de quienes estan esperando el mensaje. Probablemente estan esperando 4 bytes al inicio, con la longitud del mensaje, y estas enviando solamente 2 (por eso dices 0000 que son dos bytes en ceros y luego la longitud con 0061 o sea 97).
Te recomiendo modifiques el ejemplo de Server.java para que espere los mensajes que tu vas a enviar y te los conteste. Con eso puedes hacer pruebas sin tener que conectarte a otro sistema.
Además sin saber qué hace tu método read(input) no puedo ayudarte más. Tal vez todo el problema reside ahí, aunque dices que ya es un hecho que no estan recibiendo del otro lado lo que esperan. Cuando la escribes a disco, tienes un archivo solamente con el mensaje? revisalo bien para que veas cómo se escribió el mensaje ahí; los primeros dos bytes son la longitud y luego viene tu mensaje, eso lo pueden revisar los encargados del otro sistema para que te digan si esta bien formado o le falta algo.
Aclaración
Con respecto a los caracteres de inicio de mensaje 0000. Es como dices, están esperando 4 bytes al inicio con la longitud del mensaje, pero aun cuando pongo m.write(output,4), la respeusta sigue siendo nula. cuando escribo en el archivo imprime el mensaje con su encabezado y demas,aunque no quiero el enzabezado.
{ISO0150000500200703C048000C0800416582251200000238400A0000000108984000000591624380629051201200113010100003490000000002130491
Si te fijas al inicio lo que aparece es una llave, o una letra, o cualquier simbolo extraño.
--
Con respecto al metodo read, es con el que leo la respuesta del socket, aquí va:
public String read(InputStream input) throws SocketTimeoutException, IOException
{
BufferedReader d;
StringBuffer sb;
String temp;
try
{
d = new BufferedReader(new InputStreamReader(input));
sb = new StringBuffer();
temp = null;
sb.append(d.readLine());
if(sb.length()>0 && !sb.toString().trim().equals("null"))
{
temp = sb.toString();
}
}
catch(SocketTimeoutException ex)
{
throw new SocketTimeoutException(ex.getMessage());
}
catch (IOException ex)
{
throw new IOException(ex.getMessage());
}
return temp;
}
Yo asumo que temp es la respuesta recibida.
Que opinas?
inicio del mensaje
Si no quieres los encabezados ISO entonces simplemente quitalos de la configuracion.
En cuanto a los "simbolos raros" que ves al principio, pues es el encabezado de longitud de mensaje. Si tienes linux o Mac, en una terminal ve el principio del archivo con hexdump (en windows no sé qué programas haya para ver el contenido de archivos binarios). La longitud se manda en binario siempre; si pides 4 bytes, entonces si la longitud mide por ejemplo 200, van a estar los primeros tres bytes en ceros y el tercer byte contiene la longitud (200). Es un byte con valor 200. No se mandan los digitos ASCII 2, 0, 0 (que serian tres bytes, con valores 50, 48, 48).
Si lo que te van a devolver el algo similar a lo que envias, tu método read() está mal. No puedes hacer readline porque no viene cambio de linea. Tienes que leer el encabezado de longitud, y luego crear un buffer de ese tamaño y leer esos bytes. Fijate en el ejemplo de Client.java para que veas la lectura de mensajes (Server.java también lo tiene). Primero tienes que leer bytes tal cual porque es lo que viene en la longitud. Suponiendo que sean 4 bytes, entonces lees un byte[] de longitud 4 y luego lo conviertes a entero:
tienes además que hacer un ciclo para ir llenando mbuf porque no es seguro que te va a llegar el mensaje completo en una sola lectura:
Obviamente agregando las validaciones para casos de que se cierre el stream, te devuelvan -1 en el read, etc. Revisa los ejemplos Client.java y Server.java para que veas la manera en que se leen mensajes.
Excelente
Gracias por tu dedicación! Voy a probar...
No logro Obtener respuesta
He modificado un poco la forma en que el ejemplo CLIENTE.java lee el mensaje, pero luego de mucho tarda mucho al entrar en el metodo leer, aqui te va el codigo:
public void leer()
{
final Log log = LogFactory.getLog(Main.class);
boolean done=true;
byte[] lenbuf = new byte[4];
pending.put(this.isomsg.getField(11).toString(), this.isomsg);
try {
//For high volume apps you will be better off only reading the stream in one thread
//and then using another thread to parse the buffers and process the responses
//Otherwise the network buffer might fill up and you can miss a message.
//while (sock != null && sock.isConnected()) {
sock.getInputStream().read(lenbuf);
int size = ((lenbuf[0] & 0xff) << 24) | ((lenbuf[1] & 0xff) << 16) | ((lenbuf[2] & 0xff) << 8) | (lenbuf[3] & 0xff);;
byte[] buf = new byte[size];
//We're not expecting ETX in this case
while (sock.getInputStream().read(buf) < size) {
try {
//We'll use this header length as a reference.
//In practice, ISO headers for any message type are the same length.
String respHeader = messageFact.getIsoHeader(0x200);
this.resp = messageFact.parseMessage(buf,
respHeader == null ? 12 : respHeader.length());
log.debug(String.format("Read response %s conf %s: %s",
this.resp.getField(11), this.resp.getField(38), new String(buf)));
pending.remove(this.resp.getField(11).toString());
} catch (ParseException ex)
{
log.error("Parsing response", ex);
}
//} else {
//pending.clear();
//return;
//}
}
} catch (IOException ex) {
if (done) {
log.info(String.format("Socket closed because we're done (%d pending)", pending.size()));
} else {
log.error(String.format("Reading responses, %d pending", pending.size()), ex);
try {
sock.close();
} catch (IOException ex2) {};
}
} finally {
if (sock != null) {
try {
sock.close();
} catch (IOException ex) {};
}
}
}
Que crees que pueda ser?
Cuando ejecuto el metodo write de "resp", para escribirlo en un (FILEOUTPUTSTREAM) me da un error.
Que puede ser?
MMM, problemas problemitas,
MMM, problemas problemitas, disculpa Enrique podrias postear ejemplos de mensajes ISO 8583 que hayas usado?, esto de implementar iso sin un cliente que me diga como es bien complejo.
Además, ¿has usado DataElements que usen tipo BINARIO ? aca me golpean si pongo algo como 0510101usando LLVAR, creo que quieren que sea solo 10101.
Bueno ejemplillos de mensajes serian muy utiles gracias (si es posible de ambas versiones 1987 y 2003, de haberlos).
ejemplos
En el repositorio encuentran en eclipse-project/src/j8583/example el archivo parse.txt que contiene esto:
ISO0250000550210B23A80012EA080180000000014000004650000000000003000042813054746877112594604280428081103123173766123456123456=00123442579114472300614209027600TESTSOLAB TEST-3 DF MX484012B123PRO1+000013 0000P0312304ABCD040ABCD8123477547
ISO0250000550210B23A80012EA080180000000014000004650000000000003000042813060446877413010304280428070903123173766123456123456=00123442579414474500637107053300TESTSOLAB TEST-3 DF MX484012B123PRO1+000013 0000P0312304ABCD040ABCD6421234099
Es mal lugar para postearlo porque seguramente no se van a ver los espacios al final. A ver si asi:
[ISO0250000550210B23A80012EA080180000000014000004650000000000003000042813054746877112594604280428081103123173766123456123456=00123442579114472300614209027600TESTSOLAB TEST-3 DF MX484012B123PRO1+000013 0000P0312304ABCD040ABCD8123477547 ]
[ISO0250000550210B23A80012EA080180000000014000004650000000000003000042813060446877413010304280428070903123173766123456123456=00123442579414474500637107053300TESTSOLAB TEST-3 DF MX484012B123PRO1+000013 0000P0312304ABCD040ABCD6421234099 ]
Si no quieren encabezados entonces le quitan lo que va antes del 0200 y 0210. Estos mensajes se pueden parsear con el programa Example.java que usa el config.xml de ese mismo directorio.
Pregunta
Un ejemplo de una trama buena en mi caso, es la siguiente :
4500 008d 579f 4000 7e06 13aa c0a8 b202
0a64 1413 c2aa 1d98 45cf 6f67 73a3 0553
5018 4029 f7ac 0000 [ 0000 0061 0200 ] 3020
4580 20c0 800c 0030 0000 0000 0002 0200.........etc
Yo estoy enviando lo siguiente:
4500 008a 9239 4000 3b06 0657 c0a8 c7be
0a64 1413 f0ff 1d98 35d8 54f1 c12c 00f4
5018 8000 8124 [ 0000 ] **** **** **** 4953 4f30 3135 3030.... etc
Los caracteres que me faltan son los que estan en corchetes [ 0000 0061 0200 ] en la trama buena (la primera) . Siempre debo enviar los primeros 4 ceros [0000], luego la longitud [0061], luego el tipo de mensaje [0200], luego el mensaje. Esto debería ir en el lugar de los asteriscos (los asteriscos no salen, es para denotar la posicion donde deben salir, solo sigue el mensaje normal).
Mis preguntas son:
1- Por qué crees que no están saliendo esos caracteres?
2 - Como puedo convertir la trama que envío a ese formato (4500 008d 579f... etc) para probar si estoy enviando lo que me piden?
No entiendo cual es el problema aquí, pero no obtengo ninguna respuesta, ya que no estoy enviando la trama como me la piden.
Que crees?
no creo que tengas que
no creo que tengas que enviar un byte en puros ceros, creo que realmente se usan dos bytes para la longitud pero obviamente tu mensaje mide 97 bytes y por lo tanto nada más usas el segundo byte.
El tipo de mensaje va despues del encabezado ISO. El hexdump que me muestras empieza con 49, 53, 4f, que en hexadecimal son las letras I, S, O. Luego sigue 0, 1, 5, 0, 0, etc. Estas mandando encabezado ISO. El encabezado ISO es opcional; si no te lo estan pidiendo, no lo mandes. Quitalo de la configuración del MessageFactory. Pero lo que sí es un hecho es que antes del encabezado ISO debe venir la longitud, que segun tu no viene (o la quitaste con lo de los asteriscos)
No
Lo que digo de la longitud es que no esta saliendo en mi mensaje, los asteriscos solo los puse para resaltarte que en ese lugar deben salir los 4 ceros de incio [0000] (estos siempre deben salir pero no se como pronerlos), la longitud [0061] y luego el tipo de mensaje[0200].
Lee bien mi respuesta. No
Lee bien mi respuesta. No vamos a salir de lo mismo. No son 4 ceros, es un byte completo en puros ceros y luego un byte que dice 97 porque eso mide (o deberia medir) tu mensaje. Luego un byte con el 0200. Pero estas generando el encabezado ISO y por eso no sale como lo quieres. No te puedo ayudar más porque es problema con tu aplicación o la manera en que estas usando la librería, no es problema con la librería en sí. Si quieres soporte o asesoría ya específicamente para tu aplicación podemos hablarlo, enviame un mensaje privado.
MessageFactory mal inicializada
Hola, muy bueno el proyecto, muy interesante e interesado en poder utilizarlo en un proyecto que estamos desarrollando.
tengo un par de consultas, capaz que alguien ya le paso,
(me importe las fuentes a mi proyecto para poder mirar y debugear :-) )
Me esta tirando el siguiente error ...
ISO8583 File not found in classpath: /home/jp/tmp/nb/del/src/com/solab/iso8583/config.xml
el archivo existe en esa ruta.
me cambie las lineas en ConfigParser:
por
y obtuve la salida :
ISO8583 Parsing config from classpath file /home/jp/tmp/nb/del/src/com/solab/iso8583/config.xml
ISO8583 MessageFactory adding parse map for type 0200 with fields [3, 4, 7, 11, 12, 13, 15, 17, 32, 35, 37, 41, 43, 48, 49, 60, 61, 100, 102]
ISO8583 MessageFactory adding parse map for type 0210 with fields [3, 4, 7, 11, 12, 13, 15, 17, 32, 35, 37, 38, 39, 41, 43, 48, 49, 60, 61, 70, 90, 100, 102, 126]
pareciera que estuviera funcionando bien, no ?
o alguien sabe como hacer que ande sin tocar el código ?
y el otro temita que tengo cuando le envio una transaccion es el siguiente:
Tira la exception ParseException en el Processor en la linea:
Exception: Invalid ISO8583 bitmap
alguna idea ?
gracias y
saludos,
jp
soporte
la página de j8583 en SF tiene un foro para soporte, bugs, dudas, etc.
El código de MessageFactory carga por default del classpath, el path que le debes pasar entonces es "com/solab/iso8583/config.xml" y con eso lo debe de leer, no sé cómo le hayas pasado el path.
Esos logs que pusiste en negritas, efectivamente son de que ya se cargó bien la MessageFactory y tienes el mapa para parsear mensajes tipo 0200 y 0210.
La excepción de parsear el mensaje, pues habría que ver la trama que le pasas. Por lo que veo, el bitmap está mal, pero sin ver qué le pasaste no hay manera de tener "alguna idea".
lo que le paso
gracias por tu respuesta.
no se si seguir el hilo aca ... o irme a SF ... como prefieras.
lo que le estoy pasando es,
96054-865440114605-1280-47-1282022807154708048800000001618361856561618-12518565683618701805408210110011211111567694950495432323232323232323232324514848560348484956535609821011008079835446480749494849545248
esto es un System.out en la clase Procesor, del byte[] msg.
tengo un simulador de transacciones en vb. que me envía transacciones y lo aproveche para testear.
gracias,
saludos,
?
qué se supone que es esa trama? no le veo para nada cara de ISO8583. Si mandas imprimir un byte[] a System.out normalmente nada más sale una dirección en memoria, no imprime el contenido del arreglo; no sé qué hayas hecho para imprimir eso.