Class CaldavSyncStorage
No business logic: what a pair means, when it may be created, whether a deletion propagates — all of that belongs to the service. What lives here is the mechanical part the service should not have to remember, above all that an href is stored decoded and without its trailing slash. A binding that compared raw hrefs would lose its pair the first time a server answered a differently-escaped one, and that is not a decision, it is an invariant.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionstatic StringcanonicalHref(String href) An href reduced to what identifies the resource: its percent-decoded path, without a trailing slash.longcountObjects(long calendarSyncId) How many objects a pair maps.voiddeleteObject(long id) Forgets one object mapping.intdeleteObjects(long calendarSyncId) Drops every object mapping of a pair, leaving the pair itself in place.voiddeletePair(long id) Removes a pair and, by the foreign key, its object mappings.org.springframework.data.domain.Page<Long> getDueAccounts(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, int offset, int limit) The users whose bindings are due, oldest waiting first.org.springframework.data.domain.Page<org.exoplatform.caldav.model.CalendarSync> getDuePairs(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, int offset, int limit) One page of pairs in a given state whose last synchronisation ended before a cutoff, or has never ended.getMirrorEventId(long userIdentityId, long serverId, String icsUid) The eXo event a copy eXo wrote into this user's mirror stands for.org.exoplatform.caldav.model.ObjectSyncgetObjectByEvent(long calendarSyncId, long localEventId) The mapping for one eXo event inside a pair.org.exoplatform.caldav.model.ObjectSyncgetObjectByUid(long calendarSyncId, String icsUid) The mapping for one iCalendar object inside a pair.org.springframework.data.domain.Page<org.exoplatform.caldav.model.ObjectSync> getObjects(long calendarSyncId, int offset, int limit) One page of a pair's object mappings.org.springframework.data.domain.Page<org.exoplatform.caldav.model.ObjectSync> getObjectsByEvent(long localEventId, int offset, int limit) One page of the mappings of a single eXo event, across every user's collections.org.exoplatform.caldav.model.CalendarSyncgetPair(long id) One binding by its identifier, whoever it belongs to.org.exoplatform.caldav.model.CalendarSyncgetPairByLocalCalendar(long userIdentityId, long serverId, String localCalendarSyncUid) The pair bound to one local calendar.org.exoplatform.caldav.model.CalendarSyncgetPairByRemoteHref(long userIdentityId, long serverId, String remoteHref) The pair bound to one remote collection, matched on the canonical path.List<org.exoplatform.caldav.model.CalendarSync> getPairs(long userIdentityId, long serverId) Every pair a user holds on one server.List<org.exoplatform.caldav.model.CalendarSync> getPairsByOrigin(long userIdentityId, long serverId, org.exoplatform.caldav.model.SyncOrigin origin) The pairs of one origin a user holds on a server.booleanisEventMapped(long localEventId) Whether an eXo event is already mapped.booleanisMirrorOwned(long userIdentityId, long serverId, String icsUid) Whether this iCalendar object is a copy eXo itself wrote into the user's mirror.mappedEventIds(long userIdentityId, Collection<Long> localEventIds) Which of these eXo events already carry a copy.mappedEventIds(Collection<Long> localEventIds) Which of these eXo events carry a copy for ANYONE.org.exoplatform.caldav.model.ObjectSyncsaveObject(org.exoplatform.caldav.model.ObjectSync object) Creates or updates an object mapping, canonicalising its href on the way in.org.exoplatform.caldav.model.CalendarSyncsavePair(org.exoplatform.caldav.model.CalendarSync pair) Creates or updates a pair, canonicalising its href on the way in.
-
Constructor Details
-
CaldavSyncStorage
public CaldavSyncStorage()
-
-
Method Details
-
getPairs
Every pair a user holds on one server.- Parameters:
userIdentityId- identity of the userserverId- declared server registration- Returns:
- the user's pairs on that server
-
getPairByLocalCalendar
public org.exoplatform.caldav.model.CalendarSync getPairByLocalCalendar(long userIdentityId, long serverId, String localCalendarSyncUid) The pair bound to one local calendar.- Parameters:
userIdentityId- identity of the userserverId- declared server registrationlocalCalendarSyncUid- agenda's immutable calendar anchor- Returns:
- the pair, or null when the calendar is not bound
-
getPairByRemoteHref
public org.exoplatform.caldav.model.CalendarSync getPairByRemoteHref(long userIdentityId, long serverId, String remoteHref) The pair bound to one remote collection, matched on the canonical path.Resolved in memory over the user's own pairs rather than by a query: the href column is too long to index on MySQL under utf8mb4, and a person's pairs are few. Querying it would have meant either a scan or a schema contortion, for a set that fits in a handful of rows.
- Parameters:
userIdentityId- identity of the userserverId- declared server registrationremoteHref- the collection href, in any spelling- Returns:
- the pair, or null when the collection is not bound
-
getPairsByOrigin
public List<org.exoplatform.caldav.model.CalendarSync> getPairsByOrigin(long userIdentityId, long serverId, org.exoplatform.caldav.model.SyncOrigin origin) The pairs of one origin a user holds on a server. A list even forSyncOrigin.MIRROR, which should be single: the database cannot enforce that uniqueness, so the caller is given what is actually there rather than the first of several.- Parameters:
userIdentityId- identity of the userserverId- declared server registrationorigin- which side created the collection- Returns:
- the matching pairs
-
getDuePairs
public org.springframework.data.domain.Page<org.exoplatform.caldav.model.CalendarSync> getDuePairs(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, int offset, int limit) One page of pairs in a given state whose last synchronisation ended before a cutoff, or has never ended.- Parameters:
status- the state to selectbefore- pairs last synchronised strictly before this instantoffset- page offset, in pageslimit- page size- Returns:
- one page of due pairs, oldest synchronisation first
-
getDueAccounts
public org.springframework.data.domain.Page<Long> getDueAccounts(org.exoplatform.caldav.model.CalendarSyncStatus status, Date before, int offset, int limit) The users whose bindings are due, oldest waiting first. The account-wise form ofgetDuePairs(org.exoplatform.caldav.model.CalendarSyncStatus, java.util.Date, int, int), and what the sweep asks: batching bindings let one user's collections fill a whole run, so no other account was reached at all.- Parameters:
status- the binding state that counts as sweepablebefore- bindings last synchronised strictly before this instantoffset- page indexlimit- how many users one page carries- Returns:
- one page of user identities
-
getPair
public org.exoplatform.caldav.model.CalendarSync getPair(long id) One binding by its identifier, whoever it belongs to.Returns it without checking ownership on purpose: the check belongs to the caller that knows who is asking, and hiding it here would make a service look safe while the storage quietly decided for it.
- Parameters:
id- the binding's identifier- Returns:
- the binding, or null when there is none
-
savePair
@Transactional public org.exoplatform.caldav.model.CalendarSync savePair(org.exoplatform.caldav.model.CalendarSync pair) Creates or updates a pair, canonicalising its href on the way in.- Parameters:
pair- the pair to persist- Returns:
- the persisted pair, carrying its identifier
-
deletePair
@Transactional public void deletePair(long id) Removes a pair and, by the foreign key, its object mappings.- Parameters:
id- technical identifier of the pair
-
getObjectByUid
The mapping for one iCalendar object inside a pair.- Parameters:
calendarSyncId- the pairicsUid- the iCalendar UID- Returns:
- the mapping, or null when the object is unknown
-
isMirrorOwned
Whether this iCalendar object is a copy eXo itself wrote into the user's mirror.Ownership expressed per object rather than per collection. Until now a mirror copy was protected by where it lived — the inbound sweep skipped the dedicated collection wholesale — so pointing the mirror at a calendar the inbound half also reads would have removed the protection entirely, and eXo would have imported its own copies back as duplicate personal events.
The mapping table is the authority because its row is saved in the same flow as the PUT that created the object: by the time any inbound pass can see the object, the row exists. The one window it does not cover is an interruption between the two — the PUT went through and the row was never saved — which leaves an unowned copy the next push reconciles.
- Parameters:
userIdentityId- identity of the user whose copies are asked aboutserverId- the declared server registrationicsUid- the iCalendar UID being imported- Returns:
- true when one of this user's mirror pairs already maps that UID
-
getMirrorEventId
The eXo event a copy eXo wrote into this user's mirror stands for.The companion of
isMirrorOwned(long, long, String)and asked in the same breath (EXO-89807): the inbound half recognises one of eXo's own copies and drops it, but the owner's answer is written on that copy and has to be recorded against something. The mapping that knows which event lives on the MIRROR pair, and the pair reading the collection is a different one, so nothing pair-scoped can answer this.Two mirror pairs holding the same UID is not a state this connector creates — a user has one mirror per server — and if it ever arises, the copies stand for different events and no answer can be attributed to either without guessing. Ambiguity therefore answers "no event", the same as "never pushed": nothing is recorded rather than something recorded against the wrong meeting.
- Parameters:
userIdentityId- identity of the user whose copies are asked aboutserverId- the declared server registrationicsUid- the iCalendar UID being read- Returns:
- the event the copy stands for, or null when it is not ours, names no event, or names more than one
-
getObjectByEvent
public org.exoplatform.caldav.model.ObjectSync getObjectByEvent(long calendarSyncId, long localEventId) The mapping for one eXo event inside a pair.- Parameters:
calendarSyncId- the pairlocalEventId- the eXo event- Returns:
- the mapping, or null when the event has never been pushed
-
getObjects
public org.springframework.data.domain.Page<org.exoplatform.caldav.model.ObjectSync> getObjects(long calendarSyncId, int offset, int limit) One page of a pair's object mappings.- Parameters:
calendarSyncId- the pairoffset- page offset, in pageslimit- page size- Returns:
- one page of mappings, by identifier
-
getObjectsByEvent
public org.springframework.data.domain.Page<org.exoplatform.caldav.model.ObjectSync> getObjectsByEvent(long localEventId, int offset, int limit) One page of the mappings of a single eXo event, across every user's collections.The set an edit of that event is allowed to reach — every copy that already exists, and nothing else.
- Parameters:
localEventId- the eXo eventoffset- page offset, in pageslimit- page size- Returns:
- one page of mappings, by identifier
-
countObjects
public long countObjects(long calendarSyncId) How many objects a pair maps.- Parameters:
calendarSyncId- the pair- Returns:
- the mapping count
-
isEventMapped
public boolean isEventMapped(long localEventId) Whether an eXo event is already mapped. The question the backfill asks before creating a row, and the reason re-running it creates nothing.- Parameters:
localEventId- the eXo event- Returns:
- true when a mapping exists
-
mappedEventIds
Which of these eXo events already carry a copy. The batch form ofisEventMapped(long), for callers holding a list: the seeding pass asks about a user's whole upcoming window on every sweep, and asking one event at a time made the steady state — where every one of them is already mapped — cost a query per meeting to learn there was nothing to do.- Parameters:
userIdentityId- the identity whose mappings count, so the copy made for the first attendee does not answer for every other attendeelocalEventIds- the eXo events to ask about- Returns:
- the identifiers among them that are mapped, empty when none are
-
mappedEventIds
Which of these eXo events carry a copy for ANYONE. Kept for the callers that genuinely ask the global question; a per-user pass wantsmappedEventIds(long, Collection)instead, or the first attendee copied answers for every other attendee.- Parameters:
localEventIds- the eXo events to ask about- Returns:
- the identifiers among them that are mapped
-
saveObject
@Transactional public org.exoplatform.caldav.model.ObjectSync saveObject(org.exoplatform.caldav.model.ObjectSync object) Creates or updates an object mapping, canonicalising its href on the way in.- Parameters:
object- the mapping to persist- Returns:
- the persisted mapping, carrying its identifier
-
deleteObjects
@Transactional public int deleteObjects(long calendarSyncId) Drops every object mapping of a pair, leaving the pair itself in place.- Parameters:
calendarSyncId- the pair- Returns:
- how many mappings were removed
-
deleteObject
public void deleteObject(long id) Forgets one object mapping.What a mapping with nothing behind it gets: dropping it is how the object becomes importable again, rather than being skipped for ever by a row that describes an event no longer there.
- Parameters:
id- the mapping's identifier
-
canonicalHref
An href reduced to what identifies the resource: its percent-decoded path, without a trailing slash.The Java counterpart of the browser connector's collectionPath. The same collection is written
%40by one server and@by a client, reported with and without a trailing slash, and reached through more than one host — none of which makes it a different collection. An href that cannot be parsed is returned trimmed rather than rejected: this is a normalisation, not a validation, and refusing to store an odd href would lose the binding rather than protect it.- Parameters:
href- a collection or object href, absolute or relative- Returns:
- the canonical path, or the trimmed input when it cannot be parsed
-