Class CaldavServerService

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

@Service public class CaldavServerService extends Object
The registry of CalDAV servers a deployment offers its users: what an administrator declares in the third section of the agenda administration page. Holds all the business logic — who may write (platform administrators), the provider naming that bridges each registration to an agenda remote provider with zero agenda backend change, the seeding that migrates the legacy configuration property, and the URL resolution the per-user connector settings read.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
    The name the Bluemind seed is declared under.
    static final String
    Legacy configuration property telling whether the single CalDAV connector is enabled; read once, to give the seed row its initial activation.
    static final String
    Provider name of the seed registration — the name the kernel plugin has always registered on the agenda side — and the prefix every derived provider name starts with.
    static final String
    Legacy configuration property holding the single CalDAV server URL.
    static final String
    Address the Bluemind seed row is declared with: a placeholder an administrator is expected to replace with the DAV endpoint of their own BlueMind, whose shape it mirrors (BlueMind serves DAV under /dav/ and answers there with 401 Basic realm="bm.basic.auth.v2"; the bare host only redirects).
    static final String
    Address the Stalwart seed row falls back to when the deployment named none through CALDAV_SERVER_URL_PROPERTY.
    static final String
    The name the Stalwart seed is declared under.
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    canEdit(String username)
    Whether a user may edit the registry: platform administrators only.
    long
    countServerReferences(long serverId)
    Counts the connected accounts referencing a registration: the user contexts holding a CaldavServerId setting whose value is this row's id.
    org.exoplatform.caldav.model.CaldavServer
    createServer(org.exoplatform.caldav.model.CaldavServer server, String username)
    Declares a new CalDAV server.
    void
    deleteServer(long serverId, String username)
    Deletes a declared server.
    org.exoplatform.caldav.model.CaldavServer
    getServerById(long serverId)
    One registration by its technical identifier.
    The stored image of a registration, as a stream the REST layer serves — email-connector's illustration mechanics.
    List<org.exoplatform.caldav.model.CaldavServer>
    The registrations, seed first.
    org.exoplatform.caldav.model.CaldavServer
    resolveServer(Long serverId)
    Resolves the registration a user's account reads and pushes through: the row the account references when it references one and that row still exists, else the seed row, else null.
    Resolves the CalDAV base URL a user's account reads and pushes through: the URL of the resolved registration, else null — the caller then falls back to the legacy configuration property, which is today's behaviour for deployments that never touched the registry.
    protected void
    Seeds the two default servers into an EMPTY registry — never over an administrator's rows: Stalwart, under the fixed legacy provider name so accounts connected before the registry existed keep resolving; its URL comes from the legacy property when set, else the literal default, and its activation from the legacy enabled property (historically enabled). Bluemind, a normally-named row whose agenda remote provider is upserted here, since no kernel plugin declares it.
    org.exoplatform.caldav.model.CaldavServer
    setServerActive(long serverId, boolean active, String username)
    Activates or deactivates a declared server, propagating the switch to the agenda remote provider so the connector appears in — or leaves — every user's connectors list.
    void
    Defers the seeding of the registry to the portal container's post-create phase — the same deferral agenda's own provider plugin uses — because the Bluemind default needs its agenda remote provider written, and agenda's kernel services are only safely callable once the portal container is up.
    org.exoplatform.caldav.model.CaldavServer
    updateServer(org.exoplatform.caldav.model.CaldavServer server, String username)
    Updates a declared server: name, description, URL, activation, whether the copies pushed to it carry answer links, and the two lists of behaviours this server is excused for.

    Methods inherited from class java.lang.Object

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

    • CALDAV_PROVIDER_NAME

      public static final String CALDAV_PROVIDER_NAME
      Provider name of the seed registration — the name the kernel plugin has always registered on the agenda side — and the prefix every derived provider name starts with.
      See Also:
    • CALDAV_SERVER_URL_PROPERTY

      public static final String CALDAV_SERVER_URL_PROPERTY
      Legacy configuration property holding the single CalDAV server URL. Becomes the seed row, then stays forever as a deprecated fallback for deployments whose registry is empty. Never dropped.
      See Also:
    • CALDAV_ENABLED_PROPERTY

      public static final String CALDAV_ENABLED_PROPERTY
      Legacy configuration property telling whether the single CalDAV connector is enabled; read once, to give the seed row its initial activation.
      See Also:
    • STALWART_SERVER_NAME

      public static final String STALWART_SERVER_NAME
      The name the Stalwart seed is declared under.
      See Also:
    • BLUEMIND_SERVER_NAME

      public static final String BLUEMIND_SERVER_NAME
      The name the Bluemind seed is declared under.
      See Also:
    • DEFAULT_STALWART_URL

      public static final String DEFAULT_STALWART_URL
      Address the Stalwart seed row falls back to when the deployment named none through CALDAV_SERVER_URL_PROPERTY.

      It is a placeholder, and it is one on purpose (EXO-89794). This constant used to read http://localhost:8888/dav/cal/{username}/ — the local development rig — so a fresh install shipped an active registration pointing at its own loopback interface, through which a connected user could drive the relay's verbs at a row nobody had typed. A product default must not name a host that exists only on a developer's machine, and it must certainly not arrive switched on.

      The replacement is an RFC 2606 .invalid name, which is guaranteed never to resolve: it cannot be a live target under any deployment's resolver, it reads unmistakably as "replace me", and it fails the address check — which is what makes the row arrive inactive, see seedDefaultServers(). The rig keeps working the documented way, by setting CALDAV_SERVER_URL_PROPERTY (plus the opt-ins the address check reads); it no longer works by being the shipped default.

      See Also:
    • DEFAULT_BLUEMIND_URL

      public static final String DEFAULT_BLUEMIND_URL
      Address the Bluemind seed row is declared with: a placeholder an administrator is expected to replace with the DAV endpoint of their own BlueMind, whose shape it mirrors (BlueMind serves DAV under /dav/ and answers there with 401 Basic realm="bm.basic.auth.v2"; the bare host only redirects).

      An RFC 2606 .invalid name for the same reason as DEFAULT_STALWART_URL: it can never resolve, so the row can never be a live target, and it fails the address check — so the row is seeded inactive rather than offered to users as a connector that goes nowhere.

      Note also that BlueMind sends no CORS headers, so connecting from the browser needs the portal to front it on its own origin.

      See Also:
  • Constructor Details

    • CaldavServerService

      public CaldavServerService()
  • Method Details

    • start

      @PostConstruct public void start()
      Defers the seeding of the registry to the portal container's post-create phase — the same deferral agenda's own provider plugin uses — because the Bluemind default needs its agenda remote provider written, and agenda's kernel services are only safely callable once the portal container is up.
    • seedDefaultServers

      protected void seedDefaultServers()
      Seeds the two default servers into an EMPTY registry — never over an administrator's rows:
      • Stalwart, under the fixed legacy provider name so accounts connected before the registry existed keep resolving; its URL comes from the legacy property when set, else the literal default, and its activation from the legacy enabled property (historically enabled).
      • Bluemind, a normally-named row whose agenda remote provider is upserted here, since no kernel plugin declares it.

      A seeded row is switched ON only when its address passes the same check an administrator's would (EXO-89794). Seeding used to be exempt from the address check of EXO-89774 altogether, which left the loophole that check was written to close: a fresh install carried an active registration at http://localhost:8888/dav/cal/{username}/, so a connected user could drive the relay's allowed verbs at loopback through a row nobody had typed. Neither the check nor the seeds are the thing to drop; what had to go is the row arriving switched on without ever meeting the check.

      So the seeds are still written — they are the pre-filled form an administrator edits, and skipping them would leave a fresh install with an empty administration screen and no hint of what belongs in it — but their activation is the address check's answer, not a constant:

      • An address the deployment actually named and vouched for — through CALDAV_SERVER_URL_PROPERTY, plus whichever of the four exo.agenda.caldav.server.* opt-ins that address needs — passes, and the row is seeded active exactly as before. This is how the local development rig keeps working: through its documented properties, not through a default that walks past them.
      • Anything else — both shipped placeholders included — is seeded inactive, and said out loud in the log (see isDeclarableSeedAddress(String, String)). Inactive is the honest state for an address nobody has vouched for: no user is offered the connector, nothing can be driven at it, and switching it on later is a write that setServerActive(long, boolean, String) already puts through the full check. The administrator edits the row, which is checked too, and turns it on — the check is never bypassed, only deferred to the person who knows the address.

      This governs a fresh registry and nothing else. The guard below is the whole upgrade story: a deployment that already holds rows returns before any of this runs, so an install that has been serving its users for months does not find its servers deactivated — or judged at all — by taking this version.

    • getServers

      public List<org.exoplatform.caldav.model.CaldavServer> getServers()
      The registrations, seed first. Callable by any authenticated user: the rows hold nothing secret — no credential ever enters this table — and the browser needs the names and URLs to offer the connectors.
      Returns:
      every registration
    • getServerById

      public org.exoplatform.caldav.model.CaldavServer getServerById(long serverId) throws org.exoplatform.commons.exception.ObjectNotFoundException
      One registration by its technical identifier.
      Parameters:
      serverId - technical identifier of the registration
      Returns:
      the registration
      Throws:
      org.exoplatform.commons.exception.ObjectNotFoundException - when no registration carries that id
    • createServer

      public org.exoplatform.caldav.model.CaldavServer createServer(org.exoplatform.caldav.model.CaldavServer server, String username) throws IllegalAccessException
      Declares a new CalDAV server. The provider name is derived from the row id (agenda.caldavCalendar.<id>), then the matching agenda remote provider is upserted under that name — which is all agenda needs: its existing enabled-check and connected-provider binding key on the name.
      Parameters:
      server - registration to create (id and provider name ignored)
      username - user declaring the server
      Returns:
      the created registration
      Throws:
      IllegalAccessException - when the user is not a platform administrator
      IllegalArgumentException - when the registration, its name or its URL is missing
    • updateServer

      public org.exoplatform.caldav.model.CaldavServer updateServer(org.exoplatform.caldav.model.CaldavServer server, String username) throws IllegalAccessException, org.exoplatform.commons.exception.ObjectNotFoundException
      Updates a declared server: name, description, URL, activation, whether the copies pushed to it carry answer links, and the two lists of behaviours this server is excused for. The provider name never changes, and the activation is propagated to the agenda remote provider — the switch users' connector lists actually read.
      Parameters:
      server - registration carrying the id to update and the new values
      username - user updating the server
      Returns:
      the updated registration
      Throws:
      IllegalAccessException - when the user is not a platform administrator
      IllegalArgumentException - when the registration, its name or its URL is missing
      org.exoplatform.commons.exception.ObjectNotFoundException - when no registration carries that id
    • setServerActive

      public org.exoplatform.caldav.model.CaldavServer setServerActive(long serverId, boolean active, String username) throws IllegalAccessException, org.exoplatform.commons.exception.ObjectNotFoundException
      Activates or deactivates a declared server, propagating the switch to the agenda remote provider so the connector appears in — or leaves — every user's connectors list.
      Parameters:
      serverId - technical identifier of the registration
      active - whether users may connect to this server
      username - user flipping the switch
      Returns:
      the updated registration
      Throws:
      IllegalAccessException - when the user is not a platform administrator
      org.exoplatform.commons.exception.ObjectNotFoundException - when no registration carries that id
      IllegalArgumentException - carrying a message code when the row is being ACTIVATED and its stored address is one the platform must not be made to connect to, or caldav.managed.serverInUse when the row is the one managed mode synchronises everybody with
    • deleteServer

      public void deleteServer(long serverId, String username) throws IllegalAccessException, org.exoplatform.commons.exception.ObjectNotFoundException
      Deletes a declared server. Refused — with the number of blocked accounts — while ANY user's connection references the row: deleting under them would silently re-point their stored credentials at whatever the resolution falls back to, which is a different server. The administrator deactivates instead, users disconnect, then the delete goes through. Legacy accounts (no stored reference) never block a delete: they resolve through the seed then the property, exactly as before the registry. Before the row goes, its agenda remote provider is disabled — agenda has no provider-delete API, so disabling is what actually removes the connector from every user's list; the orphaned provider row stays, disabled and invisible.
      Parameters:
      serverId - technical identifier of the registration
      username - user deleting the server
      Throws:
      IllegalAccessException - when the user is not a platform administrator
      org.exoplatform.commons.exception.ObjectNotFoundException - when no registration carries that id
      IllegalStateException - carrying the message code caldav.server.referenced:<count> when connected accounts still reference the row (the REST layer answers 409)
      IllegalArgumentException - carrying caldav.managed.serverInUse when the row is the one managed mode synchronises everybody with (the REST layer answers 400)
    • countServerReferences

      public long countServerReferences(long serverId)
      Counts the connected accounts referencing a registration: the user contexts holding a CaldavServerId setting whose value is this row's id. The enumeration is by setting NAME (the settings API offers no by-value filter), each candidate's value then compared — the same walk email-connector does to find a connector's users.
      Parameters:
      serverId - technical identifier of the registration
      Returns:
      number of accounts whose stored connection references the row
    • getServerImageInputStream

      public InputStream getServerImageInputStream(long serverId) throws org.exoplatform.commons.exception.ObjectNotFoundException
      The stored image of a registration, as a stream the REST layer serves — email-connector's illustration mechanics.
      Parameters:
      serverId - technical identifier of the registration
      Returns:
      the image stream, or null when the row holds no image
      Throws:
      org.exoplatform.commons.exception.ObjectNotFoundException - when no registration carries that id
    • resolveServer

      public org.exoplatform.caldav.model.CaldavServer resolveServer(Long serverId)
      Resolves the registration a user's account reads and pushes through: the row the account references when it references one and that row still exists, else the seed row, else null. This single resolution rule is shared by the URL resolution below and by the relay's authorization check — the relay refuses any target that is not the row this method answers for the user.
      Parameters:
      serverId - registration the user's account references, or null
      Returns:
      the resolved registration, or null when the registry answers nothing
    • resolveServerUrl

      public String resolveServerUrl(Long serverId)
      Resolves the CalDAV base URL a user's account reads and pushes through: the URL of the resolved registration, else null — the caller then falls back to the legacy configuration property, which is today's behaviour for deployments that never touched the registry.
      Parameters:
      serverId - registration the user's account references, or null
      Returns:
      the resolved base URL, or null when the registry answers nothing
    • canEdit

      public boolean canEdit(String username)
      Whether a user may edit the registry: platform administrators only. This is the same gate email-connector's admin registry uses (EmailConnectorService.canEdit), minus its blank-username-passes quirk — an anonymous caller is refused here.
      Parameters:
      username - user asking to write
      Returns:
      true when the user is a platform administrator