Patrones de Integracion

ODBC/JDBC, REST APIs, IBM MQ, Kafka, data queues, integracion basada en archivos y patrones event-driven para conectar IBM i con el mundo.

Panorama de integracion

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.

Principio clave: No existe un unico patron ideal. Las arquitecturas de integracion exitosas combinan multiples enfoques segun el caso de uso. Lo importante es elegir conscientemente y no caer en patrones por defecto.

Integracion via REST APIs

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.

Exponer un programa RPG como API REST

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.

RPG — Service Program para API REST
**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;

Consumir APIs externas desde IBM i

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:

SQL — Consumir API REST desde IBM i
-- 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

  • Expone RPG/COBOL como APIs
  • Mapping JSON automatico
  • Swagger/OpenAPI generado
  • Autenticacion integrada
  • Sin codigo HTTP manual

IBM i como cliente HTTP

  • SYSTOOLS.HTTPGETCLOB/HTTPPOSTCLOB
  • JSON_TABLE para parsear respuestas
  • Soporte TLS/SSL nativo
  • Certificados client-side
  • Ideal para consumir microservices
Tip: Para APIs de alto volumen, considerar usar Node.js en PASE como capa intermedia. Node.js maneja concurrencia y JSON de forma nativa, y puede llamar a programas RPG via toolkit o stored procedures.

ODBC/JDBC como puente de datos

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.

Java — Conexion JDBC a IBM i
// 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);
Python — Conexion ODBC a IBM i
# 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)

  • Driver nativo: jt400.jar
  • Soporta SSL/TLS
  • Connection pooling nativo
  • Acceso a data queues y IFS
  • Stored procedures con output params
  • Ideal para aplicaciones Java/Spring

ODBC (Access Client Solutions)

  • Driver: IBM i Access ODBC Driver
  • Compatible con cualquier lenguaje
  • Python, C#, PHP, Node.js, etc.
  • Configuracion via DSN o connection string
  • Mas universal pero ligeramente mas lento
  • Ideal para integracion multi-lenguaje
Best practice: Siempre usar connection pooling en produccion. Cada conexion JDBC/ODBC consume un job en IBM i. Sin pooling, una aplicacion web puede generar cientos de jobs y saturar el sistema.

IBM MQ y mensajeria

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).

RPG — Enviar mensaje a cola MQ
**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.

CL — Administrar IBM MQ en IBM i
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)

Data queues como middleware ligero

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.

CL — Crear y usar data queues
-- 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')
RPG — Comunicacion via data queue
**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 mensaje

Data Queues (nativo IBM i)

  • Integrado en el OS, sin costo adicional
  • Extremadamente rapidas (microsegundos)
  • Soporte FIFO, LIFO y keyed
  • Wait con timeout para consumidores
  • Solo dentro de IBM i (o via JTOpen)
  • Sin entrega garantizada cross-platform

IBM MQ

  • Producto separado con licencia
  • Mas overhead pero mas funcionalidad
  • Solo FIFO (con prioridades)
  • Triggers y dead-letter queues
  • Multi-plataforma (IBM i, Linux, cloud)
  • Entrega garantizada transaccional

Integracion basada en archivos

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.

CL — Importar/Exportar archivos CSV
-- 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*:
SQL — COPY INTO para carga masiva
-- 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;
Atencion: La integracion file-based tiene latencia inherente (minutos a horas). No es apropiada para escenarios que requieren datos en tiempo real. Ademas, es propensa a errores si no se implementa control de duplicados e idempotencia.

Event-driven con journals

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.

CL — Configurar journaling para CDC
-- 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
SQL — Leer journal entries como tabla
-- 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

  • Leer journal entries periodicamente con SQL
  • Simple de implementar
  • Latencia: segundos a minutos
  • No requiere software adicional
  • Ideal para replicacion interna

Precisely Connect CDC

  • Lee journals en tiempo real
  • Publica cambios a Kafka/MQ/archivos
  • Transformacion de datos inline
  • Soporte multi-tabla y multi-formato
  • Ideal para replicacion a data lakes

WebSockets y tiempo real

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.

Node.js en PASE — WebSocket server
// 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));
});
Arquitectura recomendada: Usar Node.js en PASE como capa de WebSockets que se conecta a Db2 for i via idb-pconnector. Esto combina la velocidad del acceso local a datos con la flexibilidad de Node.js para manejo de conexiones concurrentes.

Patrones y anti-patrones

Anti-patrones (evitar)

  • Acceso directo a tablas desde apps externas sin capa de abstraccion
  • FTP manual sin automatizacion ni validacion
  • Polling agresivo contra tablas de produccion
  • Conexiones JDBC sin pooling (un job por request)
  • Integracion punto a punto sin middleware
  • Ignorar el manejo de errores y reintentos
  • Formatos de datos sin versionamiento
  • Transformaciones de datos en el canal de transporte

Patrones recomendados

  • APIs REST con contratos versionados
  • Stored procedures como capa de abstraccion de datos
  • CDC basado en journals para replicacion
  • Data queues para IPC dentro de IBM i
  • IBM MQ para integracion cross-platform confiable
  • Connection pooling con limites configurados
  • Idempotencia en todos los endpoints
  • Circuit breaker para llamadas a servicios externos

Patron: Strangler Fig para integracion gradual

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

1. WrapExponer programas existentes como APIs REST via IWS sin modificar nada
2. RouteRedirigir consumidores del archivo FTP al nuevo endpoint REST
3. MigrateRefactorizar el programa backend para optimizar el contrato API
4. RetireEliminar el proceso FTP legacy cuando todos los consumidores migraron

Guia de decision

La siguiente matriz ayuda a elegir el mecanismo de integracion adecuado segun las caracteristicas del escenario:

MecanismoLatenciaVolumenComplejidadCostoCaso de uso ideal
REST API (IWS)msBajo-MedioBajaIncluidoCRUD, consultas online
JDBC/ODBCmsMedio-AltoBajaIncluidoReporting, ETL, apps externas
IBM MQms-segAltoMediaLicenciaIntegracion enterprise cross-platform
Data Queuesmicro-segMedioBajaIncluidoIPC dentro de IBM i
Archivos (FTP/IFS)min-hrsMuy altoBajaIncluidoBatch, carga masiva
Journal CDCsegAltoMediaIncluido*Replicacion, event streaming
WebSockets (Node)msBajo-MedioMediaIncluidoDashboards en vivo, notificaciones
Kafka ConnectsegMuy altoAltaLicencia*Event streaming enterprise
Recomendacion general: Comenzar con REST APIs para integracion sincrona y data queues para asincrona dentro de IBM i. Escalar a IBM MQ cuando se necesite integracion cross-platform confiable. Usar CDC con journals para replicacion de datos. Reservar la integracion file-based solo para cargas masivas batch.