Maratón Behind the Code Latinoamérica: Sé parte del Desafío. Inscríbete antes del 7 de Setiembre.

Aplicaciones nativas de JavaScript en IBM i con Node.js

Introducción

Node.js es un proyecto de código abierto basado en el motor JavaScript de Google Chrome V8. Proporciona una plataforma para que aplicaciones JavaScript del lado del servidor se ejecuten sin navegadores. El modelo de E/S basado en eventos, y no bloqueante hace que sea ligero y de uso eficiente. También proporciona varios módulos incorporados para simplificar la programación, especialmente para las aplicaciones de trabajo en red. Existen muchos más módulos de terceros que se pueden instalar fácilmente con la herramienta npm (módulos empaquetados en nodos) incorporada para extender Node.js.

Nota: Node.js es una marca comercial oficial de Joyent.

Node.js ahora es compatible con la plataforma IBM i. La oferta de programa licenciado (LPO) de IBM i Open Source Solutions 5733OPS ha sido creada para entregar tecnologías de código abierto en IBM i. Está incluida dentro del Bonus Pack para el sistema operativo IBM i. Después de instalar esta LPO gratuita, se la atiende por medio del PTF del grupo 5733OPS.

Node.js transcodifica el código JavaScript a código de máquina

Además de las principales funciones de Node.js en IBM, también proporciona las dos siguientes extensiones específicas de IBM i:

  • DB2 de IBM® para la biblioteca de acceso de i que contiene servicios de JavaScript que se pueden llamar para interactuar con los objetos de la base de datos DB2 for i.
  • Kit de herramientas de Node.js para IBM i que permite que el usuario acceda a recursos del sistema de IBM i por medio de XMLSERVICE, como el estado y los valores del sistema, información de los trabajos, espacios de usuario, colas de datos, información de objetos, etc.

Infraestructura de Node.js para IBM i

Este artículo introduce los aspectos básicos de Node.js y describe cómo empezar a utilizarlo en IBM i. Le guía por medio de la instalación de Node.js en IBM i y utiliza algunos ejemplos para guiarle paso a paso a lo largo del proceso.

Requisitos previos del software

Node.js for IBM i está empaquetado como parte de 5733OPS, que solo es compatible con IBM i 7.1 o superior. Node.js se entrega en la opción 10 de esta nueva LPO. Además de instalar la nueva LPO, se requieren más programas de software para utilizar Node.js en IBM i.

  • Programas licenciados necesarios: 5733OPS, opción 10-Node.js v6.x 5770SS1, opción 33-Entorno de Soluciones de Aplicaciones Portátiles 5733SC1, opción 1-OpenSSH, OpenSSL, zlib 5770DG1,*BASE – servidor HTTP de IBM para i

  • Software opcional exigido si es necesario extender Node.js más allá de sus capacidades instaladas. Npm requiere de Python (5733OPS, opción 4) para instalar complementos de terceros. GCC es obligatorio para instalar complementos de terceros basados en C/C++ por medio de npm. Git (5733OPS, opción 7) es necesario para instalar complementos de terceros que utilizan Github como repositorio de código fuente por medio de npm

Para la instalación en PASE de Python y de otros binarios de código abierto, consulte el manual y la documentación online de Tecnologías de Código Abierto .

Instale Node.js en IBM i

Instale la opción 10 del producto 5733OPS desde los archivos de imágenes o medios físicos en DVD. Después, aplique el último grupo PTF de 5733OPS para obtener el soporte más reciente de Node.js:

  • Grupo PTF de SF99123 de IBM i 7.1 – nivel 3 (o superior)
  • Grupo PTF de SF99223 de IBM i 7.2 – nivel 3 (o superior)
  • Grupo PTF de SF99225 de IBM i 7.3 – nivel 3 (o superior)

Después de que todo esté instalado correctamente, el directorio /QOpenSys/QIBM/ProdData/OPS/Node6 se creará.

