Class CaldavAnswerAdoptionService

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

@Service public class CaldavAnswerAdoptionService extends Object
Reads the one field a user may answer through their own calendar — their own PARTSTAT on a copy eXo pushed — and records it in agenda (EXO-89681).

This is deliberately the narrowest possible inbound mapping. The mirror is eXo's projection and stays one; the single thing that flows back is the owner's participation, read from the one ATTENDEE line whose address is the account owner's own — the same identity the write side names for them. No server-supplied address ever resolves to any other eXo user: one line, on an object eXo wrote, in a collection eXo created, on an account the user holds. That is the narrow version of the ATTENDEE mapping CaldavInboundService defers as a trust-boundary question, and it sidesteps that question entirely.

The caller decides when to ask and what to do with the object afterwards. This service only turns "what the client wrote" into "what agenda records", and says whether it changed anything.

Two callers ask, on two different signals, and that is deliberate. CaldavMirrorVerificationService asks when a copy's ETag has moved away from the one eXo recorded — the server's own statement that a client wrote after eXo did, which is what tells a phone's answer from an eXo answer not yet pushed. CaldavInboundService asks when the collection's sync report names one of eXo's own copies as changed (EXO-89807), because a server can record an answer without moving the value the first signal reads, and did: on BlueMind the answer sat on the copy for hours while its ETag never moved. Neither signal supersedes the other; between them they cover the servers that publish a version and the servers that publish one but do not move it. Whichever asks, the answers below are the same, and asking twice about one copy costs nothing — an answer agenda already holds is not adopted again.

  • Constructor Details

    • CaldavAnswerAdoptionService

      public CaldavAnswerAdoptionService()
  • Method Details

    • adoptAnswer

      public CaldavAnswerAdoptionService.Outcome adoptAnswer(long userIdentityId, long localEventId, String remoteIcs)
      Adopts the owner's answer from a copy a client rewrote, series and single occurrences alike.

      The master component carries the answer to the whole meeting; an override component carrying a RECURRENCE-ID is a client answering a single occurrence, and it is mapped to agenda's own per-occurrence shape: the exceptional occurrence is looked up — created when the answer is the first thing to distinguish that instance — and the response recorded on it, exactly as agenda's own REST endpoint answers one occurrence. The master is adopted first, deliberately: recording a series response resets the responses of its exceptional occurrences, so the other order would erase the per-occurrence answers just adopted.

      Parameters:
      userIdentityId - identity of the account's owner
      localEventId - the agenda event the object's mapping row names
      remoteIcs - the object as the client left it on the server
      Returns:
      whether anything was adopted, whether adopting it failed, and whether the object could be read at all
    • holdsUnrecordedAnswer

      public boolean holdsUnrecordedAnswer(long userIdentityId, long localEventId, String remoteIcs)
      Whether a copy carries an answer of the owner's that agenda does not hold (EXO-89814) — asked, and answered, without recording anything.

      What it is for. The caller is about to overwrite the copy — a settings round repairing a copy whose content differs while its version never moved — and needs to know whether doing so would destroy the only record of an answer. That is a different question from adoptAnswer(long, long, String): adopting needs the direction proven and this does not, because refusing to write is safe whichever way the difference runs.

      The same three refusals apply and are the whole of the answer's meaning: a line that is not the owner's is not theirs to answer on, NEEDS-ACTION is not an answer, and an answer agenda already holds is not one at risk. So a copy eXo has just written — every one of which carries NEEDS-ACTION until somebody answers — reads as holding nothing, which is what keeps a settings round doing its work on the copies that have nothing to lose.

      Occurrences are read as the series is: an override carrying a RECURRENCE-ID states an answer to one instance, and losing that is the same loss. It is compared against the response agenda gives for that occurrence, exceptional or not, which is the same reading adoptOnOccurrence(long, long, org.exoplatform.caldav.model.IcsEvent, org.exoplatform.agenda.constant.EventAttendeeResponse) does before deciding there is nothing to record.

      Reads only. Nothing here creates an exceptional occurrence or sends a response — a question asked on the way to refusing a write must not itself change what agenda holds.

      Parameters:
      userIdentityId - identity of the account's owner
      localEventId - the agenda event the copy's mapping row names
      remoteIcs - the copy as the server holds it
      Returns:
      true when the copy states an answer of the owner's that agenda does not already hold