Class CaldavServerOwnerService
BlueMind only, deliberately — through the installed subscription
channel (CalendarSubscriptionChannelRegistry), BlueMind's being the
one there is. The owner is read from BlueMind's
subscription listing through its own REST API
(the channel's ownersOf, in the BlueMind add-on; kept by
CaldavServerOwnerStorage), because BlueMind is the server on
which nothing over CalDAV tells a subscribed colleague's calendar from
the account's own (the channel's container naming). The RFC analogue
would be DAV:owner (RFC 3744 §5.1) read per collection, which
Stalwart answers truthfully and the classifier already reads through
CalendarCollection#isSharedWith; a server that answers it wrongly
has, so far, been BlueMind alone, so no second implementation is made
here, and a server of any other shape gets AccountCalendarOwners.silent()
— its behaviour is unchanged by this witness.
Which servers are BlueMind's: an account whose principal has
BlueMind's …/principals/__uids__/<uid>/ spelling
(the channel's userUidOf), the same rule the naming
witness is read under. A server of that spelling that is not BlueMind —
Apple's retired Calendar Server used it — would be asked and fail to
answer, and its eXo-shaped collections that nobody here recognises would
then wait rather than be adopted; no such server is known to be in use.
What one pass costs. The witness handed out is deferred: nothing is read until a collection needs it. Its first question is answered from the storage's cache — one hour by default, per account — and reaches the server only on a miss. A calendar the cached listing does not name is the one thing that forces a read within the TTL: once per account per pass, however many such calendars the pass meets, so a share made after the entry was written is classified in the pass that first sees it. A session BlueMind opened as an entry other than the account's recorded principal — credentials re-pointed since the entry was written — spends that same one refresh; if the fresh listing still names another entry, the witness is unavailable.
Fail closed, and say so once. A listing that cannot be had — no
login and password to open the REST session with, a refused or
unreachable server, a mismatched entry, an answer of the wrong shape — is
AccountCalendarOwners.unavailable() for the pass, on which the
classifier adopts nothing it does not already recognise; nothing is
cached for it, so the next pass tries again. Said once per account per
process at warn and at debug after that: the condition can last, and a
line every five minutes per user would bury the one that mattered.
Evicted when eXo knows better. A share eXo grants or revokes and a
subscription it follows change what the sharee's mailbox sees, and the
account itself changes hands on connect, disconnect or new credentials;
each drops the entry (evict(long, long)) on the node that made the change.
The cache is node-local: another node learns of it within the TTL, or
sooner through the miss-refresh above. Connect and disconnect are made by
CaldavConnectorServiceImpl, a Kernel component that reaches this
bean through the Kernel/Spring bridge — which exports @Service
beans and nothing else (KernelContainerLifecyclePlugin), so this
class is one, as every sibling resolved through that seam is; a plain
@Component would leave those two evictions silently unwired.
The one cost that is per pass. A mismatched entry — the listing
names an entry other than the account's recorded principal — spends the
pass's refresh, and the fresh listing is kept (@CachePut) whether
or not it is believed. When the mismatch is a stale entry, the refresh
settles it and the next pass is served from the cache. When it is durable
— the REST session and the DAV principal naming two different entries for
one credential set, a case not observed — every pass and every agenda
open spends one REST read and gets the unavailable witness: the cost the
classification had before the cache, said once at warn. Dropping the
entry instead would make each such pass two reads rather than one.
The product using the user's stored credentials during their own pass is what every DAV request of that pass already does; nothing here stores, logs or forwards them, and the session is closed by the client.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidevict(long userIdentityId, long serverId) Drops what the cache holds for one account, because eXo itself changed what that account sees or who it is.ownersOf(long userIdentityId, CalDavEndpoint endpoint, String principal) The server's word on the owners of an account's calendars, to be heard at most once per pass and read from the server at most once more.
-
Constructor Details
-
CaldavServerOwnerService
public CaldavServerOwnerService()
-
-
Method Details
-
ownersOf
public AccountCalendarOwners ownersOf(long userIdentityId, CalDavEndpoint endpoint, String principal) The server's word on the owners of an account's calendars, to be heard at most once per pass and read from the server at most once more.Deferred: nothing is fetched here. The listing is read the first time the classifier asks about a calendar the other witnesses could not settle — from the cache when it holds the account, else from the server — and kept for the rest of the pass; a pass that never asks costs no request (
AccountCalendarOwners.deferred(Supplier, Supplier)).- Parameters:
userIdentityId- the connected user, whose stored credentials open the session and whose entry the cache keepsendpoint- the account's DAV endpoint, minted from the registry for that user's eXo loginprincipal- the account's owncurrent-user-principal, as the discovery walk answered it; null when the server named none- Returns:
- the witness: silent for a server that is not BlueMind's, deferred otherwise
-
evict
public void evict(long userIdentityId, long serverId) Drops what the cache holds for one account, because eXo itself changed what that account sees or who it is.- Parameters:
userIdentityId- the connected userserverId- the declared server registration, zero for the legacy property
-