Interface CaldavCalendarSyncDAO
- All Superinterfaces:
org.springframework.data.repository.CrudRepository<CaldavCalendarSyncEntity,,Long> org.springframework.data.jpa.repository.JpaRepository<CaldavCalendarSyncEntity,,Long> org.springframework.data.repository.ListCrudRepository<CaldavCalendarSyncEntity,,Long> org.springframework.data.repository.ListPagingAndSortingRepository<CaldavCalendarSyncEntity,,Long> org.springframework.data.repository.PagingAndSortingRepository<CaldavCalendarSyncEntity,,Long> org.springframework.data.repository.query.QueryByExampleExecutor<CaldavCalendarSyncEntity>,org.springframework.data.repository.Repository<CaldavCalendarSyncEntity,Long>
Two shapes of read, deliberately kept apart. Everything scoped to one user on one server is read whole: a person has a handful of calendars, and paginating that would cost more than it saves. Everything that spans users — what the background sweep does — is paginated, because that set grows with the deployment and a full read of it would grow with it.
-
Method Summary
Modifier and TypeMethodDescriptionbooleanexistsByServerIdAndOriginAndLocalCalendarSyncUid(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String localCalendarSyncUid) Whether any user of this deployment holds a pair of one origin on one server for one calendar anchor.booleanexistsByServerIdAndOriginAndRemoteHref(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String remoteHref) Whether any user of this deployment holds a pair of one origin on one server recorded at one collection path.booleanexistsByServerIdAndOriginNotAndRemoteHrefEndingWith(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String suffix) Whether any user of this deployment holds a calendar binding on one server for a collection whose path ends with one segment.org.springframework.data.domain.Page<CaldavCalendarSyncEntity> findByServerId(long serverId, org.springframework.data.domain.Pageable pageable) Every pair on one server, paginated.findByUserIdentityIdAndServerId(long userIdentityId, long serverId) Every pair a user holds on one server.findByUserIdentityIdAndServerIdAndLocalCalendarSyncUid(long userIdentityId, long serverId, String localCalendarSyncUid) The pair bound to one local calendar.findByUserIdentityIdAndServerIdAndOrigin(long userIdentityId, long serverId, org.exoplatform.caldav.model.SyncOrigin origin) The pairs of one origin a user holds on a server.org.springframework.data.domain.Page<CaldavCalendarSyncEntity> findDue(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, org.springframework.data.domain.Pageable pageable) Pairs in a given state whose last synchronisation ended before a cutoff, or has never ended.org.springframework.data.domain.Page<Long> findDueAccounts(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, org.springframework.data.domain.Pageable pageable) The users whose bindings are due, oldest first.findPairsByAnchorPreferring(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String localCalendarSyncUid, org.exoplatform.caldav.model.CalendarSyncStatus preferred, org.springframework.data.domain.Pageable pageable) The pairs of one origin on one server for one calendar anchor, the one to name first first.findPairsByRemoteHrefPreferring(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String remoteHref, org.exoplatform.caldav.model.CalendarSyncStatus preferred, org.springframework.data.domain.Pageable pageable) The pairs of one origin on one server recorded at one collection path, the one to name first first.Methods inherited from interface org.springframework.data.repository.CrudRepository
count, delete, deleteAll, deleteAll, deleteAllById, deleteById, existsById, findById, saveMethods inherited from interface org.springframework.data.jpa.repository.JpaRepository
deleteAllByIdInBatch, deleteAllInBatch, deleteAllInBatch, deleteInBatch, findAll, findAll, flush, getById, getOne, getReferenceById, saveAllAndFlush, saveAndFlushMethods inherited from interface org.springframework.data.repository.ListCrudRepository
findAll, findAllById, saveAllMethods inherited from interface org.springframework.data.repository.ListPagingAndSortingRepository
findAllMethods inherited from interface org.springframework.data.repository.PagingAndSortingRepository
findAllMethods inherited from interface org.springframework.data.repository.query.QueryByExampleExecutor
count, exists, findAll, findBy, findOne
-
Method Details
-
findByUserIdentityIdAndServerId
Every pair a user holds on one server. The set the engine matches remote collections against, in memory: matching by href in SQL would need an index on a column too long for one on MySQL, and this set is small enough that the question does not arise.- Parameters:
userIdentityId- identity of the userserverId- declared server registration- Returns:
- the user's pairs on that server, in no particular order
-
findByUserIdentityIdAndServerIdAndLocalCalendarSyncUid
Optional<CaldavCalendarSyncEntity> findByUserIdentityIdAndServerIdAndLocalCalendarSyncUid(long userIdentityId, long serverId, String localCalendarSyncUid) The pair bound to one local calendar. The lookup the outbound half performs before deciding whether a calendar needs creating remotely.- Parameters:
userIdentityId- identity of the userserverId- declared server registrationlocalCalendarSyncUid- agenda's immutable calendar anchor- Returns:
- the pair, if the calendar is already bound
-
findByUserIdentityIdAndServerIdAndOrigin
List<CaldavCalendarSyncEntity> findByUserIdentityIdAndServerIdAndOrigin(long userIdentityId, long serverId, org.exoplatform.caldav.model.SyncOrigin origin) The pairs of one origin a user holds on a server. Used withSyncOrigin.MIRRORto find the single mirror pair — a list rather than an optional because the database cannot enforce that uniqueness (the anchor is null there, and standard SQL leaves NULL rows outside a unique index), so the caller must be able to see a duplicate rather than have one silently picked for it.- Parameters:
userIdentityId- identity of the userserverId- declared server registrationorigin- which side created the collection- Returns:
- the matching pairs
-
findDue
@Query("SELECT p FROM CaldavCalendarSyncEntity p WHERE p.status = :status AND (p.lastSyncEnd IS NULL OR p.lastSyncEnd < :before)") org.springframework.data.domain.Page<CaldavCalendarSyncEntity> findDue(@Param("status") org.exoplatform.caldav.model.CalendarSyncStatus status, @Param("before") Date before, org.springframework.data.domain.Pageable pageable) Pairs in a given state whose last synchronisation ended before a cutoff, or has never ended. What the background sweep selects on.Written as JPQL rather than derived from the method name: the derived form of this predicate needs the status repeated on both sides of the OR, which produces a name nobody can read and a parameter that must be passed twice.
- Parameters:
status- the state to selectbefore- pairs last synchronised strictly before this instantpageable- page and sort; required, this set spans every user- Returns:
- one page of due pairs
-
findDueAccounts
@Query("SELECT p.userIdentityId FROM CaldavCalendarSyncEntity p WHERE p.status = :status AND (p.lastSyncEnd IS NULL OR p.lastSyncEnd < :before) GROUP BY p.userIdentityId ORDER BY MIN(COALESCE(p.lastSyncEnd, {d \'1970-01-01\'})) ASC") org.springframework.data.domain.Page<Long> findDueAccounts(@Param("status") org.exoplatform.caldav.model.CalendarSyncStatus status, @Param("before") Date before, org.springframework.data.domain.Pageable pageable) The users whose bindings are due, oldest first. The sweep works account by account, so this is the set it must page through. Paging the BINDINGS instead let one user's collections fill a whole batch — a user with forty of them, all stale after an outage, occupied every run and no other account was ever reached. Grouping puts one row per user in the page, so a batch of ten is ten users however many collections each of them holds. Ordered by each user's oldest binding, so the account waiting longest is served first.- Parameters:
status- the binding state that counts as sweepablebefore- bindings last synchronised strictly before this instantpageable- page and sort; required, this set spans every user- Returns:
- one page of user identities
-
findByServerId
org.springframework.data.domain.Page<CaldavCalendarSyncEntity> findByServerId(long serverId, org.springframework.data.domain.Pageable pageable) Every pair on one server, paginated. Used when a registration is deactivated or removed and its bindings have to be dealt with.- Parameters:
serverId- declared server registrationpageable- page and sort; required, this set spans every user- Returns:
- one page of pairs on that server
-
existsByServerIdAndOriginAndLocalCalendarSyncUid
boolean existsByServerIdAndOriginAndLocalCalendarSyncUid(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String localCalendarSyncUid) Whether any user of this deployment holds a pair of one origin on one server for one calendar anchor.Asked with
SyncOrigin.EXOto decide whether a collection under the outbound prefix was minted by this deployment (EXO-90226): the slug eXo mints carries the calendar's anchor, and an EXO pair on the server for that anchor means the calendar behind the collection exists here. Deliberately spanning every user — the pair that answers may be another user's on a shared account — and every status: a paused or tombstoned pair still names a calendar this deployment made.Keyed on the anchor rather than on the href, because the server may report an eXo-made collection under a path other than the one it was created at (BlueMind republishes them under another parent), and the anchor is the part of the path that survives that. Its sibling
existsByServerIdAndOriginAndRemoteHref(long, org.exoplatform.caldav.model.SyncOrigin, java.lang.String)answers by the recorded path instead, for the shape where the slug is the part that changed.What it costs: a point lookup on
IDX_CALDAV_CALENDAR_SYNC_ORIGIN (SERVER_ID, ORIGIN, LOCAL_CALENDAR_SYNC_UID), changeset 1.0.0-48 — covering, one row (EXPLAIN on MySQL 8.0.37, recorded in the changeset). Before that index it walked the table: neither the unique index nor the status one leads with the server. It matters because the calendar list asks it on every listing since EXO-90234, per colleague's share — the user's own pairs still answer first, in memory — and the sweep asks it for a prefixed collection this user does not hold.- Parameters:
serverId- the declared server registrationorigin- which side created the collectionlocalCalendarSyncUid- agenda's immutable calendar anchor- Returns:
- true when such a pair exists, whoever holds it
-
existsByServerIdAndOriginAndRemoteHref
boolean existsByServerIdAndOriginAndRemoteHref(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String remoteHref) Whether any user of this deployment holds a pair of one origin on one server recorded at one collection path.The second arm of the ownership question (EXO-90226), asked with
SyncOrigin.EXOwhen the anchor arm above found nothing. A server may republish an eXo-made collection under a slug that is not the anchor eXo minted — prefix kept, suffix replaced, the shape EXO-89590 recorded against BlueMind — and then the slug names no calendar here while the collection is still one this deployment made. The path a pair records is what answers that shape, whenever the record holds the published path. Like its sibling, deliberately every user and every status.The href is compared as stored, which is canonical (the storage canonicalises on save); the caller canonicalises what it asks with. The href itself cannot be indexed — the column is too long for MySQL under utf8mb4, which is why the unique constraint is carried by the anchor (changeset 1.0.0-5) — but
IDX_CALDAV_CALENDAR_SYNC_ORIGIN's(SERVER_ID, ORIGIN)prefix bounds it to one server's pairs of one origin (1.0.0-48). On a single-server deployment that is still most of the table, so it stays behind the anchor arm: asked only after that one has missed — once per pass for a prefixed collection this deployment holds no anchor for, and, since EXO-90234, once per calendar listing for the same collection.- Parameters:
serverId- the declared server registrationorigin- which side created the collectionremoteHref- the collection path, canonical- Returns:
- true when such a pair exists, whoever holds it
-
existsByServerIdAndOriginNotAndRemoteHrefEndingWith
boolean existsByServerIdAndOriginNotAndRemoteHrefEndingWith(long serverId, org.exoplatform.caldav.model.SyncOrigin origin, String suffix) Whether any user of this deployment holds a calendar binding on one server for a collection whose path ends with one segment.The third arm of the ownership question (EXO-90347), asked with
SyncOrigin.MIRRORas the origin to leave out, once the server's own listing has named another owner for an eXo-shaped collection the two arms above did not recognise. On BlueMind one container is listed under each subscriber's home — the colleague's pair records it under hers, the sharee's listing spells it under his — so neither the anchor (the pair is REMOTE: a calendar she imported, whose slug is not her anchor) nor the recorded path answers, while the container uid, the last segment, is the same on both. A binding of any origin but the mirror ledger and of any status: a colleague who has since deleted her calendar in eXo still holds a tombstone naming the collection as hers.A
LIKE '%/<uid>'the href column cannot be indexed for, as its siblings' notes say; asked only after both other arms have missed and the server has named another owner — a colleague's share, at most once per such share per pass.- Parameters:
serverId- the declared server registrationorigin- the origin to leave out, the mirror ledger'ssuffix- a slash and the container uid, as the canonical path ends- Returns:
- true when such a binding exists, whoever holds it
-
findPairsByAnchorPreferring
@Query("SELECT p FROM CaldavCalendarSyncEntity p WHERE p.serverId = :serverId AND p.origin = :origin AND p.localCalendarSyncUid = :localCalendarSyncUid ORDER BY CASE WHEN p.status = :preferred THEN 0 ELSE 1 END, p.id ASC") List<CaldavCalendarSyncEntity> findPairsByAnchorPreferring(@Param("serverId") long serverId, @Param("origin") org.exoplatform.caldav.model.SyncOrigin origin, @Param("localCalendarSyncUid") String localCalendarSyncUid, @Param("preferred") org.exoplatform.caldav.model.CalendarSyncStatus preferred, org.springframework.data.domain.Pageable pageable) The pairs of one origin on one server for one calendar anchor, the one to name first first.The who form of
existsByServerIdAndOriginAndLocalCalendarSyncUid(long, org.exoplatform.caldav.model.SyncOrigin, java.lang.String), asked withSyncOrigin.EXOonce a listed collection is known to be a colleague's eXo calendar and the calendar list wants to say whose (EXO-90237): the pair's user is the owner. Same predicate, same span — every user, every status — and the same index, 1.0.0-48, serving it (see the sibling's note); asked once per colleague's share per listing, after the existence question has already said there is one to find.Ordered so that the first row is the one to believe, should there ever be more than one: the unique index
(USER_IDENTITY_ID, SERVER_ID, LOCAL_CALENDAR_SYNC_UID)leaves two users free to record the same anchor on the same server — a database restored and re-pointed, a calendar whose rows were copied between accounts — and a listing that named a different owner on each refresh would be worse than one that is wrong the same way twice. A pair in thepreferredstate (active, from the caller) is a calendar still exported, so its user is the likelier owner; among equals the oldest row, by identifier, is the one that has been true longest. The caller passes a page of one.- Parameters:
serverId- the declared server registrationorigin- which side created the collectionlocalCalendarSyncUid- agenda's immutable calendar anchorpreferred- the state a pair should be in to be named firstpageable- how many to name; a page of one in practice- Returns:
- the matching pairs, preferred state first, then oldest first
-
findPairsByRemoteHrefPreferring
@Query("SELECT p FROM CaldavCalendarSyncEntity p WHERE p.serverId = :serverId AND p.origin = :origin AND p.remoteHref = :remoteHref ORDER BY CASE WHEN p.status = :preferred THEN 0 ELSE 1 END, p.id ASC") List<CaldavCalendarSyncEntity> findPairsByRemoteHrefPreferring(@Param("serverId") long serverId, @Param("origin") org.exoplatform.caldav.model.SyncOrigin origin, @Param("remoteHref") String remoteHref, @Param("preferred") org.exoplatform.caldav.model.CalendarSyncStatus preferred, org.springframework.data.domain.Pageable pageable) The pairs of one origin on one server recorded at one collection path, the one to name first first.The who form of
existsByServerIdAndOriginAndRemoteHref(long, org.exoplatform.caldav.model.SyncOrigin, java.lang.String), for the shape where the slug is not the anchor and the recorded path is what recognised the collection (EXO-90237). Same span, same cost — a walk, since the href column cannot be indexed — and the same ordering rule asfindPairsByAnchorPreferring(long, org.exoplatform.caldav.model.SyncOrigin, java.lang.String, org.exoplatform.caldav.model.CalendarSyncStatus, org.springframework.data.domain.Pageable), for the same reason: the path is unique to nobody in the schema, and the owner named must not depend on row order.- Parameters:
serverId- the declared server registrationorigin- which side created the collectionremoteHref- the collection path, canonicalpreferred- the state a pair should be in to be named firstpageable- how many to name; a page of one in practice- Returns:
- the matching pairs, preferred state first, then oldest first
-