Skip to content

Commit

Permalink
Polish apache#6170 : [Feature] Introducing the externalized configura…
Browse files Browse the repository at this point in the history
…tion for ServiceNameMapping
  • Loading branch information
mercyblitz committed Jun 17, 2020
1 parent 719bad7 commit cac3c0d
Show file tree
Hide file tree
Showing 12 changed files with 522 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.apache.dubbo.common.URL;

import java.net.NetworkInterface;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.regex.Pattern;

Expand All @@ -44,6 +45,11 @@ public interface CommonConstants {

String ANY_VALUE = "*";

/**
* @since 2.7.8
*/
char COMMA_SEPARATOR_CHAR = ',';

String COMMA_SEPARATOR = ",";

String DOT_SEPARATOR = ".";
Expand Down Expand Up @@ -314,4 +320,27 @@ public interface CommonConstants {

String SSL_ENABLED_KEY = "ssl-enabled";


/**
* The parameter key for the class path of the ServiceNameMapping {@link Properties} file
*
* @since 2.7.8
*/
String SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY = "service-name-mapping.properties-path";

/**
* The default class path of the ServiceNameMapping {@link Properties} file
*
* @since 2.7.8
*/
String DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH = "META-INF/dubbo/service-name-mapping.properties";

/**
* The parameter key of the subscribed services. If there is a multiple-values, the {@link #COMMA_SEPARATOR "comma"}
* is the separator.
*
* @since 2.7.8
*/
String SUBSCRIBED_SERVICES_KEY = "subscribed-services";

}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ static String normalize(String path) {
if (index > -1) {
normalizedPath = normalizedPath.substring(0, index);
}
return replace(normalizedPath, "//", "/");

while (normalizedPath.contains("//")) {
normalizedPath = replace(normalizedPath, "//", "/");
}

return normalizedPath;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.dubbo.metadata;


import org.apache.dubbo.common.URL;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.apache.dubbo.common.utils.CollectionUtils.isNotEmpty;

/**
* The composite implementation of {@link ServiceNameMapping}
*
* @see ParameterizedServiceNameMapping
* @see PropertiesFileServiceNameMapping
* @see DynamicConfigurationServiceNameMapping
* @since 2.7.8
*/
public class CompositeServiceNameMapping implements ServiceNameMapping {

private List<ServiceNameMapping> serviceNameMappings;

public CompositeServiceNameMapping() {
this.serviceNameMappings = initServiceNameMappings();
}

private List<ServiceNameMapping> initServiceNameMappings() {
Set<ServiceNameMapping> serviceNameMappings = getExtensionLoader(ServiceNameMapping.class)
.getSupportedExtensionInstances();

Iterator<ServiceNameMapping> iterator = serviceNameMappings.iterator();

while (iterator.hasNext()) {
ServiceNameMapping serviceNameMapping = iterator.next();
if (this.getClass().equals(serviceNameMapping.getClass())) {
iterator.remove(); // remove self
}
}

return new LinkedList<>(serviceNameMappings);
}

@Override
public void map(URL exportedURL) {
serviceNameMappings.forEach(serviceNameMapping -> serviceNameMapping.map(exportedURL));
}

@Override
public Set<String> get(URL subscribedURL) {
Set<String> serviceNames = null;
for (ServiceNameMapping serviceNameMapping : serviceNameMappings) {
serviceNames = serviceNameMapping.get(subscribedURL);
if (isNotEmpty(serviceNames)) {
break;
}
}
return serviceNames == null ? emptySet() : unmodifiableSet(serviceNames);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

/**
* The {@link ServiceNameMapping} implementation based on {@link DynamicConfiguration}
*
* @since 2.7.5
*/
public class DynamicConfigurationServiceNameMapping implements ServiceNameMapping {

Expand All @@ -45,6 +47,12 @@ public class DynamicConfigurationServiceNameMapping implements ServiceNameMappin

private final Logger logger = LoggerFactory.getLogger(getClass());

/**
* The priority of {@link DynamicConfigurationServiceNameMapping} is
* lower than {@link ParameterizedServiceNameMapping}
*/
static final int PRIORITY = PropertiesFileServiceNameMapping.PRIORITY + 1;

@Override
public void map(URL exportedURL) {

Expand Down Expand Up @@ -113,4 +121,9 @@ private void execute(Runnable runnable) {
}
}
}

@Override
public int getPriority() {
return PRIORITY;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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.dubbo.metadata;

import org.apache.dubbo.common.URL;

import java.util.Set;

import static org.apache.dubbo.common.constants.CommonConstants.SUBSCRIBED_SERVICES_KEY;

/**
* The parameterized implementation of {@link ServiceNameMapping}
*
* @see ReadOnlyServiceNameMapping
* @since 2.7.8
*/
public class ParameterizedServiceNameMapping extends ReadOnlyServiceNameMapping {

/**
* The priority of {@link PropertiesFileServiceNameMapping}
*/
static final int PRIORITY = MAX_PRIORITY + 99;

@Override
public Set<String> get(URL subscribedURL) {
return getValue(subscribedURL.getParameter(SUBSCRIBED_SERVICES_KEY));
}

@Override
public int getPriority() {
return PRIORITY;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*
* 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.dubbo.metadata;

import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.Configuration;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.PathUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import static java.lang.String.format;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.utils.StringUtils.SLASH;
import static org.apache.dubbo.metadata.MetadataConstants.KEY_SEPARATOR;

/**
* The externalized {@link Properties} file implementation of {@link ServiceNameMapping},
* the default properties class path is
* {@link CommonConstants#DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH "/META-INF/dubbo/service-name-mapping.properties"},
* whose format as following:
* <pre>
* dubbo\:com.acme.Interface1\:default = Service1
* thirft\:com.acme.InterfaceX = Service1,Service2
* rest\:com.acme.interfaceN = Service3
* </pre>
* <p>
* THe search path could be configured by the externalized property {@link CommonConstants#SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY}
*
* @see ReadOnlyServiceNameMapping
* @see ParameterizedServiceNameMapping
* @since 2.7.8
*/
public class PropertiesFileServiceNameMapping extends ReadOnlyServiceNameMapping {

/**
* The priority of {@link PropertiesFileServiceNameMapping} is
* lower than {@link ParameterizedServiceNameMapping}
*/
static final int PRIORITY = ParameterizedServiceNameMapping.PRIORITY + 1;


private final List<Properties> propertiesList;

public PropertiesFileServiceNameMapping() {
this.propertiesList = loadPropertiesList();
}

@Override
public Set<String> get(URL subscribedURL) {
String propertyKey = getPropertyKey(subscribedURL);
String propertyValue = null;

for (Properties properties : propertiesList) {
propertyValue = properties.getProperty(propertyKey);
if (propertyValue != null) {
break;
}
}

return getValue(propertyValue);
}

private String getPropertyKey(URL url) {
String protocol = url.getProtocol();
String serviceInterface = url.getServiceInterface();
// Optional
String group = url.getParameter(GROUP_KEY);
String version = url.getParameter(VERSION_KEY);

StringBuilder propertyKeyBuilder = new StringBuilder(protocol)
.append(KEY_SEPARATOR)
.append(serviceInterface);

appendIfPresent(propertyKeyBuilder, group);
appendIfPresent(propertyKeyBuilder, version);

return propertyKeyBuilder.toString();
}

private void appendIfPresent(StringBuilder builder, String value) {
if (!StringUtils.isBlank(value)) {
builder.append(KEY_SEPARATOR).append(value);
}
}

private List<Properties> loadPropertiesList() {
List<Properties> propertiesList = new LinkedList<>();
String propertiesPath = getPropertiesPath();
try {
Enumeration<java.net.URL> resources = ClassUtils.getClassLoader().getResources(propertiesPath);
while (resources.hasMoreElements()) {
java.net.URL resource = resources.nextElement();
InputStream inputStream = resource.openStream();
Properties properties = new Properties();
properties.load(new InputStreamReader(inputStream, "UTF-8"));
propertiesList.add(properties);
}
} catch (IOException e) {
if (logger.isErrorEnabled()) {
logger.error(format("The path of ServiceNameMapping's Properties file[path : %s] can't be loaded", propertiesPath), e);
}
}
return propertiesList;
}

private String getPropertiesPath() {
Configuration configuration = ApplicationModel.getEnvironment().getConfiguration();
String propertyPath = configuration.getString(SERVICE_NAME_MAPPING_PROPERTIES_FILE_KEY, DEFAULT_SERVICE_NAME_MAPPING_PROPERTIES_PATH);
propertyPath = PathUtils.normalize(propertyPath);
if (propertyPath.startsWith(SLASH)) {
propertyPath = propertyPath.substring(SLASH.length());
}
return propertyPath;
}

}
Loading

0 comments on commit cac3c0d

Please sign in to comment.