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).
Start by creating a file at src/main/java/org/acme/Sample.java and adding the following to it:
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;
}
}
Next, create a mock service whose
get()
method returns a random list of samples.Create a file at
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}
]
}
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.
Creating the Periodic Reports
The last step is to write the necessary Java code to generate the reports. Create a new file at
The last step is to write the necessary Java code to generate the reports. Create a new file at
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.
To trigger report to start generating (by triggering Quarkus Live Reload), access the following endpoint:Warning: If you are running this example on Windows, be sure to change theFileWriter
in theonStart
method to use an appropriate directory.
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.
You should see new reports every second. When done, press
CTRL+C
to stop the tail.