Integración de Oracle Application Framework con XML Publisher

Introducción

Oracle Application Framework (OAF) permite generar reportes PDF mediante la integración con XML Publisher. Este proceso puede implementarse de dos formas principales: utilizando objetos de vista (VO) o mediante procedimientos PL/SQL. A continuación se presentan ambas alternativas con ejemplos prácticos de implementación.

Método de integración usando View Objects

Generación de datos en el Application Module

El primer paso consiste en crear un método dentro del módulo de aplicación que genere la estructura XML a partir de los datos del View Object. El siguiente ejemplo muestra cómo implementar esta funcionalidad:

import oracle.jbo.XMLInterface;
import oracle.xml.parser.v2.XMLNode;

public XMLNode obtenerDocumentoXML(String identificador)
{
  ReporteDataVOImpl vistaDatos = getReporteDataVO1();
  vistaDatos.executeQuery();
  XMLNode nodoXML = ((XMLNode) vistaDatos.writeXML(4, XMLInterface.XML_OPT_ALL_ROWS));
  return nodoXML;
}

Procesamiento en el Controller

Una vez obtenidos los datos XML, el controller debe procesar la conversión a formato PDF. El método siguiente configura los encabezados HTTP necesarios y utiliza TemplateHelper para realizar la transformación:

public void generarReportePDF(OAPageContext contextoPagina, OAWebBean componenteWeb, 
                              XMLNode documentoXML, String identificador)
{
  HttpServletResponse respuesta = (HttpServletResponse) 
    contextoPagina.getRenderingContext().getServletResponse();
  
  String tipoCambio = contextoPagina.getParameter("TipoCambio");
  
  String dispositionContenido = "attachment;filename=Reporte" + identificador + ".pdf";
  respuesta.setHeader("Content-Disposition", dispositionContenido);
  respuesta.setContentType("application/pdf");
  
  try
  {
    ByteArrayOutputStream flujoSalida = new ByteArrayOutputStream();
    documentoXML.print(flujoSalida);
    
    ByteArrayInputStream flujoEntrada = new ByteArrayInputStream(flujoSalida.toByteArray());
    
    OADBTransactionImpl transaccion = (OADBTransactionImpl) 
      contextoPagina.getApplicationModule(componenteWeb).getOADBTransaction();
    
    String nombrePlantilla = "RPT_PLANTILLA_REPORTE";
    
    TemplateHelper.processTemplate(
      transaccion.getAppsContext(), 
      "APLICACION", 
      nombrePlantilla, 
      "es", 
      "MX", 
      flujoEntrada,
      TemplateHelper.OUTPUT_TYPE_PDF, 
      null, 
      respuesta.getOutputStream()
    );
    
    respuesta.getOutputStream().flush();
    respuesta.getOutputStream().close();
  }
  catch (Exception excepcion)
  {
    respuesta.setContentType("text/html");
    throw new OAException(excepcion.getMessage(), OAException.ERROR);
  }
  
  contextoPagina.setDocumentRendered(false);
}

Manejo de eventos de formulario

El evento de formulario debe invocar los métodos creados para generar el reporte:

public void processFormRequest(OAPageContext contextoPagina, OAWebBean componenteWeb)
{
  String nombreEvento = contextoPagina.getParameter(EVENT_PARAM);
  
  if("imprimir".equals(nombreEvento))
  {
    String identificador = contextoPagina.getParameter("Identificador");
    Serializable[] parametros = { identificador };
    
    XMLNode documentoXML = (XMLNode) am.invokeMethod("obtenerDocumentoXML", parametros);
    generarReportePDF(contextoPagina, componenteWeb, documentoXML, identificador);
  }
}

Método de integración usando PL/SQL

Procedimiento de generación de XML

Este método resulta útil cuando la lógica de negocio reside en la base de datos. El procedimiento PL/SQL construye un CLOB con la estructura XML requerida:

PROCEDURE generar_xml_pedido(
  p_id_pedido        IN NUMBER,
  x_resultado_xml    OUT CLOB
) IS
BEGIN
  dbms_lob.createtemporary(x_resultado_xml, TRUE);
  
  l_cadena_temp := '<?xml version="1.0" encoding="UTF-8"??>' || chr(10) || 
                   '<datos_pedido>' || chr(10);
  
  dbms_lob.writeappend(
    lob_loc => x_resultado_xml,
    amount  => length(l_cadena_temp),
    buffer  => l_cadena_temp
  );
  
  l_cadena_temp := l_cadena_temp || '<productos>' || r_datos.productos || 
                   '</productos>' || chr(10);
  l_cadena_temp := l_cadena_temp || '</datos_pedido>';
  
  dbms_lob.writeappend(
    lob_loc => x_resultado_xml,
    amount  => length(l_cadena_temp),
    buffer  => l_cadena_temp
  );
