Archivos de May, 2007

COBOL-CICS: Vamos a Pseudo-Conversar un poco.

El la entrega anterior, vimos como generar un programa COBOL que llamaba a un mapa que mostraba un banner con el Texto Hola Mamones. En el tocho de hoy, vamos a complicar un poco el programa, con el fin de explicar como funciona el procedimiento pseudo-conversacional.

Para ello, añadiremos unos campos en los que, depende de lo que rellenemos, el programa escribirá un texto, o no escribirá nada, y se verá como en modo pseudo-conversacional el CICS no se quedará pillado con la tarea de esperar a que el usuario haga algo.

Como funciona el modo Pseudo-Conversacional?

En los sistemas monousuario / monotarea tradicionales (como DOS), cuando el usuario lanzaba un programa, el procesador dedicaba todos sus recursos a ese programa, y estaba siempre en memoria. Si el programa necesitaba la interacción del usuario, el programa en memoria paraba su ejecución, hasta que el usuario respondiera, pero la CPU no atendía nada más.

Como en un sistema multiusuario, esto es una grave pérdida de recursos, se diseño el modo de programación pseudo-conversacional. Esta metodología, implica que el programa se ejecuta desde el principio al lanzar la transacción que lo llama, hace una acción (por ejemplo, muestra una pantalla con campos a rellenar) y termina dicho programa (pero NO la transacción). Cuando el usuario hace algo (por ejemplo, da al Enter después de rellenar los campos), ese programa vuelve a ejecutarse desde el principio, hace una acción (por ejemplo, recoge los campos escritos por pantalla) y vuelve a terminar (aunque repito que NO la transacción). Esto hace que el CICS mientras el usuario está escribiendo algo, como el programa se ha ejecutado y ha terminado, no consuma nada de memoria RAM, salvo una pequeña zona de memoria común, que es la que controla el ámbito de la transacción, y como dicho área lleva la cuenta de por ejemplo, quien lanzó la transacción y desde donde, dicho programa se ejecutará siempre usando el área común de acuerdo a los parámetros de su sesión..

Os preguntaréis como si el MISMO programa, se ejecuta y termina, puede hacer cosas diferentes cada vez. Ahí reside la clave del pseudo-conversacional. Usando el área común de memoria del CICS asociada a esa transacción, a la que hemos dicho al programa que use tantos bytes de ella, yo puedo controlar cuando ese programa lo he lanzado por primera vez, o es una llamada que viene de antes, y todo con variables que defina dentro de ese área de memoria. Así que la clave es: tengo que saber que hace mi programa en cada momento, por que pasos se ejecuta, y guardar en ese área común los datos que yo considere necesarios para que el programa siga progresando hasta que la transacción se de por finalizada por el programa.

Vamos a programar un poco

Para ver esto de manera practica, voy a listar el programita que he hecho y os voy a explicar que proceso sigue, aunque no nos meteremos de lleno en el área común, porque francamente, solo haremos dos iteraciones del programa, una para mostrar el mapa y otra para dar un resultado. Para empezar, hemos cogido nuestro mapa BMS de la vez pasada y hemos modificado algunas cosas, añadiendo algunos campos, El código es el que sigue:

HOL2MP   DFHMSD TYPE=DSECT,MODE=INOUT,TERM=ALL,STORAGE=AUTO,LANG=COBOL
HOL2MP   DFHMDI SIZE=(24,80),LINE=1,COLUMN=1,COLOR=GREEN,HILIGHT=OFF,  X
MAPATTS=(COLOR,HILIGHT),DSATTS=HILIGHT,CTRL=FREEKB
DFHMDF POS=(1,1),LENGTH=6,INITIAL='HOL2MP',                   X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMDF POS=(3,10),LENGTH=43,                                  X
INITIAL='PROGRAMA HOLA MAMONES PSEUDOCONVERSACIONAL',   X
ATTRB=(ASKIP,NORM),COLOR=RED
DFHMDF POS=(10,1),LENGTH=6,ATTRB=(ASKIP,NORM),                X
COLOR=YELLOW,INITIAL='CAMPO1:'
CAMPO1   DFHMDF POS=(10,10),LENGTH=10,ATTRB=(UNPROT,NORM,IC)
DFHMDF POS=(11,1),LENGTH=6,ATTRB=(ASKIP,NORM),                X
COLOR=YELLOW,INITIAL='CAMPO2:'
CAMPO2   DFHMDF POS=(11,10),LENGTH=10,ATTRB=(UNPROT,NORM)
MSG      DFHMDF POS=(20,10),LENGTH=60,ATTRB=ASKIP,COLOR=NEUTRAL
DFHMSD TYPE=FINAL
END

Este mapset y mapa lo hemos llamado HOL2MP, y como podéis ver, hemos añadido algunos campos: Por un lado, campos que solo muestran títulos por pantalla, y por otro, campos como CAMPO1, CAMPO2 y MSG, que serán los campos con los que trabajaremos con el programa. CAMPO1 y CAMPO2 serán editables (UNPROT) y el campo MSG que serán de mensajes que queremos que deje en caso de error o lo que nos dé la gana.

Si compilamos este mapa, veremos que la COPY que deberemos pegar en la WORKING-STORAGE SECTION, es algo más grande y con mas movidas que la primera que hicimos:

01 HOL2MP  PIC X(1000).
01  HOL2MPI REDEFINES HOL2MP.
02  FILLER PIC X(12).
02  CAMPO1L    COMP  PIC  S9(4).
02  CAMPO1F    PICTURE X.
02  FILLER REDEFINES CAMPO1F.
03 CAMPO1A    PICTURE X.
02  FILLER   PICTURE X(1).
02  CAMPO1I  PIC X(10).
02  CAMPO2L    COMP  PIC  S9(4).
02  CAMPO2F    PICTURE X.
02  FILLER REDEFINES CAMPO2F.
03 CAMPO2A    PICTURE X.
02  FILLER   PICTURE X(1).
02  CAMPO2I  PIC X(10).
02  MSGL    COMP  PIC  S9(4).
02  MSGF    PICTURE X.
02  FILLER REDEFINES MSGF.
03 MSGA    PICTURE X.
02  FILLER   PICTURE X(1).
02  MSGI  PIC X(60).
01  HOL2MPO REDEFINES HOL2MPI.
02  FILLER PIC X(12).
02  FILLER PICTURE X(3).
02  CAMPO1H    PICTURE X.
02  CAMPO1O  PIC X(10).
02  FILLER PICTURE X(3).
02  CAMPO2H    PICTURE X.
02  CAMPO2O  PIC X(10).
02  FILLER PICTURE X(3).
02  MSGH    PICTURE X.
02  MSGO  PIC X(60).

Veremos entre otras cosas las Redefines que hay entre el mapa de entrada y de salida, y si os fijáis (lo he puesto en negrita), están los campos de entrada y de salida (CAMPO1I, CAMPO1O, etc). Además, hay un campo interesante llamado CAMPOH, que asignándole un valor, podemos hacer que dicho valor parpadee, sea video inverso, etc.

Sin más, pasaré a poner el programa que he escrito, así lo explicaremos paso a paso. Lo he llamado HOL2, para que no interfiera con el primero que hicimos.

*************************************************************
*
*  PROGRAMA DE PRUEBA DE CICS-COBOL
*
*************************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. HOL2.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
*===============================================================
* LA COPY DEL MAPA GENERADO
*===============================================================
01 HOL2MP  PIC X(1000).
01  HOL2MPI REDEFINES HOL2MP.
02  FILLER PIC X(12).
02  CAMPO1L    COMP  PIC  S9(4).
02  CAMPO1F    PICTURE X.
02  FILLER REDEFINES CAMPO1F.
03 CAMPO1A    PICTURE X.
02  FILLER   PICTURE X(1).
02  CAMPO1I  PIC X(10).
02  CAMPO2L    COMP  PIC  S9(4).
02  CAMPO2F    PICTURE X.
02  FILLER REDEFINES CAMPO2F.
03 CAMPO2A    PICTURE X.
02  FILLER   PICTURE X(1).
02  CAMPO2I  PIC X(10).
02  MSGL    COMP  PIC  S9(4).
02  MSGF    PICTURE X.
02  FILLER REDEFINES MSGF.
03 MSGA    PICTURE X.
02  FILLER   PICTURE X(1).
02  MSGI  PIC X(60).
01  HOL2MPO REDEFINES HOL2MPI.
02  FILLER PIC X(12).
02  FILLER PICTURE X(3).
02  CAMPO1H    PICTURE X.
02  CAMPO1O  PIC X(10).
02  FILLER PICTURE X(3).
02  CAMPO2H    PICTURE X.
02  CAMPO2O  PIC X(10).
02  FILLER PICTURE X(3).
02  MSGH    PICTURE X.
02  MSGO  PIC X(60).
*===============================================================
* FIN DE LA COPY DEL MAPA GENERADO
*===============================================================
*
*
01 MI-COMMAREA.
03 CAMPOINICIO PIC X(8).
*
* COPIAMOS AYUDAS DE BMS PARA HACER BONITO EL TERMINAL
COPY DFHAID.
COPY DFHBMSCA.
*
LINKAGE SECTION.
PROCEDURE DIVISION.
*
IF EIBCALEN = 0
MOVE LOW-VALUES TO HOL2MP
PERFORM MANDAR-MAPONLY
PERFORM RETORNO-TRANS
END-IF.
*
EXEC CICS RECEIVE MAP('HOL2MP')
INTO(HOL2MPI)
NOHANDLE
END-EXEC.
*
EVALUATE EIBRESP
WHEN DFHRESP(NORMAL)
CONTINUE
WHEN DFHRESP(MAPFAIL)
PERFORM FALLO-MAPA
PERFORM FIN-PGM
END-EVALUATE.
*===============================================================
* RESPUESTA AL MAPA
*===============================================================
MOVE CAMPO1I TO CAMPO2O.
MOVE DFHBLINK TO MSGH.
MOVE 'OK!!' TO CAMPO1O.
MOVE 'HA!HA!HA! ESTOY USANDO LA MAINFRAME!!11!!1!' TO MSGO.
EXEC CICS SEND MAP('HOL2MP')
ERASE
FROM(HOL2MPO)
NOHANDLE
END-EXEC.
EXEC CICS RETURN
END-EXEC.
GOBACK.
*===============================================================
* PROCEDIMIENTO DEL PSEUDO-CONVERSACIONAL
*===============================================================
RETORNO-TRANS.
EXEC CICS RETURN
TRANSID(EIBTRNID)
COMMAREA(MI-COMMAREA)
LENGTH(8)
END-EXEC.
GOBACK.
*===============================================================
* RESTO DE PROCEDIMIENTOS
*===============================================================
MANDAR-MAPONLY.
EXEC CICS SEND MAP('HOL2MP')
MAPONLY
ERASE
NOHANDLE
END-EXEC.
*
FALLO-MAPA.
MOVE DFHBLINK TO MSGH.
MOVE 'FALLO DEL MAPA!' TO MSGO.
EXEC CICS SEND MAP('HOL2MP')
ERASE
FROM(HOL2MPO)
NOHANDLE
END-EXEC.
*
FIN-PGM.
EXEC CICS RETURN
END-EXEC.
GOBACK.

