java.lang.Object
dk.cloudcreate.essentials.components.queue.postgresql.PostgresqlDurableQueues
All Implemented Interfaces:
dk.cloudcreate.essentials.components.foundation.Lifecycle, dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues, dk.cloudcreate.essentials.shared.Lifecycle

public final class PostgresqlDurableQueues extends Object implements dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
Postgresql version of the DurableQueues concept.
Works together with UnitOfWorkFactory in order to support queuing message together with business logic (such as failing to handle an Event, etc.)

Security
DurableQueues allows the user of the component to override the getSharedQueueTableName(), which is the name of the table that will contain all messages (across all QueueName's)
Note:
To support customization of storage table name, the sharedQueueTableName will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.

Security Note:
It is the responsibility of the user of this component to sanitize the sharedQueueTableName to ensure the security of all the SQL statements generated by this component.
The PostgresqlDurableQueues component will call the PostgresqlUtil.checkIsValidTableOrColumnName(String) method to validate the table name as a first line of defense.
The PostgresqlUtil.checkIsValidTableOrColumnName(String) provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
However, Essentials components as well as PostgresqlUtil.checkIsValidTableOrColumnName(String) does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.
The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.

It is highly recommended that the sharedQueueTableName value is only derived from a controlled and trusted source.
To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide the sharedQueueTableName value.
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    protected static enum 
     
    static class 
     

    Nested classes/interfaces inherited from interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues

    dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues.QueueingSortOrder
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
     
    protected ConcurrentMap<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName,Instant>
    Contains the timestamp of the last performed resetMessagesStuckBeingDelivered(QueueName) check
    Only used if transactionalMode has value TransactionalMode.SingleOperationTransaction
  • Constructor Summary

    Constructors
    Constructor
    Description
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory)
    Create DurableQueues with sharedQueueTableName: "durable_queues" and the default JacksonJSONSerializer using createDefaultObjectMapper() configuration
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer)
    Create DurableQueues with custom jsonSerializer with sharedQueueTableName: "durable_queues"
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, String sharedQueueTableName, dk.cloudcreate.essentials.components.foundation.postgresql.MultiTableChangeListener<dk.cloudcreate.essentials.components.foundation.postgresql.TableChangeNotification> multiTableChangeListener, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
    Create DurableQueues with custom jsonSerializer and sharedQueueTableName
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, String sharedQueueTableName, dk.cloudcreate.essentials.components.foundation.postgresql.MultiTableChangeListener<dk.cloudcreate.essentials.components.foundation.postgresql.TableChangeNotification> multiTableChangeListener, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory, dk.cloudcreate.essentials.components.foundation.messaging.queue.TransactionalMode transactionalMode, Duration messageHandlingTimeout)
    Create DurableQueues with custom jsonSerializer and sharedQueueTableName
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
    Create DurableQueues with custom jsonSerializer with sharedQueueTableName: "durable_queues"
    PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
    Create DurableQueues with sharedQueueTableName: "durable_queues" and the default JacksonJSONSerializer using createDefaultObjectMapper() configuration
  • Method Summary

    Modifier and Type
    Method
    Description
    final boolean
    acknowledgeMessageAsHandled(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.AcknowledgeMessageAsHandled operation)
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    addInterceptor(dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor interceptor)
     
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer
    consumeFromQueue(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue operation)
     
    static com.fasterxml.jackson.databind.ObjectMapper
    Default ObjectMapper supporting Jdk8Module, JavaTimeModule, EssentialTypesJacksonModule and EssentialsImmutableJacksonModule, which is used together with the JacksonJSONSerializer
    protected dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer
    createQueuePollingOptimizerFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue operation)
    Override this method to provide another QueuePollingOptimizer than the default QueuePollingOptimizer.SimpleQueuePollingOptimizer
    Only called if the PostgresqlDurableQueues is configured with a MultiTableChangeListener
    final boolean
    deleteMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.DeleteMessage operation)
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    getDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetDeadLetterMessage operation)
     
    final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    getDeadLetterMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetDeadLetterMessages operation)
     
    final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor>
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    getNextMessageReadyForDelivery(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetNextMessageReadyForDelivery operation)
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    getQueuedMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessage operation)
     
    dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessageCounts
    getQueuedMessageCountsFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessageCountsFor operation)
     
    final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    getQueuedMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessages operation)
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName>
    getQueueNameFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId queueEntryId)
     
    final Set<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName>
     
    final String
    The name of the shared table where all queue messages are stored
    final long
    getTotalDeadLetterMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetTotalDeadLetterMessagesQueuedFor operation)
     
    final long
    getTotalMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetTotalMessagesQueuedFor operation)
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.TransactionalMode
     
    final Optional<dk.cloudcreate.essentials.components.foundation.transaction.UnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.UnitOfWork>>
     
    final boolean
    hasMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName)
     
    final boolean
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    markAsDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.MarkAsDeadLetterMessage operation)
     
    final int
    purgeQueue(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.PurgeQueue operation)
     
    final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.NextQueuedMessage>
    queryForMessagesSoonReadyForDelivery(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, Instant withNextDeliveryTimestampAfter, int maxNumberOfMessagesToReturn)
     
    protected final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    queryQueuedMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues.QueueingSortOrder queueingSortOrder, PostgresqlDurableQueues.IncludeMessages includeMessages, long startIndex, long pageSize)
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId
    queueMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessage operation)
     
    protected final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId
    queueMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, dk.cloudcreate.essentials.components.foundation.messaging.queue.Message message, boolean isDeadLetterMessage, Optional<Exception> causeOfEnqueuing, Optional<Duration> deliveryDelay)
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId
    queueMessageAsDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessageAsDeadLetterMessage operation)
     
    final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId>
    queueMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessages operation)
     
    final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    removeInterceptor(dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor interceptor)
     
    protected final void
    resetMessagesStuckBeingDelivered(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName)
    This operation will scan for messages that has been marked as QueuedMessage.isBeingDelivered() for longer than messageHandlingTimeoutMs
    All messages found will have QueuedMessage.isBeingDelivered() and QueuedMessage.getDeliveryTimestamp() reset
    Only relevant for when using TransactionalMode.SingleOperationTransaction
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    resurrectDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ResurrectDeadLetterMessage operation)
     
    final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage>
    retryMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.RetryMessage operation)
     
    final void
     
    final void
     

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

    Methods inherited from interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues

    acknowledgeMessageAsHandled, addInterceptors, consumeFromQueue, consumeFromQueue, deleteMessage, getDeadLetterMessage, getDeadLetterMessages, getNextMessageReadyForDelivery, getQueuedMessage, getQueuedMessageCountsFor, getQueuedMessages, getTotalDeadLetterMessagesQueuedFor, getTotalMessagesQueuedFor, markAsDeadLetterMessage, markAsDeadLetterMessage, markAsDeadLetterMessage, purgeQueue, queryForMessagesSoonReadyForDelivery, queueMessage, queueMessage, queueMessage, queueMessage, queueMessage, queueMessageAsDeadLetterMessage, queueMessages, queueMessages, queueMessages, resurrectDeadLetterMessage, retryMessage
  • Field Details

    • DEFAULT_DURABLE_QUEUES_TABLE_NAME

      public static final String DEFAULT_DURABLE_QUEUES_TABLE_NAME
      See Also:
    • lastResetStuckMessagesCheckTimestamps

      protected ConcurrentMap<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName,Instant> lastResetStuckMessagesCheckTimestamps
      Contains the timestamp of the last performed resetMessagesStuckBeingDelivered(QueueName) check
      Only used if transactionalMode has value TransactionalMode.SingleOperationTransaction
  • Constructor Details

    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory)
      Create DurableQueues with sharedQueueTableName: "durable_queues" and the default JacksonJSONSerializer using createDefaultObjectMapper() configuration
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
      Create DurableQueues with sharedQueueTableName: "durable_queues" and the default JacksonJSONSerializer using createDefaultObjectMapper() configuration
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
      queuePollingOptimizerFactory - optional QueuePollingOptimizer factory that creates a QueuePollingOptimizer per ConsumeFromQueue command - if set to null createQueuePollingOptimizerFor(ConsumeFromQueue) is used instead
    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer)
      Create DurableQueues with custom jsonSerializer with sharedQueueTableName: "durable_queues"
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
      jsonSerializer - the JSONSerializer that is used to serialize/deserialize message payloads
    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
      Create DurableQueues with custom jsonSerializer with sharedQueueTableName: "durable_queues"
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
      jsonSerializer - the JSONSerializer that is used to serialize/deserialize message payloads
      queuePollingOptimizerFactory - optional QueuePollingOptimizer factory that creates a QueuePollingOptimizer per ConsumeFromQueue command - if set to null createQueuePollingOptimizerFor(ConsumeFromQueue) is used instead
    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, String sharedQueueTableName, dk.cloudcreate.essentials.components.foundation.postgresql.MultiTableChangeListener<dk.cloudcreate.essentials.components.foundation.postgresql.TableChangeNotification> multiTableChangeListener, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory)
      Create DurableQueues with custom jsonSerializer and sharedQueueTableName
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
      jsonSerializer - the JSONSerializer that is used to serialize/deserialize message payloads
      sharedQueueTableName - the name of the table that will contain all messages (across all QueueName's)
      Note:
      To support customization of storage table name, the sharedQueueTableName will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.

      Security Note:
      It is the responsibility of the user of this component to sanitize the sharedQueueTableName to ensure the security of all the SQL statements generated by this component.
      The PostgresqlDurableQueues component will call the PostgresqlUtil.checkIsValidTableOrColumnName(String) method to validate the table name as a first line of defense.
      The PostgresqlUtil.checkIsValidTableOrColumnName(String) provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
      However, Essentials components as well as PostgresqlUtil.checkIsValidTableOrColumnName(String) does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
      The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
      Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
      Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.

      It is highly recommended that the sharedQueueTableName value is only derived from a controlled and trusted source.
      To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide the sharedQueueTableName value.
      multiTableChangeListener - optional MultiTableChangeListener that allows PostgresqlDurableQueues to use QueuePollingOptimizer
      queuePollingOptimizerFactory - optional QueuePollingOptimizer factory that creates a QueuePollingOptimizer per ConsumeFromQueue command - if set to null createQueuePollingOptimizerFor(ConsumeFromQueue) is used instead
    • PostgresqlDurableQueues

      public PostgresqlDurableQueues(dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.jdbi.HandleAwareUnitOfWork> unitOfWorkFactory, dk.cloudcreate.essentials.components.foundation.json.JSONSerializer jsonSerializer, String sharedQueueTableName, dk.cloudcreate.essentials.components.foundation.postgresql.MultiTableChangeListener<dk.cloudcreate.essentials.components.foundation.postgresql.TableChangeNotification> multiTableChangeListener, Function<dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue,dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer> queuePollingOptimizerFactory, dk.cloudcreate.essentials.components.foundation.messaging.queue.TransactionalMode transactionalMode, Duration messageHandlingTimeout)
      Create DurableQueues with custom jsonSerializer and sharedQueueTableName
      Parameters:
      unitOfWorkFactory - the UnitOfWorkFactory needed to access the database
      jsonSerializer - the JSONSerializer that is used to serialize/deserialize message payloads
      sharedQueueTableName - the name of the table that will contain all messages (across all QueueName's)
      Note:
      To support customization of storage table name, the sharedQueueTableName will be directly used in constructing SQL statements through string concatenation, which exposes the component to SQL injection attacks.

      Security Note:
      It is the responsibility of the user of this component to sanitize the sharedQueueTableName to ensure the security of all the SQL statements generated by this component.
      The PostgresqlDurableQueues component will call the PostgresqlUtil.checkIsValidTableOrColumnName(String) method to validate the table name as a first line of defense.
      The PostgresqlUtil.checkIsValidTableOrColumnName(String) provides an initial layer of defense against SQL injection by applying naming conventions intended to reduce the risk of malicious input.
      However, Essentials components as well as PostgresqlUtil.checkIsValidTableOrColumnName(String) does not offer exhaustive protection, nor does it assure the complete security of the resulting SQL against SQL injection threats.
      The responsibility for implementing protective measures against SQL Injection lies exclusively with the users/developers using the Essentials components and its supporting classes.
      Users must ensure thorough sanitization and validation of API input parameters, column, table, and index names.
      Insufficient attention to these practices may leave the application vulnerable to SQL injection, potentially endangering the security and integrity of the database.

      It is highly recommended that the sharedQueueTableName value is only derived from a controlled and trusted source.
      To mitigate the risk of SQL injection attacks, external or untrusted inputs should never directly provide the sharedQueueTableName value.
      multiTableChangeListener - optional MultiTableChangeListener that allows PostgresqlDurableQueues to use QueuePollingOptimizer
      queuePollingOptimizerFactory - optional QueuePollingOptimizer factory that creates a QueuePollingOptimizer per ConsumeFromQueue command - if set to null createQueuePollingOptimizerFor(ConsumeFromQueue) is used instead
      transactionalMode - The TransactionalMode for this DurableQueues instance. If set to TransactionalMode.SingleOperationTransaction then the consumer MUST call the DurableQueues.acknowledgeMessageAsHandled(AcknowledgeMessageAsHandled) explicitly in a new UnitOfWork
      messageHandlingTimeout - Only required if transactionalMode is TransactionalMode.SingleOperationTransaction.
      The parameter defines the timeout for messages being delivered, but haven't yet been acknowledged. After this timeout the message delivery will be reset and the message will again be a candidate for delivery
  • Method Details

    • builder

      public static PostgresqlDurableQueuesBuilder builder()
    • getSharedQueueTableName

      public final String getSharedQueueTableName()
      The name of the shared table where all queue messages are stored
      Returns:
      the name of the shared table where all queue messages are stored
    • getInterceptors

      public final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor> getInterceptors()
    • start

      public final void start()
      Specified by:
      start in interface dk.cloudcreate.essentials.shared.Lifecycle
    • stop

      public final void stop()
      Specified by:
      stop in interface dk.cloudcreate.essentials.shared.Lifecycle
    • isStarted

      public final boolean isStarted()
      Specified by:
      isStarted in interface dk.cloudcreate.essentials.shared.Lifecycle
    • getTransactionalMode

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.TransactionalMode getTransactionalMode()
      Specified by:
      getTransactionalMode in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getUnitOfWorkFactory

      public final Optional<dk.cloudcreate.essentials.components.foundation.transaction.UnitOfWorkFactory<? extends dk.cloudcreate.essentials.components.foundation.transaction.UnitOfWork>> getUnitOfWorkFactory()
      Specified by:
      getUnitOfWorkFactory in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getQueueNames

      public final Set<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName> getQueueNames()
      Specified by:
      getQueueNames in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • consumeFromQueue

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueueConsumer consumeFromQueue(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue operation)
      Specified by:
      consumeFromQueue in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • createQueuePollingOptimizerFor

      protected dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuePollingOptimizer createQueuePollingOptimizerFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ConsumeFromQueue operation)
      Override this method to provide another QueuePollingOptimizer than the default QueuePollingOptimizer.SimpleQueuePollingOptimizer
      Only called if the PostgresqlDurableQueues is configured with a MultiTableChangeListener
      Parameters:
      operation - the operation for which the QueuePollingOptimizer will be responsible
      Returns:
      the QueuePollingOptimizer
    • queueMessage

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId queueMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessage operation)
      Specified by:
      queueMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • queueMessageAsDeadLetterMessage

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId queueMessageAsDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessageAsDeadLetterMessage operation)
      Specified by:
      queueMessageAsDeadLetterMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • queueMessage

      protected final dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId queueMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, dk.cloudcreate.essentials.components.foundation.messaging.queue.Message message, boolean isDeadLetterMessage, Optional<Exception> causeOfEnqueuing, Optional<Duration> deliveryDelay)
    • queueMessages

      public final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId> queueMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.QueueMessages operation)
      Specified by:
      queueMessages in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • retryMessage

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> retryMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.RetryMessage operation)
      Specified by:
      retryMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • markAsDeadLetterMessage

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> markAsDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.MarkAsDeadLetterMessage operation)
      Specified by:
      markAsDeadLetterMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • resurrectDeadLetterMessage

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> resurrectDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.ResurrectDeadLetterMessage operation)
      Specified by:
      resurrectDeadLetterMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • acknowledgeMessageAsHandled

      public final boolean acknowledgeMessageAsHandled(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.AcknowledgeMessageAsHandled operation)
      Specified by:
      acknowledgeMessageAsHandled in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • deleteMessage

      public final boolean deleteMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.DeleteMessage operation)
      Specified by:
      deleteMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getNextMessageReadyForDelivery

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> getNextMessageReadyForDelivery(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetNextMessageReadyForDelivery operation)
      Specified by:
      getNextMessageReadyForDelivery in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • resetMessagesStuckBeingDelivered

      protected final void resetMessagesStuckBeingDelivered(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName)
      This operation will scan for messages that has been marked as QueuedMessage.isBeingDelivered() for longer than messageHandlingTimeoutMs
      All messages found will have QueuedMessage.isBeingDelivered() and QueuedMessage.getDeliveryTimestamp() reset
      Only relevant for when using TransactionalMode.SingleOperationTransaction
      Parameters:
      queueName - the queue for which we're looking for messages stuck being marked as QueuedMessage.isBeingDelivered()
    • hasMessagesQueuedFor

      public final boolean hasMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName)
      Specified by:
      hasMessagesQueuedFor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getTotalMessagesQueuedFor

      public final long getTotalMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetTotalMessagesQueuedFor operation)
      Specified by:
      getTotalMessagesQueuedFor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getQueuedMessageCountsFor

      public dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessageCounts getQueuedMessageCountsFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessageCountsFor operation)
      Specified by:
      getQueuedMessageCountsFor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getTotalDeadLetterMessagesQueuedFor

      public final long getTotalDeadLetterMessagesQueuedFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetTotalDeadLetterMessagesQueuedFor operation)
      Specified by:
      getTotalDeadLetterMessagesQueuedFor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • purgeQueue

      public final int purgeQueue(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.PurgeQueue operation)
      Specified by:
      purgeQueue in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • queryForMessagesSoonReadyForDelivery

      public final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.NextQueuedMessage> queryForMessagesSoonReadyForDelivery(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, Instant withNextDeliveryTimestampAfter, int maxNumberOfMessagesToReturn)
      Specified by:
      queryForMessagesSoonReadyForDelivery in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getQueuedMessages

      public final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> getQueuedMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessages operation)
      Specified by:
      getQueuedMessages in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getDeadLetterMessages

      public final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> getDeadLetterMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetDeadLetterMessages operation)
      Specified by:
      getDeadLetterMessages in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • queryQueuedMessages

      protected final List<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> queryQueuedMessages(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName queueName, dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues.QueueingSortOrder queueingSortOrder, PostgresqlDurableQueues.IncludeMessages includeMessages, long startIndex, long pageSize)
    • addInterceptor

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues addInterceptor(dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor interceptor)
      Specified by:
      addInterceptor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • removeInterceptor

      public final dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues removeInterceptor(dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueuesInterceptor interceptor)
      Specified by:
      removeInterceptor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getQueueNameFor

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueName> getQueueNameFor(dk.cloudcreate.essentials.components.foundation.messaging.queue.QueueEntryId queueEntryId)
      Specified by:
      getQueueNameFor in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getDeadLetterMessage

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> getDeadLetterMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetDeadLetterMessage operation)
      Specified by:
      getDeadLetterMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • getQueuedMessage

      public final Optional<dk.cloudcreate.essentials.components.foundation.messaging.queue.QueuedMessage> getQueuedMessage(dk.cloudcreate.essentials.components.foundation.messaging.queue.operations.GetQueuedMessage operation)
      Specified by:
      getQueuedMessage in interface dk.cloudcreate.essentials.components.foundation.messaging.queue.DurableQueues
    • createDefaultObjectMapper

      public static com.fasterxml.jackson.databind.ObjectMapper createDefaultObjectMapper()
      Default ObjectMapper supporting Jdk8Module, JavaTimeModule, EssentialTypesJacksonModule and EssentialsImmutableJacksonModule, which is used together with the JacksonJSONSerializer
      Returns:
      the default ObjectMapper