END generar_xml_pedido;

Nota importante: Es fundamnetal liberar los objetos LOB temporales después de su uso para evitar problemas de rendimiento en el tablespace temporal. El código siguiente muestra la forma correcta de gestionar estos recursos:

vn_xml_clob              CLOB;
vs_cadena_xml            CLOB;

vs_cadena_xml := '<lista_productos></lista_productos>';

dbms_lob.createtemporary(vn_xml_clob, TRUE);
dbms_lob.append(vn_xml_clob, vs_cadena_xml);

os_xml := vn_xml_clob;
dbms_lob.freetemporary(vn_xml_clob);

Invocación desde el Application Module

El módulo de aplicación debe ejecutar el procedimiento PL/SQL y recuperar el CLOB generado:

public CLOB obtenerXMLPedido(String identificadorPedido)
{
  Number numeroPedido = null;
  CLOB documentoTemporal = null;
  
  OADBTransaction transaccionDB = getOADBTransaction();
  OracleCallableStatement declaracion = null;
  
  try
  {
    numeroPedido = new Number(identificadorPedido);
    
    String sqlConsulta = "BEGIN pkg_reportes.generar_xml_pedido(" +
                         "p_id_pedido=> :1, x_resultado_xml=>:2); END;";
    
    declaracion = (OracleCallableStatement) transaccionDB.createCallableStatement(sqlConsulta, 1);
    declaracion.setNUMBER(1, numeroPedido);
    declaracion.registerOutParameter(2, Types.CLOB);
    declaracion.execute();
    
    documentoTemporal = declaracion.getCLOB(2);
    declaracion.close();
  }
  catch (Exception error)
  {
    throw OAException.wrapperException(error);
  }
  
  return documentoTemporal;
}

Generación del PDF desde el Controller

El controller procesa el CLOB recibido y lo convierte a PDF utilizando la plantilla correspondiente:

public void generarDocumentoPDF(OAPageContext contextoPagina, OAWebBean componenteWeb, 
                                CLOB documentoXML)
{
  HttpServletResponse respuesta = (HttpServletResponse) 
    contextoPagina.getRenderingContext().getServletResponse();
  
  String dispositionContenido = "attachment;filename=SolicitudPago.pdf";
  respuesta.setHeader("Content-Disposition", dispositionContenido);
  respuesta.setContentType("application/pdf");
  
  try
  {
    Reader lectorEntrada = documentoXML.getCharacterStream();
    
    OADBTransactionImpl transaccion = (OADBTransactionImpl) 
      contextoPagina.getApplicationModule(componenteWeb).getOADBTransaction();
    
    String nombrePlantilla = "RPT_SOLICITUD_PAGO";
    
    TemplateHelper.processTemplate(
      transaccion.getAppsContext(), 
      "APLICACION", 
      nombrePlantilla, 
      "es", 
      "MX", 
      lectorEntrada,
      TemplateHelper.OUTPUT_TYPE_PDF, 
      null, 
      respuesta.getOutputStream()
    );
    
    respuesta.getOutputStream().flush();
    respuesta.getOutputStream().close();
  }
  catch (Exception excepcion)
  {
    respuesta.setContentType("text/html");
    throw new OAException(excepcion.getMessage(), OAException.ERROR);
  }
  
  contextoPagina.setDocumentRendered(false);
}

Configuración del evento de impresión

String nombreEvento = contextoPagina.getParameter(EVENT_PARAM);

if("imprimir".equals(nombreEvento))
{
  String identificadorPago = contextoPagina.getParameter("IdSolicitudPago");
  Serializable[] parametros = { identificadorPago };
  
  CLOB documentoTemporal = (CLOB) am.invokeMethod("obtenerXMLPedido", parametros);
  generarDocumentoPDF(contextoPagina, componenteWeb, documentoTemporal);
}

Consideraciones de implementación

La elección entre ambos métodos depende de los requisitos específicos del proyecto. El enfoque con View Objects resulta más sencillo cuando los datos ya están disponibles en la capa de aplicación, mientras que el método PL/SQL es preferible cuando la lógica de generación de datos reside en la base de datos o cuando se requiere mayor control sobre la estructura XML construida.

Es importante liberar los recursos temporales LOB después de su uso para prevenir problemas de memoria y crecimiento excesivo del tablespace temporal. Además, se debe configurar correctamente el nombre de la plantilla y los parámetros de idioma y territorio según la instalación de XML Publisher disponible.

Etiquetas: oracle-application-framework oaf xml-publisher pl-sql oracle-applications

Publicado el 9-7 16:58