Como podéis ver, justo después de la COPY del mapa, hay una variable que he creado llamada MI-COMMAREA, de 8 caracteres de tamaño. Esta será ese área común que se mantendrá intacta durante el transcurso de toda la transacción.

También haremos una COPY de las ayudas que CICS nos brinda para poner colorines y parpadeos a nuestros mapas (DFHBMSCA), y la lista de IDentificadores de Atención, es decir, lo que significa para CICS si doy al Enter en mi terminal, o al PF3 (DFHAID). Esto hará que llevemos un control por si el usuario ha tecleado algo que no debía, o que hacer si ha dado al enter, o lo que sea.

Sin más, empezamos con los procedimientos, y los iré explicando a medida que sigamos el flujo de nuestro programa. Cuando lanzamos la transacción que invoca al programa HOL2, lo primero que va a hacer es comprobar si la longitud del área común de memoria (EIBCALEN) es cero. Esto nos indica si el programa es llamado por primera vez, o se ha ejecutado más veces. Si es cero, es que es la primera vez que llamamos al programa porque ese área todavía no se ha usado, en cambio si contiene algo, significa que el programa ya ha dejado algo anteriormente, por lo que nos indica que este programa ya ha sido invocado con anterioridad en esta transacción.
Resumiendo, con ese IF lo que estamos comprobando es si el programa se ha ejecutado por primera vez.

Siguiendo nuestro flujo, y dado que es la primera vez que lo lanzamos, la longitud es cero. Así pues, lo que va a hacer es inicializar la memoria que ocupara el mapa a ceros binarios para machacar los residuos de memoria que pudieran quedar en ese área por otra transacción y que pueden llegar a poner algún dato en algún campo “lo he visto” (LOW-VALUES) y seguidamente, llamará al procedimiento de MANDAR-MAPONLY. Este procedimiento enviará nuestro mapa con los 3 campos por pantalla, pero sin valores, para que el usuario tenga con que trabajar. El vería algo como esto:

HOL2MP

PROGRAMA HOLA MAMONES PSEUDOCONVERSACIONAL

CAMPO1
CAMPO2

Y seguidamente, ejecutamos un RETORNO-TRANS. Este procedimiento hace que el programa termine, pero no sin antes hacer un EXEC CICS RETURN y le pasemos nuestro ID único de la transacción que hemos lanzado y nuestro área común llamada MI-COMMAREA. A partir de este momento, en nuestra área común, CICS almacenará diversos datos (entre otros, el ID de nuestra transacción asociada a nuestro terminal), para que la transacción sepa donde se ha terminado de ejecutar nuestro programa. Así que el CICS esta libre para hacer caso a mas gente.

Mientras tanto, el usuario ha rellenado “HOLA” en el CAMPO1, y le ha dado al enter. En este momento, CICS recibe una interrupción porque alguien ha dado al enter en nuestro terminal, y como CICS sabe que transacción teníamos en ese terminal, vuelve a ejecutar el programa HOL2.

Atención: Ahora, la longitud del área común NO es cero, debido a que hemos grabado varias cosas al hacer el CICS RETURN de antes, así que el IF se lo salta y va directamente a ejecutar la recepción del mapa. Pueden pasar dos cosas: Que el mapa se reciba bien, con datos, y que se los pase a todos los campos que acaban en I (CAMPO1I, CAMPO2I), o que se reciba mal (sin rellenar). Para eso, usamos el control de errores de a continuación, de acuerdo a lo que contenga la variable EIBRESP.
Si DFHRESP es NORMAL, es decir, que no ha habido errores al recibir el mapa, continuamos y nos salimos de la evaluación. Eso hará que el programa continúe en secuencia y haga lo siguiente: Que mueva el contenido del CAMPO1I al CAMPO2O, que hagamos un parpadeo al campo de mensaje y que cuyo contenido de salida sea ‘HA!HA!HA! ESTOY USANDO LA MAINFRAME!!11!!1!’ y pondremos un OK en el CAMPO1O. Con estos datos, enviaremos el MAPA con un SEND MAP, y los campos que hemos tocado que acaban en O, son los que se visualizarán.

