org.apache.pulsar.common.lookup.GetTopicsResult Maven / Gradle / Ivy
/*
* 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.pulsar.common.lookup;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import lombok.Getter;
import lombok.ToString;
import org.apache.pulsar.common.api.proto.CommandGetTopicsOfNamespace;
import org.apache.pulsar.common.api.proto.CommandGetTopicsOfNamespaceResponse;
import org.apache.pulsar.common.naming.TopicName;
import org.apache.pulsar.common.topics.TopicList;
/***
* A value object.
* - The response of HTTP API "admin/v2/namespaces/{domain}/topics" is a topic(non-partitioned topic or partitions)
* array. It will be wrapped to "topics: {topic array}, topicsHash: null, filtered: false, changed: true".
* - The response of binary API {@link CommandGetTopicsOfNamespace} is a {@link CommandGetTopicsOfNamespaceResponse},
* it will be transferred to a {@link GetTopicsResult}.
* See more details https://github.com/apache/pulsar/pull/14804.
*/
@ToString
public class GetTopicsResult {
/**
* Non-partitioned topics, and topic partitions of partitioned topics.
*/
@Getter
private final List nonPartitionedOrPartitionTopics;
/**
* The topics have been filtered by Broker using a regexp. Otherwise, the client should do a client-side filter.
* There are three cases that brokers will not filter the topics:
* 1. the lookup service is typed HTTP lookup service, the HTTP API has not implemented this feature yet.
* 2. the broker does not support this feature(in other words, its version is lower than "2.11.0").
* 3. the input param "topicPattern" is too long than the broker config "subscriptionPatternMaxLength".
*/
@Getter
private final boolean filtered;
/**
* The topics hash that was calculated by {@link TopicList#calculateHash(List)}. The param topics that will be used
* to calculate the hash code is only contains the topics that has been filtered.
* Note: It is always "null" if broker did not filter the topics when calling the API
* "LookupService.getTopicsUnderNamespace"(in other words, {@link #filtered} is false).
*/
@Getter
private final String topicsHash;
/**
* The topics hash has changed after compare with the input param "topicsHash" when calling
* "LookupService.getTopicsUnderNamespace".
* Note: It is always set "true" if the input param "topicsHash" that used to call
* "LookupService.getTopicsUnderNamespace" is null or the "LookupService" is "HttpLookupService".
*/
@Getter
private final boolean changed;
/**
* Partitioned topics and non-partitioned topics.
* In other words, there is no topic partitions of partitioned topics in this list.
* Note: it is not a field of the response of "LookupService.getTopicsUnderNamespace", it is generated in
* client-side memory.
*/
private volatile List topics;
/**
* This constructor is used for binary API.
*/
public GetTopicsResult(List nonPartitionedOrPartitionTopics, String topicsHash, boolean filtered,
boolean changed) {
this.nonPartitionedOrPartitionTopics = nonPartitionedOrPartitionTopics;
this.topicsHash = topicsHash;
this.filtered = filtered;
this.changed = changed;
}
/**
* This constructor is used for HTTP API.
*/
public GetTopicsResult(String[] nonPartitionedOrPartitionTopics) {
this(Arrays.asList(nonPartitionedOrPartitionTopics), null, false, true);
}
public List getTopics() {
if (topics != null) {
return topics;
}
synchronized (this) {
if (topics != null) {
return topics;
}
// Group partitioned topics.
List grouped = new ArrayList<>();
for (String topic : nonPartitionedOrPartitionTopics) {
String partitionedTopic = TopicName.get(topic).getPartitionedTopicName();
if (!grouped.contains(partitionedTopic)) {
grouped.add(partitionedTopic);
}
}
topics = grouped;
return topics;
}
}
public GetTopicsResult filterTopics(Pattern topicsPattern) {
List topicsFiltered = TopicList.filterTopics(getTopics(), topicsPattern);
// If nothing changed.
if (topicsFiltered.equals(getTopics())) {
GetTopicsResult newObj = new GetTopicsResult(nonPartitionedOrPartitionTopics, null, true, true);
newObj.topics = topics;
return newObj;
}
// Filtered some topics.
Set topicsFilteredSet = new HashSet<>(topicsFiltered);
List newTps = new ArrayList<>();
for (String tp: nonPartitionedOrPartitionTopics) {
if (topicsFilteredSet.contains(TopicName.get(tp).getPartitionedTopicName())) {
newTps.add(tp);
}
}
GetTopicsResult newObj = new GetTopicsResult(newTps, null, true, true);
newObj.topics = topicsFiltered;
return newObj;
}
}