Caso de uso: Backend Jasper
En el caso del servidor de reportes de Jasper, hay varias cosas que cambiaron respecto del uso del servlet, la principal de ellas es que todo recurso se almacena en el servidor de reportes y se accede desde alli. Entiendase por recurso, todo archivo necesario para generar el reporte, incluido su propio fuente y los datos.
Otro punto que cambio, es que no se entregan reportes pre-compilados al servidor sino que se entrega siempre su fuente y se compilan dentro del mismo cuando se crea el reporte propiamente dicho, sin ese paso el archivo jrxml es un archivo mas.
Volviendo al tema de los datos, debido a que los mismos deben estar almacenados en el servidor de reportes para ser accedidos, es necesario que seamos eficientes en su uso. Hay que evitar incorporar datos superfluos que no agregan información y sirven solo a meros aspectos cosmeticos e intentar que la cantidad de filas sean las necesarias siempre que se pueda, quizas podamos obtener 200Mb en una consulta pero sin dudas no podemos realizar un POST de ese tamaño sin mayores problemas.
Para mayor informacion de como trabaja internamente el servidor Jasper y sus capacidades leer aqui
Accediendo a los recursos
El repositorio de Jasper internamente esta organizado como un filesystem, con lo cual existe una raiz y un conjunto de subcarpetas. En particular, desde Arai-Reportes hemos decidido que cada proyecto tenga su subcarpeta dentro de la cual tiene dominio y contiene sus reportes.
Por ejemplo para el proyecto Pilaga, su carpeta raiz (la cual podemos obtener via el recurso carpetas) se encontraria en /reportes/pilaga.
Este tipo de organizacion, tambien implica que los recursos se identifican y acceden de manera similar a un filesystem, por ello notaran que los recursos devuelven un uri, el cual tiene el formato de un path que comienza con la carpeta base del proyecto.
Este último punto es sumamente importante, debido a que condiciona de manera absoluta la forma en la cual se deben acceder los recursos dentro de Jasper,
si los mismos se ubican e identifican mediante el uri toda referencia que contengan los reportes a dicho recurso debera ser absoluta a dicho identificador.
Supongamos por ejemplo que necesitamos incorporar una imagen en el reporte la cual se encuentra en un uriImg, la forma de referenciar a dicha imagen dentro del repositorio para incorporarla en el reporte seria la siguiente:
<image>
<imageExpression>
<![CDATA["repo:uriImg"]]>
</imageExpression>
</image>
De la misma forma, cada vez que necesitemos hacer una referencia a algun objeto del repositorio la misma debera comenzar con repo: seguido del uri absoluto del objeto.
Por ejemplo:
<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="cabecera" language="groovy" pageWidth="483" pageHeight="752" whenNoDataType="AllSectionsNoDetail" columnWidth="483" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0" uuid="b4e2b3d6-c0bc-45ed-a4d9-13664b405c46">
<property name="ireport.zoom" value="1.0"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="0"/>
<template><![CDATA["repo:/reportes/Imhotep/estilos/ImhotepStyles.jrtx"]]></template>
<queryString language="xPath">
<![CDATA[/actos_esotericos_impios/acto_esoterico]]>
</queryString>
<field name="id_acto_esoterico" class="java.lang.Integer">
<fieldDescription><![CDATA[@id_acto_esoterico]]></fieldDescription>
</field>
<field name="nombre" class="java.lang.String">
<fieldDescription><![CDATA[@nombre]]></fieldDescription>
</field>
<field name="descripcion_hechizo" class="java.lang.String">
<fieldDescription><![CDATA[@descripcion_hechizo]]></fieldDescription>
</field>
<field name="ID_CABECERA_XSL" class="java.lang.Integer">
<fieldDescription><![CDATA[/actos_esotericos_impios/acto_esoterico/@ID_CABECERA_XSL]]></fieldDescription>
</field>
<background>
<band splitType="Stretch"/>
</background>
<detail>
<band height="51">
<printWhenExpression><![CDATA[$F{ID_CABECERA_XSL}==$F{id_acto_esoterico}]]></printWhenExpression>
<textField>
<reportElement uuid="590b37ef-d876-4556-acc2-0be6f47d7c94" style="reporte_titulo" x="0" y="0" width="483" height="37"/>
<textElement/>
<textFieldExpression><![CDATA[$F{nombre}]]></textFieldExpression>
</textField>
</band>
<band height="91">
<printWhenExpression><![CDATA[$F{ID_CABECERA_XSL}==$F{id_acto_esoterico}]]></printWhenExpression>
<textField isStretchWithOverflow="true">
<reportElement uuid="fe3bac58-d5ac-4e3a-b1ad-119062a033f3" stretchType="RelativeToTallestObject" x="0" y="11" width="483" height="65" isPrintWhenDetailOverflows="true"/>
<textElement markup="html"/>
<textFieldExpression><![CDATA[$F{descripcion_hechizo}]]></textFieldExpression>
</textField>
</band>
</detail>
</jasperReport>
Notese como en esta linea estamos referenciando una hoja de estilos que subimos al servidor de reportes
<template><![CDATA["repo:/reportes/Imhotep/estilos/ImhotepStyles.jrtx"]]></template>
Creando el Reporte
Si bien un reporte Jasper internamente es un archivo jrxml, subir dicho archivo como tal no nos generara un reporte ejecutable. Para ello, es necesario un paso extra que "compila" el fuente entregado, chequea las referencias y publica el recurso que utilizaremos.
La publicacion de dicho recurso genera un uri para el mismo el cual deberemos utilizar al momento de solicitar la ejecucion del reporte, por lo tanto es sumamente recomendable por no decir imperativo.. guardar dicho uri en el sistema de forma de poder mapear la ejecucion de la operacion al reporte correspondiente.
Dicho paso se puede llevar a cabo al momento de instalacion o actualizacion del sistema, es importante en este caso que no sobreescribir o modificar recursos innecesariamente, ya que cada modificacion implica un versionado del mismo y luego es necesario especificar el nro de version en la referencia que se hace.
Para este caso se brinda en el proyecto SIU-Instalador una serie de pasos de forma que se pueda realizar la instalacion y/o actualizacion manteniendo el versionado.
Assets
Podemos llamar asset a todo recurso extra que necesite un reporte y no sea parte de su fuente o de los datos, los mismos deberian en la medida de lo posible estar almacenados en el servidor, sobre todo si deben ser consumidos al momento de la ejecucion del reporte.
Para incorporarlos al servidor de reportes, utilizaremos principalmente las invocaciones a las operaciones de archivos, donde especificaremos no solo su contenido, sino tambien su formato para que el servidor pueda llevar adelante algun tratamiento particular si asi lo requiere.
Una vez esten almacenados, podremos incorporarlos al reporte o subreporte con referencias de la forma en que mencionamos anteriormente.
Subreportes
Los subreportes son una herramienta bastante comun en el armado, lo que deberiamos tener en cuenta en este caso particular es la forma de ubicar los reportes, si bien la organizacion interna es similar a un filesystem, no posee las operaciones del mismo.. por lo que ../../autorizaciones no se va a resolver a un uri adecuado.
Lo que si podemos utilizar es parte del uri del reporte actual como punto de partida, si los subreportes a utilizar se encuentran almacenados de forma relativa a la carpeta donde se encuentra el reporte.
<parameter name="SUBREPORT_DIR" class="java.lang.String" isForPrompting="false">
<defaultValueExpression><![CDATA["repo:/reportes/diaguita/acto_adjudicacion/actos_administrativos/"]]></defaultValueExpression>
</parameter>
.
.
.
.
<subreport>
<subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "clausulas_particulares"]]></subreportExpression>
</subreport>
En ese caso podriamos indicar el parametro SUBREPORT_DIR durante la ejecucion del reporte como repo:/reportes/diaguita/acto_adjudicacion/ si el archivo estuviera localizado dentro de esa carpeta.