La pantalla sería algo como esto:

HOL2MP

PROGRAMA HOLA MAMONES PSEUDOCONVERSACIONAL

CAMPO1   OK!!
CAMPO2   HOLA

HA!HA!HA! ESTOY USANDO LA MAINFRAME!!11!!1!

Por último, saldremos del programa con un EXEC CICS RETURN, pero como no guardaremos nada con ese return en nuestra área común, ni siquiera nuestro ID de transacción, para el CICS eso significa que ha terminado nuestro programa y con ello, la transacción. Facilillo, no? Pues en esto se basa todo.

Supongamos que el usuario NO teclea nada, en vez de teclear algo. Para el CICS, eso es un FALLO, y debe ser tratado como tal. Hay que tener en cuenta que si al CICS no le das de comer datos, que va a procesar? Por eso lo trata como fallo. El fallo en este caso es el MAPFAIL, y eso lo sabremos cuando evaluemos el EIBRESP. Así pues, si el mapa ha fallado porque está carente de contenido, nuestro programa entonces ejecutará un procedimiento llamado FALLO-MAPA, que pondrá en mensaje FALLO DEL MAPA en el campo del mensaje MSGO, y luego hará una SEND del mapa. Y de ahí, se irá a FIN-PGM, que hará un EXEC CICS RETURN y saldremos del programa y de la transacción.

HOL2MP

PROGRAMA HOLA MAMONES PSEUDOCONVERSACIONAL

CAMPO1
CAMPO2

FALLO DEL MAPA!

A partir de aquí, es complicarlo como uno quiera. Se pueden usar las DFHAID para salirnos de la transacción si hemos pulsado F3, por ejemplo, o se pueden añadir mas campos, que sean leídos y escritos desde un fichero, en definitiva, se pueden hacer virguerías, pero todo se basa en lo mismo: un EXEC CICS RETUN con datos de nuestra área común para hacer que nuestro programa, que siempre se ejecutará una y otra vez hasta que al CICS RETURN no le pasemos nada, tenga los datos adecuados para tratar nuestro flujo del programa.

Mi primer programa COBOL-CICS

Bueno, en el tocho de hoy, vamos a centrarnos en como crear un programa COBOL que mediante una transacción CICS, se ejecute y nos saque por pantalla un “Hola Mamones”

Pero antes de meternos en el rollo de programar, primero hay que aclarar una serie de conceptos de CICS.

Para empezar, una transacción CICS puede ser de muy diversa índole y puede ser lanzada de muchas maneras: La puedes teclear en tu terminal, la puedes lanzar por un socket, o incluso puedes hacer un FTP y lanzar un JCL que a su vez lance una transacción, siempre y cuando se cumplan los requisitos de seguridad, y demás que obviaremos porque me eternizaría (aun mas). En nuestro caso, vamos a centrarnos en la parte más tradicional del CICS, es decir, que un usuario teclee una transacción y le salga por pantalla un mensaje.

Ni que decir tiene que CICS es un sistema muy robusto, tanto, que se queja por todo. Pero por TO-DO. Esa es una de las razones por las que es muy difícil que se cuelgue un programa, porque tienes que tener en cuenta todas las variables posibles de error y codificarlas, porque de lo contrario, CICS cancela la transacción así por las buenas, y con un bonito ABEND de regalo. Así que hay que tener cuidado a la hora de programar, pero no os preocupéis, el programa que vamos a codificar es tan sencillo que no hará falta realizar ningún tipo de control de errores. De hecho, ni siquiera lo haremos pseudo-conversacional, porque solo haremos que se muestre un mensaje y saldremos del programa, con lo que el CICS finalizará la transacción. No obstante, si os animáis, en una entrega posterior, podemos complicar un poco el programa para que veáis más conceptos de CICS.

Así que vamos al meollo de la cuestión: Hemos hablado de Transacciones, de Programas y de Pantallas de usuario. Pues en CICS hay que crear las 3 cosas: Hay que crear un programa, hay que crear la transacción que llamará al programa, y hay que crear la pantalla del usuario. Empezaremos por este último paso.

Creación de la Pantalla

Una Pantalla de usuario, o, en la jerga CICSera, mapa BMS (Basic Mapping Support), es una plantilla de lo que queremos que aparezca por la pantalla del terminal cuando invoques a la transacción: Puede ser un título, o unos campos a rellenar, o cualquier cosa que se te ocurra en 24 lineas por 80 columnas. En nuestro caso, pondremos un cuadrado mas o menos centrado y su interior, el texto Hola Mamones, y podemos utilizar alguna característica 3270, como poner un color, por ejemplo. Todo esto lo voy a hacer a mano, pero existen muchas herramientas como VisualAge por ejemplo que te hacen las pantallas automáticamente. Pero a mi me gusta mas hacerlo a mano, porque se optimiza mucho mas el código (si, también me gusta escribir HTML en el Notepad, ¿pasa algo? xDDD).

