WorkflowOutboxMessage.java

package org.hammer.audio.workflow.collaboration.outbox;

import java.time.Instant;
import java.util.Objects;
import org.hammer.audio.workflow.collaboration.store.StoredWorkflowOutboxEntry;

/**
 * Transport-neutral envelope published from one committed durable outbox row.
 *
 * @param eventId stable transport idempotency key
 * @param sessionId owning collaboration session
 * @param sequence durable session event sequence
 * @param revision semantic workflow revision
 * @param eventType stable event type
 * @param occurredAt original transaction event time
 * @param payload deterministic serialized payload
 */
public record WorkflowOutboxMessage(
    String eventId,
    String sessionId,
    long sequence,
    long revision,
    String eventType,
    Instant occurredAt,
    String payload) {

  public WorkflowOutboxMessage {
    eventId = requireNotBlank(eventId, "eventId");
    sessionId = requireNotBlank(sessionId, "sessionId");
    if (sequence <= 0 || revision <= 0) {
      throw new IllegalArgumentException("sequence and revision must be > 0");
    }
    eventType = requireNotBlank(eventType, "eventType");
    Objects.requireNonNull(occurredAt, "occurredAt");
    payload = requireNotBlank(payload, "payload");
  }

  /** Creates a publication envelope without exposing lease or retry metadata. */
  public static WorkflowOutboxMessage from(StoredWorkflowOutboxEntry entry) {
    StoredWorkflowOutboxEntry requiredEntry = Objects.requireNonNull(entry, "entry");
    return new WorkflowOutboxMessage(
        requiredEntry.eventId(),
        requiredEntry.sessionId(),
        requiredEntry.sequence(),
        requiredEntry.revision(),
        requiredEntry.eventType(),
        requiredEntry.occurredAt(),
        requiredEntry.payload());
  }

  private static String requireNotBlank(String value, String name) {
    Objects.requireNonNull(value, name);
    if (value.isBlank()) {
      throw new IllegalArgumentException(name + " must not be blank");
    }
    return value;
  }
}