diff --git a/.gitignore b/.gitignore
index 0703909..f660ab7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,3 +64,4 @@ pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
ObjectStore
+/integration-tests/nbproject/
diff --git a/integration-tests/src/main/jasperreports/ImagesReport.jrxml b/integration-tests/src/main/jasperreports/ImagesReport.jrxml
new file mode 100644
index 0000000..9f7a4bb
--- /dev/null
+++ b/integration-tests/src/main/jasperreports/ImagesReport.jrxml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/AbstractJasperResource.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/AbstractJasperResource.java
index 4ee52f2..1a9f83b 100644
--- a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/AbstractJasperResource.java
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/AbstractJasperResource.java
@@ -1,26 +1,35 @@
package io.quarkiverse.jasperreports.it;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import jakarta.inject.Inject;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.ReportContext;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.export.oasis.JROdsExporter;
import net.sf.jasperreports.engine.export.oasis.JROdtExporter;
+import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleHtmlExporterOutput;
import net.sf.jasperreports.export.SimpleOdsReportConfiguration;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
+import net.sf.jasperreports.export.SimpleXlsxReportConfiguration;
import net.sf.jasperreports.export.SimpleXmlExporterOutput;
import net.sf.jasperreports.pdf.JRPdfExporter;
public abstract class AbstractJasperResource {
+ @Inject
+ Application app;
+
protected ByteArrayOutputStream exportCsv(JasperPrint jasperPrint) throws JRException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
JRCsvExporter exporter = new JRCsvExporter();
@@ -45,12 +54,18 @@ protected ByteArrayOutputStream exportXml(JasperPrint jasperPrint, boolean embed
return outputStream;
}
- protected ByteArrayOutputStream exportHtml(JasperPrint jasperPrint) throws JRException {
+ protected ByteArrayOutputStream exportHtml(JasperPrint jasperPrint, ReportContext reportContext)
+ throws JRException, IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
HtmlExporter exporter = new HtmlExporter(DefaultJasperReportsContext.getInstance());
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
- exporter.setExporterOutput(new SimpleHtmlExporterOutput(outputStream));
+
+ SimpleHtmlExporterOutput htmlExporter = new SimpleHtmlExporterOutput(outputStream);
+ htmlExporter.setImageHandler(app.getImageHandler());
+
+ exporter.setExporterOutput(htmlExporter);
+ exporter.setReportContext(reportContext);
exporter.exportReport();
return outputStream;
@@ -104,4 +119,20 @@ protected ByteArrayOutputStream exportPdf(JasperPrint jasperPrint) throws JRExce
return outputStream;
}
-}
\ No newline at end of file
+ protected ByteArrayOutputStream exportXlsx(JasperPrint jasperPrint) throws JRException {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+ JRXlsxExporter exporter = new JRXlsxExporter();
+
+ exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
+ exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
+
+ SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
+ configuration.setOnePagePerSheet(true);
+ exporter.setConfiguration(configuration);
+
+ exporter.exportReport();
+ return outputStream;
+ }
+
+}
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/Application.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/Application.java
new file mode 100644
index 0000000..f7290d1
--- /dev/null
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/Application.java
@@ -0,0 +1,54 @@
+package io.quarkiverse.jasperreports.it;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.event.Observes;
+
+import org.jboss.logging.Logger;
+
+import io.quarkus.runtime.ShutdownEvent;
+import io.quarkus.runtime.StartupEvent;
+import net.sf.jasperreports.engine.export.FileHtmlResourceHandler;
+
+@ApplicationScoped
+public class Application {
+
+ private static final Logger LOG = Logger.getLogger(Application.class);
+
+ private FileHtmlResourceHandler imageHandler;
+
+ private Path tempFolder;
+
+ void onStart(@Observes StartupEvent evt) throws IOException {
+ tempFolder = Files.createTempDirectory("jasperreports");
+ imageHandler = new FileHtmlResourceHandler(tempFolder.toFile(), "/images/{0}");
+ }
+
+ void onStop(@Observes ShutdownEvent evt) throws IOException {
+ if (null != tempFolder) {
+ Files.walk(tempFolder).forEach((p) -> {
+ try {
+ Files.delete(p);
+ } catch (IOException ex) {
+ LOG.warn(ex.getMessage());
+ }
+ });
+
+ if (Files.exists(tempFolder)) {
+ Files.delete(tempFolder);
+ }
+ }
+ }
+
+ public FileHtmlResourceHandler getImageHandler() {
+ return imageHandler;
+ }
+
+ public Path getTempFolder() {
+ return tempFolder;
+ }
+
+}
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/ImageResource.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/ImageResource.java
new file mode 100644
index 0000000..11a1d1f
--- /dev/null
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/ImageResource.java
@@ -0,0 +1,44 @@
+package io.quarkiverse.jasperreports.it;
+
+import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+
+import jakarta.enterprise.context.RequestScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.core.Response;
+
+import org.jboss.logging.Logger;
+
+@Path("images")
+@RequestScoped
+public class ImageResource {
+
+ private static final Logger LOG = Logger.getLogger(ImageResource.class);
+
+ @Inject
+ Application app;
+
+ @GET
+ @Path("{fileName}")
+ public Response get(@PathParam("fileName") final String fileName) throws IOException {
+ final var path = java.nio.file.Path.of(app.getTempFolder().toString(), fileName);
+
+ if (Files.exists(path) && Files.isRegularFile(path) && Files.isReadable(path)) {
+ final String contentType = Files.probeContentType(path);
+
+ LOG.debugf("Loading file %s of type %s", path.toString(), contentType);
+
+ try (final InputStream is = Files.newInputStream(path)) {
+ return Response.ok(is.readAllBytes(), contentType).build();
+ }
+ }
+
+ return Response.status(NOT_FOUND).build();
+ }
+}
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsImageResource.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsImageResource.java
new file mode 100644
index 0000000..ae39dfd
--- /dev/null
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsImageResource.java
@@ -0,0 +1,117 @@
+package io.quarkiverse.jasperreports.it;
+
+import static io.quarkiverse.jasperreports.it.ExtendedMediaType.APPLICATION_PDF;
+import static io.quarkiverse.jasperreports.it.ExtendedMediaType.APPLICATION_XLSX;
+import static jakarta.ws.rs.core.MediaType.TEXT_HTML;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.core.Context;
+import jakarta.ws.rs.core.HttpHeaders;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.UriInfo;
+
+import org.eclipse.microprofile.openapi.annotations.media.Content;
+import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
+
+import io.quarkiverse.jasperreports.repository.ReadOnlyStreamingService;
+import io.quarkus.logging.Log;
+import net.sf.jasperreports.engine.JREmptyDataSource;
+import net.sf.jasperreports.engine.JRException;
+import net.sf.jasperreports.engine.JRParameter;
+import net.sf.jasperreports.engine.JasperFillManager;
+import net.sf.jasperreports.engine.JasperPrint;
+import net.sf.jasperreports.engine.SimpleReportContext;
+
+@Path("jasper/image")
+@ApplicationScoped
+public class JasperReportsImageResource extends AbstractJasperResource {
+
+ private static final String TEST_REPORT_NAME = "ImagesReport.jasper";
+
+ @Context
+ UriInfo uriInfo;
+
+ @Inject
+ ReadOnlyStreamingService repo;
+
+ @APIResponse(responseCode = "200", description = "Fetch an HTML report with images", content = @Content(mediaType = TEXT_HTML))
+ @GET
+ @Path("html")
+ public Response getHtml() throws JRException, IOException {
+ final SimpleReportContext reportContext = new SimpleReportContext();
+ final Map params = new HashMap<>();
+ params.put(JRParameter.REPORT_LOCALE, Locale.US);
+ params.put(JRParameter.REPORT_CONTEXT, reportContext);
+ params.put("QUARKUS_URL", uriInfo.getBaseUri().toString());
+
+ final long start = System.currentTimeMillis();
+ final JasperPrint jasperPrint = JasperFillManager.getInstance(repo.getContext()).fillFromRepo(TEST_REPORT_NAME, params,
+ new JREmptyDataSource());
+
+ final Response.ResponseBuilder response = Response.ok();
+ ByteArrayOutputStream outputStream = exportHtml(jasperPrint, reportContext);
+ Log.infof("HTML creation time : %s", (System.currentTimeMillis() - start));
+ response.entity(outputStream.toByteArray());
+ response.type(TEXT_HTML);
+
+ return response.build();
+ }
+
+ @APIResponse(responseCode = "200", description = "Fetch a PDF report with images", content = @Content(mediaType = APPLICATION_PDF))
+ @GET
+ @Path("pdf")
+ public Response getPdf() throws JRException {
+ final SimpleReportContext reportContext = new SimpleReportContext();
+ final Map params = new HashMap<>();
+ params.put(JRParameter.REPORT_LOCALE, Locale.US);
+ params.put(JRParameter.REPORT_CONTEXT, reportContext);
+ params.put("QUARKUS_URL", uriInfo.getBaseUri().toString());
+
+ final long start = System.currentTimeMillis();
+ final JasperPrint jasperPrint = JasperFillManager.getInstance(repo.getContext()).fillFromRepo(TEST_REPORT_NAME, params,
+ new JREmptyDataSource());
+
+ final Response.ResponseBuilder response = Response.ok();
+ ByteArrayOutputStream outputStream = exportPdf(jasperPrint);
+ Log.infof("PDF creation time : %s", (System.currentTimeMillis() - start));
+ response.entity(outputStream.toByteArray());
+ response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=jasper.pdf");
+ response.type(APPLICATION_PDF);
+
+ return response.build();
+ }
+
+ @APIResponse(responseCode = "200", description = "Fetch an XLSX report with images", content = @Content(mediaType = APPLICATION_XLSX))
+ @GET
+ @Path("xlsx")
+ public Response getXlsx() throws JRException {
+ final SimpleReportContext reportContext = new SimpleReportContext();
+ final Map params = new HashMap<>();
+ params.put(JRParameter.REPORT_LOCALE, Locale.US);
+ params.put(JRParameter.REPORT_CONTEXT, reportContext);
+ params.put("QUARKUS_URL", uriInfo.getBaseUri().toString());
+
+ final long start = System.currentTimeMillis();
+ final JasperPrint jasperPrint = JasperFillManager.getInstance(repo.getContext()).fillFromRepo(TEST_REPORT_NAME, params,
+ new JREmptyDataSource());
+
+ final Response.ResponseBuilder response = Response.ok();
+ ByteArrayOutputStream outputStream = exportXlsx(jasperPrint);
+ Log.infof("XLSX creation time : %s", (System.currentTimeMillis() - start));
+ response.entity(outputStream.toByteArray());
+ response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=jasper.xlsx");
+ response.type(APPLICATION_XLSX);
+
+ return response.build();
+ }
+
+}
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsStyleResource.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsStyleResource.java
index c24fff1..6686810 100644
--- a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsStyleResource.java
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsStyleResource.java
@@ -24,6 +24,7 @@
import static jakarta.ws.rs.core.MediaType.WILDCARD;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -82,8 +83,9 @@ public class JasperReportsStyleResource extends AbstractJasperResource {
})
@GET
public Response get(@Context HttpHeaders headers,
- @DefaultValue("false") @QueryParam("embedded") boolean embedded) throws JRException {
+ @DefaultValue("false") @QueryParam("embedded") boolean embedded) throws JRException, IOException {
+ final SimpleReportContext reportContext = new SimpleReportContext();
final Map params = new HashMap<>();
Document document = JRXmlUtils.parse(JRLoader.getLocationInputStream("data/northwind.xml"));
params.put(JRXPathQueryExecuterFactory.PARAMETER_XML_DATA_DOCUMENT, document);
@@ -91,7 +93,7 @@ public Response get(@Context HttpHeaders headers,
params.put(JRXPathQueryExecuterFactory.XML_NUMBER_PATTERN, "#,##0.##");
params.put(JRXPathQueryExecuterFactory.XML_LOCALE, Locale.ENGLISH);
params.put(JRParameter.REPORT_LOCALE, Locale.US);
- params.put(JRParameter.REPORT_CONTEXT, new SimpleReportContext());
+ params.put(JRParameter.REPORT_CONTEXT, reportContext);
final long start = System.currentTimeMillis();
final JasperPrint jasperPrint = JasperFillManager.getInstance(repo.getContext()).fillFromRepo(TEST_REPORT_NAME, params);
@@ -114,7 +116,7 @@ public Response get(@Context HttpHeaders headers,
response.type(MediaType.APPLICATION_XML);
}
case TEXT_HTML -> {
- ByteArrayOutputStream outputStream = exportHtml(jasperPrint);
+ ByteArrayOutputStream outputStream = exportHtml(jasperPrint, reportContext);
Log.infof("HTML creation time : %s", (System.currentTimeMillis() - start));
response.entity(outputStream.toByteArray());
response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=jasper.html");
diff --git a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsXmlResource.java b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsXmlResource.java
index 8011e73..b6d59a1 100644
--- a/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsXmlResource.java
+++ b/integration-tests/src/main/java/io/quarkiverse/jasperreports/it/JasperReportsXmlResource.java
@@ -17,6 +17,7 @@
package io.quarkiverse.jasperreports.it;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@@ -48,14 +49,12 @@
import net.sf.jasperreports.engine.SimpleReportContext;
import net.sf.jasperreports.engine.export.ooxml.JRDocxExporter;
import net.sf.jasperreports.engine.export.ooxml.JRPptxExporter;
-import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.query.JRXPathQueryExecuterFactory;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.engine.util.JRXmlUtils;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleXlsReportConfiguration;
-import net.sf.jasperreports.export.SimpleXlsxReportConfiguration;
import net.sf.jasperreports.pdf.JRPdfExporter;
import net.sf.jasperreports.poi.export.JRXlsExporter;
@@ -69,6 +68,8 @@ public class JasperReportsXmlResource extends AbstractJasperResource {
@Inject
ReadOnlyStreamingService repo;
+ final SimpleReportContext reportContext = new SimpleReportContext();
+
private JasperPrint fill() throws JRException {
long start = System.currentTimeMillis();
@@ -79,7 +80,7 @@ private JasperPrint fill() throws JRException {
params.put(JRXPathQueryExecuterFactory.XML_NUMBER_PATTERN, "#,##0.##");
params.put(JRXPathQueryExecuterFactory.XML_LOCALE, Locale.ENGLISH);
params.put(JRParameter.REPORT_LOCALE, Locale.US);
- params.put(JRParameter.REPORT_CONTEXT, new SimpleReportContext());
+ params.put(JRParameter.REPORT_CONTEXT, reportContext);
JasperPrint jasperPrint = JasperFillManager.getInstance(repo.getContext()).fillFromRepo(TEST_REPORT_NAME, params);
@@ -119,10 +120,10 @@ public Response xml(@QueryParam("embedded") boolean embedded) throws JRException
@GET
@Path("html")
@APIResponse(responseCode = "200", description = "Document downloaded", content = @Content(mediaType = MediaType.APPLICATION_OCTET_STREAM, schema = @Schema(type = SchemaType.STRING, format = "binary")))
- public Response html() throws JRException {
+ public Response html() throws JRException, IOException {
long start = System.currentTimeMillis();
JasperPrint jasperPrint = fill();
- ByteArrayOutputStream outputStream = exportHtml(jasperPrint);
+ ByteArrayOutputStream outputStream = exportHtml(jasperPrint, reportContext);
Log.infof("HTML creation time : %s", (System.currentTimeMillis() - start));
final Response.ResponseBuilder response = Response.ok(outputStream.toByteArray());
response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=jasper.html");
@@ -200,22 +201,11 @@ public Response docx() throws JRException {
public Response xlsx() throws JRException {
long start = System.currentTimeMillis();
JasperPrint jasperPrint = fill();
-
- JRXlsxExporter exporter = new JRXlsxExporter();
-
- exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(outputStream));
- SimpleXlsxReportConfiguration configuration = new SimpleXlsxReportConfiguration();
- configuration.setOnePagePerSheet(true);
- exporter.setConfiguration(configuration);
-
- exporter.exportReport();
-
+ ByteArrayOutputStream outputStream = exportXlsx(jasperPrint);
Log.infof("XLSX creation time : %s", (System.currentTimeMillis() - start));
final Response.ResponseBuilder response = Response.ok(outputStream.toByteArray());
response.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=jasper.xlsx");
- response.header(HttpHeaders.CONTENT_TYPE, ExtendedMediaType.APPLICATION_XLSX);
+ response.type(ExtendedMediaType.APPLICATION_XLSX);
return response.build();
}
diff --git a/integration-tests/src/main/resources/META-INF/resources/jasperreports.gif b/integration-tests/src/main/resources/META-INF/resources/jasperreports.gif
new file mode 100644
index 0000000..f7b16fb
Binary files /dev/null and b/integration-tests/src/main/resources/META-INF/resources/jasperreports.gif differ
diff --git a/integration-tests/src/main/resources/images/jasperreports.svg b/integration-tests/src/main/resources/images/jasperreports.svg
new file mode 100644
index 0000000..8fe60c5
--- /dev/null
+++ b/integration-tests/src/main/resources/images/jasperreports.svg
@@ -0,0 +1,22 @@
+
+
+
\ No newline at end of file
diff --git a/integration-tests/src/test/java/io/quarkiverse/jasperreports/it/JasperReportsImageResourceTest.java b/integration-tests/src/test/java/io/quarkiverse/jasperreports/it/JasperReportsImageResourceTest.java
new file mode 100644
index 0000000..a06a8a0
--- /dev/null
+++ b/integration-tests/src/test/java/io/quarkiverse/jasperreports/it/JasperReportsImageResourceTest.java
@@ -0,0 +1,62 @@
+package io.quarkiverse.jasperreports.it;
+
+import static io.quarkiverse.jasperreports.it.ExtendedMediaType.APPLICATION_PDF;
+import static io.quarkiverse.jasperreports.it.ExtendedMediaType.APPLICATION_XLSX;
+import static io.restassured.RestAssured.given;
+import static jakarta.ws.rs.core.HttpHeaders.CONTENT_LENGTH;
+import static jakarta.ws.rs.core.MediaType.TEXT_HTML;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.emptyString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+public class JasperReportsImageResourceTest {
+
+ @Test
+ public void testExportHTML() {
+ given()
+ .when().get("/jasper/image/html")
+ .then()
+ .assertThat()
+ .statusCode(200)
+ .contentType(equalTo(TEXT_HTML))
+ .header(CONTENT_LENGTH, Integer::parseInt, greaterThan(0))
+ .body(notNullValue())
+ .and()
+ .body(not(emptyString()))
+ .and()
+ .body(not(containsString("