Un MAPSET es un conjunto de mapas, que, al igual que los de las webs, pueden definir regiones dentro de la pantalla que cada una tenga características distintas, pero en nuestro caso, vamos a crear un mapset y un mapa que ocupe toda la pantalla, para hacerlo mas fácil. El código que yo he hecho ha sido este:

HOLAMP   DFHMSD TYPE=DSECT,MODE=INOUT,TERM=ALL,STORAGE=AUTO,LANG=COBOL
HOLAMP   DFHMDI SIZE=(24,80),LINE=1,COLUMN=1,COLOR=GREEN,HILIGHT=OFF,  X
MAPATTS=(COLOR,HILIGHT),DSATTS=HILIGHT,CTRL=FREEKB
DFHMDF POS=(10,10),LENGTH=20,INITIAL='********************',  X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMDF POS=(11,10),LENGTH=20,INITIAL='*                  *',  X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMDF POS=(12,10),LENGTH=20,INITIAL='*  HOLA, MAMONES!  *',  X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMDF POS=(13,10),LENGTH=20,INITIAL='*                  *',  X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMDF POS=(14,10),LENGTH=20,INITIAL='********************',  X
COLOR=BLUE,ATTRB=(ASKIP,NORM)
DFHMSD TYPE=FINAL
END

Tanto al mapset como al mapa, lo he llamado HOLAMP. También guardaremos el fichero con el mismo nombre, ya que el CICS va a ir a buscar ese fichero y debe coincidir con el nombre del mapa. Como podréis ver, hay 3 tipos de “instrucciones”:
- DFHMSD, hace referencia al MAPSET. Tiene una serie de variables que no comentaré aquí porque me alargaría todavía más, pero ya veis que el subtipo TYPE da la referencia de donde empieza y donde acaba.
- DFHMDI, hace referencia al MAPA en cuestión, y como podréis ver entre otros parámetros, muestra el tamaño de dicho mapa.
- DFHMDF, hace referencia a los CAMPOS de ese mapa. Cada campo puede ser editable o no, y podría cada uno tener colores distintos, etc. También se le indica la posición de ese campo dentro del mapa con el parámetro POS. En nuestro caso, este mapa solo va a mostrar datos, nada mas, por lo que en el campo INITIAL pondremos el contenido que queramos poner, en nuestro caso, el banner, y queremos que sea de color azul.

Con esto, ya tenemos los datos que saldrán por pantalla. Lo siguiente que haríamos, será compilar dicho mapa con el compilador de COBOL, con un JCL, finalizado el cual dejará dos ficheros: Uno, el mapa compilado y linkeditado que usará el CICS para mostrarlo por pantalla, y el otro, la COPY del mapa. Este último fichero sirve para que, añadiéndolo al programa en la WORKING-STORAGE SECTION, el programa tenga la referencia de a que llamar para que el CICS lo llame. Generalmente, este fichero si tuviera campos editables y para rellenar, sería muy larga, porque todo mapa tiene un campo que se trata como entrada (I) que es cuando el usuario ha introducido algo, y otro que se trata como Salida(O) que es cuando el CICS le debe responder en un campo. Por ejemplo, si tuviéramos un campo llamado DNI para rellenar, el compilador haría 2 Redefines de ese campo: DNII cuando el usuario Introduzca el DNI, y DNIO cuando el programa quiera escribir ahí un DNI de una base de datos, por ejemplo. El caso es que nos ha salido un churro como este:

01  HOLAMP PIC X(100).
01  HOLAMPI REDEFINES HOLAMP.
02  FILLER PIC X(12).
01  HOLAMPO REDEFINES HOLAMPI.
02  FILLER PIC X(12).

Traduciendo, el mapa ocupará 100 bytes, y luego deja 12 bytes (no me digáis para que, que no tengo ni idea), y como no tiene campos editables de entrada ni de salida, el mapa de entrada HOLAMPI es redefinido con el de salida (HOLAMPO). Pues esas 5 líneas las pegaremos en nuestro programa COBOL cuando lo escribamos, en la zona WORKING-STORAGE SECTION.

Creación del programa

Lo malo del COBOL, es que es estricto de narices en su escritura y su estructura, y un espacio de más o de menos en ciertas columnas puede hacer que el programa (por ejemplo, los comentarios empiezan con asterisco en la columna 8, y solo en la 8) da mil quebraderos de cabeza. Lo bueno, es que una vez superada esa tocada de narices, programas líneas una detrás de otra como si estuvieras manteniendo una conversación en ingles, y es tremendamente fácil y potente. Para mí, mucho más fácil que JAVA o C.

Sin mas, el programa sería algo tan sencillo como esto:

