pl.allegro.tech.hermes.consumers.consumer.Message Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hermes-consumers Show documentation
Show all versions of hermes-consumers Show documentation
Fast and reliable message broker built on top of Kafka.
package pl.allegro.tech.hermes.consumers.consumer;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import org.apache.avro.Schema;
import org.apache.commons.lang3.ArrayUtils;
import pl.allegro.tech.hermes.api.ContentType;
import pl.allegro.tech.hermes.api.Header;
import pl.allegro.tech.hermes.api.SubscriptionPolicy;
import pl.allegro.tech.hermes.common.kafka.KafkaTopicName;
import pl.allegro.tech.hermes.common.kafka.offset.PartitionOffset;
import pl.allegro.tech.hermes.domain.filtering.FilterableMessage;
import pl.allegro.tech.hermes.schema.CompiledSchema;
import java.net.URI;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import static java.util.stream.Collectors.toList;
/**
* Implementation note: this class is partially mutable and may be accessed from multiple
* threads involved in message lifecycle, it must be thread safe.
*/
public class Message implements FilterableMessage {
private final String id;
private final PartitionOffset partitionOffset;
private final String topic;
private final String subscription;
private final boolean hasSubscriptionIdentityHeaders;
private final ContentType contentType;
private final Optional> schema;
private final long publishingTimestamp;
private final long readingTimestamp;
private final byte[] data;
private int retryCounter = 0;
private final long partitionAssignmentTerm;
private final Map externalMetadata;
private final List additionalHeaders;
private final Set succeededUris = Sets.newHashSet();
private long currentMessageBackoff = -1;
public Message(String id,
String topic,
byte[] content,
ContentType contentType,
Optional> schema,
long publishingTimestamp,
long readingTimestamp,
PartitionOffset partitionOffset,
long partitionAssignmentTerm,
Map externalMetadata,
List additionalHeaders,
String subscription,
boolean hasSubscriptionIdentityHeaders) {
this.id = id;
this.data = content;
this.topic = topic;
this.contentType = contentType;
this.schema = schema;
this.publishingTimestamp = publishingTimestamp;
this.readingTimestamp = readingTimestamp;
this.partitionOffset = partitionOffset;
this.partitionAssignmentTerm = partitionAssignmentTerm;
this.externalMetadata = ImmutableMap.copyOf(externalMetadata);
this.additionalHeaders = ImmutableList.copyOf(additionalHeaders);
this.subscription = subscription;
this.hasSubscriptionIdentityHeaders = hasSubscriptionIdentityHeaders;
}
public long getPublishingTimestamp() {
return publishingTimestamp;
}
public long getReadingTimestamp() {
return readingTimestamp;
}
public long getOffset() {
return partitionOffset.getOffset();
}
public long getPartitionAssignmentTerm() {
return partitionAssignmentTerm;
}
@Override
public byte[] getData() {
return data;
}
@Override
public ContentType getContentType() {
return contentType;
}
public int getPartition() {
return partitionOffset.getPartition();
}
public String getTopic() {
return topic;
}
public boolean isTtlExceeded(long ttlMillis) {
long currentTimestamp = System.currentTimeMillis();
return currentTimestamp > readingTimestamp + ttlMillis;
}
public synchronized void incrementRetryCounter(Collection succeededUris) {
this.retryCounter++;
this.succeededUris.addAll(succeededUris.stream().map(URI::toString).collect(toList()));
}
public synchronized int getRetryCounter() {
return retryCounter;
}
@Override
public Optional> getSchema() {
return schema;
}
public String getId() {
return id;
}
public synchronized Set getSucceededUris() {
return succeededUris;
}
@Override
public Map getExternalMetadata() {
return externalMetadata;
}
public List getAdditionalHeaders() {
return additionalHeaders;
}
public synchronized long updateAndGetCurrentMessageBackoff(SubscriptionPolicy subscriptionPolicy) {
if (currentMessageBackoff == -1) {
currentMessageBackoff = subscriptionPolicy.getMessageBackoff();
} else {
currentMessageBackoff = Math.min(subscriptionPolicy.getBackoffMaxIntervalMillis(),
(long) (currentMessageBackoff * subscriptionPolicy.getBackoffMultiplier()));
}
return currentMessageBackoff;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Message other = (Message) obj;
return Objects.equals(this.id, other.id);
}
public static Builder message() {
return new Builder();
}
public KafkaTopicName getKafkaTopic() {
return partitionOffset.getTopic();
}
public PartitionOffset getPartitionOffset() {
return partitionOffset;
}
public synchronized boolean hasNotBeenSentTo(String uri) {
return !succeededUris.contains(uri);
}
public long getSize() {
return ArrayUtils.getLength(data);
}
public boolean hasSubscriptionIdentityHeaders() {
return hasSubscriptionIdentityHeaders;
}
public String getSubscription() {
return subscription;
}
public static class Builder {
private String id;
private PartitionOffset partitionOffset;
private String topic;
private String subscription;
private boolean hasSubscriptionIdentityHeaders;
private ContentType contentType;
private Optional> schema;
private long publishingTimestamp;
private long readingTimestamp;
private byte[] data;
private long partitionAssignmentTerm = -1;
private Map externalMetadata = Collections.emptyMap();
private List additionalHeaders = Collections.emptyList();
public Builder() {
}
public Builder fromMessage(Message message) {
this.id = message.getId();
this.data = message.getData();
this.contentType = message.getContentType();
this.topic = message.getTopic();
this.subscription = message.getSubscription();
this.hasSubscriptionIdentityHeaders = message.hasSubscriptionIdentityHeaders();
this.publishingTimestamp = message.getPublishingTimestamp();
this.readingTimestamp = message.getReadingTimestamp();
this.partitionOffset = message.partitionOffset;
this.partitionAssignmentTerm = message.partitionAssignmentTerm;
this.externalMetadata = message.getExternalMetadata();
this.additionalHeaders = message.getAdditionalHeaders();
this.schema = message.getSchema();
return this;
}
public Builder withData(byte[] data) {
this.data = data;
return this;
}
public Builder withSchema(CompiledSchema schema) {
this.schema = Optional.of(schema);
return this;
}
public Builder withExternalMetadata(Map externalMetadata) {
this.externalMetadata = ImmutableMap.copyOf(externalMetadata);
return this;
}
public Builder withAdditionalHeaders(List additionalHeaders) {
this.additionalHeaders = ImmutableList.copyOf(additionalHeaders);
return this;
}
public Builder withContentType(ContentType contentType) {
this.contentType = contentType;
return this;
}
public Builder withNoSchema() {
this.schema = Optional.empty();
return this;
}
public Message build() {
return new Message(
id, topic, data, contentType, schema, publishingTimestamp, readingTimestamp, partitionOffset, partitionAssignmentTerm, externalMetadata, additionalHeaders, subscription, hasSubscriptionIdentityHeaders
);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy