/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.kafka.streams.processor.internals;
import org.apache.kafka.common.internals.Topic;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
/**
* InternalTopicConfig captures the properties required for configuring
* the internal topics we create for change-logs and repartitioning etc.
*/
public class InternalTopicConfig {
public enum CleanupPolicy { compact, delete }
private final String name;
private final Map<String, String> logConfig;
private final Set<CleanupPolicy> cleanupPolicies;
private Long retentionMs;
public InternalTopicConfig(final String name, final Set<CleanupPolicy> defaultCleanupPolicies, final Map<String, String> logConfig) {
Objects.requireNonNull(name, "name can't be null");
Topic.validate(name);
if (defaultCleanupPolicies.isEmpty()) {
throw new IllegalArgumentException("Must provide at least one cleanup policy");
}
this.name = name;
this.cleanupPolicies = defaultCleanupPolicies;
this.logConfig = logConfig;
}
/* for test use only */
boolean isCompacted() {
return cleanupPolicies.contains(CleanupPolicy.compact);
}
private boolean isCompactDelete() {
return cleanupPolicies.contains(CleanupPolicy.compact) && cleanupPolicies.contains(CleanupPolicy.delete);
}
/**
* Get the configured properties for this topic. If rententionMs is set then
* we add additionalRetentionMs to work out the desired retention when cleanup.policy=compact,delete
*
* @param additionalRetentionMs - added to retention to allow for clock drift etc
* @return Properties to be used when creating the topic
*/
public Properties toProperties(final long additionalRetentionMs) {
final Properties result = new Properties();
for (Map.Entry<String, String> configEntry : logConfig.entrySet()) {
result.put(configEntry.getKey(), configEntry.getValue());
}
if (retentionMs != null && isCompactDelete()) {
result.put(InternalTopicManager.RETENTION_MS, String.valueOf(retentionMs + additionalRetentionMs));
}
if (!logConfig.containsKey(InternalTopicManager.CLEANUP_POLICY_PROP)) {
final StringBuilder builder = new StringBuilder();
for (CleanupPolicy cleanupPolicy : cleanupPolicies) {
builder.append(cleanupPolicy.name()).append(",");
}
builder.deleteCharAt(builder.length() - 1);
result.put(InternalTopicManager.CLEANUP_POLICY_PROP, builder.toString());
}
return result;
}
public String name() {
return name;
}
public void setRetentionMs(final long retentionMs) {
if (!logConfig.containsKey(InternalTopicManager.RETENTION_MS)) {
this.retentionMs = retentionMs;
}
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final InternalTopicConfig that = (InternalTopicConfig) o;
return Objects.equals(name, that.name) &&
Objects.equals(logConfig, that.logConfig) &&
Objects.equals(retentionMs, that.retentionMs) &&
Objects.equals(cleanupPolicies, that.cleanupPolicies);
}
@Override
public int hashCode() {
return Objects.hash(name, logConfig, retentionMs, cleanupPolicies);
}
}