Etiqueta

13 febrero 2020

Cómo mostrar un PDF desde un campo BLOB de Oracle sobre el navegador, sin descargarlo

En este artículo quiero mostrarles un "truco" ideado por Francesco Del Dotto de soporte Omnis en Italia, de modo que lo primero es agradecer su tiempo y darle mi enhorabuena ante la pericia demostrada.


En principio podría pensarse que se trata de algo sencillo de hacer desde Omnis Studio, ya conocemos el método Do $cinst.$clientcommand("assignpdf",row) donde el parámetro row se define como row(html-object-name,pdf-parameters,pdf-id,timeout,pdf-filename), pero el reto está precisamente en el parámetro pdf-filename, es decir que el uso de éste método requiere de la presencia física del fichero con el documento pdf, pero el reto que se plantea en el enunciado de este artículo, es enviar al navegador del cliente, un documento pdf que se encuentra en una variable binary y no en un fichero físico.

La parte digamos "sencilla" fue construir el método (denominado muestraPdf) javascript que se encargaría de mostrar el documento, pasándole el contenido del campo BLOB de oracle y que mostramos a continuación:

# El dato BLOB de Oracle es iDocumentos.DOCUMENTO
# pdfBuffer es una variable var de JavaScript
# el método ha sido marcado como "Execute On Client" 

Calculate pdfBuffer as iDocumentos.DOCUMENTO
JavaScript: var arrayBuffer = base64ToArrayBuffer(pdfBuffer);
JavaScript: function base64ToArrayBuffer(base64) {
JavaScript: var binaryString = window.atob(base64);
JavaScript: var binaryLen = binaryString.length;
JavaScript: var bytes = new Uint8Array(binaryLen);
JavaScript: for (var i = 0; i < binaryLen; i++) {
JavaScript: var ascii = binaryString.charCodeAt(i);
JavaScript: bytes[i] = ascii;
JavaScript: }
JavaScript: return bytes;
JavaScript: }
JavaScript: var blob = new Blob([arrayBuffer], {type: "application/pdf"});
JavaScript: var link = window.URL.createObjectURL(blob);
JavaScript: window.open(link);

El problema estriba en como invocar a éste método desde el lado del servidor, ya que sólo existe en el navegador del cliente y por tanto sólo puede ser invocado desde un método que (al igual que este) haya sido marcado como "Execute On Client", el problema es que la recuperación del campo BLOB con el contenido del PDF, debe hacerse desde un método creado y ejecutado en el entorno del servidor, es decir que no puede llevar la marca "Execute On Client", y es aquí donde llega el "truco de Francesco".

Para que la magia tenga su efecto, lo primero que hacemos es colocar un "Timer Control" sobre el formulario remoto...


...al que incluiremos en su método "$event" el código siguiente y que estratégicamente habremos marcado como "Execute On Client":

On evTimer
Do $cinst.$objs.timerObj.$running.$assign(kFalse)
Do $cinst.$muestraPdf()

El truco consiste en activar el timer alojado en el navegador del cliente desde el servidor, el cual se encargará a su vez de invocar al método "$muestraPdf()" ademas de auto-desactivarse.

A continuación mostramos la secuencia que obtiene el campo BLOB de oracle y activa el timer:

Calculate lCompara as con("where ROWID = '";iListaDctos.ROWID;"'")
Do iDocumentos.$select(lComparaReturns #F
If flag true
Do iDocumentos.$fetch()
If not(isclear(iDocumentos.DOCUMENTO))
Do $cinst.$objs.timerObj.$running.$assign(kTrue)
End If
End If

El código encargado de recuperar el documento desde la base de datos, es también el encargado de activar el timer, que fue previamente alojado en el navegador del cliente.

Gracias de nuevo a Francesco de soporte Omnis, por este maravilloso truco.