EvaluationPdfService.java

package com.tdmconsult.ete.evaluation;

import com.tdmconsult.ete.configuration.MyConfigurationProperties;
import com.tdmconsult.ete.masterdata.Security;
import com.tdmconsult.ete.utils.PdfUtils;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver;

@Service
@RequiredArgsConstructor
@Transactional
@Slf4j
public class EvaluationPdfService {

    private final EvaluationService evaluationService;
    private final MyConfigurationProperties myConfigurationProperties;

    public InputStream getAsPdfStream(final Security security, final int fiscalYear) throws IOException {

        final var position = evaluationService.getEvaluationState(security, fiscalYear);

        final var bookTemplate = "book-single-position.html";
        final var context = new Context(Locale.GERMAN, Map.of(
                "fiscalYear", fiscalYear,
                "position", position,
                "creationDate", LocalDate.now()));

        final var resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("book/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML");
        resolver.setCharacterEncoding("UTF-8");

        // 2. Template Engine initialisieren
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(resolver);
        templateEngine.addDialect(new LayoutDialect());

        final var timing = StopWatch.createStarted();

        log.info("PDF generation before engine after {}", timing.formatTime());
        final var html = templateEngine.process(bookTemplate, context)
                .replace("<h5>", "<h5 data-pdf-bookmark=\"none\">");
        log.info("PDF generation after engine after {}", timing.formatTime());

        try (final var plainOutputStream = renderPlainHtmlToPdf(html, myConfigurationProperties)) {

            final var outputStream = plainOutputStream;
            // more manipulations may come her, e.g. martermarking...

            log.info("PDF generation done in {}", timing.formatTime());
            return outputStream.toInputStream();
        }
    }

    public InputStream getAsPdfStream(final int fiscalYear) throws IOException {

        final var positions = evaluationService.getEvaluationStates(fiscalYear)
                .stream().filter(EvaluationStateDto::isRequiresEoyProcessing)
                .sorted(Comparator.comparing(a -> Objects.requireNonNull(a.getSecurity()).name()))
                .toList();

        final var bookTemplate = "book-multi-positions.html";
        final var context = new Context(Locale.GERMAN, Map.of(
                "fiscalYear", fiscalYear,
                "positions", positions,
                "creationDate", LocalDate.now()));

        final var resolver = new ClassLoaderTemplateResolver();
        resolver.setPrefix("book/templates/");
        resolver.setSuffix(".html");
        resolver.setTemplateMode("HTML");
        resolver.setCharacterEncoding("UTF-8");

        // 2. Template Engine initialisieren
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(resolver);
        templateEngine.addDialect(new LayoutDialect());

        final var timing = StopWatch.createStarted();

        log.info("PDF generation before engine after {}", timing.formatTime());
        final var html = templateEngine.process(bookTemplate, context)
                .replace("<h5>", "<h5 data-pdf-bookmark=\"none\">");
        log.info("PDF generation after engine after {}", timing.formatTime());

        try (final var plainOutputStream = renderPlainHtmlToPdf(html, myConfigurationProperties)) {

            final var outputStream = plainOutputStream;
            // more manipulations may come her, e.g. martermarking...

            log.info("PDF generation done in {}", timing.formatTime());
            return outputStream.toInputStream();
        }
    }

    private static ByteArrayOutputStream renderPlainHtmlToPdf(
            final String html,
            final MyConfigurationProperties myConfigurationProperties) throws IOException {

        final var output = new ByteArrayOutputStream();
        PdfUtils.renderToOutputStream(html, myConfigurationProperties.getPdf(), output);
        return output;
    }
}