Interface CalendarSubscriptionDAO

All Superinterfaces:
org.springframework.data.repository.CrudRepository<CalendarSubscriptionEntity,Long>, org.springframework.data.jpa.repository.JpaRepository<CalendarSubscriptionEntity,Long>, org.springframework.data.repository.ListCrudRepository<CalendarSubscriptionEntity,Long>, org.springframework.data.repository.ListPagingAndSortingRepository<CalendarSubscriptionEntity,Long>, org.springframework.data.repository.PagingAndSortingRepository<CalendarSubscriptionEntity,Long>, org.springframework.data.repository.query.QueryByExampleExecutor<CalendarSubscriptionEntity>, org.springframework.data.repository.Repository<CalendarSubscriptionEntity,Long>

public interface CalendarSubscriptionDAO extends org.springframework.data.jpa.repository.JpaRepository<CalendarSubscriptionEntity,Long>
Reads and writes calendar subscriptions (EXO-90278).

The refresh job runs on every node of a cluster, so the rows it works on are shared between nodes, and its writes carry their correctness in their WHERE clause, as email-connector's EmailSyncStateDAO does: a claim lands only on a due row nobody holds — or whose holder's claim went stale — and the row count it returns is the answer; an outcome is recorded, and a claim released, only by the node holding it.

  • Method Summary

    Modifier and Type
    Method
    Description
    int
    claim(long id, String node, Date now, Date staleBefore)
    The owner's claim, for a refresh asked now: the same as the job's, due or not.
    int
    claimDue(long id, String node, Date now, Date staleBefore)
    The job's claim: lands only on a subscription still due and held by nobody live, so of every node trying at once exactly one sees a row count of one.
    findByCalendarId(long calendarId)
    Finds the subscription of a calendar.
    Finds the subscription of a user to a URL.
    findByUserIdentityId(long userIdentityId, org.springframework.data.domain.Pageable pageable)
    Finds a user's subscriptions.
    findDueIds(Date now, Date staleBefore, org.springframework.data.domain.Pageable pageable)
    The subscriptions due for a refresh that nobody holds a live claim on, the one waiting longest first.
    int
    recordFailure(long id, String node, Date attempt, String lastError, Date nextRefreshDate)
    Records a failed refresh and releases the claim, only by the node holding it.
    int
    recordSuccess(long id, String node, String urlKey, String etag, String lastModified, String contentHash, Integer refreshMinutes, Date attempt, boolean truncated, Date nextRefreshDate)
    Records a successful refresh and releases the claim — only by the node that holds it, and only while the subscription still points at the URL that was read: an edit of the URL during the refresh leaves the row to the next one.
    int
    release(long id, String node)
    Releases a claim without recording anything, only by the node holding it.
    int
    updateUrl(long id, String urlEncrypted, String urlKey, Date now)
    Points a subscription at a new URL and makes it due at once, forgetting the validators and the digest of the previous URL.

    Methods inherited from interface org.springframework.data.repository.CrudRepository

    count, delete, deleteAll, deleteAll, deleteAllById, deleteById, existsById, findById, save

    Methods inherited from interface org.springframework.data.jpa.repository.JpaRepository

    deleteAllByIdInBatch, deleteAllInBatch, deleteAllInBatch, deleteInBatch, findAll, findAll, flush, getById, getOne, getReferenceById, saveAllAndFlush, saveAndFlush

    Methods inherited from interface org.springframework.data.repository.ListCrudRepository

    findAll, findAllById, saveAll

    Methods inherited from interface org.springframework.data.repository.ListPagingAndSortingRepository

    findAll

    Methods inherited from interface org.springframework.data.repository.PagingAndSortingRepository

    findAll

    Methods inherited from interface org.springframework.data.repository.query.QueryByExampleExecutor

    count, exists, findAll, findBy, findOne
  • Method Details

    • findByCalendarId

      CalendarSubscriptionEntity findByCalendarId(long calendarId)
      Finds the subscription of a calendar.
      Parameters:
      calendarId - technical identifier of the calendar
      Returns:
      the subscription, or null when the calendar has none
    • findByUrlKey

      CalendarSubscriptionEntity findByUrlKey(String urlKey)
      Finds the subscription of a user to a URL.
      Parameters:
      urlKey - SHA-256 of the user and the normalized URL
      Returns:
      the subscription, or null when none
    • findByUserIdentityId

      List<CalendarSubscriptionEntity> findByUserIdentityId(long userIdentityId, org.springframework.data.domain.Pageable pageable)
      Finds a user's subscriptions.
      Parameters:
      userIdentityId - identity identifier of the user
      pageable - the page, whose sort orders them
      Returns:
      the subscriptions, never null
    • findDueIds

      @Query("SELECT s.id FROM AgendaCalendarSubscription s WHERE s.nextRefreshDate <= :now AND (s.claimedDate IS NULL OR s.claimedDate < :staleBefore) ORDER BY s.nextRefreshDate ASC, s.id ASC") List<Long> findDueIds(@Param("now") Date now, @Param("staleBefore") Date staleBefore, org.springframework.data.domain.Pageable pageable)
      The subscriptions due for a refresh that nobody holds a live claim on, the one waiting longest first.
      Parameters:
      now - a subscription whose next refresh is at or before this instant is due
      staleBefore - a claim taken strictly before this instant no longer counts
      pageable - the batch
      Returns:
      technical identifiers of the due subscriptions
    • claimDue

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.claimedBy = :node, s.claimedDate = :now WHERE s.id = :id AND s.nextRefreshDate <= :now AND (s.claimedDate IS NULL OR s.claimedDate < :staleBefore)") int claimDue(@Param("id") long id, @Param("node") String node, @Param("now") Date now, @Param("staleBefore") Date staleBefore)
      The job's claim: lands only on a subscription still due and held by nobody live, so of every node trying at once exactly one sees a row count of one.
      Parameters:
      id - technical identifier of the subscription
      node - the claiming node
      now - the claim's stamp; the row must be due at this instant
      staleBefore - a claim taken strictly before this instant may be taken over
      Returns:
      one when the caller now holds the claim, zero otherwise
    • claim

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.claimedBy = :node, s.claimedDate = :now WHERE s.id = :id AND (s.claimedDate IS NULL OR s.claimedDate < :staleBefore)") int claim(@Param("id") long id, @Param("node") String node, @Param("now") Date now, @Param("staleBefore") Date staleBefore)
      The owner's claim, for a refresh asked now: the same as the job's, due or not.
      Parameters:
      id - technical identifier of the subscription
      node - the claiming node
      now - the claim's stamp
      staleBefore - a claim taken strictly before this instant may be taken over
      Returns:
      one when the caller now holds the claim, zero otherwise
    • recordSuccess

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.etag = :etag, s.lastModified = :lastModified, s.contentHash = :contentHash, s.refreshMinutes = :refreshMinutes, s.lastSuccessDate = :attempt, s.lastAttemptDate = :attempt, s.lastError = NULL, s.truncated = :truncated, s.nextRefreshDate = :nextRefreshDate, s.claimedBy = NULL, s.claimedDate = NULL WHERE s.id = :id AND s.claimedBy = :node AND s.urlKey = :urlKey") int recordSuccess(@Param("id") long id, @Param("node") String node, @Param("urlKey") String urlKey, @Param("etag") String etag, @Param("lastModified") String lastModified, @Param("contentHash") String contentHash, @Param("refreshMinutes") Integer refreshMinutes, @Param("attempt") Date attempt, @Param("truncated") boolean truncated, @Param("nextRefreshDate") Date nextRefreshDate)
      Records a successful refresh and releases the claim — only by the node that holds it, and only while the subscription still points at the URL that was read: an edit of the URL during the refresh leaves the row to the next one.
      Parameters:
      id - technical identifier of the subscription
      node - the node holding the claim
      urlKey - the key of the URL that was read
      etag - the entity tag read
      lastModified - the Last-Modified header read
      contentHash - digest of the body imported
      refreshMinutes - refresh interval the feed advertised, null for none
      attempt - when the refresh ran
      truncated - whether only part of the feed was imported
      nextRefreshDate - when the next refresh is due
      Returns:
      one when recorded, zero otherwise
    • recordFailure

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.lastAttemptDate = :attempt, s.lastError = :lastError, s.nextRefreshDate = :nextRefreshDate, s.claimedBy = NULL, s.claimedDate = NULL WHERE s.id = :id AND s.claimedBy = :node") int recordFailure(@Param("id") long id, @Param("node") String node, @Param("attempt") Date attempt, @Param("lastError") String lastError, @Param("nextRefreshDate") Date nextRefreshDate)
      Records a failed refresh and releases the claim, only by the node holding it. The last good copy, its validators and its digest are left as they were.
      Parameters:
      id - technical identifier of the subscription
      node - the node holding the claim
      attempt - when the refresh ran
      lastError - message code of the failure
      nextRefreshDate - when the next attempt is due
      Returns:
      one when recorded, zero otherwise
    • release

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.claimedBy = NULL, s.claimedDate = NULL WHERE s.id = :id AND s.claimedBy = :node") int release(@Param("id") long id, @Param("node") String node)
      Releases a claim without recording anything, only by the node holding it.
      Parameters:
      id - technical identifier of the subscription
      node - the node holding the claim
      Returns:
      one when released, zero otherwise
    • updateUrl

      @Transactional @Modifying(clearAutomatically=true, flushAutomatically=true) @Query("UPDATE AgendaCalendarSubscription s SET s.urlEncrypted = :urlEncrypted, s.urlKey = :urlKey, s.etag = NULL, s.lastModified = NULL, s.contentHash = NULL, s.nextRefreshDate = :now WHERE s.id = :id") int updateUrl(@Param("id") long id, @Param("urlEncrypted") String urlEncrypted, @Param("urlKey") String urlKey, @Param("now") Date now)
      Points a subscription at a new URL and makes it due at once, forgetting the validators and the digest of the previous URL.
      Parameters:
      id - technical identifier of the subscription
      urlEncrypted - the new URL encrypted
      urlKey - the key of the new URL
      now - the instant it becomes due
      Returns:
      one when the row exists, zero otherwise