Después de que el entorno de software esté preparado, siga los siguientes pasos para verificar la instalación:

  1. Inicie una sesión de Qshell utilizando el siguiente comando de la CL
    QSH
    o, inicie una sesión de PASE con el siguiente comando de la CL.
    CALL QP2TERM
  2. Ejecute el siguiente comando para crear los enlaces globales para el tiempo de ejecución de Node.js. Después, es posible llamar a Node.js desde cualquier lugar.
    /QOpenSys/QIBM/ProdData/OPS/Node6/bin/nodever.sh 6
  3. Ejecute los siguientes comandos para verificar el nivel de la versión del tiempo de ejecución de Node.js. Estos dos comandos están ubicados en /QOpenSys/QIBM/ProdData/OPS/Node6/bin.

    node –v
    El resultado debe ser una versión válida de Node.js en el sistema, como v6.9.1.
    npm –v
    El resultado debe ser una versión válida de npm en el sistema, como 3.10.8.

    Figure 1. Validación de la instalación de Node.js para IBM i
    Validación de la instalación de Node.js para IBM i

Si la información de la versión parece válida, la instalación fue correcta.

Nota: En las sesiones de Qshell, algunas aplicaciones de Node.js pueden lanzar un error signal 5. Este error es causado por un límite de hebras de Qshell. Consulte la documentación del IBM Knowledge Center .

Es posible eliminar el límite añadiendo variables de entorno QIBM_MULTI_THREADED con el valor Y y después restaurar la sesión de Qshell. O es posible utilizar las sesiones de PASE para sus aplicaciones.

El siguiente comando de CL inicia un proceso de Qshell capaz de manejar varias hebras

ADDENVVAR ENVVAR(QIBM_MULTI_THREADED) VALUE(Y)

Figure 2. Active la capacidad de varias hebras de Qshell
Active Qshell para la capacidad de multiproceso

Información general del ejemplo

Las secciones anteriores hicieron una introducción de cómo instalar el tiempo de ejecución de Node.js en IBM i. En las secciones restantes, se presenta un ejemplo de programación para mostrar la capacidad de Node.js para i. Este ejemplo crea un servidor web que permite que los usuarios hagan consultas a la base de datos de DB2 for i y ejecuten comandos de la CL utilizando un navegador web.

Nota: Node.js no es compatible con archivos de origen codificados con EBCDIC. Utilice una codificación UTF-8 o CCSID compatible con UTF-8, como 819 (ISO 8859-1 ASCII).

Cree una aplicación web con Node.js

Todas las funciones principales de Node.js se permiten en IBM i. Una de las funciones principales es lo fácil que es crear un servidor web utilizando el soporte de Node.js para IBM i.

  1. Cree un archivo llamado sample.js con el siguiente contenido en cualquier directorio del sistema de archivos, por ejemplo, /home/njs/sample.js. El siguiente código crea el servidor web y proporciona un sencillo sitio web de «Hola, Mundo». En el siguiente código de ejemplo, reemplace IP_Address con la dirección IP real de su servidor y reemplace Puerto con el número de puerto al que el servidor debe escuchar.


var http = require('http');
var ip = "IP_Address";
var port = Port;
var webserver = http.createServer((req, res) => {
  res.writeHead(200, {'Content‑Type': 'text/plain'});
  res.end('Hello World\n');
});
webserver.listen(port, ip);
console.log('Server running at http://' + ip + ':' + port);

                

  1. Después de crear y personalizar el archivo, ejecute el programa JavaScript para iniciar el servidor web.

node /home/njs/sample.js

Si se muestra el siguiente mensaje, el servidor web se está ejecutando correctamente.

Server running at http://_IP_address_:_puerto_/

Ahora, es posible abrir el navegador para acceder al servidor web iniciado por Node.js. El sitio «Hola, Mundo» se muestra igual que en la siguiente imagen.

Verifique el servidor web

  1. Apague el servidor web.

En este ejemplo, el servidor web está escuchando al puerto 8081 para aceptar la solicitud y para responder. Para apagar este servidor web, tenemos que finalizar el trabajo manualmente. Para finalizar el trabajo del servidor web, pulse la tecla Esc dentro de la sesión de QSH y seleccione la opción 2 para trabajar con los trabajos actuales. Después, finalice el trabajo ejecutando el programa node con la opción 4 tal como se muestra en la Imagen 6.

Finalice manualmente el trabajo Node.js

Para automatizar la administración del servidor web de Node.js, es posible crear comandos personalizados de CL para realizar estas operaciones. Es posible encontrar más información acerca de crear un comando personalizado de CL en el «Paso 9 – Crear un comando personalizado de CL para iniciar el servidor Tomcat» del artículo, Acelere su servidor de Tomcat en IBM i.

  1. Entregue páginas web estáticas.

