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.