*************************************************
*
*  PROGRAMA HOLA MAMONES DE CICS-COBOL
*
*************************************************
IDENTIFICATION DIVISION.
PROGRAM-ID. HOLA.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 HOLAMP  PIC X(1000).
01  HOLAMPI REDEFINES HOLAMP.
02  FILLER PIC X(12).
01  HOLAMPO REDEFINES HOLAMPI.
02  FILLER PIC X(12).
*
PROCEDURE DIVISION.
*
MOSTRAR-MAPA.
EXEC CICS SEND MAP('HOLAMP')
MAPONLY
ERASE
NOHANDLE
END-EXEC.
FIN-PGM.
EXEC CICS RETURN
END-EXEC.
GOBACK.

Lo cojonudo del caso es que casi hay más líneas de código de la “estructura” obligatoria a seguir de COBOL, que lo que realmente hace el programa. Pero vamos, lo que hemos puesto es lo siguiente:
- En la Working, hemos pegado la copy del mapa que hemos hecho antes.
- Hemos escrito un procedimiento llamado MOSTRAR-MAPA que no hace más que un EXEC CICS enviando el mapa. Con la opción MAPONLY, te curas en salud y te pasas por el forro la gestión de errores porque con esto le dices al CICS que solo va a mostrar un mapa, y que el usuario no va a teclear nada más.
- Y hemos escrito otro procedimiento llamado FIN-PGM que lo que hace es devolver el control al CICS. Como van seguidos, una vez ejecutado el MOSTRAR-MAPA, ejecutará este y por lo tanto, saldrá del CICS.

Con otro JCL, compilaremos dicho programa y su programa linkeditado se quedará en una librería que el CICS tenga configurada como de carga de programas (al igual que el mapa), y deberá llamarse igual que el PROGRAM-ID que hemos puesto (en nuestro caso, el fichero se llamará HOLA).

Creación de la Transacción y definición en el CICS

Bueno, estamos en la recta final del tocho. Ahora que tenemos el programa y el mapa compilados, hay que molestar al CICS para decirle que tiene disponibles un programa y un mapa para que vía una transacción, muestre todo. Para ello, la herramienta que utilizaremos para molestar al CICS es la transacción CEDA.

Usando la CEDA (no tiene nada que ver con ceder el paso xDDD), definiremos la transacción, el programa y el mapa. CICS, para poder administrarse mejor, esta dividido en Grupos de aplicaciones, ya que si no, nos volveríamos locos si tenemos miles de programas y hay que buscar alguno en concreto. Es por ello, que crearemos un grupo llamado HOLA, en el que definiremos el programa, la transacción y el mapa. Decir también que el grupo se crea cuando creemos el primer miembro del grupo, por ejemplo, si empezamos definiendo el programa, y siempre que tengamos los permisos adecuados para ejecutar la transacción CEDA, haremos lo siguiente:

CEDA DEF PROG (HOLA) GROUP (HOLA)

Ahora, definiremos el mapa con el comando siguiente:

CEDA DEF MAP (HOLAMP) GROUP (HOLA)

Y por último, definiremos la transacción, la llamaremos HOLA (como tiene 4 caracteres, va que ni pintado) y le pondremos como parámetro cual es el programa que tiene que llamar en primer lugar, que, como en nuestro caso es HOLA, pues lo pondremos así:

CEDA DEF TRANS(HOLA) PROG(HOLA) GROUP(HOLA)

Bien, hasta aquí tenemos todo definido. Si hacemos un CEDA DI GROUP (HOLA), aparecerá una lista tal que esta:

DI GROUP(HOLA)
ENTER COMMANDS
NAME     TYPE         GROUP                                   DATE   TIME
HOLAMP   MAPSET       HOLA                                    07.137 13.00.01
HOLA     PROGRAM      HOLA                                    07.137 12.59.45
HOLA     TRANSACTION  HOLA                                    07.137 12.59.32

Pero faltan dos pasos todavía: Hay que INSTALAR lo definido para que el CICS lo recuerde siempre a partir de ahora, y eso con poner una I a continuación del grupo en las tres líneas, y damos al enter, se instalará todo, y debería quedarse la pantalla algo como esto:

DI GROUP(HOLA)
ENTER COMMANDS
NAME     TYPE         GROUP                                   DATE   TIME
HOLAMP   MAPSET       HOLA     i                           INSTALL SUCCESSFUL
HOLA     PROGRAM      HOLA     i                           INSTALL SUCCESSFUL
HOLA     TRANSACTION  HOLA     i                           INSTALL SUCCESSFUL

Ya estamos listos? No. Falta un último paso: Cargar el programa. Con la CEDA, hemos definido el programa y lo hemos instalado, pero con eso no basta, el código binario del programa se debe cargar en la región del CICS, para así poder ser ejecutado. Con el mapa no es necesario, porque es el programa quien llama al mapa, pero el programa debe estar siempre cargado. Así que haremos uso de la transacción CEMT para cargarlo.

Si hacemos un CEMT S PROG(HOLA), tendría que salir algo similar a esto:

S PROG(HOLA)
STATUS:  RESULTS - OVERTYPE TO MODIFY
Prog(HOLA    ) Leng(0000000000) Cob Pro Ena Pri     Ced
Res(000) Use(0000000000) Bel Uex Ful Qua

