ODBC/JDBC, REST APIs, IBM MQ, Kafka, data queues, integracion basada en archivos y patrones event-driven para conectar IBM i con el mundo.
IBM i raramente opera en aislamiento. En la empresa moderna, necesita comunicarse con aplicaciones web, ERPs en cloud, sistemas de analytics, aplicaciones mobile y otros mainframes. La buena noticia es que IBM i ofrece multiples mecanismos de integracion, desde los mas tradicionales (archivos planos) hasta los mas modernos (REST APIs, eventos en tiempo real).
La eleccion del patron de integracion correcto depende de factores como la latencia requerida, el volumen de datos, la frecuencia de actualizacion y las capacidades de ambos extremos.
Sincrona (Request/Response)
REST APIs, ODBC/JDBC, llamadas a programa. El cliente espera la respuesta. Ideal para consultas y transacciones en linea.
Asincrona (Messaging)
IBM MQ, data queues, Kafka. El emisor no espera respuesta inmediata. Ideal para desacoplamiento y procesamiento batch.
Event-Driven (CDC)
Journals, triggers, log-based CDC. El sistema reacciona a cambios en los datos. Ideal para replicacion y notificaciones.
IBM Integrated Web Services (IWS) permite exponer programas RPG, COBOL y procedimientos de service programs como REST APIs sin necesidad de reescribirlos. El servidor IWS actua como wrapper que convierte parametros JSON a parametros de programa y viceversa.
El flujo tipico es: se crea un service program con procedimientos exportados, se registra en IWS como servicio web, y IWS genera automaticamente el mapping JSON. No se necesita codigo adicional para la capa HTTP.
**free
// Procedimiento exportado: GetCustomer
// IWS lo expone como GET /api/customers/{id}
dcl-proc GetCustomer export;
dcl-pi *n;
custId packed(7:0) const;
custName char(40);
custAddr char(60);
custBal packed(11:2);
httpStatus packed(3:0);
end-pi;
exec sql
SELECT CUSNAM, CUSADR, CUSBAL
INTO :custName, :custAddr, :custBal
FROM CUSTMAST
WHERE CUSID = :custId;
if sqlcode = 0;
httpStatus = 200;
else;
httpStatus = 404;
custName = 'Not Found';
endif;
return;
end-proc;IBM i puede tambien actuar como cliente HTTP usando las funciones SQL de HTTP o mediante programas RPG con las APIs de sockets. La forma mas moderna es usando las funciones SYSTOOLS:
-- Llamar a una API externa usando SYSTOOLS.HTTPGETCLOB
SELECT *
FROM JSON_TABLE(
SYSTOOLS.HTTPGETCLOB(
'https://api.example.com/products',
'{"header":"Accept,application/json"}'
),
'$.products[*]'
COLUMNS(
product_id INTEGER PATH '$.id',
name VARCHAR(100) PATH '$.name',
price DECIMAL(9,2) PATH '$.price'
)
) AS products;
-- POST con cuerpo JSON
VALUES SYSTOOLS.HTTPPOSTCLOB(
'https://api.example.com/orders',
'{"header":"Content-Type,application/json"}',
'{"customerId": 12345, "items": [{"sku": "ABC", "qty": 2}]}'
);IWS como servidor REST
IBM i como cliente HTTP
La forma mas directa de acceder a datos de IBM i desde aplicaciones externas es mediante conexiones ODBC (Open Database Connectivity) o JDBC (Java Database Connectivity). Db2 for i es una base de datos relacional completa y ambos drivers permiten ejecutar SQL estandar contra ella.
// Dependencia: jt400.jar (IBM Toolbox for Java)
import com.ibm.as400.access.AS400JDBCDriver;
String url = "jdbc:as400://MISERVER;naming=sql;"
+ "libraries=PRODLIB,DATALIB;"
+ "date format=iso;";
Connection conn = DriverManager.getConnection(
url, "USUARIO", "PASSWORD"
);
// Consulta SQL estandar
PreparedStatement ps = conn.prepareStatement(
"SELECT CUSID, CUSNAM, CUSBAL " +
"FROM PRODLIB.CUSTMAST " +
"WHERE CUSBAL > ? " +
"ORDER BY CUSNAM"
);
ps.setBigDecimal(1, new BigDecimal("1000.00"));
ResultSet rs = ps.executeQuery();
// Llamar a stored procedure
CallableStatement cs = conn.prepareCall(
"CALL PRODLIB.PROCESS_ORDER(?, ?, ?)"
);
cs.setInt(1, orderId);
cs.setString(2, custId);
cs.registerOutParameter(3, Types.CHAR);
cs.execute();
String result = cs.getString(3);# pip install pyodbc
import pyodbc
# Configurar conexion ODBC
conn = pyodbc.connect(
'DRIVER={IBM i Access ODBC Driver};'
'SYSTEM=MISERVER;'
'UID=USUARIO;'
'PWD=PASSWORD;'
'DBQ=PRODLIB DATALIB;'
'NAM=1;' # SQL naming
)
cursor = conn.cursor()
# Consulta directa
cursor.execute("""
SELECT CUSID, CUSNAM, CUSBAL
FROM PRODLIB.CUSTMAST
WHERE STATE = ?
""", ('CA',))
for row in cursor.fetchall():
print(f"{row.CUSID}: {row.CUSNAM} - ${row.CUSBAL}")
# Ejecutar procedimiento almacenado
cursor.execute("CALL PRODLIB.CALC_TOTALS(?, ?)",
('2024-01', 'NORTH'))
conn.commit()JDBC (Java Toolbox)
ODBC (Access Client Solutions)
IBM MQ (antes MQSeries/WebSphere MQ) es el middleware de mensajeria empresarial mas usado en entornos IBM i. Proporciona entrega garantizada de mensajes entre aplicaciones, incluso si una de las partes esta temporalmente caida.
IBM MQ for IBM i corre nativamente en el sistema. Los programas RPG/COBOL pueden poner y obtener mensajes de colas MQ usando las APIs MQI (Message Queue Interface).
**free
// Enviar un mensaje a una cola IBM MQ
dcl-s mqHConn int(10);
dcl-s mqHObj int(10);
dcl-s mqCC int(10);
dcl-s mqRC int(10);
dcl-s msgData char(1024);
// Conectar al queue manager
MQCONN('QMGR01' : mqHConn : mqCC : mqRC);
// Abrir cola para output
dcl-ds mqOD likeds(MQOD_t);
mqOD.ObjectName = 'ORDERS.OUT';
MQOPEN(mqHConn : mqOD : MQOO_OUTPUT : mqHObj : mqCC : mqRC);
// Preparar y enviar mensaje
msgData = '{"orderId":12345,"action":"process"}';
dcl-ds mqMD likeds(MQMD_t);
mqMD.Format = 'MQSTR';
mqMD.Persistence = MQPER_PERSISTENT;
dcl-ds mqPMO likeds(MQPMO_t);
MQPUT(mqHConn : mqHObj : mqMD : mqPMO :
%len(%trimr(msgData)) : %addr(msgData) :
mqCC : mqRC);
// Cerrar y desconectar
MQCLOSE(mqHConn : mqHObj : MQCO_NONE : mqCC : mqRC);
MQDISC(mqHConn : mqCC : mqRC);Entrega garantizada
MQ asegura que el mensaje llega exactamente una vez (once-and-only-once). Si el receptor esta caido, el mensaje espera en la cola.
Transaccional
PUT y GET pueden participar en transacciones. Si el programa falla, el mensaje vuelve a la cola automaticamente (rollback).
Multi-plataforma
MQ conecta IBM i con Linux, Windows, z/OS, cloud. Un mismo queue manager puede comunicar cualquier combinacion de plataformas.
STRMQM MQMNAME(QMGR01) Iniciar queue manager ENDMQM MQMNAME(QMGR01) Detener queue manager DSPMQM Mostrar queue managers WRKMQMQ MQMNAME(QMGR01) Trabajar con colas DSPMQMQ MQMNAME(QMGR01) Mostrar definicion de colas QNAME(ORDERS.OUT) CRTMQMQ MQMNAME(QMGR01) Crear nueva cola QNAME(ORDERS.IN) QTYPE(*LCL)
Las data queues son un mecanismo nativo de IBM i para comunicacion inter-proceso (IPC). Son mas simples que IBM MQ pero extremadamente rapidas y no requieren software adicional. Son ideales para comunicacion entre programas dentro del mismo IBM i o entre IBM i y aplicaciones Java/Node.js via JTOpen.
-- Crear una data queue
CRTDTAQ DTAQ(MYLIB/ORDERQ) MAXLEN(64000) +
SEQ(*KEYED) KEYLEN(10) +
TEXT('Cola de ordenes de compra')
-- Crear data queue FIFO (sin clave)
CRTDTAQ DTAQ(MYLIB/LOGQ) MAXLEN(1024) +
SEQ(*FIFO) +
TEXT('Cola de log de eventos')**free
// PRODUCTOR: Enviar registro a data queue
dcl-s dtaqName char(10) inz('ORDERQ');
dcl-s dtaqLib char(10) inz('MYLIB');
dcl-s dtaqKey char(10);
dcl-s dtaqData char(1000);
dtaqKey = 'ORD' + %char(%date():*iso0);
dtaqData = '{"order":12345,"customer":"ACME","total":1500.00}';
QSNDDTAQ(dtaqName : dtaqLib :
%len(%trimr(dtaqData)) : dtaqData :
%len(dtaqKey) : dtaqKey);
// -------------------------------------------
// CONSUMIDOR: Leer de data queue (con wait)
dcl-s waitTime packed(5:0) inz(-1); // -1 = esperar indefinido
QRCVDTAQ(dtaqName : dtaqLib :
%len(dtaqData) : dtaqData :
waitTime : // timeout en segundos
'GE' : // operador de comparacion
%len(dtaqKey) : dtaqKey);
// dtaqData ahora contiene el mensaje
// El programa se bloquea hasta que llegue un mensajeData Queues (nativo IBM i)
IBM MQ
La integracion por archivos es el patron mas antiguo pero sigue siendo valido para procesamiento batch, intercambio de datos con sistemas legacy y carga masiva. IBM i soporta multiples formatos y protocolos de transferencia.
FTP/SFTP nativo
IBM i incluye servidor FTP y SFTP nativos. Los archivos se depositan en el IFS y se procesan con programas batch.
IFS como punto de intercambio
El Integrated File System permite compartir archivos via NFS, Samba (NetServer) o carpetas mapeadas desde Windows.
CPYF / CPYFRMIMPF
Comandos CL para copiar datos entre archivos fisicos y formatos CSV/delimitados. CPYFRMIMPF importa CSV a tablas DB2.
Connect CDC (file-based)
Herramienta de Precisely que captura cambios y genera archivos de delta para consumo externo.
-- Exportar tabla a CSV en el IFS
CPYTOIMPF FROMFILE(PRODLIB/CUSTOMERS)
TOSTMF('/home/exports/customers.csv')
MBROPT(*REPLACE)
STMFCCSID(1208)
RCDDLM(*CRLF)
DTAFMT(*DLM)
STRDLM(*DBLQ)
FLDDLM(',')
-- Importar CSV desde IFS a tabla DB2
CPYFRMIMPF FROMSTMF('/home/imports/orders.csv')
TOFILE(PRODLIB/ORDERS)
MBROPT(*ADD)
RCDDLM(*CRLF)
DTAFMT(*DLM)
STRDLM(*DBLQ)
FLDDLM(',')
-- FTP automatizado desde CL
FTP RMTSYS('192.168.1.100')
// El script FTP se pasa via ADDFTP*:-- Cargar CSV directo a tabla via SQL COPY FROM '/home/imports/sales_data.csv' INTO PRODLIB.SALES_STAGING (SALE_ID, CUST_ID, AMOUNT, SALE_DATE) USING DELIMITERS ',' SKIP 1; -- saltar header -- Exportar resultado de query a CSV COPY ( SELECT CUSID, CUSNAM, CUSBAL, REGION FROM PRODLIB.CUSTMAST WHERE REGION = 'NORTH' ) TO '/home/exports/north_customers.csv' USING DELIMITERS ',' WITH HEADER;
Los journals de IBM i registran cada cambio (INSERT, UPDATE, DELETE) en los archivos fisicos. Esta capacidad nativa es la base para implementar Change Data Capture (CDC), que permite reaccionar a cambios en tiempo casi real sin modificar las aplicaciones existentes.
-- Crear journal receiver y journal
CRTJRNRCV JRNRCV(MYLIB/CDCRCV0001)
THRESHOLD(100000)
CRTJRN JRN(MYLIB/CDCJRN)
JRNRCV(MYLIB/CDCRCV0001)
MNGRCV(*SYSTEM)
DLTRCV(*YES)
-- Iniciar journaling en tabla
STRJRNPF FILE(MYLIB/CUSTOMERS)
JRN(MYLIB/CDCJRN)
IMAGES(*BOTH) -- before + after image
OMTJRNE(*OPNCLO) -- omitir open/close
-- Ver entradas del journal
DSPJRN JRN(MYLIB/CDCJRN)
FILE(MYLIB/CUSTOMERS)
RCVRNG(*CURCHAIN)
ENTTYP(PT UP DL) -- insert, update, delete-- Consultar cambios recientes via SQL
SELECT
JOURNAL_ENTRY_TYPE,
ENTRY_TIMESTAMP,
JOURNAL_CODE,
CUSID,
CUSNAM,
CUSBAL
FROM TABLE(
QSYS2.DISPLAY_JOURNAL(
JOURNAL_LIBRARY => 'MYLIB',
JOURNAL_NAME => 'CDCJRN',
STARTING_TIMESTAMP => CURRENT_TIMESTAMP - 1 HOURS,
JOURNAL_ENTRY_TYPES => 'PT,UP,DL',
JOURNAL_CODES => 'R',
FILE_NAME => 'CUSTOMERS'
)
) AS jrn
ORDER BY ENTRY_TIMESTAMP DESC;Journal nativo + polling
Precisely Connect CDC
Para integracion en tiempo real bidireccional, IBM i puede usar WebSocketsa traves de Node.js en PASE o mediante aplicaciones Java en la JVM integrada. Esto permite construir dashboards en vivo, notificaciones push y comunicacion bidireccional con aplicaciones web modernas.
// Servidor WebSocket en IBM i (PASE)
const WebSocket = require('ws');
const { Connection } = require('idb-pconnector');
const wss = new WebSocket.Server({ port: 8080 });
// Pool de conexiones a Db2
const pool = new Connection({
url: '*LOCAL',
username: 'WEBUSER',
});
wss.on('connection', (ws) => {
console.log('Cliente conectado');
ws.on('message', async (msg) => {
const request = JSON.parse(msg);
if (request.action === 'getInventory') {
const stmt = await pool.prepareStatement(
'SELECT ITEM, QTY, PRICE FROM INVENTORY WHERE WHSE = ?'
);
stmt.bindParam([request.warehouse]);
const results = await stmt.execute();
ws.send(JSON.stringify({ type: 'inventory', data: results }));
}
});
// Enviar actualizaciones cada 5 segundos
const interval = setInterval(async () => {
const alerts = await pool.query(
"SELECT * FROM ALERTS WHERE STATUS = 'NEW'"
);
if (alerts.length > 0) {
ws.send(JSON.stringify({ type: 'alert', data: alerts }));
}
}, 5000);
ws.on('close', () => clearInterval(interval));
});Anti-patrones (evitar)
Patrones recomendados
Cuando se moderniza la integracion, el patron Strangler Fig permite migrar de integracion file-based a APIs de forma incremental: se crea una nueva capa API que internamente sigue usando los mismos programas, y se van migrando los consumidores uno a uno.
Fases del Strangler Fig
La siguiente matriz ayuda a elegir el mecanismo de integracion adecuado segun las caracteristicas del escenario: