io.streamnative.pulsar.handlers.kop.utils.NamedURIUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pulsar-protocol-handler-kafka Show documentation
Show all versions of pulsar-protocol-handler-kafka Show documentation
Kafka on Pulsar implemented using Pulsar Protocol Handler
/**
* Copyright (c) 2019 - 2024 StreamNative, Inc.. All Rights Reserved.
*/
/**
* Licensed 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 io.streamnative.pulsar.handlers.kop.utils;
import static java.util.Collections.singletonList;
import io.streamnative.pulsar.handlers.kop.NamedURI;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriBuilderException;
import org.apache.commons.lang3.StringUtils;
public class NamedURIUtils {
private static final String SEPARATOR = ",";
private static final List SUPPORTED_URI_SCHEMES = List.of("http", "https");
private static final String DEFAULT_SCHEMA = "http";
public static List parseListeners(
String listenersConfig,
String listenerProtocolMapConfig,
int deprecatedPort) {
List listeners = Optional.ofNullable(listenersConfig)
.map(config -> Arrays.stream(config.split(SEPARATOR))
.map(String::trim)
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
if (listeners.isEmpty() || listeners.get(0).isEmpty()) {
listeners = singletonList(DEFAULT_SCHEMA + "://0.0.0.0:" + deprecatedPort);
}
List uris = listeners.stream()
.map(listener ->
constructNamedURI(listener, getListenerProtocolMap(listenerProtocolMapConfig)))
.collect(Collectors.toList());
List namedUris =
uris.stream().filter(uri -> uri.name() != null).toList();
if (namedUris.stream().map(NamedURI::name).distinct().count() != namedUris.size()) {
throw new IllegalArgumentException(
"More than one listener was specified with same name. Listener names must be unique.");
}
return uris;
}
private static NamedURI constructNamedURI(String listener, Map listenerProtocolMap) {
URI uri;
try {
uri = new URI(listener);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(
"Listener '" + listener + "' is not a valid URI: " + e.getMessage());
}
if (uri.getPort() == -1) {
throw new IllegalArgumentException(
"Listener '" + listener + "' must specify a port.");
}
if (SUPPORTED_URI_SCHEMES.contains(uri.getScheme())) {
return new NamedURI(uri, null); // unnamed.
}
String uriName = uri.getScheme().toLowerCase();
String protocol = listenerProtocolMap.get(uriName);
if (protocol == null) {
throw new IllegalArgumentException(
"Listener '" + uri + "' has an unsupported scheme '" + uri.getScheme() + "'");
}
try {
return new NamedURI(
UriBuilder.fromUri(listener).scheme(protocol).build(),
uriName);
} catch (UriBuilderException e) {
throw new IllegalArgumentException(
"Listener '" + listener + "' with protocol '" + protocol + "' is not a valid URI.");
}
}
public static Map getListenerProtocolMap(String listenerProtocolMapConfig) {
Map result = getMap(listenerProtocolMapConfig)
.entrySet()
.stream()
.collect(Collectors.toMap(
e -> e.getKey().toLowerCase(),
e -> e.getValue().toLowerCase()));
for (Map.Entry entry : result.entrySet()) {
if (!SUPPORTED_URI_SCHEMES.contains(entry.getValue())) {
throw new IllegalArgumentException(
"Listener '" + entry.getKey()
+ "' specifies an unsupported protocol: " + entry.getValue());
}
if (SUPPORTED_URI_SCHEMES.contains(entry.getKey())) {
// forbid http:https and https:http
if (!entry.getKey().equals(entry.getValue())) {
throw new IllegalArgumentException(
"Listener name '" + entry.getKey() + "' is a supported protocol, so the "
+ "corresponding protocol specified in "
+ listenerProtocolMapConfig + " must be '" + entry.getKey() + "'");
}
}
}
return result;
}
public static Map getMap(String propertyName) {
if (StringUtils.isEmpty(propertyName)) {
return new HashMap<>();
}
String[] list = propertyName.split(SEPARATOR);
Map map = new HashMap<>();
for (String entry : list) {
String[] keyValue = entry.split("\\s*:\\s*", -1);
if (keyValue.length != 2) {
throw new IllegalArgumentException("Map entry should have form :");
}
if (keyValue[0].isEmpty()) {
throw new IllegalArgumentException(
"Entry '" + entry + "' in " + propertyName + " does not specify a key");
}
if (map.containsKey(keyValue[0])) {
throw new IllegalArgumentException(
"Entry '" + keyValue[0] + "' was specified more than once in " + propertyName);
}
map.put(keyValue[0], keyValue[1]);
}
return map;
}
}