-
Notifications
You must be signed in to change notification settings - Fork 802
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
579 additions
and
1 deletion.
There are no files selected for viewing
146 changes: 146 additions & 0 deletions
146
core/src/main/java/org/apache/servicecomb/core/filter/FilterChainsManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/* | ||
* 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.servicecomb.core.filter; | ||
|
||
import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.appendLine; | ||
import static org.apache.servicecomb.foundation.common.utils.StringBuilderUtils.deleteLast; | ||
import static org.apache.servicecomb.swagger.invocation.InvocationType.CONSUMER; | ||
import static org.apache.servicecomb.swagger.invocation.InvocationType.PRODUCER; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Map.Entry; | ||
|
||
import org.apache.servicecomb.core.SCBEngine; | ||
import org.apache.servicecomb.core.filter.config.FilterChainsConfig; | ||
import org.apache.servicecomb.core.filter.config.TransportFiltersConfig; | ||
import org.apache.servicecomb.swagger.invocation.InvocationType; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class FilterChainsManager { | ||
private TransportFiltersConfig transportFiltersConfig; | ||
|
||
private FilterManager filterManager; | ||
|
||
private FilterChainsConfig consumerChainsConfig; | ||
|
||
private FilterChainsConfig producerChainsConfig; | ||
|
||
private boolean enabled; | ||
|
||
@Autowired | ||
public FilterChainsManager setTransportFiltersConfig(TransportFiltersConfig transportFiltersConfig) { | ||
this.transportFiltersConfig = transportFiltersConfig; | ||
return this; | ||
} | ||
|
||
@Value("${servicecomb.filter-chains.enabled:false}") | ||
public FilterChainsManager setEnabled(boolean enabled) { | ||
this.enabled = enabled; | ||
return this; | ||
} | ||
|
||
public FilterManager getFilterManager() { | ||
return filterManager; | ||
} | ||
|
||
@Autowired | ||
public FilterChainsManager setFilterManager(FilterManager filterManager) { | ||
this.filterManager = filterManager; | ||
return this; | ||
} | ||
|
||
public FilterChainsManager init(SCBEngine engine) { | ||
transportFiltersConfig.load(); | ||
filterManager.init(engine); | ||
|
||
consumerChainsConfig = new FilterChainsConfig(transportFiltersConfig, CONSUMER); | ||
producerChainsConfig = new FilterChainsConfig(transportFiltersConfig, PRODUCER); | ||
|
||
return this; | ||
} | ||
|
||
public boolean isEnabled() { | ||
return enabled; | ||
} | ||
|
||
public FilterChainsManager addProviders(FilterProvider... providers) { | ||
return addProviders(Arrays.asList(providers)); | ||
} | ||
|
||
public FilterChainsManager addProviders(Collection<FilterProvider> providers) { | ||
filterManager.addProviders(providers); | ||
return this; | ||
} | ||
|
||
public FilterNode createConsumerFilterChain(String microservice) { | ||
return createFilterNode(consumerChainsConfig, microservice); | ||
} | ||
|
||
public FilterNode createProducerFilterChain(String microservice) { | ||
return createFilterNode(producerChainsConfig, microservice); | ||
} | ||
|
||
public List<Filter> createConsumerFilters(String microservice) { | ||
return createFilters(consumerChainsConfig, microservice); | ||
} | ||
|
||
public List<Filter> createProducerFilters(String microservice) { | ||
return createFilters(producerChainsConfig, microservice); | ||
} | ||
|
||
public String collectResolvedChains() { | ||
// currently not implement consumer filter chain, so not print consumer information now. | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
// appendLine(sb, "consumer filters: %s", filterManager.getConsumerFilters()); | ||
appendLine(sb, "producer filters: %s", filterManager.getProducerFilters()); | ||
// collectChainsByInvocationType(sb, consumerChainsConfig, CONSUMER); | ||
collectChainsByInvocationType(sb, producerChainsConfig, PRODUCER); | ||
|
||
return deleteLast(sb, 1).toString(); | ||
} | ||
|
||
private void collectChainsByInvocationType(StringBuilder sb, FilterChainsConfig chainsConfig, | ||
InvocationType invocationType) { | ||
appendLine(sb, "%s chains:", invocationType.name().toLowerCase(Locale.US)); | ||
appendLine(sb, " default: %s", chainsConfig.getDefaultChain()); | ||
for (Entry<String, List<Object>> entry : chainsConfig.getMicroserviceChains().entrySet()) { | ||
appendLine(sb, " %s: %s", entry.getKey(), entry.getValue()); | ||
} | ||
} | ||
|
||
private FilterNode createFilterNode(FilterChainsConfig chainsConfig, String microservice) { | ||
List<Filter> filters = createFilters(chainsConfig, microservice); | ||
return FilterNode.buildChain(filters); | ||
} | ||
|
||
private List<Filter> createFilters(FilterChainsConfig chainsConfig, String microservice) { | ||
if (!enabled) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
List<Object> chain = chainsConfig.findChain(microservice); | ||
return filterManager.createFilters(chain); | ||
} | ||
} |
148 changes: 148 additions & 0 deletions
148
core/src/main/java/org/apache/servicecomb/core/filter/FilterManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* | ||
* 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.servicecomb.core.filter; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.servicecomb.core.SCBEngine; | ||
import org.apache.servicecomb.core.filter.config.TransportFilterConfig; | ||
import org.apache.servicecomb.core.filter.impl.TransportFilters; | ||
import org.apache.servicecomb.foundation.common.utils.SPIServiceUtils; | ||
import org.apache.servicecomb.swagger.invocation.InvocationType; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class FilterManager { | ||
interface Factory { | ||
Filter create(); | ||
} | ||
|
||
private SCBEngine engine; | ||
|
||
private final List<FilterProvider> providers = new ArrayList<>( | ||
SPIServiceUtils.getOrLoadSortedService(FilterProvider.class)); | ||
|
||
private final Map<String, Factory> factoryMap = new HashMap<>(); | ||
|
||
private final List<String> consumerFilters = new ArrayList<>(); | ||
|
||
private final List<String> producerFilters = new ArrayList<>(); | ||
|
||
@Autowired(required = false) | ||
public void addProviders(Collection<FilterProvider> providers) { | ||
this.providers.addAll(providers); | ||
} | ||
|
||
public List<String> getConsumerFilters() { | ||
return consumerFilters; | ||
} | ||
|
||
public List<String> getProducerFilters() { | ||
return producerFilters; | ||
} | ||
|
||
public void init(SCBEngine engine) { | ||
this.engine = engine; | ||
List<Class<? extends Filter>> filterClasses = providers.stream() | ||
.flatMap(provider -> provider.getFilters().stream()) | ||
.collect(Collectors.toList()); | ||
|
||
for (Class<? extends Filter> filterClass : filterClasses) { | ||
FilterMeta meta = filterClass.getAnnotation(FilterMeta.class); | ||
Factory factory = buildFactory(filterClass, meta); | ||
|
||
if (factoryMap.put(meta.name(), factory) != null) { | ||
throw new IllegalStateException( | ||
String.format("duplicated filter, name=%s, class=%s", meta.name(), filterClass.getName())); | ||
} | ||
|
||
if (Arrays.binarySearch(meta.invocationType(), InvocationType.CONSUMER) >= 0) { | ||
consumerFilters.add(meta.name()); | ||
} | ||
if (Arrays.binarySearch(meta.invocationType(), InvocationType.PRODUCER) >= 0) { | ||
producerFilters.add(meta.name()); | ||
} | ||
} | ||
} | ||
|
||
public List<Filter> createFilters(List<Object> chain) { | ||
return chain.stream() | ||
.map(filterConfig -> { | ||
Filter filter = createFilter(filterConfig); | ||
filter.init(engine); | ||
return filter; | ||
}) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
private Filter createFilter(Object filterConfig) { | ||
if (filterConfig instanceof String) { | ||
return createFilterByName((String) filterConfig); | ||
} | ||
|
||
if (filterConfig instanceof TransportFilterConfig) { | ||
return createTransportFilter((TransportFilterConfig) filterConfig); | ||
} | ||
|
||
throw new IllegalStateException("not support create filter by " + filterConfig); | ||
} | ||
|
||
private Filter createTransportFilter(TransportFilterConfig config) { | ||
TransportFilters transportFilters = new TransportFilters(); | ||
for (Entry<String, List<Object>> entry : config.getFiltersByTransport().entrySet()) { | ||
List<Filter> filters = createFilters(entry.getValue()); | ||
transportFilters.getChainByTransport().put(entry.getKey(), FilterNode.buildChain(filters)); | ||
} | ||
return transportFilters; | ||
} | ||
|
||
private Filter createFilterByName(String filterName) { | ||
Factory factory = factoryMap.get(filterName); | ||
if (factory != null) { | ||
return factory.create(); | ||
} | ||
|
||
throw new IllegalStateException("filter not exist, name=" + filterName); | ||
} | ||
|
||
private Factory buildFactory(Class<? extends Filter> filterClass, FilterMeta meta) { | ||
if (meta.shareable()) { | ||
Filter filter = createFilter(filterClass); | ||
return () -> filter; | ||
} | ||
|
||
return () -> createFilter(filterClass); | ||
} | ||
|
||
private Filter createFilter(Class<? extends Filter> filterClass) { | ||
try { | ||
Filter filter = filterClass.newInstance(); | ||
filter.init(engine); | ||
return filter; | ||
} catch (Exception e) { | ||
throw new IllegalStateException("failed to create filter.", e); | ||
} | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
core/src/main/java/org/apache/servicecomb/core/filter/config/FilterChainsConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* | ||
* 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.servicecomb.core.filter.config; | ||
|
||
import static org.apache.servicecomb.core.filter.config.TransportFiltersConfig.FILTER_CHAINS_PREFIX; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Locale; | ||
import java.util.Map; | ||
import java.util.stream.Collectors; | ||
|
||
import org.apache.commons.configuration.Configuration; | ||
import org.apache.servicecomb.config.ConfigUtil; | ||
import org.apache.servicecomb.swagger.invocation.InvocationType; | ||
|
||
import com.netflix.config.DynamicPropertyFactory; | ||
|
||
public class FilterChainsConfig { | ||
private final List<Object> defaultChain; | ||
|
||
private final Map<String, List<Object>> microserviceChains = new HashMap<>(); | ||
|
||
private final TransportFiltersConfig transportFiltersConfig; | ||
|
||
public FilterChainsConfig(TransportFiltersConfig transportFiltersConfig, InvocationType type) { | ||
this.transportFiltersConfig = transportFiltersConfig; | ||
|
||
Configuration config = (Configuration) DynamicPropertyFactory.getBackingConfigurationSource(); | ||
String root = FILTER_CHAINS_PREFIX + type.name().toLowerCase(Locale.US); | ||
defaultChain = resolve(ConfigUtil.getStringList(config, root + ".default")); | ||
loadMicroserviceChains(config, root + ".policies"); | ||
} | ||
|
||
public List<Object> getDefaultChain() { | ||
return defaultChain; | ||
} | ||
|
||
public Map<String, List<Object>> getMicroserviceChains() { | ||
return microserviceChains; | ||
} | ||
|
||
public List<Object> findChain(String microservice) { | ||
return microserviceChains.getOrDefault(microservice, defaultChain); | ||
} | ||
|
||
private void loadMicroserviceChains(Configuration config, String policiesRoot) { | ||
config.getKeys(policiesRoot).forEachRemaining(qualifiedKey -> { | ||
String microserviceName = qualifiedKey.substring(policiesRoot.length() + 1); | ||
List<String> chain = ConfigUtil.getStringList(config, qualifiedKey); | ||
|
||
microserviceChains.put(microserviceName, resolve(chain)); | ||
}); | ||
} | ||
|
||
private List<Object> resolve(List<String> rawChain) { | ||
return rawChain.stream() | ||
.map(value -> { | ||
TransportFilterConfig config = transportFiltersConfig.getConfig(value); | ||
return config == null ? value : config; | ||
}) | ||
.collect(Collectors.toList()); | ||
} | ||
} |
Oops, something went wrong.