30/8/10

Generar un PDF en APEX a través de BI publisher

Este procedimiento, encontrado en el foro de APEX, permite generar un PDF de un report layout de APEX a través de una llamada interna al BI publisher.
En este caso nos lo almacena en la tabla pdf_to_mail.

1. Código completo
PROCEDURE getReportPDF
    (pservidor in varchar2,
    p_id_envio in number,
    pReportName IN VARCHAR2,
    p_filename in varchar2
    )
IS
  vReportURL       VARCHAR2(255);
  vBlobRef         BLOB;
  vRequest         Utl_Http.req;
  vResponse        Utl_Http.resp;
  vData            RAW(32767);
  l_fname          varchar2(200) := 'fact_' || p_filename ||'.pdf';
  l_des            varchar2(200) := 'Factura imprimida a dia ' || to_char(sysdate, 'dd/mm/yyyy');
  l_dominio        VARCHAR2(100);
  vCookieNameList  Owa_Cookie.vc_arr;
  vCookieValueList Owa_Cookie.vc_arr;
  vCookieCount     INTEGER;
  vCookieList      Utl_Http.cookie_table;
BEGIN
l_dominio := '192.168.100.174';
  ------------------------------------------------------------------
  -- Construimos la URL para llamar al report
  ------------------------------------------------------------------
  vReportURL := pservidor || '/f?p='|| -- has to be changed
                Apex_Application.g_flow_id    ||':0:'||
                Apex_Application.g_instance   ||':'  ||
                'PRINT_REPORT='||pReportName;
  ------------------------------------------------------------------
  -- Recogemos la referencia del BLOB
  ------------------------------------------------------------------

  INSERT INTO pdf_to_mail
    (id_envio, pdf, descript, mimetype, filename, last_update_date
    )
  VALUES
    (p_id_envio, Empty_Blob(), l_des,'application/pdf', l_fname, sysdate
    )
  RETURNING PDF INTO vBlobRef;
  ------------------------------------------------------------------
  -- Almacenamos todas las cookies de la solicitacion(request)
  -- original del APEX y las enviamos con nuestra
  -- solicitud(request) HTTP. La cookie de sesion es
  -- la importante ya que sin esa cookie APEX no nos dejaría
  -- pasar al identificador de sesión.
  ------------------------------------------------------------------  
  Owa_Cookie.get_all
    ( names    => vCookieNameList
    , vals     => vCookieValueList
    , num_vals => vCookieCount
    );
  FOR ii IN 1 .. vCookieNameList.COUNT
  LOOP
      vCookieList(ii).name   := vCookieNameList(ii);
      vCookieList(ii).value  := vCookieValueList(ii);
      vCookieList(ii).domain := l_dominio;
      vCookieList(ii).path   := '/';
  END LOOP;
  Utl_Http.add_cookies(vCookieList);
  ------------------------------------------------------------------
  -- Recogemos el fichero PDF del APEX simulando una
  -- llamada al informe desde el navegador
  -------------------------------------------------------------------  
  vRequest := Utl_Http.begin_request(vReportUrl);
  Utl_Http.set_header(vRequest, 'User-Agent', 'Mozilla/4.0');
  vResponse := Utl_Http.get_response(vRequest);
  LOOP
      BEGIN
          -----------------------------------------------------------
          -- leemos la siguiente porcion de datos binarios
          -----------------------------------------------------------
          Utl_Http.read_raw(vResponse, vData);
          -----------------------------------------------------------
          -- y la añadimos a nuestro BLOB para el fichero PDF
          -----------------------------------------------------------
          Dbms_Lob.writeAppend
            ( lob_loc => vBlobRef
            , amount  => Utl_Raw.length(vData)
            , buffer  => vData
            );
      EXCEPTION WHEN Utl_Http.END_OF_BODY THEN
          EXIT; -- exit loop
      END;
  END LOOP;
  Utl_Http.end_response(vResponse);
  null;
end getReportPDF;

2. Análisis de código
2.1 Parámetros
PROCEDURE getReportPDF
    (pservidor in varchar2,
    p_id_envio in number,
    pReportName IN VARCHAR2,
    p_filename in varchar2
    )
IS
...
pservidor: será la dirección del servidor donde se encuentre el BI publisher.
p_id_envio: se le pasa un número para si fuera necesario el caso identificar el envío.
pReportName: nombre del report layout en el APEX.
p_filename: el nombre que tendrá el archivo generado.
2.2 Variables
...
  vReportURL       VARCHAR2(255);
  vBlobRef         BLOB;
  vRequest         Utl_Http.req;
  vResponse        Utl_Http.resp;
  vData            RAW(32767);
  l_fname          varchar2(200) := 'fact_' || p_filename ||'.pdf';
  l_des            varchar2(200) := 'Factura imprimida a dia ' || to_char(sysdate, 'dd/mm/yyyy');
  l_dominio        VARCHAR2(100);
  vCookieNameList  Owa_Cookie.vc_arr;
  vCookieValueList Owa_Cookie.vc_arr;
  vCookieCount     INTEGER;
  vCookieList      Utl_Http.cookie_table;
...
vReportURL: dirección del servidor para ejecutar el report.
vBlobRef: BLOB donde se almacenará el PDF creado.
vRequest: se almacena la solicitación al lanzar el PDF.
vResponse: esta es la respuesta, o sea, de aquí sacaremos el PDF.
vData: será una variable de transición que irá leyendo porciones del PDF para añadirlas al BLOB;
l_fname: nombre del fichero
l_des: descripción del fichero.
l_dominio: la dirección del dominio donde se encuentra el APEX.
2.3 Variables para las cookies
Estas son necesarias para almacenar las cookies originales de la sesion de APEX ya que sin ellas APEX no podrá identificar la sesion. En concreto son:
vCookieNameList.
vCookieValueList.
vCookieCount.
vCookieList.
2.4 Cuerpo
Pasamos a realizar un pequeño análisis del cuerpo. De aquello que no está en los comentarios de la función
Se construye la URL para llamar al report
  vReportURL := pservidor || '/f?p='||
                Apex_Application.g_flow_id    ||':0:'||
                Apex_Application.g_instance   ||':'  ||
                'PRINT_REPORT='||pReportName;
Se obtiene la referencia al BLOB
Se realiza un INSERT en la tabla destino del BLOB y nos devuelve la referencia al mismo.
  INSERT INTO pdf_to_mail
    (id_envio, pdf, descript, mimetype, filename, last_update_date
    )
  VALUES
    (p_id_envio, Empty_Blob(), l_des,'application/pdf', l_fname, sysdate
    )
  RETURNING PDF INTO vBlobRef;
2.5 Se obtiene el pdf
Como se aprecia se simula una llamada desde el navegador para generar el PDF. Para escribir en el BLOB se utiliza el paquete DBMS_LOB que nos permite manejar los BLOB y los CLOB. También es interesante echar un vistazo al paquete UTL_RAW ya que ambos están muy relacionados.
  vRequest := Utl_Http.begin_request(vReportUrl);
  Utl_Http.set_header(vRequest, 'User-Agent', 'Mozilla/4.0');
  vResponse := Utl_Http.get_response(vRequest);
  LOOP
      BEGIN
          -----------------------------------------------------------
          -- leemos la siguiente porcion de datos binarios
          -----------------------------------------------------------
          Utl_Http.read_raw(vResponse, vData);
          -----------------------------------------------------------
          -- y la añadimos a nuestro BLOB para el fichero PDF
          -----------------------------------------------------------
          Dbms_Lob.writeAppend
            ( lob_loc => vBlobRef
            , amount  => Utl_Raw.length(vData)
            , buffer  => vData
            );
      EXCEPTION WHEN Utl_Http.END_OF_BODY THEN
          EXIT; -- exit loop
      END;
  END LOOP;
  Utl_Http.end_response(vResponse);
  null;
end getReportPDF;

3. Fuente
Hilo específico

No hay comentarios:

Publicar un comentario