Class CaldavServerStorage

java.lang.Object
org.exoplatform.caldav.storage.CaldavServerStorage

@Component public class CaldavServerStorage extends Object
Maps CalDAV server registrations between their JPA entity and the credential-free CaldavServer DTO. No business logic lives here: the provider-name derivation is mechanical (the seed name is given by the service, every other row derives its name from its own id) and the choices — who may write, when to seed — belong to the service.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final Long
    Fallback cache-busting version for rows whose image has no readable modification date.
    static final String
    FileService namespace the uploaded server images are stored under.
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    long
    Counts the registrations — what the seeding decision reads: the seed row is only ever written into an empty registry, so an administrator's edits are never overwritten by a restart.
    org.exoplatform.caldav.model.CaldavServer
    createSeedServer(org.exoplatform.caldav.model.CaldavServer server, String providerName)
    Creates the seed registration under the fixed legacy provider name — the one row whose provider the kernel plugin already registers, so the accounts connected before the registry existed keep resolving through it.
    org.exoplatform.caldav.model.CaldavServer
    createServer(org.exoplatform.caldav.model.CaldavServer server, String providerNamePrefix)
    Creates a registration whose provider name derives from its own row id (<providerNamePrefix>.<id>).
    boolean
    deleteServer(long serverId)
    Deletes a registration row and, with it, its uploaded image — the file has no other referrer, so keeping it would only leak storage.
    List<org.exoplatform.caldav.model.ForeignWriter>
    getForeignWriters(long serverId, long today, long retentionDays)
    Which other eXo deployments have been seen writing meeting copies into this server's accounts (EXO-89824), most recently seen first.
    org.exoplatform.caldav.model.CaldavServer
    getServerById(long id)
    Reads one registration by its technical identifier.
    org.exoplatform.caldav.model.CaldavServer
    Reads one registration by the agenda remote provider it is bridged to.
    List<org.exoplatform.caldav.model.CaldavServer>
    Reads every registration, seed first (it holds the lowest id by construction).
    void
    mergeForeignWriter(long serverId, String authority, long today, long retentionDays)
    Records that another eXo deployment was seen writing into an account on this server, and ages out what has not been seen for long enough.
    void
    Adds what a pass saw to a registration's rolling observation summary, and forgets what no longer belongs in it.
    org.exoplatform.caldav.model.CaldavServer
    updateServer(org.exoplatform.caldav.model.CaldavServer server)
    Updates the user-editable fields of a registration: name, description, URL, activation, whether the copies pushed to this server carry answer links, the two lists of behaviours this server is excused for, and the copy-settings stamp the service computed for this write.

    Methods inherited from class java.lang.Object

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

    • NAME_SPACE

      public static final String NAME_SPACE
      FileService namespace the uploaded server images are stored under.
      See Also:
    • DEFAULT_LAST_MODIFIED

      public static final Long DEFAULT_LAST_MODIFIED
      Fallback cache-busting version for rows whose image has no readable modification date.
  • Constructor Details

    • CaldavServerStorage

      public CaldavServerStorage()
  • Method Details

    • getServers

      public List<org.exoplatform.caldav.model.CaldavServer> getServers()
      Reads every registration, seed first (it holds the lowest id by construction).
      Returns:
      all registrations, ordered by id
    • getServerById

      public org.exoplatform.caldav.model.CaldavServer getServerById(long id)
      Reads one registration by its technical identifier.
      Parameters:
      id - technical identifier of the registration
      Returns:
      the registration, or null when the row does not exist
    • getServerByProviderName

      public org.exoplatform.caldav.model.CaldavServer getServerByProviderName(String providerName)
      Reads one registration by the agenda remote provider it is bridged to.
      Parameters:
      providerName - name of the agenda remote provider
      Returns:
      the registration, or null when none carries that name
    • countServers

      public long countServers()
      Counts the registrations — what the seeding decision reads: the seed row is only ever written into an empty registry, so an administrator's edits are never overwritten by a restart.
      Returns:
      number of registration rows
    • createServer

      @Transactional public org.exoplatform.caldav.model.CaldavServer createServer(org.exoplatform.caldav.model.CaldavServer server, String providerNamePrefix)
      Creates a registration whose provider name derives from its own row id (<providerNamePrefix>.<id>). Two steps in one transaction — insert, then name the row after the id the insert produced — because the column is NOT NULL and the id does not exist before the insert. The transaction keeps the intermediate placeholder name unobservable.
      Parameters:
      server - registration to create (provider name ignored)
      providerNamePrefix - prefix the provider name is derived from
      Returns:
      the created registration, carrying its id and provider name
    • createSeedServer

      @Transactional public org.exoplatform.caldav.model.CaldavServer createSeedServer(org.exoplatform.caldav.model.CaldavServer server, String providerName)
      Creates the seed registration under the fixed legacy provider name — the one row whose provider the kernel plugin already registers, so the accounts connected before the registry existed keep resolving through it.
      Parameters:
      server - registration to create
      providerName - fixed provider name of the seed
      Returns:
      the created registration
    • updateServer

      @Transactional public org.exoplatform.caldav.model.CaldavServer updateServer(org.exoplatform.caldav.model.CaldavServer server)
      Updates the user-editable fields of a registration: name, description, URL, activation, whether the copies pushed to this server carry answer links, the two lists of behaviours this server is excused for, and the copy-settings stamp the service computed for this write. The provider name never changes — it is the join key user settings and agenda rows hang from, and neither is the rolling observation summary, which is the sweep's to write (see mergeObservedQuirks(long, java.util.Map<org.exoplatform.caldav.utils.ServerQuirkSummary.Observation, java.lang.Long>, org.exoplatform.caldav.utils.ServerQuirkSummary.Retention)) and would otherwise be erased by every administrator save.
      Parameters:
      server - registration carrying the id to update and the new values
      Returns:
      the updated registration, or null when the row does not exist
    • deleteServer

      @Transactional public boolean deleteServer(long serverId)
      Deletes a registration row and, with it, its uploaded image — the file has no other referrer, so keeping it would only leak storage.
      Parameters:
      serverId - technical identifier of the registration
      Returns:
      true when a row was deleted, false when none carried that id
    • getForeignWriters

      public List<org.exoplatform.caldav.model.ForeignWriter> getForeignWriters(long serverId, long today, long retentionDays)
      Which other eXo deployments have been seen writing meeting copies into this server's accounts (EXO-89824), most recently seen first.

      Its own read rather than a field on the registration, and deliberately: the registration is built positionally through an all-args constructor that a score of call sites already pass, and a field there would also be a field an administrator's save could carry back — this is evidence written by the inbound pass, and nothing a drawer sends must be able to overwrite it. The provider-config endpoint reads the same way, for the same reason.

      Aged on read. The list is rewritten only when a foreign copy is seen, so a deployment that stopped writing here would otherwise stay on it for ever: what has not been seen within the retention is left out of the answer, whatever the row still holds.

      Parameters:
      serverId - technical identifier of the registration
      today - the current epoch day
      retentionDays - how long an unseen deployment stays on the list
      Returns:
      the deployments seen writing here, empty when none has been or the row is gone, never null
    • mergeForeignWriter

      @Transactional public void mergeForeignWriter(long serverId, String authority, long today, long retentionDays)
      Records that another eXo deployment was seen writing into an account on this server, and ages out what has not been seen for long enough.

      Read, modify, write on one short column, the way mergeObservedQuirks(long, java.util.Map<org.exoplatform.caldav.utils.ServerQuirkSummary.Observation, java.lang.Long>, org.exoplatform.caldav.utils.ServerQuirkSummary.Retention) does, and with the same accepted race: two passes landing together can lose one of two observations, and nothing is decided from the exact contents — the list answers "is another deployment writing here", and a deployment that wrote once writes again. The race stays inside this column: the entity is updated dynamically, so the statement carries this column alone and cannot revert an administrator's concurrent save.

      Writes only when the result differs. A deployment seen twice on the same day produces the same string, and this column must not become a write on every pass of every account: the condition it records lasts weeks, and the row is read by a drawer somebody opens twice.

      Parameters:
      serverId - technical identifier of the registration
      authority - the deployment just seen, or null to age the list without adding to it
      today - the current epoch day
      retentionDays - how long an unseen deployment stays on the list
    • mergeObservedQuirks

      @Transactional public void mergeObservedQuirks(long serverId, Map<ServerQuirkSummary.Observation,Long> increments, ServerQuirkSummary.Retention retention)
      Adds what a pass saw to a registration's rolling observation summary, and forgets what no longer belongs in it.

      Read, merge, prune and write in one transaction, and touching that one column only. This is the sweep talking, not an administrator: routing it through updateServer(org.exoplatform.caldav.model.CaldavServer) would let a background pass overwrite a name or a URL somebody is editing in the drawer at the same moment.

      What may be forgotten is the service's decision and this method's mechanics. The rules arrive as a ServerQuirkSummary.Retention, because working out which records a reclassification has replaced, and how long silence is allowed to last, is policy; applying the answer to a stored string is mapping.

      One record is never dropped, whatever the rules say: an excused one. The excusal itself lives in the three lists on this row and would survive either way, which is precisely the danger — an excusal still in force with no entry in the drawer is one an administrator can neither see nor untick. Forgetting the evidence must never outlive the decision made from it. It is checked here rather than in the policy because it is a fact about this row, and the row is what this layer holds.

      Two passes racing on one server can still lose an increment, and that is accepted: the number answers "does this server always do this, or did it happen once", and no decision is made from its exact value.

      Parameters:
      serverId - technical identifier of the registration

      An empty batch is not a reason to do nothing. A converged account observes no divergence at all, which is exactly the account whose stale records want clearing; gating the whole method on having something to add meant the cleanup only ever ran on servers that were still misbehaving. It reads and prunes regardless, and writes only when the result differs from what is stored — so a settled row costs one read per interval and no write.

      increments - how many times each behaviour was seen since the last write, empty when the pass found nothing
      retention - what this write is allowed to forget