En 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.
¿Cómo 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 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, ¿qué 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 RETURN 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.
Comentarios