En el código JavaScript anterior, el servidor web solo está respondiendo con «Hola, Mundo» a cualquier solicitud. Ahora, extenderemos el programa sample.js para leer contenido desde un archivo estático y para responder al cuando se haya solicitado la URL, http://:port/sample.html, desde un navegador.

Para responder con páginas web estáticas a un cliente, Node.js requiere el módulo del sistema de archivos «fs» y del módulo «url» para analizar la cadena de caracteres de la solicitud. Es necesario actualizar el archivo sample.js para incluir estos módulos adicionales. Acuérdese de actualizar los valores de la dirección IP y del puerto. Es posible actualizar el siguiente archivo sample.js con sus valores:


var http = require('http');
var fs = require('fs');
var url = require('url');
var ip = "IP_Address";
var port = Port;
var webserver = http.createServer((req, res) => {
  var realPath = __dirname + url.parse(req.url).pathname;
  fs.exists(realPath, (exists) => {
    if(!exists){
      res.writeHead(404, {'Content‑Type': 'text/plain'});
      res.end("404 Not Found");
    } else {
      var file = fs.createReadStream(realPath);
      res.writeHead(200, {'Content‑Type': 'text/html'});
      file.on('data', res.write.bind(res));
      file.on('close', res.end.bind(res));
      file.on('error', function(err){
        res.writeHead(500, {'Content‑Type': 'text/plain'});
        res.end("500 Internal Server Error");
      });
    }
  });
});
webserver.listen(port, ip);
console.log('Server running at http://' + ip + ':' + port);

                

Nota: __dirname es una variable interna de Node.js para obtener el nombre del directorio en el que reside el script que se está ejecutando actualmente.

Después, cree un archivo HTML estático llamado sample.html con el siguiente contenido y súbalo al mismo directorio del archivo sample.js.


<!DOCTYPE HTML>
<html lang="en‑US">
    <head>
        <meta http‑equiv="Content‑Type" content="text/html; charset=utf‑8" />
        <title>Node.js for i Sample</title>
    </head>
    <style>
input {
  height:30px;
  border:#ccc solid 1px
}
input[type="text"] {
  width:500px
}
input[type="submit"] {
  margin:1em;
  width:120px
}
</style>
    <body>
        <form name="input" action="query" method="get">
            <div>SQL Command </div>
            <input type="text" name="sql" placeholder="SELECT ∗ FROM ..."/>
            <input type="submit" value="Query"/>
        </form>
        <form name="input" action="cmd" method="get">
            <div>CL Command </div>
            <input type="text" name="cl" placeholder="WRKSYSSTS"/>
            <input type="submit" value="Run"/>
        </form>
    </body>
</html>



                

  1. Vuelva a ejecutar el archivo sample.js.

Primero, apague el servidor que se está ejecutando y vuelva a iniciar el servidor web tal como se describe en el Paso 2. Ahora es posible lanzar el navegador para acceder a la página de muestra – http://ip:port/sample.html

Entregue una página web estática

Aunque por ahora solo está sirviendo una página estática, la infraestructura mínima de la aplicación web está lista. Es posible ver lo fácil que es empezar. No se necesitó ninguna configuración adicional del servidor de aplicaciones ni fue obligatorio seguir ningún paso especial para la implementación. En las siguientes secciones se enriquecerá el ejemplo con más códigos de JavaScript para completar algunas funciones importantes, ejecutar declaraciones SQL y comandos de CL.

Acceder a datos de DB2 for i

En esta sección, se enriquece el ejemplo para acceder a datos de DB2 for i data utilizando las APIs de la biblioteca de acceso de DB2 for i. La aplicación web le permite ejecutar cualquier declaración SQL en la página web y mostrar el resultado.

Advertencia: el siguiente ejemplo demuestra las capacidades de acceder a datos por medio de Node.js. En la práctica, la intención no será externalizar un comando o interfaz de SQL para un usuario. El servidor Node.js se ejecuta con las autoridades del usuario que inició el servidor web.

La extensión DB2 for i es un conjunto de APIs de JavaScript establecido para manipular las bases de datos de DB2 en IBM i. Proporciona interfaces de JavaScript que corresponden a la interfaz del nivel de llamadas (CLI) de SQL de DB2 for i SQL. Todas las APIs de CLI de DB2 se han expuesto en la extensión. La biblioteca de acceso se envía con Node.js para IBM i y se encuentra en: /QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/.

