Class CaldavMirrorRelocationService

java.lang.Object
org.exoplatform.caldav.service.CaldavMirrorRelocationService

@Service public class CaldavMirrorRelocationService extends Object

Moves the copies already on the server when the destination changes.

The problem. EXO-89760 let an administrator say, per server, where the meeting copies are written. On its own that setting only governs the next push: the copies already written stay in the calendar they were put in, indefinitely, while every new one lands somewhere else. A user then has their meetings split across two calendars with nothing saying why, and a setting that silently strands a hundred objects in the calendar it just stopped using is worse than no setting at all.

The idiom already exists; this is its bulk case. The push path has moved a single copy between collections since EXO-89597 — write into the new place, then conditionally delete the old one, keeping it when the delete is refused because a client edited it (CaldavPushService's mappingElsewhere / removeWhatWasLeftBehind). Nothing here invents a second discipline; it applies that one to every mapped object of a mirror, a page at a time.

The pair is re-pointed first. Before a single object moves, the destination is resolved and written onto the mirror pair — so from that instant every new push and every repair goes to the new collection, and the relocation is only ever catching the backlog up. Re-pointing last would leave a window in which the sweep wrote into the calendar being emptied.

Resumability is the mapping row itself, and deliberately nothing else. The row's own href is the progress marker: an object whose href is not under the destination has not moved yet, whatever happened to the process that was moving it. A restart therefore re-enters exactly where it stopped, with no bookkeeping to reconcile. A "moving" value on the pair's status was the obvious alternative and is the wrong one twice over — every existing status value gates other machinery (the sweep's due-pair query, the deletion guards, the settings screen), and a crash with a sticky status leaves the pair stuck in a state nothing clears.

The answer is read before the move, and that ordering is the whole of it. A copy whose ETag has moved away from the one eXo recorded was written by the user's own client, and the answer on it is their latest word (EXO-89681). Once the mapping points at the new href, the old copy is no longer watched by anything — the verification pass lists the destination collection and nothing else — so an answer left on it would simply be lost. Reading first is the same ordering the sweep already enforces between adoption and repair, for the same reason.

What it refuses to do. It never deletes the emptied collection. Removing a calendar from somebody's account is exactly what this add-on's deletion guards exist to prevent, and the cost of leaving it is nothing: an empty calendar is inert, it is visible, and the user can remove it themselves if they want to. It never re-pushes a copy that is already under the destination, so an account that was already converged comes out of a pass having written, moved and deleted nothing at all.

What a refusal costs. A copy the server would not remove is logged once — not once per sweep, which would bury the line it is meant to stand out in — counted, and left where it is. While anything was refused or failed the change is not stamped as applied, so the next pass tries again.

  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    forget(long userIdentityId)
    Forgets what is remembered about an account's refused removals, so that a fresh attempt says out loud what it finds.
    relocate(long userIdentityId, String username, org.exoplatform.caldav.model.CaldavUserSetting settings, org.exoplatform.caldav.model.CalendarSync mirror)
    Brings the copies already on the server to where the destination now says they go.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • CaldavMirrorRelocationService

      public CaldavMirrorRelocationService()
  • Method Details

    • relocate

      public MirrorRelocation relocate(long userIdentityId, String username, org.exoplatform.caldav.model.CaldavUserSetting settings, org.exoplatform.caldav.model.CalendarSync mirror)
      Brings the copies already on the server to where the destination now says they go.

      Called only when a copy-governing setting has changed (EXO-89759), which is the one moment the destination can have moved: the fingerprint that moves that stamp reads the model's own fields, so mirrorTarget is in it without naming itself. On the far commoner change that is not a destination change — the answer-links switch, an excusal list — the destination resolves to the collection the pair already points at, nothing is pending, and this costs one resolution and one page read.

      Parameters:
      userIdentityId - identity of the user whose copies are moved
      username - their eXo login, which the credentials provider maps to their account on the server
      settings - the connected account
      mirror - the binding standing for the mirror collection
      Returns:
      what the pass moved, and whether the change may be stamped applied
    • forget

      public void forget(long userIdentityId)
      Forgets what is remembered about an account's refused removals, so that a fresh attempt says out loud what it finds.
      Parameters:
      userIdentityId - identity of the user