En este artículo vamos a hablar sobre cómo insertar dinámicamente una imagen después de consumir una API REST desde BIRT.
Índice de contenidos
1. Introducción
La motivación de este tutorial surgió al intentar encontrar una manera de mejorar las gráficas de ofrece por defecto BIRT. BIRT es una herramienta similar a Jasper Report de código abierto promovida por Eclipse.
Las principales ventajas de BIRT son:
- Admite diferentes datasource y tipo de datos para generar informes.
- Permite diferentes formatos de salida usando un mismo informe como plantilla (PDF, PPTX, DOCX, etc).
- Tiene una gran integración con Java.
Las principales desventajas de BIRT son:
- La falta de documentación en la web sobre él y la que hay es muy antigua o está desactualizada.
- El look & feel de las gráficas que se propone desde el asistente por defecto de la herramienta tiene un diseño algo antiguo. En este tutorial vamos a dar una alternativa para mejorar en algo esta última desventaja.
2. Entorno
El tutorial está escrito usando el siguiente entorno:
- Hardware: Portátil Apple M1 Pro 16′ (M1, 32 GB).
- Sistema Operativo: Mac OS Sonoma 14.4.1
- BIRT report-designer-all-in-one 4.15.0-202403270652 macosx.cocoa.x86_64.tar.gz.sha512
3. Preparando el entorno
Para ejecutar la última versión de BIRT desde un M1 debemos seguir los siguientes pasos:
- Nos descargamos la última versión de la página oficial.
- Para ejecutar BIRT desde un M1 hay que ejecutar el siguiente comando:
<pre class="lang:xml"> $> sudo xattr -rd com.apple.quarantine ./eclipse.app
<pre class="lang:xml"> $> open ./eclipse.app
Este comando sirve para sacar de la cuarentena de Apple el ejecutable. Es el equivalente a permitir la ejecución de un desarrollador no identificado o de la Apple Store.
NOTA: Si no crees que lo has descargado de la fuente oficial o tienes dudas sobre la seguridad, no lo ejecutes pero solo he sido capaz de abrir BIRT después de ejecutarlo. Si no me salia el siguiente mensaje al ejecutar el open:
3.1. Una API REST Mock que consumir
En un ejemplo real utilizaremos una API REST que dado un identificador y tipo de gráfico nos devuelva la imagen de la gráfica generado con Chart Js por ejemplo. Pero para probar la inserción dinámica de imágenes en BIRT con vale con una API Mockedada como las que ofrece la página https://dummyjson.com, la qual nos devuelve un JSON como este:
<pre class="lang:xml"> {
"id": 1,
"title": "iPhone 9",
"description": "An apple mobile which is nothing like apple",
"price": 549,
"discountPercentage": 12.96,
"rating": 4.69,
"stock": 94,
"brand": "Apple",
"category": "smartphones",
"thumbnail": "https://cdn.dummyjson.com/product-images/1/thumbnail.jpg",
"images": [
"https://cdn.dummyjson.com/product-images/1/1.jpg",
"https://cdn.dummyjson.com/product-images/1/2.jpg",
"https://cdn.dummyjson.com/product-images/1/3.jpg",
"https://cdn.dummyjson.com/product-images/1/4.jpg",
"https://cdn.dummyjson.com/product-images/1/thumbnail.jpg"
]
}
Para el ejemplo consumiremos los campos id, title y la primera de imágenes.
3.2. Explorando BIRT
Como primer elemento que vemos en BIRT tenemos el menú «Data Explorer» que nos da una visión por paquetes de las diferentes partes referente a Datos que podemos usar para generar el informe (Data Source, Data Set, Variables, etc).
Nosotros nos centraremos en estos componentes para nuestro ejemplo. Para empezar a construirlo añadiremos:
- En el layout hay un componente de tipo imagen.
- En el paquete DataSource un nuevo datasource script.
- En las variables declarar
- HTMLJSON (variable de tipo informe). En esta variable se almacenará la respuesta al API Rest moqueada en formato Json.
- recNum (variable de tipo informe y con valor 0). En esta variable almacenaremos los elementos recorridos (o leídos) por el datasource.
- len (variable de tipo informe y con valor 1). En esta variable almacenaremos el número de registros totales que tiene la respuesta. Como no es un array y solo es un elemento, lo fijamos directamente en 1.
- En el layout, tenemos que insertar un elemento de tipo Image. Si navegamos por los diferentes elementos del «Data Explorer» como el DataSource Script podemos ver tres partes importantes:
- Selector Script: Selector en los que puedes introducir lógica en forma de script para ese elemento.
- Pestaña Script: Parte donde aparece el editor donde introducir el script.
- Pestaña Layout: Parte donde vuelves a ver cómo están dispuestos cada componente de nuestro informe.
Para consumir el api desde el data source en la pestaña Script y el selector open con el siguiente código:
<pre class="lang:xml">// Lectura de la respuesta al api rest
importPackage(Packages.java.io);
importPackage(Packages.java.net);
var inStream = new URL("https://dummyjson.com/products/1").openStream();
var inStreamReader = new InputStreamReader(inStream);
var bufferedReader = new BufferedReader(inStreamReader);
var line;
var result = "";
while ((line = bufferedReader.readLine()) != null)
result += line;
inStream.close();
// Convertimos la respuesta a JSON
var json = JSON.parse(result);
// Almacenamos el JSON en la variable HTMLJSON
vars["HTMLJSON"] = json;
Para leer la respuesta y poder usarla dentro del componente Image, tenemos que incluir un nuevo dataset con los siguientes campos:
Aunque en el ejemplo solo utilizaremos los campos imageUrl y imageLogo para el ejemplo de imagen dinámica, se podría inserta tanto el campo id como title en el report.
Para recorrer la respuesta y almacenarla en el dataset, tenemos que introducir el siguiente código en la pestaña de script en el selector fetch.
<pre class="lang:xml">importPackage(Packages.java.io);
importPackage(Packages.java.lang);
importPackage(Packages.java.net);
// Incluir dependencia en la carpeta plugins
importPackage(Packages.javax.imageio);
// Condición de parada para dejar de recorrer el dataset
if (vars["recNum"] >= vars["len"])
return false;
// Lectura de las variables de tipo String
row["id"] = vars["HTMLJSON"].id;
row["title"] = vars["HTMLJSON"].title;
row["imageUrl"] = vars["HTMLJSON"].images[0];
// Convertir imageUrl en un tipo Blod capaz de renderizar
var myUrl = new Packages.java.net.URL(row["imageUrl"]);
var img = ImageIO.read(myUrl)
var bas = new ByteArrayOutputStream();
ImageIO.write(img, "jpg", bas);
row["imageLogo"] = bas.toByteArray();
NOTA: Habría que incluir el jar commons-io-2.16.1.jar de esta página e incluirlo en la siguiente ruta para que pueda ser importada desde el script.
<pre class="lang:xml"> $> open /Users/ddelcastillo/Desktop/eclipse.app/Contents/Eclipse/plugins
Para poder hacer una prueba integrada de que el data source lee la api y el dataset es capaz de procesar la respuesta deberíamos ver esto en al Edit > Preview Results. Se debería ver algo parecido a esto:
NOTA: En ejemplo vemos como el código sólo carga un registro, ya que la respuesta del mock no es un array y solo tiene un producto, pero se podría cargar el dataset con más registros.
3.3. Generando documentos
Después de comprobar que somos capaces de consumir el API REST y cargar el dataset, podemos insertar la fila del dataset que contiene la imagen como Blob de la siguiente manera:
Si vamos a la pestaña del layout, podemos un aspa roja como que la imagen no se ha cargado. Esto es porque la imagen se renderiza en el momento de generar el documento y no en la preview.
Con todo listo, si vamos al menú Run > View Report > In web Viewer (o cualquier otro documento PPTX, PDF, etc). Y vemos como la imagen consumida desde la API se carga correctamente:
También podemos exportar a diferentes documentos desde el visor web.
4. Conclusiones
Este tutorial se originó para intentar actualizar las gráficas en los informes de un cliente. Y aunque esperamos opciones más modernas como ChartJS con PPTXGen, el cliente perdía la posibilidad de insertar imágenes en tablas. Ya que el nuevo stack propuesto para generar informes no lo permitía.
Por eso, decidimos explorar la posibilidad de integrar una API REST a su sistema de generación de informes para que el cliente no perdiera ninguna funcionalidad de los informes actuales sin dejar de actualizar el stack usando cualquier tecnología más actual para generar gráficas. A veces es mejor trabajar en una integración mejorando un poco la solución que ya tenemos a empezar con una tecnología diferente desde cero.
Os dejo el proyecto de ejemplo de tutorial por si os es útil.
5. Referencias
- Como consumir una API REST desde BIRT : .
- Plugin Da Vinci Chart para BIRT: