#920: EmployeeCache.kt

projectforge-business/src/main/kotlin/org/projectforge/business/fibu/EmployeeCache.kt Type: Spring Component / Cache · Purpose: In-memory cache of all employees with computed time-dependent attributes · Path: projectforge-business/src/main/kotlin/org/projectforge/business/fibu/EmployeeCache.kt 209 lines · 143 code · 43 comments · 23 blank
High-performance cache that maintains a snapshot of all non-deleted employees along with their current status, annualLeave, and weeklyWorkingHours — computed from EmployeeValidSinceAttrDO entries. Extends AbstractCache which provides the refresh/expiry infrastructure. Exposed as a @Component singleton accessible via EmployeeCache.instance.

Architecture & Design

Cache Storage

The internal employeeMap is a Map<Long, EmployeeDO> keyed by employee database PK. It is not synchronized — only written during refresh() and replaced atomically via assignment. Read-only access from multiple threads is safe because each refresh creates a new map instance.

Refresh Strategy

The refresh() method (called by AbstractCache / CacheHelper with synchronization) executes within an isolated read-only transaction:

  1. Load all non-deleted employees: from EmployeeDO t where deleted=false
  2. Apply STATUS entries: Query the latest validSinceEff entries of type STATUS, grouped by employee ID, taking the first record per group.
  3. Apply ANNUAL_LEAVE entries: Same grouping pattern — resolves annual leave days valid today.
  4. Apply WEEKLY_HOURS entries: Same grouping — resolves weekly working hours.
  5. Replace map: The final map is assigned to this.employeeMap.

Time-Dependent Attribute Resolution

The getLatestValidSinceEntries(type) method executes a JPQL query ordering by employee.id, validSince DESC, then groups by employee ID using Kotlin's groupBy. The first element of each group (most recent validSince) is selected. A comment in the source notes that a subquery-based approach (SELECT MAX(validSince)) failed under PostgreSQL with missing entries, leading to this post-query grouping approach.

Key Query Methods

MethodDescription
getEmployee(id)Returns cached employee, resolving the user field via UserGroupCache if not initialized.
getEmployeeIfNotInitialized(emp)Checks HibernateUtils.isFullyInitialized(); if the entity isn't fully loaded, retrieves the cached version.
getEmployeeByUserId(userId)Reverse lookup — finds an employee by their associated user ID.
getEmployeeIdByUserId(userId)Reverse lookup returning only the employee ID (avoids full entity load).
getUser(employee)Resolution helper for PFUserDO via UserGroupCache.
getUserByEmployee(employeeId)Resolves user from employee ID, going through the cached employee.
setTimeDependentAttrs(employee)Mutates a given EmployeeDO's status, annualLeave, and weeklyWorkingHours from cached values. Used by DAO layer to populate transient fields.
findByStaffNumber(staffNumber)Looks up employee by staff number (overloaded for Int and String).

Named Query

The companion object defines queryAllValidSinceValues — a JPQL string used by getLatestValidSinceEntries():

SELECT t FROM EmployeeValidSinceAttrDO t
WHERE t.type=:type AND t.deleted=false
ORDER BY t.employee.id, t.validSince DESC

Git History

868d6abb7 2025 -> 2026
6a32032d6 Hibernate.isInitialized(obj) -> HibernateUtils.isFullyInitialized(obj).
28efde264 Employee: weeklyWorkingHours now as time-dependent attr. eintritt/austritt: timestamp -> date
63081666f Source file headers: 2024-> 2025.
4ae4f3ea3 Bugfixes while going-live...
50c3b7b46 Migration stuff in progress... (all tests of all packages: OK).
4942c854d Migration stuff in progress...
d394f410f Migration stuff in progress... (all tests of all packages: OK).
b71b5073d Migration stuff in progress... (all tests of all packages: OK).
ffb18cf8f Migration stuff in progress...
1012e347a 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.
b5dc26e24 Migration stuff in progress... (all tests of all packages: OK).
b0efaddc2 Migration stuff in progress... (all tests of all packages: OK).
c14b18a48 Migration stuff in progress... (all tests of all packages: OK).