Class TxnId

java.lang.Object
org.jpos.transaction.TxnId

public class TxnId extends Object
Distributed transaction identifier intended to be used as an ISO-8583 Retrieval Reference Number (DE-037, RRN).

This class encodes a transaction timestamp (UTC, second precision), a node identifier, and a per-node transaction counter suffix into a single long. It supports:

  • A canonical numeric form (id()).
  • A stable human-readable form (toString()) suitable for logs and debugging.
  • A compact base-36 form (toRrn()) suitable for ISO-8583 field 37 (RRN).
  • A filesystem-friendly relative path (toFile()) that partitions by date/time.

RRN length constraint and long-term viability. ISO-8583 DE-037 limits the Retrieval Reference Number to 12 characters. When rendered in base 36, this implementation therefore enforces the numeric ceiling "zzzzzzzzzzzz" (base 36), exposed as MAX_VALUE, so that toRrn() always fits within 12 characters.

This ceiling is purely a numeric bound required for DE-037 compliance; it is not derived from the YYY-DDD-SSSSS-NNN-TTTTT field layout. Nevertheless, when TxnIds are created through create(ZonedDateTime, int, long), the encoded timestamp remains comfortably below this bound for several centuries.

In practice, the maximum semantically valid timestamp that can be encoded while still satisfying the DE-037 12-character constraint is 2473-12-31 23:59:59 UTC. This places the effective limit more than four centuries in the future, making the scheme safe for long-term production use.

Uniqueness model. The identifier is composed of:

  • YYY: years since 2000 (000..999).
  • DDD: day of year (001..366).
  • SSSSS: second of day (00000..86399).
  • NNN: node id (000..999).
  • TTTTT: last 5 digits of a per-node transaction counter (00000..99999).

Collisions are prevented as long as, for a given (UTC second, node), the TTTTT suffix is not reused.

Time semantics. All time components are encoded in UTC to avoid daylight-saving and timezone ambiguity. The timestamp component has second precision.