Como podréis observar, el campo Leng está a ceros, es decir, el CICS sabe que tiene algo reservado, pero no está ocupado. Así que si ponemos el cursor entre el campo Pri y el campo Ced, y tecleamos una N (Newcopy), al pulsar Enter el valor de Leng debe cambiar y mostrar el tamaño en bytes del programa, quedando algo así como esto:

S PROG(HOLA)
STATUS:  RESULTS - OVERTYPE TO MODIFY
Prog(HOLA    ) Leng(0000004736) Cob Pro Ena Pri  N  Ced     NORMAL
Res(000) Use(0000000000) Bel Uex Ful Qua

Pues bien, ya está todo preparado. Si tecleamos en nuestra pantalla, la transacción HOLA, veremos lo siguiente:

********************
*                  *
*  HOLA, MAMONES!  *
*                  *
********************

Y con esto, se acaba la transacción, y evidentemente ha sido instantánea.

Si lo pedís y estáis interesados, podría escribir en otra entrega la manera de complicar un poquito el programa y hacer que interactúe el usuario, de tal forma, que según la opción que teclee, le salga un mensaje u otro, y todo de manera conversacional.

CICS o Como Intentar Codificar Sabiamente.

El presente articulo hará un repaso general sobre lo que es el CICS, actualmente, el sistema transaccional mas extendido del planeta. El CICS (Customer Interface Control System) es un producto que corre bajo mainframe (z/Series) o mini (i/Series) y se usa sobre todo para el sistema conversacional entre el usuario y la máquina, dicho de otro modo, es el interfaz del usuario a los programas de aplicación codificados para un uso concreto.

A este respecto, el usuario teclea una transacción y el sistema le da un resultado por pantalla o ejecuta una acción determinada, que puede convertirse en una cadena de acciones hasta que se consigue el resultado. El típico ejemplo: Consultar  el estado de licencia de una Diosa. El usuario introduce el nombre de la transacción, y le sale una pantalla donde introduce el número de Diosa, y al dar al Intro, le devuelve en pantalla el estado de su licencia, el tipo y si esta suspendida o no. O el sistema Amadeus de Reserva de Vuelos, es una infraestructura CICS como una casa. Facil, no?

Ya, si, bueno, pero como funca esto?

El CICS es básicamente un sistema donde residen una serie de transacciones de control del sistema y luego, transacciones de usuario. Todas las transacciones tienen un nombre de 4 caracteres que las identifica inequívocamente, de tal forma que por ejemplo, las que empiezan por una C, son transacciones de sistema (CEDA, CEMT, CESN, CEDF, etc).

Este sistema se ubica en la memoria del mainframe nada mas ejecutarse, y reserva una gran zona de memoria en función de la configuración que tenga, que se llama Región de CICS. Dentro de esta región, es donde residen las diversas tablas de configuración del CICS, entre ellas las tablas de transacciones, además de transacciones que están en vuelo o ejecutándose en este momento en forma de pequeños programas reutilizables.

Todas las transacciones tienen asociadas un programa inicial que será el que llame a otros programas o que a su vez, llame a otras transacciones. Este programa inicial suele estar escrito en COBOL por tradición, pero puede estar escrito en cualquier lenguaje como C, C++ o incluso JAVA. Este programa realiza su función, pero tiene intercaladas varias instrucciones de la forma EXEC CICS Bleh, siendo Bleh un parámetro del API del CICS. Por ejemplo, EXEC CICS SEND MAP (MAPA02) lo que hace es enviar un mapa de pantalla llamado MAPA02 al CICS, que lo mostrará por el terminal donde ha sido llamada esa transacción. Por otra parte, la eficiencia de programación de esos programitas es muy alta y se cuida hasta el ultimo detalle, ya que como son muy simples, se pueden optimizar muchísimo, al contrario que los mega-programas con cientos de funciones y procedimientos (eso no quita para que una transacción tenga asociado un programa de la pera, pero no suele ser lo habitual, ya que es mas fácil partir el programa en una o mas transacciones que luego se ejecutarán encadenadas que una única con un programa enorme, por evidentes motivos de rendimiento).

El funcionamiento es el siguiente: Cuando el usuario teclea la transacción, el CICS dedica su tiempo de CPU a atender ese usuario mientras la transacción esta en vuelo. ¿Como funciona el tema?

Pues el programa entre otras cosas, lo primero que hace es un EXEC CICS RECEIVE MAP con lo que captura las variables de la pantalla (o dicho de otro modo, los datos que el usuario ha tecleado). Con esos datos, el programa realiza la tarea que deba realizar y una vez obtenidos los resultados, el programa manda un EXEC CICS SEND MAP con la información que ha pedido, y en esos momentos puede decirse que la transacción está finalizada momento en que el CICS empieza a hacer caso de mas transacciones que le pueden estar llegando desde otros terminales.

¿Programación en pseudo-qué?

