com.xlrit.gears.plugin.jasper.JasperDocumentProcessor Maven / Gradle / Ivy
package com.xlrit.gears.plugin.jasper;
import java.io.*;
import java.nio.file.Files;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.xlrit.gears.engine.meta.PrintOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xlrit.gears.base.content.ContentRef;
import com.xlrit.gears.base.model.Document;
import com.xlrit.gears.base.content.ContentStore;
import com.xlrit.gears.engine.document.DocumentProcessor;
import com.xlrit.gears.engine.meta.MetaManager;
import lombok.RequiredArgsConstructor;
import net.sf.jasperreports.engine.*;
@Component
@Order(200)
@RequiredArgsConstructor
public class JasperDocumentProcessor implements DocumentProcessor {
private static final Logger LOG = LoggerFactory.getLogger(JasperDocumentProcessor.class);
private final JasperProperties properties;
private final MetaManager metaManager;
private final ContentStore contentStore;
private final ObjectMapper objectMapper;
private final JasperExportManager exportManager = JasperExportManager.getInstance(DefaultJasperReportsContext.getInstance());
@Override
public boolean supports(Document doc) {
return "pdf".equals(doc.getType())
&& doc.getTemplate() != null
&& doc.getTemplate().endsWith(".jrxml");
}
@Override
public ContentRef process(Document doc) {
if (properties.isDebug()) {
properties.getDir().mkdirs();
writeParametersAsJson(doc);
writeExampleTemplate(doc);
}
try {
JasperReport report = getReportTemplate(doc.getTemplate());
JRDataSource dataSource = createDataSource(doc.getParameters());
Map params = new HashMap<>();
JasperPrint print = JasperFillManager.fillReport(report, params, dataSource);
byte[] data = exportReport(print, doc.getType());
if (properties.isDebug()) {
writeToFile(doc, data);
}
return contentStore.putContent(doc.getFilename(), getContentType(doc.getType()), data);
}
catch (JRException e) {
throw new RuntimeException("Unable to create report document", e);
}
}
private String getContentType(String documentType) {
return switch (documentType) {
case "pdf" -> "application/pdf";
case "xml" -> "application/xml";
default -> throw new RuntimeException("Unsupported document type: " + documentType);
};
}
private byte[] exportReport(JasperPrint print, String type) throws JRException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
exportReport(print, type, os);
os.flush();
return os.toByteArray();
}
catch (IOException e) {
throw new RuntimeException("Unable to export to byte array output stream", e);
}
}
private void exportReport(JasperPrint print, String type, OutputStream outputStream) throws JRException {
switch (type) {
case "pdf" -> exportManager.exportToPdfStream(print, outputStream);
case "xml" -> exportManager.exportToXmlStream(print, outputStream);
default -> throw new RuntimeException("Unsupported document type: " + type);
}
}
private JasperReport getReportTemplate(String resourceName) {
Resource template = new ClassPathResource(resourceName);
try (InputStream is = template.getInputStream()) {
return JasperCompileManager.compileReport(is);
}
catch (IOException | JRException e) {
throw new RuntimeException("Unable to load report template '" + resourceName + "'", e);
}
}
private JRDataSource createDataSource(Object parameters) {
return switch (properties.getDatasource()) {
case DEFAULT -> createDefaultDataSource(parameters);
case JSON -> createJsonDataSource(parameters);
default -> throw new UnsupportedOperationException("Unknown datasource mode: " + properties.getDatasource());
};
}
private CustomCollectionDataSource createDefaultDataSource(Object parameters) {
Collection> collection =
parameters instanceof Collection
? (Collection>) parameters
: Collections.singletonList(parameters);
return new CustomCollectionDataSource(metaManager, collection);
}
private CustomJsonQLDataSource createJsonDataSource(Object parameters) {
try {
JsonNode json = toJson(parameters);
return new CustomJsonQLDataSource(json, null);
}
catch (JRException e) {
throw new RuntimeException(e);
}
}
private void writeParametersAsJson(Document doc) {
try {
JsonNode json = toJson(doc.getParameters());
File file = new File(properties.getDir(), doc.getFilename() + ".json");
LOG.info("Writing document parameters as JSON to {}", file);
objectMapper.writeValue(file, json);
}
catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private void writeExampleTemplate(Document doc) {
ExampleTemplateWriter exampleTemplateWriter = new ExampleTemplateWriter(metaManager);
exampleTemplateWriter.processParameters(doc.getParameters());
exampleTemplateWriter.print();
}
private void writeToFile(Document doc, byte[] data) {
try {
File file = new File(properties.getDir(), doc.getFilename());
LOG.info("Writing result to {}", file.getAbsolutePath());
Files.write(file.toPath(), data);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
private JsonNode toJson(Object params) {
return metaManager.requireTypeInfo(params).serialize(params, objectMapper, PrintOptions.NONE);
}
}