Query-range semantics. Because the numeric encoding is ordered by UTC time, callers can build inclusive numeric bounds for index range scans. For “between local dates” queries, this class provides DST-safe helpers that define a local day as the half-open interval [startOfDay(d), startOfDay(d+1)) in the requested zone and then converts that to an inclusive UTC-second range.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Inclusive numeric id range suitable for DB index range scans.
  • Method Summary

    Modifier and Type
    Method
    Description
    static TxnId
    create(Instant instant, int node, long transactionId)
    Creates a new TxnId from an Instant (assumed UTC), node, and transaction suffix.
    static TxnId
    create(ZonedDateTime zonedDateTime, int node, long transactionId)
    Creates a new TxnId from a timestamp, node, and transaction suffix.
    boolean
     
    static TxnId
    Parses a TxnId from an ISO-8583 DE-037 Retrieval Reference Number (RRN) in base 36.
    int
     
    long
    id()
    Returns the canonical numeric representation of this transaction id.
    idRange(Instant fromUtc, Instant toUtc)
    Computes an inclusive numeric id range for the given UTC instant range.
    idRange(LocalDate fromLocalDate, LocalDate toLocalDate, ZoneId zone)
    Computes an inclusive numeric id range for transactions between the given local dates, inclusive on both ends, in the provided time zone.
    idRange(LocalDateTime fromLocalDateTime, LocalDateTime toLocalDateTime, ZoneId zone)
    Inclusive range for local date-times in zone.
    Inclusive range for zoned date-times.
    static long
    lowerBoundId(Instant instantUtc)
    Computes the lowest possible TxnId numeric value for the given UTC second, suitable for an inclusive range lower bound.
    static long
    lowerBoundId(LocalDate localDate, ZoneId zone)
    Inclusive lower bound id for the start of the given local day in zone.
    static TxnId
    parse(long id)
    Parses a TxnId from its canonical numeric value.
    static TxnId
    parse(String idString)
    Parses a TxnId from its human-readable form YYY-DDD-SSSSS-NNN-TTTTT.
    Returns a relative file path suitable to store contents of this transaction.
    Returns a compact base-36 rendering of id() suitable for ISO-8583 DE-037 (RRN).
    Returns the human-readable form: YYY-DDD-SSSSS-NNN-TTTTT.
    static long
    upperBoundId(Instant instantUtc)
    Computes the highest possible TxnId numeric value for the given UTC second, suitable for an inclusive range upper bound.
    static long
    upperBoundId(LocalDate localDate, ZoneId zone)
    Inclusive upper bound id for the end of the given local day in zone.

    Methods inherited from class Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Method Details

    • id

      public long id()
      Returns the canonical numeric representation of this transaction id.

      Note: not all numeric values are necessarily a valid structured TxnId; use parse(String) when validation of the human-readable components is required.

      Returns:
      the packed long value.
    • toFile

      public File toFile()
      Returns a relative file path suitable to store contents of this transaction.

      Path format: yyyy/mm/dd/hh-mm-ss-NNN-TTTTT where:

      • yyyy/mm/dd is the UTC date derived from the encoded timestamp.
      • hh-mm-ss is the UTC time (second precision).
      • NNN is the node id (000..999).
      • TTTTT is the transaction suffix (00000..99999).
      Returns:
      a File with the above relative path.
    • toString

      public String toString()
      Returns the human-readable form: YYY-DDD-SSSSS-NNN-TTTTT.

      Where:

      • YYY: years since 2000 (000..999).
      • DDD: day of year (001..366).
      • SSSSS: second of day (00000..86399).
      • NNN: node id (000..999).
      • TTTTT: transaction suffix (00000..99999).
      Overrides:
      toString in class Object
      Returns:
      the formatted TxnId string.
    • toRrn

      public String toRrn()
      Returns a compact base-36 rendering of id() suitable for ISO-8583 DE-037 (RRN).

      The numeric value is constrained to MAX_VALUE so that the base-36 string fits within 12 characters.

      Returns:
      base-36 string representation of the TxnId.
    • equals

      public boolean equals(Object o)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • create

      public static TxnId create(ZonedDateTime zonedDateTime, int node, long transactionId)
      Creates a new TxnId from a timestamp, node, and transaction suffix.

      The timestamp is converted to UTC using ZonedDateTime.withZoneSameInstant(ZoneId) and then encoded at second precision.

      Parameters:
      zonedDateTime - transaction timestamp.
      node - node id (0..999). Values outside this range are wrapped using modulo 1000.
      transactionId - per-node transaction suffix (0..99999). Values outside this range are wrapped using modulo 100000.
      Returns:
      newly created TxnId.
    • create

      public static TxnId create(Instant instant, int node, long transactionId)
      Creates a new TxnId from an Instant (assumed UTC), node, and transaction suffix.
      Parameters:
      instant - transaction timestamp in UTC.
      node - node id (0..999).
      transactionId - per-node transaction suffix (0..99999).
      Returns:
      newly created TxnId.
    • parse

      public static TxnId parse(String idString)
      Parses a TxnId from its human-readable form YYY-DDD-SSSSS-NNN-TTTTT.
      Parameters:
      idString - TxnId in YYY-DDD-SSSSS-NNN-TTTTT format (as produced by toString()).
      Returns:
      newly created TxnId.
      Throws:
      IllegalArgumentException - if idString is invalid or out of range.
    • parse

      public static TxnId parse(long id)
      Parses a TxnId from its canonical numeric value.

      This validates only the numeric bound required for DE-037 usage (see MAX_VALUE). It does not validate that each encoded component is within expected ranges.

      Parameters:
      id - numeric value.
      Returns:
      newly created TxnId.
      Throws:
      IllegalArgumentException - if the value is negative or exceeds MAX_VALUE.
    • fromRrn

      public static TxnId fromRrn(String rrn)
      Parses a TxnId from an ISO-8583 DE-037 Retrieval Reference Number (RRN) in base 36.
      Parameters:
      rrn - base-36 value (must decode to a non-negative number not exceeding MAX_VALUE).
      Returns:
      newly created TxnId.
      Throws:
      IllegalArgumentException - if rrn is invalid or out of range.
    • lowerBoundId

      public static long lowerBoundId(Instant instantUtc)
      Computes the lowest possible TxnId numeric value for the given UTC second, suitable for an inclusive range lower bound.

      This uses node=000 and suffix=00000.

      Parameters:
      instantUtc - a timestamp whose Instant.getEpochSecond() is used.
      Returns:
      inclusive lower bound id.
    • upperBoundId

      public static long upperBoundId(Instant instantUtc)
      Computes the highest possible TxnId numeric value for the given UTC second, suitable for an inclusive range upper bound.

      This uses node=999 and suffix=99999.

      Parameters:
      instantUtc - a timestamp whose Instant.getEpochSecond() is used.
      Returns:
      inclusive upper bound id.
    • idRange

      public static TxnId.TxnIdRange idRange(Instant fromUtc, Instant toUtc)
      Computes an inclusive numeric id range for the given UTC instant range.

      Both ends are treated as inclusive at second precision. Any sub-second component is ignored.

      Parameters:
      fromUtc - inclusive lower endpoint (UTC).
      toUtc - inclusive upper endpoint (UTC).
      Returns:
      inclusive numeric id range; may be empty.
    • idRange

      public static TxnId.TxnIdRange idRange(LocalDate fromLocalDate, LocalDate toLocalDate, ZoneId zone)
      Computes an inclusive numeric id range for transactions between the given local dates, inclusive on both ends, in the provided time zone.

      DST-safe strategy: define each local day as the half-open interval [startOfDay(d), startOfDay(d+1)) in zone. This avoids constructing local “end of day” timestamps (which can be ambiguous on overlap days). The resulting UTC range is then made inclusive at second precision by subtracting one second from the exclusive end.

      Parameters:
      fromLocalDate - inclusive start date in zone.
      toLocalDate - inclusive end date in zone.
      zone - time zone for interpreting local dates.
      Returns:
      inclusive numeric id range; may be empty.
    • lowerBoundId

      public static long lowerBoundId(LocalDate localDate, ZoneId zone)
      Inclusive lower bound id for the start of the given local day in zone.
      Parameters:
      localDate - local date.
      zone - zone in which the local day is defined.
      Returns:
      inclusive lower bound id.
    • upperBoundId

      public static long upperBoundId(LocalDate localDate, ZoneId zone)
      Inclusive upper bound id for the end of the given local day in zone.

      DST-safe: computed as one second before startOfDay(localDate+1) in zone.

      Parameters:
      localDate - local date.
      zone - zone in which the local day is defined.
      Returns:
      inclusive upper bound id.
    • idRange

      public static TxnId.TxnIdRange idRange(LocalDateTime fromLocalDateTime, LocalDateTime toLocalDateTime, ZoneId zone)
      Inclusive range for local date-times in zone.

      Note: this method interprets fromLocalDateTime and toLocalDateTime as local wall-clock times in zone. For DST gaps/overlaps, ZonedDateTime.of(LocalDateTime, ZoneId) applies the zone rules. If you need explicit overlap resolution (earlier vs later offset), pass ZonedDateTime values instead and use idRange(Instant, Instant) or idRange(ZonedDateTime, ZonedDateTime).

      Parameters:
      fromLocalDateTime - inclusive start time in zone.
      toLocalDateTime - inclusive end time in zone.
      zone - zone for interpreting local date-times.
      Returns:
      inclusive numeric id range; may be empty.
    • idRange

      Inclusive range for zoned date-times.
      Parameters:
      from - inclusive start time.
      to - inclusive end time.
      Returns:
      inclusive numeric id range; may be empty.