AbstractRechnungCache.ktAn in-memory performance cache layer on top of the AbstractCache framework. Invoice calculations (net/gross totals, VAT breakdown, cost assignments) are expensive because they require traversing the entire position tree with cost allocation lookups. This cache stores pre-computed RechnungInfo and RechnungPosInfo objects keyed by entity ID, with automatic refresh via the CacheHelper scheduling mechanism. The cache was refactored from synchronized blocks to ConcurrentHashMap to eliminate a deadlock.
abstract class AbstractRechnungCache(
val entityClass: KClass<out AbstractRechnungDO>,
protected val rechnungJdbcService: RechnungJdbcService,
) : AbstractCache()
| Parameter | Description |
|---|---|
entityClass | The Kotlin class reference for the invoice entity type (RechnungDO::class or EingangsrechnungDO::class) — used for JDBC queries and logging |
rechnungJdbcService | JDBC service for efficient bulk-loading of invoice info from the database (bypasses Hibernate for performance) |
| Field | Type | Description |
|---|---|---|
invoiceInfoMap | ConcurrentHashMap<Long, RechnungInfo> | Primary cache: invoice ID → aggregated invoice calculations |
invoicePosInfoMap | ConcurrentHashMap<Long, RechnungPosInfo> | Secondary cache: position ID → position-level calculations |
Both maps use ConcurrentHashMap (not synchronized blocks) — this change was made in commit 85d8930b3 to fix a deadlock that occurred when cache operations interacted with each other under synchronization.
update(invoice: AbstractRechnungDO)Forces recalculation of a single invoice and stores the result in the cache. Called when an invoice is modified (inserted, updated, or deleted through the DAO layer). Uses RechnungCalculator.calculate(invoice) to compute fresh values.
ensureRechnungInfo(rechnung: AbstractRechnungDO): RechnungInfoGuarantees a RechnungInfo exists for the given invoice. If already cached, returns the cached version (and sets rechnung.info). Otherwise calculates it via RechnungCalculator, stores in the cache, and returns. This is the preferred accessor — it works even if the position tree hasn't been lazy-loaded yet.
getRechnungInfo(rechnungId: Long?): RechnungInfo?Returns cached invoice info by ID (null-safe for the ID parameter). Calls checkRefresh() which ensures the cache is not stale.
getRechnungInfo(rechnung: AbstractRechnungDO?): RechnungInfo?Overload that extracts the ID from the entity. Null-safe.
ensureRechnungPosInfo(pos: AbstractRechnungsPositionDO): RechnungPosInfoAnalogous to ensureRechnungInfo but for individual positions. Ensures the parent invoice's RechnungInfo exists first (needed as context), then calculates position-specific info via RechnungCalculator.calculate(posInfo, pos).
getRechnungPosInfo(rechnungPosId: Long?): RechnungPosInfo?Returns cached position info by ID. Null-safe.
override fun refresh())Called automatically by the CacheHelper framework on a timer and during the checkRefresh() guard. The refresh strategy uses copy-and-swap for thread safety:
ConcurrentHashMap instances (nInvoiceInfoMap, nInvoicePosInfoMap)rechnungJdbcService.selectRechnungInfos(entityClass) — this uses JDBC directly for performance, bypassing HibernateThis approach means the cache is never stale for longer than one refresh cycle, and reads never block on the refresh operation.
RechnungCache (for RechnungDO) and EingangsrechnungCache (for EingangsrechnungDO), each providing only the entityClass parameterkotlin.reflect.KClass instead of Java's Class for type safety@Transient lateinit var info on AbstractRechnungDO is the companion field that this cache populatesLogDuration utility tracks refresh performance in the logs868d6abb7 2025 -> 2026 85d8930b3 AbstractRechnungCache: Deadlock removed by replacing sync blocks through ConcurrentHashMaps 63081666f Source file headers: 2024-> 2025. 2d324f2bb Finance: incoming invoices fixed. 12610fee2 Migration stuff in progress... (all tests of all packages: OK). ff2cc4cfa Migration stuff in progress... (all tests of all packages: OK). 190c0aea1 Migration stuff in progress... (all tests of all packages: OK). 2e9839891 Migration stuff in progress... ba2479571 Migration stuff in progress... b3293f0cc PersistenceService/Context: stats handling improved. b47c21af6 Refactored caching and calculations with invoices (not yet finished) ccb7ca64d Migration stuff in progress... 41b5c2645 Migration stuff in progress... 87dd5b87c AuftragsCache refactored, migration stuff... (all tests OK) 9408b59d7 Migration stuff in progress... 85b4e1175 PfPersistenceService and PfPersistenceContext: query renamed to executeQuery. 4c04cfd65 MAJOR-CHANGE! Migration of integer id's to Long id's (including fk's etc.) 2863b30b9 Migration stuff in progress... 067a4cbb1 Migration stuff in progress... 9d8b94352 Migration stuff in progress... 67ce75fe9 Migration stuff in progress... e33c8b9c2 Migration stuff in progress...