All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.projecthusky.communication.utils.Traceparent Maven / Gradle / Ivy

There is a newer version: 3.0.2
Show newest version
package org.projecthusky.communication.utils;

import java.util.Objects;
import java.util.random.RandomGenerator;

/**
 * A class representing a traceparent.
 * 

* The traceId value is managed in the same way as {@link java.util.UUID}. * * @see Trace Context * @author Quentin Ligier */ public class Traceparent { /** * The version of the traceparent. 8-bit unsigned integer. Version ff is invalid. */ private final byte version; /** * The trace id. Split in two longs. 16-byte unsigned integer. */ private final long traceIdMostSigBits; private final long traceIdLeastSigBits; /** * The parent id. 8-byte unsigned integer. */ private final long parentId; /** * The flags. 8-bit unsigned integer. */ private final byte flags; /** * Creates a new traceparent. * * @param version The version of the traceparent. 8-bit unsigned integer. Version ff is invalid. * @param traceIdMostSigBits The most significant bits of the traceId. 8-byte unsigned integer. * @param traceIdLeastSigBits The least significant bits of the traceId. 8-byte unsigned integer. * @param parentId The parent id. 8-byte unsigned integer. * @param flags The flags. 8-bit unsigned integer. */ public Traceparent(byte version, long traceIdMostSigBits, long traceIdLeastSigBits, long parentId, byte flags) { this.version = version; this.traceIdMostSigBits = traceIdMostSigBits; this.traceIdLeastSigBits = traceIdLeastSigBits; this.parentId = parentId; this.flags = flags; if (version == (byte) 255) { throw new IllegalArgumentException("Version ff is invalid"); } } /** * Generates a random traceparent, with version 0 and flags 0. */ public static Traceparent random() { final var random = RandomGenerator.getDefault(); return new Traceparent((byte) 0, random.nextLong(), random.nextLong(), random.nextLong(), (byte) 0); } /** * Parses a traceparent from a string. */ public static Traceparent parse(final String value) { final String[] parts = value.split("-"); if (parts.length != 4) { throw new IllegalArgumentException("Invalid traceparent format"); } if (!isLowercaseHex(parts[0], 2)) { throw new IllegalArgumentException("The traceparent version shall be a two characters string"); } final byte version = (byte)Integer.parseInt(parts[0], 16); if (!isLowercaseHex(parts[1], 32)) { throw new IllegalArgumentException("The traceparent traceId shall be a 32 characters string"); } final long traceIdMostSigBits = Long.parseUnsignedLong(parts[1].substring(0, 16), 16); final long traceIdLeastSigBits = Long.parseUnsignedLong(parts[1].substring(16, 32), 16); if (!isLowercaseHex(parts[2], 16)) { throw new IllegalArgumentException("The traceparent parentId shall be a 16 characters string"); } final long parentId = Long.parseUnsignedLong(parts[2], 16); if (!isLowercaseHex(parts[3], 2)) { throw new IllegalArgumentException("The traceparent flags shall be a two characters string"); } final byte flags = (byte)Integer.parseInt(parts[3], 16); return new Traceparent(version, traceIdMostSigBits, traceIdLeastSigBits, parentId, flags); } public int version() { return Byte.toUnsignedInt(this.version); } public String traceId() { return String.format("%016x%016x", this.traceIdMostSigBits, this.traceIdLeastSigBits); } public String parentId() { return String.format("%016x", this.parentId); } public int flags() { return Byte.toUnsignedInt(this.flags); } /** * Returns the string representation of this traceparent. */ @Override public String toString() { return String.format("%02x-%s-%s-%02x", this.version, this.traceId(), this.parentId(), this.flags); } /** * Duplicates this instance with the given version. */ public Traceparent withVersion(final String version) { if (!isLowercaseHex(version, 2)) { throw new IllegalArgumentException("The traceparent version shall be a two characters string"); } return new Traceparent((byte) Integer.parseUnsignedInt(version, 16), this.traceIdMostSigBits, this.traceIdLeastSigBits, this.parentId, this.flags); } /** * Duplicates this instance with the given trace id. */ public Traceparent withTraceId(final String traceId) { if (!isLowercaseHex(traceId, 32)) { throw new IllegalArgumentException("The traceparent traceId shall be a 32 characters string"); } final long traceIdMostSigBits = Long.parseUnsignedLong(traceId.substring(0, 16), 16); final long traceIdLeastSigBits = Long.parseUnsignedLong(traceId.substring(16, 32), 16); return new Traceparent(this.version, traceIdMostSigBits, traceIdLeastSigBits, this.parentId, this.flags); } /** * Duplicates this instance with the given parent id. */ public Traceparent withParentId(final String parentId) { if (!isLowercaseHex(parentId, 16)) { throw new IllegalArgumentException("The traceparent parentId shall be a 16 characters string"); } return new Traceparent(this.version, this.traceIdMostSigBits, this.traceIdLeastSigBits, Long.parseUnsignedLong(parentId, 16), this.flags); } /** * Duplicates this instance with the given flags. */ public Traceparent withFlags(final String flags) { if (!isLowercaseHex(flags, 2)) { throw new IllegalArgumentException("The traceparent flags shall be a two characters string"); } return new Traceparent(this.version, this.traceIdMostSigBits, this.traceIdLeastSigBits, this.parentId, (byte) Integer.parseUnsignedInt(flags, 16)); } /** * Duplicates this instance with a random parent id. */ public Traceparent withRandomParentId() { final var random = RandomGenerator.getDefault(); return new Traceparent(this.version, this.traceIdMostSigBits, this.traceIdLeastSigBits, random.nextLong(), this.flags); } /** * Checks if the given string is a lowercase hexadecimal string of the given length. * @param string The string to check. * @param length The expected length of the string. * @return True if the string is a lowercase hexadecimal string of the given length, false otherwise. */ private static boolean isLowercaseHex(final String string, final int length) { if (string.length() != length) { return false; } return string.chars().noneMatch(c -> c < '0' || c > 'f'); } @Override public boolean equals(final Object o) { if (this == o) return true; if (!(o instanceof final Traceparent that)) return false; return version == that.version && traceIdMostSigBits == that.traceIdMostSigBits && traceIdLeastSigBits == that.traceIdLeastSigBits && parentId == that.parentId && flags == that.flags; } @Override public int hashCode() { return Objects.hash(version, traceIdMostSigBits, traceIdLeastSigBits, parentId, flags); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy