Rendering Periodic Reports
The Qute templating engine can also be very useful when rendering periodic reports. This example uses the quarkus-scheduler
extension, which was added during project creation.
Creating Samples
The first step is to create an object that represents a point-in-time value (for example, ambient temperature or blood pressure of a patient).
package org.acme.qute;
public class Sample {
public boolean valid;
public String name;
public String data;
public Sample(boolean valid, String name, String data) {
this.valid = valid;
this.name = name;
this.data = data;
}
}
get()
method returns a random list of samples.src/main/java/org/acme/SampleService.java
with the following code:
package org.acme;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class SampleService {
private static final String[] names = {"James", "Deepak", "Daniel", "Shaaf", "Jeff", "Sally"};
public List<Sample> get() {
int count = new Random().nextInt(10);
List<Sample> result = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
boolean valid = false;
if (Math.random() > 0.5) {
valid = true;
}
result.add(new Sample(valid, names[(int)(Math.random() * names.length)], Math.random() + ""));
}
return result;
}
}
Creating the Template
The next step is to create the report templates. Start by creating the directory to hold them (from the project root):
mkdir -p src/main/resources/templates/reports/v1
Inside that directory, create a file named `report_01.json.template` with the following contents:
{
"time": "{now}",
"samples": [
{#for sample in samples}
\{"name": "{sample.name ?: 'Unknown'}","data": "{#if sample.valid}{sample.data}{#else}--Invalid--{/if}"}{#if count < samples.size },{/if}
{/for}
]
}
Here we are looping over the passed-in samples. You can iterate over
Iterable
, Map
, and Stream
objects. Since we are rendering JSON, we also need to escape the first of any pair of JSON-related }
or {
using \}
or \{
.
Also, note the use of the elvis operator {sample.name ?: 'Unknown'}
; if the name is null
the default value Unknown
is used.
src/main/java/org/acme/ReportGenerator.java
with the body:
package org.acme;
import java.io.FileWriter;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import io.quarkus.qute.Template;
import io.quarkus.qute.api.ResourcePath;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.scheduler.Scheduled;
@ApplicationScoped
public class ReportGenerator {
@Inject
SampleService service;
private FileWriter fout = null;
@ResourcePath("reports/v1/report_01.json.template")
Template report;
@Scheduled(cron="* * * ? * *")
void generate() throws Exception {
String result = report
.data("samples", service.get())
.data("now", java.time.LocalDateTime.now())
.render();
System.out.println("report: " + result);
if (fout != null) {
fout.write(result + "\n");
fout.flush();
}
}
void onStart(@Observes StartupEvent ev) throws Exception {
fout = new FileWriter("/tmp/report.json", true);
}
void onShutdown(@Observes ShutdownEvent ev) throws Exception {
fout.close();
fout = null;
}
}
A few notes about the implementation:
- In this case, the
@ResourcePath
qualifier is usedto specify the template pathtemplates/reports/v1/report_01.json
. - Use the
@Scheduled
annotation to instruct Quarkus to execute this method every second. For more information see the Scheduler guide. - The
TemplateInstance.render()
method triggers rendering. Note that this method blocks the current thread. - Quarkus'
StartupEvent
andShutdownEvent
manage the File I/O on startup and shutdown. Reports will be written to the/tmp
directory.
Warning: If you are running this example on Windows, be sure to change theFileWriter
in theonStart
method to use an appropriate directory.
To trigger report to start generating (by triggering Quarkus Live Reload), access the following endpoint:
curl http://localhost:8080/hello?name=Jason
Assuming no errors, the reports should generate every second. Tail the file:
tail -f /tmp/report.json
Warning: If you changed the default report location, be sure to use that file in the tail.
CTRL+C
to stop the tail.