jueves, 21 de mayo de 2015

Extraer contenido de contenedores OLE

Una funcionalidad muy útil en versiones de Forms 6i o anteriores, era la de almacenar archivos en contenedores OLE, para ello bastaba con tener un campo en el bloque asociado a un campo BLOB de la base de datos y ya era posible guardar en él archivos mediante la aplicaciones con soporte OLE2, por ejemplo WORD, EXCEL, PDF, ...

El problema es que desde Forms 9i esta funcionalidad ya no existe, por lo que hay que buscar alternativas, lo normal es a través de implementar la carga / descarga de archivos usando la librería WEBUTIL.

Aparte de tener que cambiar la implementación, el principal problema con el que me he encontrado ha sido la necesidad de migrar de un sistema a otro debido a que los archivos almacenados en un contenedor OLE tienen un envoltorio que hace imposible que se abran directamente, es necesario abrirlos a través de ese contenedor, por lo que había que hacerlo de forma manual uno a uno desde el programa.

La solución que he encontrado a este problema es mediante la aplicación 7zip para Windows que es capaz de separar el envoltorio del contenido (con la de Linux no funciona).


El PDF se encuentra en el archivo CONTENTS dentro de la carpeta "Tenant Object", como se puede observar, en este caso el envoltorio ocupa mucho más que el propio PDF. En algunos casos, puede llamarse "[1]Ole10Native", en ese caso hay que modificar el script que descomprime con 7zip.

IMPORTANTE: El código que voy a poner a continuación, debes usarlo bajo tú responsabilidad y después de haber hecho una copia de seguridad de los datos que vas a procesar, no me hago responsable de ninguna pérdida de datos por la utilización de este código.

Vamos a ver como extraer los archivos de un campo BLOB a un directorio de Oracle. Vamos a crear un directorio llamado BLOB_TEMP (en el propio servidor de base de datos) y lo mapeamos a una ruta:

CREATE DIRECTORY BLOB_TEMP as 'c:\temp\pdfs';
GRANT READ, WRITE ON DIRECTORY BLOB_TEMP TO USUARIO;

Exportamos a ese directorio el contenido del campo BLOB de la tabla

DECLARE
  CURSOR cur_pdfs IS
     SELECT i. archivo campo_blob, i.rowid || '.pdf.7z' nombre_archivo
       FROM tabla i
      WHERE DBMS_LOB.GETLENGTH(i.archivo) > 0
        AND DBMS_LOB.INSTR(i.archivo, HEXTORAW('25504446')) > 0;

  blob_length     INTEGER;
  out_file        UTL_FILE.file_type;
  v_buffer        RAW(32767);
  chunk_size      PLS_INTEGER;
  blob_position   PLS_INTEGER;
BEGIN
  FOR reg IN cur_pdfs LOOP
    blob_position := 1;
    chunk_size := 32767;
    blob_length := DBMS_LOB.getlength(reg.campo_blob);
    out_file := UTL_FILE.fopen('BLOB_TEMP', reg.nombre_archivo, 'wb', chunk_size);

    WHILE blob_position <= blob_length LOOP
      IF blob_position + chunk_size - 1 > blob_length THEN
        chunk_size := blob_length - blob_position + 1;
      END IF;

      DBMS_LOB.READ(reg.campo_blob, chunk_size, blob_position, v_buffer);
      UTL_FILE.put_raw(out_file, v_buffer, TRUE);
      blob_position := blob_position + chunk_size;
    END LOOP;

    UTL_FILE.fclose(out_file);
  END LOOP;
END;
/

Una vez tenemos los archivos, extraemos el contenido con un script, por ejemplo, le llamamos extraepdf.cmd con el siguiente contenido.

for %%f in (*.7z) do (
"C:\Program Files\7-Zip\7z.exe" e "%%f" "Tenant Object\CONTENTS"
rename CONTENTS %%f.pdf
del %%f
)?

Luego, los volvemos a cargar, sobreescribiendo el archivo en el mismo campo de la tabla.

DECLARE
  CURSOR cur_pdfs IS
     SELECT i.rowid, i.rowid || '.pdf.7z.pdf' nombre_archivo, i.archivo
       FROM tabla i
      WHERE DBMS_LOB.GETLENGTH(i.archivo) > 0
        AND DBMS_LOB.INSTR(i.archivo, HEXTORAW('25504446')) > 0;

  l_bfile       BFILE;
  v_resultado   VARCHAR2(30) := 'OK';
  v_archivo     BLOB;
BEGIN
  FOR reg IN cur_pdfs LOOP
    l_bfile := BFILENAME('BLOB_TEMP', reg.nombre_archivo);

    IF DBMS_LOB.fileexists(l_bfile) = 1 AND NVL(DBMS_LOB.getlength(l_bfile), 0) != 0 THEN
      DBMS_LOB.createtemporary(v_archivo, TRUE);
      DBMS_LOB.fileopen(l_bfile, DBMS_LOB.file_readonly);
      DBMS_LOB.loadfromfile(v_archivo, l_bfile, DBMS_LOB.getlength(l_bfile));
      DBMS_LOB.fileclose(l_bfile);
      
      UPDATE tabla i
         SET archivo = v_archivo
       WHERE rowid = reg.rowid;
       
      COMMIT;
      UTL_FILE.fremove('BLOB_TEMP', reg.nombre_archivo);
    END IF;
  END LOOP;
END;
/

domingo, 8 de febrero de 2015

Reports Builder 11g en Windows 64 bits

Por lo general, al intentar arranca Reports Builder en un Windows de 64 bits nos dará el siguiente error: "REP-50125: rwbuilder.conf:java.lang.NullPointerException"



Vamos a ver como solucionarlo suponiendo que el directorio base de Oracle es C:\Oracle (si fuese otro las rutas cambian).

Editar el archivo: C:\Oracle\Middleware\asinst_1\config\reports\bin\reports.bat

Borrar la línea: set TNS_ADMIN=%ORACLE_INSTANCE%\config

Editar el archivo: C:\Oracle\Middleware\Oracle_FRHome1\bin\rwbuilder.bat

Cambiar: $$Instance.directory$$ por: C:\Oracle\Middleware\asinst_1
Cambiar: $$Instance.oracle_home$$ por: C:\Oracle\Middleware\Oracle_FRHome1

Para arrancar el Report Builder ejecutaremos un archivo de comandos con código similar al siguiente: ReportsBuilderF11g.cmd. (Las rutas pueden variar según donde estén las plls o instalado Oracle):

SET CLASSPATH=C:\Oracle\Middleware\Oracle_FRHome1\forms\j2ee\frmsrv.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\ldapjclnt11.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\debugger.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\ewt3.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\share.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\utj.jar;C:\Oracle\Middleware\Oracle_FRHome1\jlib\zrclient.jar;C:\Oracle\Middleware\Oracle_FRHome1\reports\jlib\rwrun.jar;C:\Oracle\Middleware\Oracle_FRHome1\forms\java\frmwebutil.jar;C:\Oracle\Middleware\Oracle_FRHome1/jlib/start_dejvm.jar;C:\Oracle\Middleware\Oracle_FRHome1\opmn\lib\optic.jar
SET PATH=C:\Oracle\Middleware\Oracle_FRHome1\bin;C:\Oracle\Middleware\Oracle_FRHome1\jdk\jre\bin\client;C:\Oracle\Middleware\Oracle_FRHome1\jdk\bin
SET REPORTS_PATH=Z:\plls
SET NLS_DATE_FORMAT=DD/MM/YYYY
SET NLS_NUMERIC_CHARACTERS=,.
SET UI_ICON=Z:\iconos
SET NLS_SORT=BINARY
SET TNS_ADMIN=C:\Oracle
SET NLS_LANG=SPANISH_SPAIN.UTF8
start rwbuilder.bat USERID=USUARIO/PASSWORD@CADENA_CONEXION