Para permitir el uso de las APIs de DB2 for i, solo es necesario tener el archivo db2a.js en su código fuente.

var db = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/lib/db2a');

Para conectarse a una base de datos, es necesario establecer el nombre o seudónimo de su base de datos. Es posible emitir el comando de CL, WRKRDBDIRE, para obtener el nombre de la base de datos de destino. En el ejemplo que se muestra en la Imagen 9, el nombre de la base de datos local es G0488C55. Si es necesario conectarse a la base de datos local, puede utilizar el valor especial ‘*LOCAL’ en la API conn().

Encuentre el nombre de la base de datos local

Además del comando de CL, también es posible decidir el nombre de la base de datos local por SQL. Para iniciar la sesión interactiva de SQL y ejecutar el siguiente SQL, es posible emitir el comando STRSQL de CL.

SELECT CATALOG_NAME, CATALOG_STATUS, CATALOG_TYPE FROM QSYS2.SYSCATALOGS

Consulte el siguiente resultado.

CATALOG_NAME CATALOG_STATUS CATALOG_TYPE
G0488C55 AVAILABLE LOCAL
IASP1 VARYOFF LOCAL
LP21UT24 UNKNOWN REMOTE

Ahora, para ampliar el archivo sample.js para leer la declaración SQL de la cadena de caracteres de la consulta de la solicitud, ejecute la declaración SQL y devuelva el conjunto de resultados al navegador.

var http = require('http');
var fs = require('fs');
var url = require('url');
var db = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/lib/db2a');

var DBname = "∗LOCAL";
var userId = "UserName";
var passwd = "PassWord";
var ip = "IP_Address";
var port = 8080;

var webserver = http.createServer((req,res) => {
  var realPath = __dirname + url.parse(req.url).pathname;
  fs.exists(realPath, (exists) => {
    if(!exists){
      var sql = url.parse(req.url, true).query.sql;
      if(sql && sql.length > 0) {
        var dbconn = new db.dbconn();
        dbconn.conn(DBname, userId, passwd);  // Connect to the DB
        var stmt = new db.dbstmt(dbconn);
        stmt.exec(sql, (rs) => { // Query the statement
          res.writeHead(200, {'Content‑Type': 'text/plain'});
          res.end(JSON.stringify(rs));
          stmt.close();
          dbconn.disconn();
          dbconn.close();
        });
      }
    } else {
      var file = fs.createReadStream(realPath);
      res.writeHead(200, {'Content‑Type':'text/html'});
      file.on('data', res.write.bind(res));
      file.on('close', res.end.bind(res));
      file.on('error', (err) => {
        res.writeHead(500, {'Content‑Type':'text/plain'});
        res.end("500 Internal Server Error");
      });
    }
  });
});
webserver.listen(port, ip);
console.log('Server running at http://' + ip + ':' + port);

Cuando se actualice el código fuente, finalice el programa de Node.js y reinicie el servidor web tal como se describe en las secciones anteriores.

Después, ingrese el siguiente URL en su navegador: http://ip:port/sample.html. El código que añadimos antes, permitirá el funcionamiento de la función SQL. Ingrese cualquier declaración SQL en el primer campo y haga clic en Query. El servidor Node.js ejecuta la sentencia SQL contra la base de datos que ha especificado. Por ejemplo, la siguiente declaración SQL encuentra los archivos que más crecieron en los últimos 7 días:

 select SYS_NAME, SYS_ONAME, CURRENT_VALUE from qsys2.syslimits where sizing_name = 'MAXIMUM NUMBER OF VALID ROWS' AND lastchg > current timestamp ‑ 7 days order by current_value desc 

Consulte datos de la base de datos DB2

El resultado del conjunto de resultados está en formato JSON. Puede utilizar la función JSON.stringify() para convertirlo a texto legible, o acceder directamente a los pares de valor principal.

Resultado de la consulta SQL

Acceso a objetos activos de IBM i

El conjunto de APIs del Node.js Toolkit for IBM i se basa en XMLSERVICE para poder acceder fácilmente a objetos nativos de IBM i, como la información PTF, consultas de datos y programas. Actualmente, Node.js Toolkit for IBM i brinda las siguientes clases.

  • itoolkit – funciones e interfaces básicas para llamar a comandos de la CL, comandos de QSHELL, programas, procedimientos en programas de servicios y declaraciones SQL.
  • iwork – interfaces para obtener información del sistema y el estado de los trabajos.
  • iprod – interfaces para obtener información del producto y de PTF.
  • iuserSpace – interfaces para manipular el espacio del usuario.
  • inetwork – interfaces para obtener información de la red.
  • iobj – interfaces para obtener autoridades de objetos e información de comandos, programas y programas de servicios.
  • idataq – Interfaces para manipular colas de datos.

