Class CaldavServerOwnerStorage

java.lang.Object
org.exoplatform.caldav.storage.CaldavServerOwnerStorage

@Component public class CaldavServerOwnerStorage extends Object
The owner of every calendar an account sees, as BlueMind's subscription listing reports it, kept across passes (EXO-90347).

Why a cache, and why here. The listing costs a REST login, a GET and a logout of the user's own BlueMind session. Read only when a pass meets an eXo-shaped collection nobody here recognises, that is still every sweep — every five minutes, on every node — for every account that holds one such calendar, again each time the user opens their agenda, and once more when the hidden-calendars drawer describes a bound eXo-shaped calendar (CaldavReadService#describeCollections), where the listing is what tells a calendar adopted before EXO-90347 — a colleague's, and kept — from the user's own. Owners almost never change, so the answer is kept for meeds.cache.caldav.server.owners.ttl seconds (one hour by default, caldav.properties) and at most meeds.cache.caldav.server.owners.max accounts, through the platform's Spring cache adapter over the Kernel's ExoCache — the storage-like layer caching belongs to, tunable per deployment, and a single-flight load under Cacheable.sync(): concurrent misses on one account open one session, not two.

The key is the account and nothing less. A listing says which calendars one person's mailbox can see; served to another person it is a leak. So the key carries the two discriminators the answer depends on — the declared server and the eXo user whose stored credentials opened the session — as explicit, equals-compared fields (CaldavServerOwnerStorage.Key), never a folded hash: two users on one server, and one user on two servers, hold separate entries by construction. The principal uid the pass discovered is not part of the key, because it is derived from the same credentials; the listing carries the uid the session was authenticated as, and a reader that finds it differing from the pass's principal — credentials re-pointed at another mailbox — asks for a refresh rather than believing the entry.

What is not cached. A fetch that throws caches nothing: Spring writes no entry for a loader that failed, so an unreachable or refusing server costs one attempt per pass, as it did before the cache, and the next pass tries again. A listing that does not name a collection is cached as it came; the reader's one forced refresh(org.exoplatform.caldav.storage.CaldavServerOwnerStorage.Key, org.exoplatform.caldav.client.CalDavEndpoint) per pass is what keeps a share made after the entry was written from waiting out the TTL.

Node-local. Each node of a cluster holds its own entries and expires them on its own clock; an owner change made outside eXo — a share granted in BlueMind's webmail — is seen by a node within the TTL at the latest, and sooner on the node whose pass meets the new collection, since that is a miss it refreshes on. A change eXo itself makes is evicted at once on the node that made it (evict(org.exoplatform.caldav.storage.CaldavServerOwnerStorage.Key)), and reaches the others within the TTL.