El problema que surge es evidente: Si un usuario ha llamado a una transacción y ésta le muestra unos datos por el terminal para que los rellene y dá al intro para que se ejecute, y el usuario es lento o le da por ir a tomarse un café, ¿que? La transacción sigue corriendo y por tanto, el resto de la gente que quiera que su transacción se ejecute, se joderá y tendrá que esperar a que el gilipollas este de usuario deje de tocar los cojones y termine la transacción que empezó.

Para evitar que este tipo de usuarios gilipollas entorpezcan el trabajo a otros usuarios mas capacitados, se inventó el modo de programación PSEUDOCONVERSACIONAL. En este modo, la transacción solo está activa cuando tiene que calcular o mostrar algo, y luego le devuelve el control al CICS con un EXEC CICS RETURN. Desde un punto de vista práctico y muy resumido, y siguiendo el ejemplo de la consulta de la licencia:
1.- El usuario teclea la transacción de consulta de licencias, por ejemplo, LICC.
2.- CICS recibe la petición y lanza el programa inicial que está relacionado con esa transacción. Este programa hace un EXEC CICS SEND MAP con la pantalla y los campos a rellenar y seguidamente hace un EXEC CICS RETURN. Esto hace que el usuario tenga en la pantalla los campos a rellenar, pero el CICS está disponible para otros usuarios.
3.- El usuario rellena los campos de esa pantalla y le da al intro.
4.- En ese momento, el CICS detecta que la pantalla que había sido visualizada con la transacción LICC recibe una interrupción, por lo que activa el programa asociado y emite un EXEC CICS RECEIVE MAP. En este momento, el programa ya tiene los datos necesarios para trabajar, se conecta a la base de datos y recupera la fila y datos de la licencia de acuerdo al número de la Diosa, y una vez realizado todo el tema, el programa emite un EXEC CICS SEND MAP con la información solicitada y hace un EXEC CICS RETURN, antes de terminar el programa.

Vale, pero para que sirve todo esto?

La característica que ha hecho del CICS el mejor sistema, son 40 años de desarrollo en lo referente a la concurrencia. Además, sentó las bases del procesamiento distribuido. Imaginaos por un momento que se dispone de un repositorio de miles y miles de transacciones y programas. Yo puedo llamar a una transacción, y le meto unos datos, otro puede llamar a la misma transacción simultáneamente con unos datos iguales o diferentes a los míos, y si eso lo extrapolamos, un simple programilla que te puede hacer virguerías en una consulta o actualización de base de datos, puede ser ejecutado concurrentemente por mas de 10.000 usuarios, con unos consumos de CPU ridículos, y si se viera desbordado por el proceso de base de datos, el CICS mantiene un sistema de colas y bloqueos muy elaborado, haciendo caso a la vez a toda la gente.

Un ejemplo clarísimo son los miles y miles de cajeros que puede tener un banco repartido por todo el país, pues en la mayoría de los casos, detrás tiene un CICS que le da toda la información que solicita el cliente. Además, trata a las transacciones como una unidad, y si en algún momento el programa falla (bien porque no encuentra un tabla de base de datos, o hay un valor que no espera), el CICS se encarga de deshacer todo lo hecho hasta ahora, haciendo una serie de rollbacks automáticamente, siempre dejando el sistema en una situación coherente antes del procesamiento de esa transacción fallida.

Venga va, algo malo tiene que tener, ¿no?

Desgraciadamente, el CICS no ha evolucionado todo lo rápido que debiera en la inclusión de nuevas tecnologías, y la actualización de las comunicaciones a TCP/IP se ha ido haciendo mediante parches y mas parches (CICS Transaction Gateway, CICSsockets, etc), por lo que otras tecnologías le han ido ganando terreno en este campo. Por si fuera poco, el CICS tiene una limitación: Solo se ejecuta en una CPU. Si tuviéramos 32 procesadores, el CICS solo vería uno de los 32, por lo que el rendimiento sería sumamente bajo en comparación con el maquinón.
Afortunadamente a este respecto, los desarrolladores de CICS idearon un sistema de CICSes concurrentes: Los TOR y los AOR.

Un TOR (Terminal Owning Region) es un CICS que solo recibe peticiones, y el proceso lo deriva entre uno o mas AOR (Application Owning Region) que son CICSes que tratan las peticiones y cuyo resultado se lo devuelven al TOR. De este modo, podría tener un TOR y muchos AOR, de tal forma que, en conjunción con otras arquitecturas como Datasharing del DB2, balancearía el proceso entre todos esos CICSes, y como cada uno de ellos coge una CPU, podría tener muchos CICSes concurrentes en un entorno multiprocesador y mejorar el rendimiento de una manera asombrosa, haciendo caso a cientos de miles de usuarios concurrentes. Iberdrola, por ejemplo, tiene una configuración de TOR y muchos AOR que le permiten hacer caso a varias decenas de miles de usuarios en todo el mundo, al igual que Kutxa o Caja Vital, aunque su configuración de TOR y AORs es más pequeña.

Sin mas, en la siguiente entrega explicaré como hacer una pequeña transacción que haga que nos muestre por pantalla “Hola, Mamones” y así podréis ver lo sencillo que es hacer un pequeño programa en COBOL y como crear una transacción asociada.