PdfRenderer.javaPdfRenderer is a Spring @Service with a single public method render(String stylesheet, String groovyXml, Map<String, Object> data). The rendering pipeline proceeds in four stages:
Before any transformation, the data map is enriched with standard template variables:
createdLabel — localized "created" stringloggedInUser — the current PFUserDObaseDir — resource directory path from ConfigurationServicelogoFile — full path to the configured logo imageappId / appVersion — from ProjectForgeVersion constantsorganization — from Configuration (falling back to appId)Apache FOP is configured with:
FopFactory instantiated with the font resource directory URIFOUserAgent for user-agent-level settingsFop object targeting MIME_PDF output to a ByteArrayOutputStreamsetFontBaseURL() which was removedThe XML template (groovyXml) goes through two Groovy Engine passes:
preprocessGroovyXml() — preprocesses the templateexecuteTemplate() — executes the Groovy template with the data map to produce final XMLConfigurationService.getResourceAsInputStream()Transformer is created with parameters from the data mapStreamSource inputSAXResult through FOP's default handler, producing PDF bytesExceptions are caught and wrapped:
| Exception | Handling |
|---|---|
FOPException | Logged and wrapped in RuntimeException |
TransformerException | Logged and wrapped in RuntimeException |
IOException (closing BAOS) | Logged and wrapped in RuntimeException |
The finally block closes the ByteArrayOutputStream and uses IOUtils.closeQuietly() for the XSLT input stream. After closing, baos.toByteArray() is called — note this works because ByteArrayOutputStream.close() is a no-op.
@Service — auto-detected Spring bean@Autowired — ConfigurationService injected@Value("${projectforge.export.logoFile}") — logo file name from application propertiesfontResourcePath via getFontResourcePath()FopFactory, Fop, FOUserAgent, FOPExceptionTransformerFactory, Transformer, StreamSource, SAXResultConfigurationService, GroovyEngine, Configuration, ProjectForgeVersion, ThreadLocalUserContextIOUtils.closeQuietly()StringUtils.defaultString()868d6abb7 2026-01-01 2025 -> 2026 63081666f 2025-01-01 Source file headers: 2024-> 2025. 5f9bbfbd3 2024-12-27 Fix typos in projectforge-business directory 67805f2fc 2024-10-08 ThreadLocalUserContext.user -> ThreadLocalUserContext.loggedInUser (renamed for avoiding mis-understandings in code). b6092df09 2024-01-09 Copyright 2023 -> 2024 ab45d51fa 2023-01-01 Copyright 2001-2022 -> 2001-2023. 5f7ef41b8 2022-02-18 Copyright 2021 -> 2022 867476f85 2021-04-19 ConfigurationService -> Kotlin (not yet tested). ceb63e8a1 2021-03-08 Source code header: (C) 2001-2021. 4f5a06d6f 2020-05-01 AppVersion removed. Git information added to ProjectForgeVersion. 7c79f1922 2020-01-03 Copyright of source header -> 2020. 73a9755df 2019-10-11 More code cleanup ... 000ca723d 2019-10-07 Remove pointless boolean expressions (business) 7e3232e60 2019-08-17 New versions of fop and batik. Jar hell of logging frameworks... dd5ca38ac 2019-06-07 CopyRight of all java file-header updated or created. a5bbdca6a 2017-12-04 Change logger to slf4j f979e8a42 2017-11-20 MGC-UPDATE: Update auf Version 3.0.0-SNAPSHOT 9ebb88522 2016-07-18 Initial commit