Node.js Toolkit for IBM i se envía con Node.js para IBM i y se encuentra en el directorio /QOpenSys/QIBM/ ProdData/OPS/Node6/os400/os400/. Para utilizar Node.js Toolkit for IBM i, primero es necesario el archivo itoolkit.js. El archivo itoolkit.js conecta el soporte de XMLSERVICE con Node.js y es la base de todas las otras funciones de Node.js Toolkit.

var xt = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/xstoolkit/lib/itoolkit');

Ahora, continuemos modificando sample.js para utilizar la clase itoolkit para ejecutar un comando de la CL.

var http = require('http');
var fs = require('fs');
var url = require('url');
var db = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/db2i/lib/db2a');
var xt = require('/QOpenSys/QIBM/ProdData/OPS/Node6/os400/xstoolkit/lib/itoolkit');

var DBname = "∗LOCAL";
var userId = "UserName";
var passwd = "Password";
var ip = "IP_Address";
var port = 8080;

var webserver = http.createServer((req,res) => {
  var realPath = __dirname + url.parse(req.url).pathname;
  fs.exists(realPath, (exists) => {
    if(!exists){
      var sql = url.parse(req.url, true).query.sql;
      var cl = url.parse(req.url, true).query.cl;
      if(sql && sql.length > 0) {
        console.log("SQL statement : " + sql);
        var dbconn = new db.dbconn();
        dbconn.conn(DBname, userId, passwd);  // Connect to the DB
        var stmt = new db.dbstmt(dbconn);
        stmt.exec(sql, (rs) => { // Query the statement
          res.writeHead(200, {'Content‑Type': 'text/plain'});
          res.end(JSON.stringify(rs));
          stmt.close();
          dbconn.disconn();
          dbconn.close();
        });
      }
      if(cl && cl.length > 0) {
        console.log("CL statement : " + cl);
        var conn = new xt.iConn(DBname, userId, passwd);
        conn.add(xt.iSh("system ‑i " + cl));
        conn.run((rs) => {
          res.writeHead(200, {'Content‑Type': 'text/plain'});
          res.end(xt.xmlToJson(rs)[0].data);
        });
      }
    } else {
      var file = fs.createReadStream(realPath);
      res.writeHead(200, {'Content‑Type':'text/html'});
      file.on('data', res.write.bind(res));
      file.on('close', res.end.bind(res));
      file.on('error', (err) => {
        res.writeHead(500, {'Content‑Type':'text/plain'});
        res.end("500 Internal Server Error");
      });
    }
  });
});
webserver.listen(port, ip);
console.log('Server running at http://' + ip + ':' + port);
 

Node.js Toolkit for IBM i permite la ejecución de varios comandos en un lote. En este ejemplo, solo tenemos que recuperar el primer resultado.

Ahora, actualice la página http://ip:port/sample.html en la sesión de su navegador. Ingrese un comando de CL en el segundo campo y haga clic en Ejecutar. Node.js Toolkit for IBM i para ejecutar el comando y devolver los resultados al navegador. En este ejemplo, se ejecuta el comando Display System Status (DSPSYSSTS) para recuperar el estado actual del sistema.

Ejecute el comando DSPSYSSTS con Node.js

La siguiente imagen muestra el resultado del comando de la CL.

Resultado del ejemplo de DSPSYSSTS

Resumen

Hace mucho tiempo JavaScript es un lenguaje de creación de scripts del navegador ampliamente usado. Ahora, Node.js se permite en el lado del servidor, lo que lo hace más útil para clientes de IBM i. Además de la API clásica de JavaScript, Node.js brinda varios módulos incorporados para construir fácilmente aplicaciones modernas. Consulte el Manual y Documentación de Node.js para obtener más detalles acerca de estas APIs incorporadas. La biblioteca de acceso de DB2 y Node.js Toolkit for IBM i amplían aún más la funcionalidad de Node.js en IBM i. Es más, hay miles de módulos de terceros que se pueden instalar con la herramienta npm. Disfrute de su experiencia al utilizar Node.js en IBM i.

Recursos