[3.0] Code reformat (#8019)

* convert files, add checker

* rename id

* tab to space

* change git attributes auto convert

* fix end new line

* fix end new line

* fix end new line

* ignore generated files

* override tomcat-embed-core version

* add ignore for codestyle/checkstyle.xml

* add ignore for codestyle/checkstyle.xml

* add rat ignore

* add suppression

* force update

* disable zk dynamic configurator
This commit is contained in:
Albumen Kevin 2021-06-10 20:13:39 +08:00 committed by GitHub
parent 724ec8b554
commit 0e66de1c61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
728 changed files with 42286 additions and 42213 deletions

24
.gitattributes vendored
View File

@ -1,4 +1,20 @@
# Git will understand that all files specified are not text, # Licensed to the Apache Software Foundation (ASF) under one or more
# and it should not try to change them. # contributor license agreements. See the NOTICE file distributed with
# This will prevent file formatting (such as `crlf` endings to `lf` endings) while commit. # this work for additional information regarding copyright ownership.
* -text # 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.
#
# Auto detect text files and perform LF normalization
* text=auto
*.java text eol=lf

View File

@ -39,7 +39,25 @@ jobs:
- name: "Build Dubbo with Maven" - name: "Build Dubbo with Maven"
run: | run: |
cd ./dubbo cd ./dubbo
./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean source:jar install -Pjacoco,rat,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true ./mvnw --batch-mode -U -e --no-transfer-progress clean source:jar install -Pjacoco,rat,checkstyle -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -Dmaven.test.skip=true -Dmaven.test.skip.exec=true
- name: "Pack rat file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/rat.zip *rat.txt -r
- name: "Upload rat file if failure"
if: failure()
uses: actions/upload-artifact@v2
with:
name: "rat-file"
path: ${{ github.workspace }}/rat.zip
- name: "Pack checkstyle file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/checkstyle.zip *checkstyle* -r
- name: "Upload checkstyle file if failure"
if: failure()
uses: actions/upload-artifact@v2
with:
name: "checkstyle-file"
path: ${{ github.workspace }}/checkstyle.zip
- name: "Calculate Dubbo Version" - name: "Calculate Dubbo Version"
id: dubbo-version id: dubbo-version
run: | run: |
@ -72,22 +90,13 @@ jobs:
- name: "Test with Maven with Integration Tests" - name: "Test with Maven with Integration Tests"
timeout-minutes: 40 timeout-minutes: 40
if: ${{ startsWith( matrix.os, 'ubuntu') }} if: ${{ startsWith( matrix.os, 'ubuntu') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true run: ./mvnw --batch-mode -U -e --no-transfer-progress clean test verify -Pjacoco -Dmaven.wagon.httpconnectionManager.ttlSeconds=120 -Dmaven.wagon.http.retryHandler.count=5 -DskipTests=false -DskipIntegrationTests=false -Dcheckstyle.skip=false -Dcheckstyle_unix.skip=false -Drat.skip=false -Dmaven.javadoc.skip=true
- name: "Test with Maven without Integration Tests" - name: "Test with Maven without Integration Tests"
env: env:
DISABLE_FILE_SYSTEM_TEST: true DISABLE_FILE_SYSTEM_TEST: true
timeout-minutes: 50 timeout-minutes: 50
if: ${{ startsWith( matrix.os, 'windows') }} if: ${{ startsWith( matrix.os, 'windows') }}
run: ./mvnw --batch-mode --no-snapshot-updates -e --no-transfer-progress clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"rat.skip=false" -D"maven.javadoc.skip=true" run: ./mvnw --batch-mode -U -e --no-transfer-progress clean test verify -Pjacoco -D"http.keepAlive=false" -D"maven.wagon.http.pool=false" -D"maven.wagon.httpconnectionManager.ttlSeconds=120" -D"maven.wagon.http.retryHandler.count=5" -DskipTests=false -DskipIntegrationTests=true -D"checkstyle.skip=false" -D"checkstyle_unix.skip=true" -D"rat.skip=false" -D"maven.javadoc.skip=true"
- name: "Pack rat file if failure"
if: failure()
run: 7z a ${{ github.workspace }}/rat.zip *rat.txt -r
- name: "Upload rat file if failure"
if: failure()
uses: actions/upload-artifact@v2
with:
name: "rat-file-${{ matrix.os }}-JDK${{ matrix.jdk }}"
path: ${{ github.workspace }}/rat.zip
- name: "Upload coverage to Codecov" - name: "Upload coverage to Codecov"
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1

View File

@ -279,4 +279,4 @@ https://developers.google.com/protocol-buffers/ and is licensed under the follow
Code generated by the Protocol Buffer compiler is owned by the owner Code generated by the Protocol Buffer compiler is owned by the owner
of the input file used when generating it. This code is not of the input file used when generating it. This code is not
standalone and requires a support library to be linked with it. This standalone and requires a support library to be linked with it. This
support library is itself covered by the above license. support library is itself covered by the above license.

28
NOTICE
View File

@ -1,14 +1,14 @@
Apache Dubbo Apache Dubbo
Copyright 2018-2021 The Apache Software Foundation Copyright 2018-2021 The Apache Software Foundation
This product includes software developed at This product includes software developed at
The Apache Software Foundation (http://www.apache.org/). The Apache Software Foundation (http://www.apache.org/).
This product contains code form the Netty Project: This product contains code form the Netty Project:
The Netty Project The Netty Project
================= =================
Please visit the Netty web site for more information: Please visit the Netty web site for more information:
* http://netty.io/ * http://netty.io/
Copyright 2014 The Netty Project Copyright 2014 The Netty Project

View File

@ -4,5 +4,6 @@
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd"> "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions> <suppressions>
<suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/> <suppress files="[\\/]src[\\/]main[\\/]java[\\/]com[\\/]alibaba[\\/]com[\\/]caucho[\\/]hessian" checks=".*"/>
<suppress files="[\\/]build[\\/]generated[\\/]source[\\/]proto" checks=".*"/>
<suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/> <suppress files="Yylex\.java" checks="AvoidEscapedUnicodeCharacters"/>
</suppressions> </suppressions>

View File

@ -12,6 +12,10 @@
<property name="fileExtensions" value="java"/> <property name="fileExtensions" value="java"/>
</module> </module>
<module name="FileTabCharacter">
<property name="fileExtensions" value="java,xml"/>
</module>
<!-- TreeWalker Checks --> <!-- TreeWalker Checks -->
<module name="TreeWalker"> <module name="TreeWalker">
<module name="SuppressWarningsHolder"/> <module name="SuppressWarningsHolder"/>

View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf" />
</module>
</module>

View File

@ -39,4 +39,4 @@ public class DubboGenerator extends AbstractGenerator {
protected String getClassSuffix() { protected String getClassSuffix() {
return "Dubbo"; return "Dubbo";
} }
} }

View File

@ -64,6 +64,7 @@
<exclude>**/.classpath</exclude> <exclude>**/.classpath</exclude>
<exclude>**/.project</exclude> <exclude>**/.project</exclude>
<exclude>**/target/**</exclude> <exclude>**/target/**</exclude>
<exclude>**/generated/**</exclude>
<exclude>**/*.log</exclude> <exclude>**/*.log</exclude>
<exclude>CONTRIBUTING.md</exclude> <exclude>CONTRIBUTING.md</exclude>
<exclude>README.md</exclude> <exclude>README.md</exclude>

View File

@ -38,4 +38,4 @@ public interface AddressListener {
} }
} }

View File

@ -1,59 +1,59 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
/** /**
* Cluster. (SPI, Singleton, ThreadSafe) * Cluster. (SPI, Singleton, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a> * <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a>
* <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a> * <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
* *
*/ */
@SPI(Cluster.DEFAULT) @SPI(Cluster.DEFAULT)
public interface Cluster { public interface Cluster {
String DEFAULT = "failover"; String DEFAULT = "failover";
/** /**
* Merge the directory invokers to a virtual invoker. * Merge the directory invokers to a virtual invoker.
* *
* @param <T> * @param <T>
* @param directory * @param directory
* @return cluster invoker * @return cluster invoker
* @throws RpcException * @throws RpcException
*/ */
@Adaptive @Adaptive
<T> Invoker<T> join(Directory<T> directory) throws RpcException; <T> Invoker<T> join(Directory<T> directory) throws RpcException;
static Cluster getCluster(String name) { static Cluster getCluster(String name) {
return getCluster(name, true); return getCluster(name, true);
} }
static Cluster getCluster(String name, boolean wrap) { static Cluster getCluster(String name, boolean wrap) {
if (StringUtils.isEmpty(name)) { if (StringUtils.isEmpty(name)) {
name = Cluster.DEFAULT; name = Cluster.DEFAULT;
} }
return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap); return ExtensionLoader.getExtensionLoader(Cluster.class).getExtension(name, wrap);
} }
} }

View File

@ -1,119 +1,119 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL; import static org.apache.dubbo.common.constants.RegistryConstants.EMPTY_PROTOCOL;
import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY; import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
/** /**
* Configurator. (SPI, Prototype, ThreadSafe) * Configurator. (SPI, Prototype, ThreadSafe)
* *
*/ */
public interface Configurator extends Comparable<Configurator> { public interface Configurator extends Comparable<Configurator> {
/** /**
* Get the configurator url. * Get the configurator url.
* *
* @return configurator url. * @return configurator url.
*/ */
URL getUrl(); URL getUrl();
/** /**
* Configure the provider url. * Configure the provider url.
* *
* @param url - old provider url. * @param url - old provider url.
* @return new provider url. * @return new provider url.
*/ */
URL configure(URL url); URL configure(URL url);
/** /**
* Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and * Convert override urls to map for use when re-refer. Send all rules every time, the urls will be reassembled and
* calculated * calculated
* *
* URL contract: * URL contract:
* <ol> * <ol>
* <li>override://0.0.0.0/...( or override://ip:port...?anyhost=true)&para1=value1... means global rules * <li>override://0.0.0.0/...( or override://ip:port...?anyhost=true)&para1=value1... means global rules
* (all of the providers take effect)</li> * (all of the providers take effect)</li>
* <li>override://ip:port...?anyhost=false Special rules (only for a certain provider)</li> * <li>override://ip:port...?anyhost=false Special rules (only for a certain provider)</li>
* <li>override:// rule is not supported... ,needs to be calculated by registry itself</li> * <li>override:// rule is not supported... ,needs to be calculated by registry itself</li>
* <li>override://0.0.0.0/ without parameters means clearing the override</li> * <li>override://0.0.0.0/ without parameters means clearing the override</li>
* </ol> * </ol>
* *
* @param urls URL list to convert * @param urls URL list to convert
* @return converted configurator list * @return converted configurator list
*/ */
static Optional<List<Configurator>> toConfigurators(List<URL> urls) { static Optional<List<Configurator>> toConfigurators(List<URL> urls) {
if (CollectionUtils.isEmpty(urls)) { if (CollectionUtils.isEmpty(urls)) {
return Optional.empty(); return Optional.empty();
} }
ConfiguratorFactory configuratorFactory = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class) ConfiguratorFactory configuratorFactory = ExtensionLoader.getExtensionLoader(ConfiguratorFactory.class)
.getAdaptiveExtension(); .getAdaptiveExtension();
List<Configurator> configurators = new ArrayList<>(urls.size()); List<Configurator> configurators = new ArrayList<>(urls.size());
for (URL url : urls) { for (URL url : urls) {
if (EMPTY_PROTOCOL.equals(url.getProtocol())) { if (EMPTY_PROTOCOL.equals(url.getProtocol())) {
configurators.clear(); configurators.clear();
break; break;
} }
Map<String, String> override = new HashMap<>(url.getParameters()); Map<String, String> override = new HashMap<>(url.getParameters());
//The anyhost parameter of override may be added automatically, it can't change the judgement of changing url //The anyhost parameter of override may be added automatically, it can't change the judgement of changing url
override.remove(ANYHOST_KEY); override.remove(ANYHOST_KEY);
if (CollectionUtils.isEmptyMap(override)) { if (CollectionUtils.isEmptyMap(override)) {
continue; continue;
} }
configurators.add(configuratorFactory.getConfigurator(url)); configurators.add(configuratorFactory.getConfigurator(url));
} }
Collections.sort(configurators); Collections.sort(configurators);
return Optional.of(configurators); return Optional.of(configurators);
} }
/** /**
* Sort by host, then by priority * Sort by host, then by priority
* 1. the url with a specific host ip should have higher priority than 0.0.0.0 * 1. the url with a specific host ip should have higher priority than 0.0.0.0
* 2. if two url has the same host, compare by priority value * 2. if two url has the same host, compare by priority value
*/ */
@Override @Override
default int compareTo(Configurator o) { default int compareTo(Configurator o) {
if (o == null) { if (o == null) {
return -1; return -1;
} }
int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost()); int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());
// host is the same, sort by priority // host is the same, sort by priority
if (ipCompare == 0) { if (ipCompare == 0) {
int i = getUrl().getParameter(PRIORITY_KEY, 0); int i = getUrl().getParameter(PRIORITY_KEY, 0);
int j = o.getUrl().getParameter(PRIORITY_KEY, 0); int j = o.getUrl().getParameter(PRIORITY_KEY, 0);
return Integer.compare(i, j); return Integer.compare(i, j);
} else { } else {
return ipCompare; return ipCompare;
} }
} }
} }

View File

@ -1,39 +1,39 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
/** /**
* ConfiguratorFactory. (SPI, Singleton, ThreadSafe) * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)
* *
*/ */
@SPI @SPI
public interface ConfiguratorFactory { public interface ConfiguratorFactory {
/** /**
* get the configurator instance. * get the configurator instance.
* *
* @param url - configurator url. * @param url - configurator url.
* @return configurator instance. * @return configurator instance.
*/ */
@Adaptive("protocol") @Adaptive("protocol")
Configurator getConfigurator(URL url); Configurator getConfigurator(URL url);
} }

View File

@ -1,72 +1,72 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.Node; import org.apache.dubbo.common.Node;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import java.util.List; import java.util.List;
/** /**
* Directory. (SPI, Prototype, ThreadSafe) * Directory. (SPI, Prototype, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a> * <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a>
* *
* @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory) * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
*/ */
public interface Directory<T> extends Node { public interface Directory<T> extends Node {
/** /**
* get service type. * get service type.
* *
* @return service type. * @return service type.
*/ */
Class<T> getInterface(); Class<T> getInterface();
/** /**
* list invokers. * list invokers.
* *
* @return invokers * @return invokers
*/ */
List<Invoker<T>> list(Invocation invocation) throws RpcException; List<Invoker<T>> list(Invocation invocation) throws RpcException;
List<Invoker<T>> getAllInvokers(); List<Invoker<T>> getAllInvokers();
URL getConsumerUrl(); URL getConsumerUrl();
boolean isDestroyed(); boolean isDestroyed();
default boolean isEmpty() { default boolean isEmpty() {
return CollectionUtils.isEmpty(getAllInvokers()); return CollectionUtils.isEmpty(getAllInvokers());
} }
default boolean isServiceDiscovery() { default boolean isServiceDiscovery() {
return false; return false;
} }
void discordAddresses(); void discordAddresses();
RouterChain<T> getRouterChain(); RouterChain<T> getRouterChain();
default boolean isNotificationReceived() { default boolean isNotificationReceived() {
return false; return false;
} }
} }

View File

@ -1,50 +1,50 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance; import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
import java.util.List; import java.util.List;
/** /**
* LoadBalance. (SPI, Singleton, ThreadSafe) * LoadBalance. (SPI, Singleton, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a> * <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a>
* *
* @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory) * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
*/ */
@SPI(RandomLoadBalance.NAME) @SPI(RandomLoadBalance.NAME)
public interface LoadBalance { public interface LoadBalance {
/** /**
* select one invoker in list. * select one invoker in list.
* *
* @param invokers invokers. * @param invokers invokers.
* @param url refer url * @param url refer url
* @param invocation invocation. * @param invocation invocation.
* @return selected invoker. * @return selected invoker.
*/ */
@Adaptive("loadbalance") @Adaptive("loadbalance")
<T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
} }

View File

@ -1,103 +1,103 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import java.util.List; import java.util.List;
/** /**
* Router. (SPI, Prototype, ThreadSafe) * Router. (SPI, Prototype, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Routing">Routing</a> * <a href="http://en.wikipedia.org/wiki/Routing">Routing</a>
* *
* @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory) * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
* @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation) * @see org.apache.dubbo.rpc.cluster.Directory#list(Invocation)
*/ */
public interface Router extends Comparable<Router> { public interface Router extends Comparable<Router> {
int DEFAULT_PRIORITY = Integer.MAX_VALUE; int DEFAULT_PRIORITY = Integer.MAX_VALUE;
/** /**
* Get the router url. * Get the router url.
* *
* @return url * @return url
*/ */
URL getUrl(); URL getUrl();
/** /**
* Filter invokers with current routing rule and only return the invokers that comply with the rule. * Filter invokers with current routing rule and only return the invokers that comply with the rule.
* *
* @param invokers invoker list * @param invokers invoker list
* @param url refer url * @param url refer url
* @param invocation invocation * @param invocation invocation
* @return routed invokers * @return routed invokers
* @throws RpcException * @throws RpcException
*/ */
<T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException; <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
/** /**
* Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a * Notify the router the invoker list. Invoker list may change from time to time. This method gives the router a
* chance to prepare before {@link Router#route(List, URL, Invocation)} gets called. * chance to prepare before {@link Router#route(List, URL, Invocation)} gets called.
* *
* @param invokers invoker list * @param invokers invoker list
* @param <T> invoker's type * @param <T> invoker's type
*/ */
default <T> void notify(List<Invoker<T>> invokers) { default <T> void notify(List<Invoker<T>> invokers) {
} }
/** /**
* To decide whether this router need to execute every time an RPC comes or should only execute when addresses or * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
* rule change. * rule change.
* *
* @return true if the router need to execute every time. * @return true if the router need to execute every time.
*/ */
boolean isRuntime(); boolean isRuntime();
/** /**
* To decide whether this router should take effect when none of the invoker can match the router rule, which * To decide whether this router should take effect when none of the invoker can match the router rule, which
* means the {@link #route(List, URL, Invocation)} would be empty. Most of time, most router implementation would * means the {@link #route(List, URL, Invocation)} would be empty. Most of time, most router implementation would
* default this value to false. * default this value to false.
* *
* @return true to execute if none of invokers matches the current router * @return true to execute if none of invokers matches the current router
*/ */
boolean isForce(); boolean isForce();
/** /**
* Router's priority, used to sort routers. * Router's priority, used to sort routers.
* *
* @return router's priority * @return router's priority
*/ */
int getPriority(); int getPriority();
default void stop() { default void stop() {
//do nothing by default //do nothing by default
} }
@Override @Override
default int compareTo(Router o) { default int compareTo(Router o) {
if (o == null) { if (o == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return Integer.compare(this.getPriority(), o.getPriority()); return Integer.compare(this.getPriority(), o.getPriority());
} }
} }

View File

@ -1,47 +1,47 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster; package org.apache.dubbo.rpc.cluster;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.Adaptive; import org.apache.dubbo.common.extension.Adaptive;
import org.apache.dubbo.common.extension.SPI; import org.apache.dubbo.common.extension.SPI;
/** /**
* RouterFactory. (SPI, Singleton, ThreadSafe) * RouterFactory. (SPI, Singleton, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Routing">Routing</a> * <a href="http://en.wikipedia.org/wiki/Routing">Routing</a>
* *
* @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory) * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
* @see org.apache.dubbo.rpc.cluster.Directory#list(org.apache.dubbo.rpc.Invocation) * @see org.apache.dubbo.rpc.cluster.Directory#list(org.apache.dubbo.rpc.Invocation)
* <p> * <p>
* Note Router has a different behaviour since 2.7.0, for each type of Router, there will only has one Router instance * Note Router has a different behaviour since 2.7.0, for each type of Router, there will only has one Router instance
* for each service. See {@link CacheableRouterFactory} and {@link RouterChain} for how to extend a new Router or how * for each service. See {@link CacheableRouterFactory} and {@link RouterChain} for how to extend a new Router or how
* the Router instances are loaded. * the Router instances are loaded.
*/ */
@SPI @SPI
public interface RouterFactory { public interface RouterFactory {
/** /**
* Create router. * Create router.
* Since 2.7.0, most of the time, we will not use @Adaptive feature, so it's kept only for compatibility. * Since 2.7.0, most of the time, we will not use @Adaptive feature, so it's kept only for compatibility.
* *
* @param url url * @param url url
* @return router instance * @return router instance
*/ */
@Adaptive("protocol") @Adaptive("protocol")
Router getRouter(URL url); Router getRouter(URL url);
} }

View File

@ -1,170 +1,170 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator; package org.apache.dubbo.rpc.cluster.configurator;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.remoting.Constants; import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.rpc.cluster.Configurator; import org.apache.dubbo.rpc.cluster.Configurator;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE; import static org.apache.dubbo.common.constants.CommonConstants.ANY_VALUE;
import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACES; import static org.apache.dubbo.common.constants.CommonConstants.INTERFACES;
import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER; import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY; import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY; import static org.apache.dubbo.common.constants.CommonConstants.VERSION_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.CATEGORY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.COMPATIBLE_CONFIG_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.DYNAMIC_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY; import static org.apache.dubbo.rpc.cluster.Constants.CONFIG_VERSION_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY; import static org.apache.dubbo.rpc.cluster.Constants.OVERRIDE_PROVIDERS_KEY;
/** /**
* AbstractOverrideConfigurator * AbstractOverrideConfigurator
*/ */
public abstract class AbstractConfigurator implements Configurator { public abstract class AbstractConfigurator implements Configurator {
private static final String TILDE = "~"; private static final String TILDE = "~";
private final URL configuratorUrl; private final URL configuratorUrl;
public AbstractConfigurator(URL url) { public AbstractConfigurator(URL url) {
if (url == null) { if (url == null) {
throw new IllegalArgumentException("configurator url == null"); throw new IllegalArgumentException("configurator url == null");
} }
this.configuratorUrl = url; this.configuratorUrl = url;
} }
@Override @Override
public URL getUrl() { public URL getUrl() {
return configuratorUrl; return configuratorUrl;
} }
@Override @Override
public URL configure(URL url) { public URL configure(URL url) {
// If override url is not enabled or is invalid, just return. // If override url is not enabled or is invalid, just return.
if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) { if (!configuratorUrl.getParameter(ENABLED_KEY, true) || configuratorUrl.getHost() == null || url == null || url.getHost() == null) {
return url; return url;
} }
/* /*
* This if branch is created since 2.7.0. * This if branch is created since 2.7.0.
*/ */
String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY); String apiVersion = configuratorUrl.getParameter(CONFIG_VERSION_KEY);
if (StringUtils.isNotEmpty(apiVersion)) { if (StringUtils.isNotEmpty(apiVersion)) {
String currentSide = url.getSide(); String currentSide = url.getSide();
String configuratorSide = configuratorUrl.getSide(); String configuratorSide = configuratorUrl.getSide();
if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) { if (currentSide.equals(configuratorSide) && CONSUMER.equals(configuratorSide) && 0 == configuratorUrl.getPort()) {
url = configureIfMatch(NetUtils.getLocalHost(), url); url = configureIfMatch(NetUtils.getLocalHost(), url);
} else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) && } else if (currentSide.equals(configuratorSide) && PROVIDER.equals(configuratorSide) &&
url.getPort() == configuratorUrl.getPort()) { url.getPort() == configuratorUrl.getPort()) {
url = configureIfMatch(url.getHost(), url); url = configureIfMatch(url.getHost(), url);
} }
} }
/* /*
* This else branch is deprecated and is left only to keep compatibility with versions before 2.7.0 * This else branch is deprecated and is left only to keep compatibility with versions before 2.7.0
*/ */
else { else {
url = configureDeprecated(url); url = configureDeprecated(url);
} }
return url; return url;
} }
@Deprecated @Deprecated
private URL configureDeprecated(URL url) { private URL configureDeprecated(URL url) {
// If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance. // If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance.
if (configuratorUrl.getPort() != 0) { if (configuratorUrl.getPort() != 0) {
if (url.getPort() == configuratorUrl.getPort()) { if (url.getPort() == configuratorUrl.getPort()) {
return configureIfMatch(url.getHost(), url); return configureIfMatch(url.getHost(), url);
} }
} else { } else {
/* /*
* override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0. * override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0.
* 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore. * 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore.
* 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider. * 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider.
*/ */
if (url.getSide(PROVIDER).equals(CONSUMER)) { if (url.getSide(PROVIDER).equals(CONSUMER)) {
// NetUtils.getLocalHost is the ip address consumer registered to registry. // NetUtils.getLocalHost is the ip address consumer registered to registry.
return configureIfMatch(NetUtils.getLocalHost(), url); return configureIfMatch(NetUtils.getLocalHost(), url);
} else if (url.getSide(CONSUMER).equals(PROVIDER)) { } else if (url.getSide(CONSUMER).equals(PROVIDER)) {
// take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch // take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
return configureIfMatch(ANYHOST_VALUE, url); return configureIfMatch(ANYHOST_VALUE, url);
} }
} }
return url; return url;
} }
private URL configureIfMatch(String host, URL url) { private URL configureIfMatch(String host, URL url) {
if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) { if (ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
// TODO, to support wildcards // TODO, to support wildcards
String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY); String providers = configuratorUrl.getParameter(OVERRIDE_PROVIDERS_KEY);
if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) { if (StringUtils.isEmpty(providers) || providers.contains(url.getAddress()) || providers.contains(ANYHOST_VALUE)) {
String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername()); String configApplication = configuratorUrl.getApplication(configuratorUrl.getUsername());
String currentApplication = url.getApplication(url.getUsername()); String currentApplication = url.getApplication(url.getUsername());
if (configApplication == null || ANY_VALUE.equals(configApplication) if (configApplication == null || ANY_VALUE.equals(configApplication)
|| configApplication.equals(currentApplication)) { || configApplication.equals(currentApplication)) {
Set<String> conditionKeys = new HashSet<String>(); Set<String> conditionKeys = new HashSet<String>();
conditionKeys.add(CATEGORY_KEY); conditionKeys.add(CATEGORY_KEY);
conditionKeys.add(Constants.CHECK_KEY); conditionKeys.add(Constants.CHECK_KEY);
conditionKeys.add(DYNAMIC_KEY); conditionKeys.add(DYNAMIC_KEY);
conditionKeys.add(ENABLED_KEY); conditionKeys.add(ENABLED_KEY);
conditionKeys.add(GROUP_KEY); conditionKeys.add(GROUP_KEY);
conditionKeys.add(VERSION_KEY); conditionKeys.add(VERSION_KEY);
conditionKeys.add(APPLICATION_KEY); conditionKeys.add(APPLICATION_KEY);
conditionKeys.add(SIDE_KEY); conditionKeys.add(SIDE_KEY);
conditionKeys.add(CONFIG_VERSION_KEY); conditionKeys.add(CONFIG_VERSION_KEY);
conditionKeys.add(COMPATIBLE_CONFIG_KEY); conditionKeys.add(COMPATIBLE_CONFIG_KEY);
conditionKeys.add(INTERFACES); conditionKeys.add(INTERFACES);
for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) { for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
String value = entry.getValue(); String value = entry.getValue();
boolean startWithTilde = startWithTilde(key); boolean startWithTilde = startWithTilde(key);
if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) { if (startWithTilde || APPLICATION_KEY.equals(key) || SIDE_KEY.equals(key)) {
if (startWithTilde) { if (startWithTilde) {
conditionKeys.add(key); conditionKeys.add(key);
} }
if (value != null && !ANY_VALUE.equals(value) if (value != null && !ANY_VALUE.equals(value)
&& !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) { && !value.equals(url.getParameter(startWithTilde ? key.substring(1) : key))) {
return url; return url;
} }
} }
} }
return doConfigure(url, configuratorUrl.removeParameters(conditionKeys)); return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
} }
} }
} }
return url; return url;
} }
private boolean startWithTilde(String key) { private boolean startWithTilde(String key) {
if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) { if (StringUtils.isNotEmpty(key) && key.startsWith(TILDE)) {
return true; return true;
} }
return false; return false;
} }
protected abstract URL doConfigure(URL currentUrl, URL configUrl); protected abstract URL doConfigure(URL currentUrl, URL configUrl);
} }

View File

@ -1,37 +1,37 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.absent; package org.apache.dubbo.rpc.cluster.configurator.absent;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator; import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
/** /**
* AbsentConfigurator * AbsentConfigurator
* *
*/ */
public class AbsentConfigurator extends AbstractConfigurator { public class AbsentConfigurator extends AbstractConfigurator {
public AbsentConfigurator(URL url) { public AbsentConfigurator(URL url) {
super(url); super(url);
} }
@Override @Override
public URL doConfigure(URL currentUrl, URL configUrl) { public URL doConfigure(URL currentUrl, URL configUrl) {
return currentUrl.addParametersIfAbsent(configUrl.getParameters()); return currentUrl.addParametersIfAbsent(configUrl.getParameters());
} }
} }

View File

@ -1,34 +1,34 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.absent; package org.apache.dubbo.rpc.cluster.configurator.absent;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.Configurator; import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
/** /**
* AbsentConfiguratorFactory * AbsentConfiguratorFactory
* *
*/ */
public class AbsentConfiguratorFactory implements ConfiguratorFactory { public class AbsentConfiguratorFactory implements ConfiguratorFactory {
@Override @Override
public Configurator getConfigurator(URL url) { public Configurator getConfigurator(URL url) {
return new AbsentConfigurator(url); return new AbsentConfigurator(url);
} }
} }

View File

@ -1,37 +1,37 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.override; package org.apache.dubbo.rpc.cluster.configurator.override;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator; import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
/** /**
* OverrideConfigurator * OverrideConfigurator
* *
*/ */
public class OverrideConfigurator extends AbstractConfigurator { public class OverrideConfigurator extends AbstractConfigurator {
public OverrideConfigurator(URL url) { public OverrideConfigurator(URL url) {
super(url); super(url);
} }
@Override @Override
public URL doConfigure(URL currentUrl, URL configUrl) { public URL doConfigure(URL currentUrl, URL configUrl) {
return currentUrl.addParameters(configUrl.getParameters()); return currentUrl.addParameters(configUrl.getParameters());
} }
} }

View File

@ -1,34 +1,34 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.override; package org.apache.dubbo.rpc.cluster.configurator.override;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.Configurator; import org.apache.dubbo.rpc.cluster.Configurator;
import org.apache.dubbo.rpc.cluster.ConfiguratorFactory; import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
/** /**
* OverrideConfiguratorFactory * OverrideConfiguratorFactory
* *
*/ */
public class OverrideConfiguratorFactory implements ConfiguratorFactory { public class OverrideConfiguratorFactory implements ConfiguratorFactory {
@Override @Override
public Configurator getConfigurator(URL url) { public Configurator getConfigurator(URL url) {
return new OverrideConfigurator(url); return new OverrideConfigurator(url);
} }
} }

View File

@ -1,114 +1,114 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.directory; package org.apache.dubbo.rpc.cluster.directory;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.RouterChain; import org.apache.dubbo.rpc.cluster.RouterChain;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
* StaticDirectory * StaticDirectory
*/ */
public class StaticDirectory<T> extends AbstractDirectory<T> { public class StaticDirectory<T> extends AbstractDirectory<T> {
private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class); private static final Logger logger = LoggerFactory.getLogger(StaticDirectory.class);
private final List<Invoker<T>> invokers; private final List<Invoker<T>> invokers;
public StaticDirectory(List<Invoker<T>> invokers) { public StaticDirectory(List<Invoker<T>> invokers) {
this(null, invokers, null); this(null, invokers, null);
} }
public StaticDirectory(List<Invoker<T>> invokers, RouterChain<T> routerChain) { public StaticDirectory(List<Invoker<T>> invokers, RouterChain<T> routerChain) {
this(null, invokers, routerChain); this(null, invokers, routerChain);
} }
public StaticDirectory(URL url, List<Invoker<T>> invokers) { public StaticDirectory(URL url, List<Invoker<T>> invokers) {
this(url, invokers, null); this(url, invokers, null);
} }
public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) { public StaticDirectory(URL url, List<Invoker<T>> invokers, RouterChain<T> routerChain) {
super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false); super(url == null && CollectionUtils.isNotEmpty(invokers) ? invokers.get(0).getUrl() : url, routerChain, false);
if (CollectionUtils.isEmpty(invokers)) { if (CollectionUtils.isEmpty(invokers)) {
throw new IllegalArgumentException("invokers == null"); throw new IllegalArgumentException("invokers == null");
} }
this.invokers = invokers; this.invokers = invokers;
} }
@Override @Override
public Class<T> getInterface() { public Class<T> getInterface() {
return invokers.get(0).getInterface(); return invokers.get(0).getInterface();
} }
@Override @Override
public List<Invoker<T>> getAllInvokers() { public List<Invoker<T>> getAllInvokers() {
return invokers; return invokers;
} }
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
if (isDestroyed()) { if (isDestroyed()) {
return false; return false;
} }
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
if (invoker.isAvailable()) { if (invoker.isAvailable()) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public void destroy() { public void destroy() {
if (isDestroyed()) { if (isDestroyed()) {
return; return;
} }
super.destroy(); super.destroy();
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
invoker.destroy(); invoker.destroy();
} }
invokers.clear(); invokers.clear();
} }
public void buildRouterChain() { public void buildRouterChain() {
RouterChain<T> routerChain = RouterChain.buildChain(getUrl()); RouterChain<T> routerChain = RouterChain.buildChain(getUrl());
routerChain.setInvokers(invokers); routerChain.setInvokers(invokers);
routerChain.loop(true); routerChain.loop(true);
this.setRouterChain(routerChain); this.setRouterChain(routerChain);
} }
@Override @Override
protected List<Invoker<T>> doList(Invocation invocation) throws RpcException { protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
List<Invoker<T>> finalInvokers = invokers; List<Invoker<T>> finalInvokers = invokers;
if (routerChain != null) { if (routerChain != null) {
try { try {
finalInvokers = routerChain.route(getConsumerUrl(), invocation); finalInvokers = routerChain.route(getConsumerUrl(), invocation);
} catch (Throwable t) { } catch (Throwable t) {
logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t); logger.error("Failed to execute router: " + getUrl() + ", cause: " + t.getMessage(), t);
} }
} }
return finalInvokers == null ? Collections.emptyList() : finalInvokers; return finalInvokers == null ? Collections.emptyList() : finalInvokers;
} }
} }

View File

@ -1,99 +1,99 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.loadbalance; package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import java.util.List; import java.util.List;
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY; import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_KEY;
import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH; import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_SERVICE_REFERENCE_PATH;
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP; import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WARMUP;
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT; import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_WEIGHT;
import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY; import static org.apache.dubbo.rpc.cluster.Constants.WARMUP_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY; import static org.apache.dubbo.rpc.cluster.Constants.WEIGHT_KEY;
/** /**
* AbstractLoadBalance * AbstractLoadBalance
*/ */
public abstract class AbstractLoadBalance implements LoadBalance { public abstract class AbstractLoadBalance implements LoadBalance {
/** /**
* Calculate the weight according to the uptime proportion of warmup time * Calculate the weight according to the uptime proportion of warmup time
* the new weight will be within 1(inclusive) to weight(inclusive) * the new weight will be within 1(inclusive) to weight(inclusive)
* *
* @param uptime the uptime in milliseconds * @param uptime the uptime in milliseconds
* @param warmup the warmup time in milliseconds * @param warmup the warmup time in milliseconds
* @param weight the weight of an invoker * @param weight the weight of an invoker
* @return weight which takes warmup into account * @return weight which takes warmup into account
*/ */
static int calculateWarmupWeight(int uptime, int warmup, int weight) { static int calculateWarmupWeight(int uptime, int warmup, int weight) {
int ww = (int) ( uptime / ((float) warmup / weight)); int ww = (int) ( uptime / ((float) warmup / weight));
return ww < 1 ? 1 : (Math.min(ww, weight)); return ww < 1 ? 1 : (Math.min(ww, weight));
} }
@Override @Override
public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) { public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
if (CollectionUtils.isEmpty(invokers)) { if (CollectionUtils.isEmpty(invokers)) {
return null; return null;
} }
if (invokers.size() == 1) { if (invokers.size() == 1) {
return invokers.get(0); return invokers.get(0);
} }
return doSelect(invokers, url, invocation); return doSelect(invokers, url, invocation);
} }
protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation); protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
/** /**
* Get the weight of the invoker's invocation which takes warmup time into account * Get the weight of the invoker's invocation which takes warmup time into account
* if the uptime is within the warmup time, the weight will be reduce proportionally * if the uptime is within the warmup time, the weight will be reduce proportionally
* *
* @param invoker the invoker * @param invoker the invoker
* @param invocation the invocation of this invoker * @param invocation the invocation of this invoker
* @return weight * @return weight
*/ */
int getWeight(Invoker<?> invoker, Invocation invocation) { int getWeight(Invoker<?> invoker, Invocation invocation) {
int weight; int weight;
URL url = invoker.getUrl(); URL url = invoker.getUrl();
// Multiple registry scenario, load balance among multiple registries. // Multiple registry scenario, load balance among multiple registries.
if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) { if (REGISTRY_SERVICE_REFERENCE_PATH.equals(url.getServiceInterface())) {
weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT); weight = url.getParameter(REGISTRY_KEY + "." + WEIGHT_KEY, DEFAULT_WEIGHT);
} else { } else {
weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT); weight = url.getMethodParameter(invocation.getMethodName(), WEIGHT_KEY, DEFAULT_WEIGHT);
if (weight > 0) { if (weight > 0) {
long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L); long timestamp = invoker.getUrl().getParameter(TIMESTAMP_KEY, 0L);
if (timestamp > 0L) { if (timestamp > 0L) {
long uptime = System.currentTimeMillis() - timestamp; long uptime = System.currentTimeMillis() - timestamp;
if (uptime < 0) { if (uptime < 0) {
return 1; return 1;
} }
int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP); int warmup = invoker.getUrl().getParameter(WARMUP_KEY, DEFAULT_WARMUP);
if (uptime > 0 && uptime < warmup) { if (uptime > 0 && uptime < warmup) {
weight = calculateWarmupWeight((int)uptime, warmup, weight); weight = calculateWarmupWeight((int)uptime, warmup, weight);
} }
} }
} }
} }
return Math.max(weight, 0); return Math.max(weight, 0);
} }
} }

View File

@ -1,131 +1,131 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.loadbalance; package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.io.Bytes; import org.apache.dubbo.common.io.Bytes;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.support.RpcUtils; import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.COMMA_SPLIT_PATTERN;
/** /**
* ConsistentHashLoadBalance * ConsistentHashLoadBalance
*/ */
public class ConsistentHashLoadBalance extends AbstractLoadBalance { public class ConsistentHashLoadBalance extends AbstractLoadBalance {
public static final String NAME = "consistenthash"; public static final String NAME = "consistenthash";
/** /**
* Hash nodes name * Hash nodes name
*/ */
public static final String HASH_NODES = "hash.nodes"; public static final String HASH_NODES = "hash.nodes";
/** /**
* Hash arguments name * Hash arguments name
*/ */
public static final String HASH_ARGUMENTS = "hash.arguments"; public static final String HASH_ARGUMENTS = "hash.arguments";
private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>(); private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
String methodName = RpcUtils.getMethodName(invocation); String methodName = RpcUtils.getMethodName(invocation);
String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName; String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;
// using the hashcode of list to compute the hash only pay attention to the elements in the list // using the hashcode of list to compute the hash only pay attention to the elements in the list
int invokersHashCode = invokers.hashCode(); int invokersHashCode = invokers.hashCode();
ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key); ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key);
if (selector == null || selector.identityHashCode != invokersHashCode) { if (selector == null || selector.identityHashCode != invokersHashCode) {
selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, invokersHashCode)); selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, invokersHashCode));
selector = (ConsistentHashSelector<T>) selectors.get(key); selector = (ConsistentHashSelector<T>) selectors.get(key);
} }
return selector.select(invocation); return selector.select(invocation);
} }
private static final class ConsistentHashSelector<T> { private static final class ConsistentHashSelector<T> {
private final TreeMap<Long, Invoker<T>> virtualInvokers; private final TreeMap<Long, Invoker<T>> virtualInvokers;
private final int replicaNumber; private final int replicaNumber;
private final int identityHashCode; private final int identityHashCode;
private final int[] argumentIndex; private final int[] argumentIndex;
ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) { ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {
this.virtualInvokers = new TreeMap<Long, Invoker<T>>(); this.virtualInvokers = new TreeMap<Long, Invoker<T>>();
this.identityHashCode = identityHashCode; this.identityHashCode = identityHashCode;
URL url = invokers.get(0).getUrl(); URL url = invokers.get(0).getUrl();
this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160); this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);
String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0")); String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0"));
argumentIndex = new int[index.length]; argumentIndex = new int[index.length];
for (int i = 0; i < index.length; i++) { for (int i = 0; i < index.length; i++) {
argumentIndex[i] = Integer.parseInt(index[i]); argumentIndex[i] = Integer.parseInt(index[i]);
} }
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
String address = invoker.getUrl().getAddress(); String address = invoker.getUrl().getAddress();
for (int i = 0; i < replicaNumber / 4; i++) { for (int i = 0; i < replicaNumber / 4; i++) {
byte[] digest = Bytes.getMD5(address + i); byte[] digest = Bytes.getMD5(address + i);
for (int h = 0; h < 4; h++) { for (int h = 0; h < 4; h++) {
long m = hash(digest, h); long m = hash(digest, h);
virtualInvokers.put(m, invoker); virtualInvokers.put(m, invoker);
} }
} }
} }
} }
public Invoker<T> select(Invocation invocation) { public Invoker<T> select(Invocation invocation) {
String key = toKey(invocation.getArguments()); String key = toKey(invocation.getArguments());
byte[] digest = Bytes.getMD5(key); byte[] digest = Bytes.getMD5(key);
return selectForKey(hash(digest, 0)); return selectForKey(hash(digest, 0));
} }
private String toKey(Object[] args) { private String toKey(Object[] args) {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
for (int i : argumentIndex) { for (int i : argumentIndex) {
if (i >= 0 && i < args.length) { if (i >= 0 && i < args.length) {
buf.append(args[i]); buf.append(args[i]);
} }
} }
return buf.toString(); return buf.toString();
} }
private Invoker<T> selectForKey(long hash) { private Invoker<T> selectForKey(long hash) {
Map.Entry<Long, Invoker<T>> entry = virtualInvokers.ceilingEntry(hash); Map.Entry<Long, Invoker<T>> entry = virtualInvokers.ceilingEntry(hash);
if (entry == null) { if (entry == null) {
entry = virtualInvokers.firstEntry(); entry = virtualInvokers.firstEntry();
} }
return entry.getValue(); return entry.getValue();
} }
private long hash(byte[] digest, int number) { private long hash(byte[] digest, int number) {
return (((long) (digest[3 + number * 4] & 0xFF) << 24) return (((long) (digest[3 + number * 4] & 0xFF) << 24)
| ((long) (digest[2 + number * 4] & 0xFF) << 16) | ((long) (digest[2 + number * 4] & 0xFF) << 16)
| ((long) (digest[1 + number * 4] & 0xFF) << 8) | ((long) (digest[1 + number * 4] & 0xFF) << 8)
| (digest[number * 4] & 0xFF)) | (digest[number * 4] & 0xFF))
& 0xFFFFFFFFL; & 0xFFFFFFFFL;
} }
} }
} }

View File

@ -1,115 +1,115 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.loadbalance; package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcStatus; import org.apache.dubbo.rpc.RpcStatus;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
/** /**
* LeastActiveLoadBalance * LeastActiveLoadBalance
* <p> * <p>
* Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers. * Filter the number of invokers with the least number of active calls and count the weights and quantities of these invokers.
* If there is only one invoker, use the invoker directly; * If there is only one invoker, use the invoker directly;
* if there are multiple invokers and the weights are not the same, then random according to the total weight; * if there are multiple invokers and the weights are not the same, then random according to the total weight;
* if there are multiple invokers and the same weight, then randomly called. * if there are multiple invokers and the same weight, then randomly called.
*/ */
public class LeastActiveLoadBalance extends AbstractLoadBalance { public class LeastActiveLoadBalance extends AbstractLoadBalance {
public static final String NAME = "leastactive"; public static final String NAME = "leastactive";
@Override @Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
// Number of invokers // Number of invokers
int length = invokers.size(); int length = invokers.size();
// The least active value of all invokers // The least active value of all invokers
int leastActive = -1; int leastActive = -1;
// The number of invokers having the same least active value (leastActive) // The number of invokers having the same least active value (leastActive)
int leastCount = 0; int leastCount = 0;
// The index of invokers having the same least active value (leastActive) // The index of invokers having the same least active value (leastActive)
int[] leastIndexes = new int[length]; int[] leastIndexes = new int[length];
// the weight of every invokers // the weight of every invokers
int[] weights = new int[length]; int[] weights = new int[length];
// The sum of the warmup weights of all the least active invokers // The sum of the warmup weights of all the least active invokers
int totalWeight = 0; int totalWeight = 0;
// The weight of the first least active invoker // The weight of the first least active invoker
int firstWeight = 0; int firstWeight = 0;
// Every least active invoker has the same weight value? // Every least active invoker has the same weight value?
boolean sameWeight = true; boolean sameWeight = true;
// Filter out all the least active invokers // Filter out all the least active invokers
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Invoker<T> invoker = invokers.get(i); Invoker<T> invoker = invokers.get(i);
// Get the active number of the invoker // Get the active number of the invoker
int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();
// Get the weight of the invoker's configuration. The default value is 100. // Get the weight of the invoker's configuration. The default value is 100.
int afterWarmup = getWeight(invoker, invocation); int afterWarmup = getWeight(invoker, invocation);
// save for later use // save for later use
weights[i] = afterWarmup; weights[i] = afterWarmup;
// If it is the first invoker or the active number of the invoker is less than the current least active number // If it is the first invoker or the active number of the invoker is less than the current least active number
if (leastActive == -1 || active < leastActive) { if (leastActive == -1 || active < leastActive) {
// Reset the active number of the current invoker to the least active number // Reset the active number of the current invoker to the least active number
leastActive = active; leastActive = active;
// Reset the number of least active invokers // Reset the number of least active invokers
leastCount = 1; leastCount = 1;
// Put the first least active invoker first in leastIndexes // Put the first least active invoker first in leastIndexes
leastIndexes[0] = i; leastIndexes[0] = i;
// Reset totalWeight // Reset totalWeight
totalWeight = afterWarmup; totalWeight = afterWarmup;
// Record the weight the first least active invoker // Record the weight the first least active invoker
firstWeight = afterWarmup; firstWeight = afterWarmup;
// Each invoke has the same weight (only one invoker here) // Each invoke has the same weight (only one invoker here)
sameWeight = true; sameWeight = true;
// If current invoker's active value equals with leaseActive, then accumulating. // If current invoker's active value equals with leaseActive, then accumulating.
} else if (active == leastActive) { } else if (active == leastActive) {
// Record the index of the least active invoker in leastIndexes order // Record the index of the least active invoker in leastIndexes order
leastIndexes[leastCount++] = i; leastIndexes[leastCount++] = i;
// Accumulate the total weight of the least active invoker // Accumulate the total weight of the least active invoker
totalWeight += afterWarmup; totalWeight += afterWarmup;
// If every invoker has the same weight? // If every invoker has the same weight?
if (sameWeight && afterWarmup != firstWeight) { if (sameWeight && afterWarmup != firstWeight) {
sameWeight = false; sameWeight = false;
} }
} }
} }
// Choose an invoker from all the least active invokers // Choose an invoker from all the least active invokers
if (leastCount == 1) { if (leastCount == 1) {
// If we got exactly one invoker having the least active value, return this invoker directly. // If we got exactly one invoker having the least active value, return this invoker directly.
return invokers.get(leastIndexes[0]); return invokers.get(leastIndexes[0]);
} }
if (!sameWeight && totalWeight > 0) { if (!sameWeight && totalWeight > 0) {
// If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on
// totalWeight. // totalWeight.
int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight); int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);
// Return a invoker based on the random value. // Return a invoker based on the random value.
for (int i = 0; i < leastCount; i++) { for (int i = 0; i < leastCount; i++) {
int leastIndex = leastIndexes[i]; int leastIndex = leastIndexes[i];
offsetWeight -= weights[leastIndex]; offsetWeight -= weights[leastIndex];
if (offsetWeight < 0) { if (offsetWeight < 0) {
return invokers.get(leastIndex); return invokers.get(leastIndex);
} }
} }
} }
// If all invokers have the same weight value or totalWeight=0, return evenly. // If all invokers have the same weight value or totalWeight=0, return evenly.
return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]); return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);
} }
} }

View File

@ -1,131 +1,131 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.loadbalance; package org.apache.dubbo.rpc.cluster.loadbalance;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
* Round robin load balance. * Round robin load balance.
*/ */
public class RoundRobinLoadBalance extends AbstractLoadBalance { public class RoundRobinLoadBalance extends AbstractLoadBalance {
public static final String NAME = "roundrobin"; public static final String NAME = "roundrobin";
private static final int RECYCLE_PERIOD = 60000; private static final int RECYCLE_PERIOD = 60000;
protected static class WeightedRoundRobin { protected static class WeightedRoundRobin {
private int weight; private int weight;
private AtomicLong current = new AtomicLong(0); private AtomicLong current = new AtomicLong(0);
private long lastUpdate; private long lastUpdate;
public int getWeight() { public int getWeight() {
return weight; return weight;
} }
public void setWeight(int weight) { public void setWeight(int weight) {
this.weight = weight; this.weight = weight;
current.set(0); current.set(0);
} }
public long increaseCurrent() { public long increaseCurrent() {
return current.addAndGet(weight); return current.addAndGet(weight);
} }
public void sel(int total) { public void sel(int total) {
current.addAndGet(-1 * total); current.addAndGet(-1 * total);
} }
public long getLastUpdate() { public long getLastUpdate() {
return lastUpdate; return lastUpdate;
} }
public void setLastUpdate(long lastUpdate) { public void setLastUpdate(long lastUpdate) {
this.lastUpdate = lastUpdate; this.lastUpdate = lastUpdate;
} }
} }
private ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap = new ConcurrentHashMap<String, ConcurrentMap<String, WeightedRoundRobin>>(); private ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap = new ConcurrentHashMap<String, ConcurrentMap<String, WeightedRoundRobin>>();
/** /**
* get invoker addr list cached for specified invocation * get invoker addr list cached for specified invocation
* <p> * <p>
* <b>for unit test only</b> * <b>for unit test only</b>
* *
* @param invokers * @param invokers
* @param invocation * @param invocation
* @return * @return
*/ */
protected <T> Collection<String> getInvokerAddrList(List<Invoker<T>> invokers, Invocation invocation) { protected <T> Collection<String> getInvokerAddrList(List<Invoker<T>> invokers, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName(); String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
Map<String, WeightedRoundRobin> map = methodWeightMap.get(key); Map<String, WeightedRoundRobin> map = methodWeightMap.get(key);
if (map != null) { if (map != null) {
return map.keySet(); return map.keySet();
} }
return null; return null;
} }
@Override @Override
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) { protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName(); String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
ConcurrentMap<String, WeightedRoundRobin> map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>()); ConcurrentMap<String, WeightedRoundRobin> map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());
int totalWeight = 0; int totalWeight = 0;
long maxCurrent = Long.MIN_VALUE; long maxCurrent = Long.MIN_VALUE;
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
Invoker<T> selectedInvoker = null; Invoker<T> selectedInvoker = null;
WeightedRoundRobin selectedWRR = null; WeightedRoundRobin selectedWRR = null;
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
String identifyString = invoker.getUrl().toIdentityString(); String identifyString = invoker.getUrl().toIdentityString();
int weight = getWeight(invoker, invocation); int weight = getWeight(invoker, invocation);
WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> { WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {
WeightedRoundRobin wrr = new WeightedRoundRobin(); WeightedRoundRobin wrr = new WeightedRoundRobin();
wrr.setWeight(weight); wrr.setWeight(weight);
return wrr; return wrr;
}); });
if (weight != weightedRoundRobin.getWeight()) { if (weight != weightedRoundRobin.getWeight()) {
//weight changed //weight changed
weightedRoundRobin.setWeight(weight); weightedRoundRobin.setWeight(weight);
} }
long cur = weightedRoundRobin.increaseCurrent(); long cur = weightedRoundRobin.increaseCurrent();
weightedRoundRobin.setLastUpdate(now); weightedRoundRobin.setLastUpdate(now);
if (cur > maxCurrent) { if (cur > maxCurrent) {
maxCurrent = cur; maxCurrent = cur;
selectedInvoker = invoker; selectedInvoker = invoker;
selectedWRR = weightedRoundRobin; selectedWRR = weightedRoundRobin;
} }
totalWeight += weight; totalWeight += weight;
} }
if (invokers.size() != map.size()) { if (invokers.size() != map.size()) {
map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD); map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);
} }
if (selectedInvoker != null) { if (selectedInvoker != null) {
selectedWRR.sel(totalWeight); selectedWRR.sel(totalWeight);
return selectedInvoker; return selectedInvoker;
} }
// should not happen here // should not happen here
return invokers.get(0); return invokers.get(0);
} }
} }

View File

@ -1,360 +1,360 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.condition; package org.apache.dubbo.rpc.cluster.router.condition;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.common.utils.UrlUtils; import org.apache.dubbo.common.utils.UrlUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Constants; import org.apache.dubbo.rpc.cluster.Constants;
import org.apache.dubbo.rpc.cluster.router.AbstractRouter; import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
import java.text.ParseException; import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY; import static org.apache.dubbo.common.constants.CommonConstants.ENABLED_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY; import static org.apache.dubbo.common.constants.CommonConstants.HOST_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY; import static org.apache.dubbo.common.constants.CommonConstants.METHOD_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY; import static org.apache.dubbo.rpc.cluster.Constants.ADDRESS_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY; import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
/** /**
* ConditionRouter * ConditionRouter
* It supports the conditional routing configured by "override://", in 2.6.x, * It supports the conditional routing configured by "override://", in 2.6.x,
* refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ . * refer to https://dubbo.apache.org/en/docs/v2.7/user/examples/routing-rule/ .
* For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter} * For 2.7.x and later, please refer to {@link org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouter}
* and {@link org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter} * and {@link org.apache.dubbo.rpc.cluster.router.condition.config.AppRouter}
* refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ . * refer to https://dubbo.apache.org/zh/docs/v2.7/user/examples/routing-rule/ .
*/ */
public class ConditionRouter extends AbstractRouter { public class ConditionRouter extends AbstractRouter {
public static final String NAME = "condition"; public static final String NAME = "condition";
private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class); private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)"); protected static final Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]"); protected static Pattern ARGUMENTS_PATTERN = Pattern.compile("arguments\\[([0-9]+)\\]");
protected Map<String, MatchPair> whenCondition; protected Map<String, MatchPair> whenCondition;
protected Map<String, MatchPair> thenCondition; protected Map<String, MatchPair> thenCondition;
private boolean enabled; private boolean enabled;
public ConditionRouter(String rule, boolean force, boolean enabled) { public ConditionRouter(String rule, boolean force, boolean enabled) {
this.force = force; this.force = force;
this.enabled = enabled; this.enabled = enabled;
if (enabled) { if (enabled) {
this.init(rule); this.init(rule);
} }
} }
public ConditionRouter(URL url) { public ConditionRouter(URL url) {
this.url = url; this.url = url;
this.priority = url.getParameter(PRIORITY_KEY, 0); this.priority = url.getParameter(PRIORITY_KEY, 0);
this.force = url.getParameter(FORCE_KEY, false); this.force = url.getParameter(FORCE_KEY, false);
this.enabled = url.getParameter(ENABLED_KEY, true); this.enabled = url.getParameter(ENABLED_KEY, true);
if (enabled) { if (enabled) {
init(url.getParameterAndDecoded(RULE_KEY)); init(url.getParameterAndDecoded(RULE_KEY));
} }
} }
public void init(String rule) { public void init(String rule) {
try { try {
if (rule == null || rule.trim().length() == 0) { if (rule == null || rule.trim().length() == 0) {
throw new IllegalArgumentException("Illegal route rule!"); throw new IllegalArgumentException("Illegal route rule!");
} }
rule = rule.replace("consumer.", "").replace("provider.", ""); rule = rule.replace("consumer.", "").replace("provider.", "");
int i = rule.indexOf("=>"); int i = rule.indexOf("=>");
String whenRule = i < 0 ? null : rule.substring(0, i).trim(); String whenRule = i < 0 ? null : rule.substring(0, i).trim();
String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim(); String thenRule = i < 0 ? rule.trim() : rule.substring(i + 2).trim();
Map<String, MatchPair> when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<String, MatchPair>() : parseRule(whenRule); Map<String, MatchPair> when = StringUtils.isBlank(whenRule) || "true".equals(whenRule) ? new HashMap<String, MatchPair>() : parseRule(whenRule);
Map<String, MatchPair> then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule); Map<String, MatchPair> then = StringUtils.isBlank(thenRule) || "false".equals(thenRule) ? null : parseRule(thenRule);
// NOTE: It should be determined on the business level whether the `When condition` can be empty or not. // NOTE: It should be determined on the business level whether the `When condition` can be empty or not.
this.whenCondition = when; this.whenCondition = when;
this.thenCondition = then; this.thenCondition = then;
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalStateException(e.getMessage(), e); throw new IllegalStateException(e.getMessage(), e);
} }
} }
private static Map<String, MatchPair> parseRule(String rule) private static Map<String, MatchPair> parseRule(String rule)
throws ParseException { throws ParseException {
Map<String, MatchPair> condition = new HashMap<String, MatchPair>(); Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
if (StringUtils.isBlank(rule)) { if (StringUtils.isBlank(rule)) {
return condition; return condition;
} }
// Key-Value pair, stores both match and mismatch conditions // Key-Value pair, stores both match and mismatch conditions
MatchPair pair = null; MatchPair pair = null;
// Multiple values // Multiple values
Set<String> values = null; Set<String> values = null;
final Matcher matcher = ROUTE_PATTERN.matcher(rule); final Matcher matcher = ROUTE_PATTERN.matcher(rule);
while (matcher.find()) { // Try to match one by one while (matcher.find()) { // Try to match one by one
String separator = matcher.group(1); String separator = matcher.group(1);
String content = matcher.group(2); String content = matcher.group(2);
// Start part of the condition expression. // Start part of the condition expression.
if (StringUtils.isEmpty(separator)) { if (StringUtils.isEmpty(separator)) {
pair = new MatchPair(); pair = new MatchPair();
condition.put(content, pair); condition.put(content, pair);
} }
// The KV part of the condition expression // The KV part of the condition expression
else if ("&".equals(separator)) { else if ("&".equals(separator)) {
if (condition.get(content) == null) { if (condition.get(content) == null) {
pair = new MatchPair(); pair = new MatchPair();
condition.put(content, pair); condition.put(content, pair);
} else { } else {
pair = condition.get(content); pair = condition.get(content);
} }
} }
// The Value in the KV part. // The Value in the KV part.
else if ("=".equals(separator)) { else if ("=".equals(separator)) {
if (pair == null) { if (pair == null) {
throw new ParseException("Illegal route rule \"" throw new ParseException("Illegal route rule \""
+ rule + "\", The error char '" + separator + rule + "\", The error char '" + separator
+ "' at index " + matcher.start() + " before \"" + "' at index " + matcher.start() + " before \""
+ content + "\".", matcher.start()); + content + "\".", matcher.start());
} }
values = pair.matches; values = pair.matches;
values.add(content); values.add(content);
} }
// The Value in the KV part. // The Value in the KV part.
else if ("!=".equals(separator)) { else if ("!=".equals(separator)) {
if (pair == null) { if (pair == null) {
throw new ParseException("Illegal route rule \"" throw new ParseException("Illegal route rule \""
+ rule + "\", The error char '" + separator + rule + "\", The error char '" + separator
+ "' at index " + matcher.start() + " before \"" + "' at index " + matcher.start() + " before \""
+ content + "\".", matcher.start()); + content + "\".", matcher.start());
} }
values = pair.mismatches; values = pair.mismatches;
values.add(content); values.add(content);
} }
// The Value in the KV part, if Value have more than one items. // The Value in the KV part, if Value have more than one items.
else if (",".equals(separator)) { // Should be separated by ',' else if (",".equals(separator)) { // Should be separated by ','
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
throw new ParseException("Illegal route rule \"" throw new ParseException("Illegal route rule \""
+ rule + "\", The error char '" + separator + rule + "\", The error char '" + separator
+ "' at index " + matcher.start() + " before \"" + "' at index " + matcher.start() + " before \""
+ content + "\".", matcher.start()); + content + "\".", matcher.start());
} }
values.add(content); values.add(content);
} else { } else {
throw new ParseException("Illegal route rule \"" + rule throw new ParseException("Illegal route rule \"" + rule
+ "\", The error char '" + separator + "' at index " + "\", The error char '" + separator + "' at index "
+ matcher.start() + " before \"" + content + "\".", matcher.start()); + matcher.start() + " before \"" + content + "\".", matcher.start());
} }
} }
return condition; return condition;
} }
@Override @Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation)
throws RpcException { throws RpcException {
if (!enabled) { if (!enabled) {
return invokers; return invokers;
} }
if (CollectionUtils.isEmpty(invokers)) { if (CollectionUtils.isEmpty(invokers)) {
return invokers; return invokers;
} }
try { try {
if (!matchWhen(url, invocation)) { if (!matchWhen(url, invocation)) {
return invokers; return invokers;
} }
List<Invoker<T>> result = new ArrayList<Invoker<T>>(); List<Invoker<T>> result = new ArrayList<Invoker<T>>();
if (thenCondition == null) { if (thenCondition == null) {
logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey()); logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
return result; return result;
} }
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
if (matchThen(invoker.getUrl(), url)) { if (matchThen(invoker.getUrl(), url)) {
result.add(invoker); result.add(invoker);
} }
} }
if (!result.isEmpty()) { if (!result.isEmpty()) {
return result; return result;
} else if (force) { } else if (force) {
logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY)); logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(RULE_KEY));
return result; return result;
} }
} catch (Throwable t) { } catch (Throwable t) {
logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t); logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
} }
return invokers; return invokers;
} }
@Override @Override
public boolean isRuntime() { public boolean isRuntime() {
// We always return true for previously defined Router, that is, old Router doesn't support cache anymore. // We always return true for previously defined Router, that is, old Router doesn't support cache anymore.
// return true; // return true;
return this.url.getParameter(RUNTIME_KEY, false); return this.url.getParameter(RUNTIME_KEY, false);
} }
@Override @Override
public URL getUrl() { public URL getUrl() {
return url; return url;
} }
boolean matchWhen(URL url, Invocation invocation) { boolean matchWhen(URL url, Invocation invocation) {
return CollectionUtils.isEmptyMap(whenCondition) || matchCondition(whenCondition, url, null, invocation); return CollectionUtils.isEmptyMap(whenCondition) || matchCondition(whenCondition, url, null, invocation);
} }
private boolean matchThen(URL url, URL param) { private boolean matchThen(URL url, URL param) {
return CollectionUtils.isNotEmptyMap(thenCondition) && matchCondition(thenCondition, url, param, null); return CollectionUtils.isNotEmptyMap(thenCondition) && matchCondition(thenCondition, url, param, null);
} }
private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) { private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) {
Map<String, String> sample = url.toMap(); Map<String, String> sample = url.toMap();
boolean result = false; boolean result = false;
for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) { for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) {
String key = matchPair.getKey(); String key = matchPair.getKey();
if (key.startsWith(Constants.ARGUMENTS)) { if (key.startsWith(Constants.ARGUMENTS)) {
if (!matchArguments(matchPair, invocation)) { if (!matchArguments(matchPair, invocation)) {
return false; return false;
} else { } else {
result = true; result = true;
continue; continue;
} }
} }
String sampleValue; String sampleValue;
//get real invoked method name from invocation //get real invoked method name from invocation
if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) { if (invocation != null && (METHOD_KEY.equals(key) || METHODS_KEY.equals(key))) {
sampleValue = invocation.getMethodName(); sampleValue = invocation.getMethodName();
} else if (ADDRESS_KEY.equals(key)) { } else if (ADDRESS_KEY.equals(key)) {
sampleValue = url.getAddress(); sampleValue = url.getAddress();
} else if (HOST_KEY.equals(key)) { } else if (HOST_KEY.equals(key)) {
sampleValue = url.getHost(); sampleValue = url.getHost();
} else { } else {
sampleValue = sample.get(key); sampleValue = sample.get(key);
if (sampleValue == null) { if (sampleValue == null) {
sampleValue = sample.get(key); sampleValue = sample.get(key);
} }
} }
if (sampleValue != null) { if (sampleValue != null) {
if (!matchPair.getValue().isMatch(sampleValue, param)) { if (!matchPair.getValue().isMatch(sampleValue, param)) {
return false; return false;
} else { } else {
result = true; result = true;
} }
} else { } else {
//not pass the condition //not pass the condition
if (!matchPair.getValue().matches.isEmpty()) { if (!matchPair.getValue().matches.isEmpty()) {
return false; return false;
} else { } else {
result = true; result = true;
} }
} }
} }
return result; return result;
} }
/** /**
* analysis the arguments in the rule. * analysis the arguments in the rule.
* Examples would be like this: * Examples would be like this:
* "arguments[0]=1", whenCondition is that the first argument is equal to '1'. * "arguments[0]=1", whenCondition is that the first argument is equal to '1'.
* "arguments[1]=a", whenCondition is that the second argument is equal to 'a'. * "arguments[1]=a", whenCondition is that the second argument is equal to 'a'.
* @param matchPair * @param matchPair
* @param invocation * @param invocation
* @return * @return
*/ */
public boolean matchArguments(Map.Entry<String, MatchPair> matchPair, Invocation invocation) { public boolean matchArguments(Map.Entry<String, MatchPair> matchPair, Invocation invocation) {
try { try {
// split the rule // split the rule
String key = matchPair.getKey(); String key = matchPair.getKey();
String[] expressArray = key.split("\\."); String[] expressArray = key.split("\\.");
String argumentExpress = expressArray[0]; String argumentExpress = expressArray[0];
final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress); final Matcher matcher = ARGUMENTS_PATTERN.matcher(argumentExpress);
if (!matcher.find()) { if (!matcher.find()) {
return false; return false;
} }
//extract the argument index //extract the argument index
int index = Integer.parseInt(matcher.group(1)); int index = Integer.parseInt(matcher.group(1));
if (index < 0 || index > invocation.getArguments().length) { if (index < 0 || index > invocation.getArguments().length) {
return false; return false;
} }
//extract the argument value //extract the argument value
Object object = invocation.getArguments()[index]; Object object = invocation.getArguments()[index];
if (matchPair.getValue().isMatch(String.valueOf(object), null)) { if (matchPair.getValue().isMatch(String.valueOf(object), null)) {
return true; return true;
} }
} catch (Exception e) { } catch (Exception e) {
logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e); logger.warn("Arguments match failed, matchPair[]" + matchPair + "] invocation[" + invocation + "]", e);
} }
return false; return false;
} }
protected static final class MatchPair { protected static final class MatchPair {
final Set<String> matches = new HashSet<String>(); final Set<String> matches = new HashSet<String>();
final Set<String> mismatches = new HashSet<String>(); final Set<String> mismatches = new HashSet<String>();
private boolean isMatch(String value, URL param) { private boolean isMatch(String value, URL param) {
if (!matches.isEmpty() && mismatches.isEmpty()) { if (!matches.isEmpty() && mismatches.isEmpty()) {
for (String match : matches) { for (String match : matches) {
if (UrlUtils.isMatchGlobPattern(match, value, param)) { if (UrlUtils.isMatchGlobPattern(match, value, param)) {
return true; return true;
} }
} }
return false; return false;
} }
if (!mismatches.isEmpty() && matches.isEmpty()) { if (!mismatches.isEmpty() && matches.isEmpty()) {
for (String mismatch : mismatches) { for (String mismatch : mismatches) {
if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) { if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
return false; return false;
} }
} }
return true; return true;
} }
if (!matches.isEmpty() && !mismatches.isEmpty()) { if (!matches.isEmpty() && !mismatches.isEmpty()) {
//when both mismatches and matches contain the same value, then using mismatches first //when both mismatches and matches contain the same value, then using mismatches first
for (String mismatch : mismatches) { for (String mismatch : mismatches) {
if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) { if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
return false; return false;
} }
} }
for (String match : matches) { for (String match : matches) {
if (UrlUtils.isMatchGlobPattern(match, value, param)) { if (UrlUtils.isMatchGlobPattern(match, value, param)) {
return true; return true;
} }
} }
return false; return false;
} }
return false; return false;
} }
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.condition; package org.apache.dubbo.rpc.cluster.router.condition;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.RouterFactory; import org.apache.dubbo.rpc.cluster.RouterFactory;
/** /**
* ConditionRouterFactory * ConditionRouterFactory
* Load when "override://" is configured {@link ConditionRouter} * Load when "override://" is configured {@link ConditionRouter}
*/ */
public class ConditionRouterFactory implements RouterFactory { public class ConditionRouterFactory implements RouterFactory {
public static final String NAME = "condition"; public static final String NAME = "condition";
@Override @Override
public Router getRouter(URL url) { public Router getRouter(URL url) {
return new ConditionRouter(url); return new ConditionRouter(url);
} }
} }

View File

@ -1,177 +1,177 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.script; package org.apache.dubbo.rpc.cluster.router.script;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.router.AbstractRouter; import org.apache.dubbo.rpc.cluster.router.AbstractRouter;
import javax.script.Bindings; import javax.script.Bindings;
import javax.script.Compilable; import javax.script.Compilable;
import javax.script.CompiledScript; import javax.script.CompiledScript;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
import javax.script.ScriptException; import javax.script.ScriptException;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.security.AccessController; import java.security.AccessController;
import java.security.CodeSource; import java.security.CodeSource;
import java.security.Permissions; import java.security.Permissions;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_SCRIPT_TYPE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_SCRIPT_TYPE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY; import static org.apache.dubbo.rpc.cluster.Constants.PRIORITY_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RUNTIME_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.TYPE_KEY;
/** /**
* ScriptRouter * ScriptRouter
*/ */
public class ScriptRouter extends AbstractRouter { public class ScriptRouter extends AbstractRouter {
public static final String NAME = "SCRIPT_ROUTER"; public static final String NAME = "SCRIPT_ROUTER";
private static final int SCRIPT_ROUTER_DEFAULT_PRIORITY = 0; private static final int SCRIPT_ROUTER_DEFAULT_PRIORITY = 0;
private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class); private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class);
private static final Map<String, ScriptEngine> ENGINES = new ConcurrentHashMap<>(); private static final Map<String, ScriptEngine> ENGINES = new ConcurrentHashMap<>();
private final ScriptEngine engine; private final ScriptEngine engine;
private final String rule; private final String rule;
private CompiledScript function; private CompiledScript function;
private AccessControlContext accessControlContext; private AccessControlContext accessControlContext;
{ {
//Just give permission of reflect to access member. //Just give permission of reflect to access member.
Permissions perms = new Permissions(); Permissions perms = new Permissions();
perms.add(new RuntimePermission("accessDeclaredMembers")); perms.add(new RuntimePermission("accessDeclaredMembers"));
// Cast to Certificate[] required because of ambiguity: // Cast to Certificate[] required because of ambiguity:
ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms); ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
accessControlContext = new AccessControlContext(new ProtectionDomain[]{domain}); accessControlContext = new AccessControlContext(new ProtectionDomain[]{domain});
} }
public ScriptRouter(URL url) { public ScriptRouter(URL url) {
this.url = url; this.url = url;
this.priority = url.getParameter(PRIORITY_KEY, SCRIPT_ROUTER_DEFAULT_PRIORITY); this.priority = url.getParameter(PRIORITY_KEY, SCRIPT_ROUTER_DEFAULT_PRIORITY);
engine = getEngine(url); engine = getEngine(url);
rule = getRule(url); rule = getRule(url);
try { try {
Compilable compilable = (Compilable) engine; Compilable compilable = (Compilable) engine;
function = compilable.compile(rule); function = compilable.compile(rule);
} catch (ScriptException e) { } catch (ScriptException e) {
logger.error("route error, rule has been ignored. rule: " + rule + logger.error("route error, rule has been ignored. rule: " + rule +
", url: " + RpcContext.getServiceContext().getUrl(), e); ", url: " + RpcContext.getServiceContext().getUrl(), e);
} }
} }
/** /**
* get rule from url parameters. * get rule from url parameters.
*/ */
private String getRule(URL url) { private String getRule(URL url) {
String vRule = url.getParameterAndDecoded(RULE_KEY); String vRule = url.getParameterAndDecoded(RULE_KEY);
if (StringUtils.isEmpty(vRule)) { if (StringUtils.isEmpty(vRule)) {
throw new IllegalStateException("route rule can not be empty."); throw new IllegalStateException("route rule can not be empty.");
} }
return vRule; return vRule;
} }
/** /**
* create ScriptEngine instance by type from url parameters, then cache it * create ScriptEngine instance by type from url parameters, then cache it
*/ */
private ScriptEngine getEngine(URL url) { private ScriptEngine getEngine(URL url) {
String type = url.getParameter(TYPE_KEY, DEFAULT_SCRIPT_TYPE_KEY); String type = url.getParameter(TYPE_KEY, DEFAULT_SCRIPT_TYPE_KEY);
return ENGINES.computeIfAbsent(type, t -> { return ENGINES.computeIfAbsent(type, t -> {
ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(type); ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName(type);
if (scriptEngine == null) { if (scriptEngine == null) {
throw new IllegalStateException("unsupported route engine type: " + type); throw new IllegalStateException("unsupported route engine type: " + type);
} }
return scriptEngine; return scriptEngine;
}); });
} }
@Override @Override
public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException { public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
if (engine == null || function == null) { if (engine == null || function == null) {
return invokers; return invokers;
} }
Bindings bindings = createBindings(invokers, invocation); Bindings bindings = createBindings(invokers, invocation);
return getRoutedInvokers(AccessController.doPrivileged((PrivilegedAction<Object>) () -> { return getRoutedInvokers(AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
try { try {
return function.eval(bindings); return function.eval(bindings);
} catch (ScriptException e) { } catch (ScriptException e) {
logger.error("route error, rule has been ignored. rule: " + rule + ", method:" + logger.error("route error, rule has been ignored. rule: " + rule + ", method:" +
invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e); invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e);
return invokers; return invokers;
} }
}, accessControlContext)); }, accessControlContext));
} }
/** /**
* get routed invokers from result of script rule evaluation * get routed invokers from result of script rule evaluation
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> List<Invoker<T>> getRoutedInvokers(Object obj) { protected <T> List<Invoker<T>> getRoutedInvokers(Object obj) {
if (obj instanceof Invoker[]) { if (obj instanceof Invoker[]) {
return Arrays.asList((Invoker<T>[]) obj); return Arrays.asList((Invoker<T>[]) obj);
} else if (obj instanceof Object[]) { } else if (obj instanceof Object[]) {
return Arrays.stream((Object[]) obj).map(item -> (Invoker<T>) item).collect(Collectors.toList()); return Arrays.stream((Object[]) obj).map(item -> (Invoker<T>) item).collect(Collectors.toList());
} else { } else {
return (List<Invoker<T>>) obj; return (List<Invoker<T>>) obj;
} }
} }
/** /**
* create bindings for script engine * create bindings for script engine
*/ */
private <T> Bindings createBindings(List<Invoker<T>> invokers, Invocation invocation) { private <T> Bindings createBindings(List<Invoker<T>> invokers, Invocation invocation) {
Bindings bindings = engine.createBindings(); Bindings bindings = engine.createBindings();
// create a new List of invokers // create a new List of invokers
bindings.put("invokers", new ArrayList<>(invokers)); bindings.put("invokers", new ArrayList<>(invokers));
bindings.put("invocation", invocation); bindings.put("invocation", invocation);
bindings.put("context", RpcContext.getClientAttachment()); bindings.put("context", RpcContext.getClientAttachment());
return bindings; return bindings;
} }
@Override @Override
public boolean isRuntime() { public boolean isRuntime() {
return this.url.getParameter(RUNTIME_KEY, false); return this.url.getParameter(RUNTIME_KEY, false);
} }
@Override @Override
public boolean isForce() { public boolean isForce() {
return url.getParameter(FORCE_KEY, false); return url.getParameter(FORCE_KEY, false);
} }
} }

View File

@ -1,45 +1,45 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.script; package org.apache.dubbo.rpc.cluster.router.script;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.RouterFactory; import org.apache.dubbo.rpc.cluster.RouterFactory;
/** /**
* ScriptRouterFactory * ScriptRouterFactory
* <p> * <p>
* Example URLS used by Script Router Factory * Example URLS used by Script Router Factory
* <ol> * <ol>
* <li> script://registryAddress?type=js&rule=xxxx * <li> script://registryAddress?type=js&rule=xxxx
* <li> script:///path/to/routerfile.js?type=js&rule=xxxx * <li> script:///path/to/routerfile.js?type=js&rule=xxxx
* <li> script://D:\path\to\routerfile.js?type=js&rule=xxxx * <li> script://D:\path\to\routerfile.js?type=js&rule=xxxx
* <li> script://C:/path/to/routerfile.js?type=js&rule=xxxx * <li> script://C:/path/to/routerfile.js?type=js&rule=xxxx
* </ol> * </ol>
* The host value in URL points out the address of the source content of the Script RouterRegistryFile etc * The host value in URL points out the address of the source content of the Script RouterRegistryFile etc
* *
*/ */
public class ScriptRouterFactory implements RouterFactory { public class ScriptRouterFactory implements RouterFactory {
public static final String NAME = "script"; public static final String NAME = "script";
@Override @Override
public Router getRouter(URL url) { public Router getRouter(URL url) {
return new ScriptRouter(url); return new ScriptRouter(url);
} }
} }

View File

@ -46,4 +46,4 @@ public class RouterCache<T> {
public void setAddrMetadata(Object addrMetadata) { public void setAddrMetadata(Object addrMetadata) {
this.addrMetadata = addrMetadata; this.addrMetadata = addrMetadata;
} }
} }

View File

@ -1,100 +1,100 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.state; package org.apache.dubbo.rpc.cluster.router.state;
import java.util.List; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.common.URL; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import java.util.List;
/** /**
* State Router. (SPI, Prototype, ThreadSafe) * State Router. (SPI, Prototype, ThreadSafe)
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Routing">Routing</a> * <a href="http://en.wikipedia.org/wiki/Routing">Routing</a>
* *
* @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory) * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
* @see Directory#list(Invocation) * @see Directory#list(Invocation)
* @since 3.0 * @since 3.0
*/ */
public interface StateRouter extends Comparable<StateRouter> { public interface StateRouter extends Comparable<StateRouter> {
int DEFAULT_PRIORITY = Integer.MAX_VALUE; int DEFAULT_PRIORITY = Integer.MAX_VALUE;
/** /**
* Get the router url. * Get the router url.
* *
* @return url * @return url
*/ */
URL getUrl(); URL getUrl();
/*** /***
* Filter invokers with current routing rule and only return the invokers that comply with the rule. * Filter invokers with current routing rule and only return the invokers that comply with the rule.
* Caching address lists in BitMap mode improves routing performance. * Caching address lists in BitMap mode improves routing performance.
* @param invokers invoker bit list * @param invokers invoker bit list
* @param cache router address cache * @param cache router address cache
* @param url refer url * @param url refer url
* @param invocation invocation * @param invocation invocation
* @param <T> * @param <T>
* @return routed invokers * @return routed invokers
* @throws RpcException * @throws RpcException
* @Since 3.0 * @Since 3.0
*/ */
<T> BitList<Invoker<T>> route(BitList<Invoker<T>> invokers, RouterCache<T> cache, URL url, Invocation invocation) <T> BitList<Invoker<T>> route(BitList<Invoker<T>> invokers, RouterCache<T> cache, URL url, Invocation invocation)
throws throws
RpcException; RpcException;
default <T> void notify(List<Invoker<T>> invokers) { default <T> void notify(List<Invoker<T>> invokers) {
} }
/** /**
* To decide whether this router need to execute every time an RPC comes or should only execute when addresses or * To decide whether this router need to execute every time an RPC comes or should only execute when addresses or
* rule change. * rule change.
* *
* @return true if the router need to execute every time. * @return true if the router need to execute every time.
*/ */
boolean isRuntime(); boolean isRuntime();
boolean isEnable(); boolean isEnable();
boolean isForce(); boolean isForce();
int getPriority(); int getPriority();
@Override @Override
default int compareTo(StateRouter o) { default int compareTo(StateRouter o) {
if (o == null) { if (o == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
return Integer.compare(this.getPriority(), o.getPriority()); return Integer.compare(this.getPriority(), o.getPriority());
} }
String getName(); String getName();
boolean shouldRePool(); boolean shouldRePool();
<T> RouterCache<T> pool(List<Invoker<T>> invokers); <T> RouterCache<T> pool(List<Invoker<T>> invokers);
void pool(); void pool();
default void stop() { default void stop() {
//do nothing by default //do nothing by default
} }
} }

View File

@ -1,37 +1,37 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster; import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
/** /**
* AvailableCluster * AvailableCluster
* *
*/ */
public class AvailableCluster implements Cluster { public class AvailableCluster implements Cluster {
public static final String NAME = "available"; public static final String NAME = "available";
@Override @Override
public <T> Invoker<T> join(Directory<T> directory) throws RpcException { public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
return new AvailableClusterInvoker<>(directory); return new AvailableClusterInvoker<>(directory);
} }
} }

View File

@ -1,34 +1,34 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* BroadcastCluster * BroadcastCluster
* *
*/ */
public class BroadcastCluster extends AbstractCluster { public class BroadcastCluster extends AbstractCluster {
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new BroadcastClusterInvoker<>(directory); return new BroadcastClusterInvoker<>(directory);
} }
} }

View File

@ -1,116 +1,116 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import java.util.List; import java.util.List;
/** /**
* BroadcastClusterInvoker * BroadcastClusterInvoker
*/ */
public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> { public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class); private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
private static final String BROADCAST_FAIL_PERCENT_KEY = "broadcast.fail.percent"; private static final String BROADCAST_FAIL_PERCENT_KEY = "broadcast.fail.percent";
private static final int MAX_BROADCAST_FAIL_PERCENT = 100; private static final int MAX_BROADCAST_FAIL_PERCENT = 100;
private static final int MIN_BROADCAST_FAIL_PERCENT = 0; private static final int MIN_BROADCAST_FAIL_PERCENT = 0;
public BroadcastClusterInvoker(Directory<T> directory) { public BroadcastClusterInvoker(Directory<T> directory) {
super(directory); super(directory);
} }
@Override @Override
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
checkInvokers(invokers, invocation); checkInvokers(invokers, invocation);
RpcContext.getServiceContext().setInvokers((List) invokers); RpcContext.getServiceContext().setInvokers((List) invokers);
RpcException exception = null; RpcException exception = null;
Result result = null; Result result = null;
URL url = getUrl(); URL url = getUrl();
// The value range of broadcast.fail.threshold must be 0100. // The value range of broadcast.fail.threshold must be 0100.
// 100 means that an exception will be thrown last, and 0 means that as long as an exception occurs, it will be thrown. // 100 means that an exception will be thrown last, and 0 means that as long as an exception occurs, it will be thrown.
// see https://github.com/apache/dubbo/pull/7174 // see https://github.com/apache/dubbo/pull/7174
int broadcastFailPercent = url.getParameter(BROADCAST_FAIL_PERCENT_KEY, MAX_BROADCAST_FAIL_PERCENT); int broadcastFailPercent = url.getParameter(BROADCAST_FAIL_PERCENT_KEY, MAX_BROADCAST_FAIL_PERCENT);
if (broadcastFailPercent < MIN_BROADCAST_FAIL_PERCENT || broadcastFailPercent > MAX_BROADCAST_FAIL_PERCENT) { if (broadcastFailPercent < MIN_BROADCAST_FAIL_PERCENT || broadcastFailPercent > MAX_BROADCAST_FAIL_PERCENT) {
logger.info(String.format("The value corresponding to the broadcast.fail.percent parameter must be between 0 and 100. " + logger.info(String.format("The value corresponding to the broadcast.fail.percent parameter must be between 0 and 100. " +
"The current setting is %s, which is reset to 100.", broadcastFailPercent)); "The current setting is %s, which is reset to 100.", broadcastFailPercent));
broadcastFailPercent = MAX_BROADCAST_FAIL_PERCENT; broadcastFailPercent = MAX_BROADCAST_FAIL_PERCENT;
} }
int failThresholdIndex = invokers.size() * broadcastFailPercent / MAX_BROADCAST_FAIL_PERCENT; int failThresholdIndex = invokers.size() * broadcastFailPercent / MAX_BROADCAST_FAIL_PERCENT;
int failIndex = 0; int failIndex = 0;
for (Invoker<T> invoker : invokers) { for (Invoker<T> invoker : invokers) {
try { try {
result = invokeWithContext(invoker, invocation); result = invokeWithContext(invoker, invocation);
if (null != result && result.hasException()) { if (null != result && result.hasException()) {
Throwable resultException = result.getException(); Throwable resultException = result.getException();
if (null != resultException) { if (null != resultException) {
exception = getRpcException(result.getException()); exception = getRpcException(result.getException());
logger.warn(exception.getMessage(), exception); logger.warn(exception.getMessage(), exception);
if (failIndex == failThresholdIndex) { if (failIndex == failThresholdIndex) {
break; break;
} else { } else {
failIndex++; failIndex++;
} }
} }
} }
} catch (Throwable e) { } catch (Throwable e) {
exception = getRpcException(e); exception = getRpcException(e);
logger.warn(exception.getMessage(), exception); logger.warn(exception.getMessage(), exception);
if (failIndex == failThresholdIndex) { if (failIndex == failThresholdIndex) {
break; break;
} else { } else {
failIndex++; failIndex++;
} }
} }
} }
if (exception != null) { if (exception != null) {
if (failIndex == failThresholdIndex) { if (failIndex == failThresholdIndex) {
logger.debug( logger.debug(
String.format("The number of BroadcastCluster call failures has reached the threshold %s", failThresholdIndex)); String.format("The number of BroadcastCluster call failures has reached the threshold %s", failThresholdIndex));
} else { } else {
logger.debug(String.format("The number of BroadcastCluster call failures has not reached the threshold %s, fail size is %s", logger.debug(String.format("The number of BroadcastCluster call failures has not reached the threshold %s, fail size is %s",
failIndex)); failIndex));
} }
throw exception; throw exception;
} }
return result; return result;
} }
private RpcException getRpcException(Throwable throwable) { private RpcException getRpcException(Throwable throwable) {
RpcException rpcException = null; RpcException rpcException = null;
if (throwable instanceof RpcException) { if (throwable instanceof RpcException) {
rpcException = (RpcException) throwable; rpcException = (RpcException) throwable;
} else { } else {
rpcException = new RpcException(throwable.getMessage(), throwable); rpcException = new RpcException(throwable.getMessage(), throwable);
} }
return rpcException; return rpcException;
} }
} }

View File

@ -1,51 +1,51 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor; import org.apache.dubbo.rpc.cluster.ProviderURLMergeProcessor;
import java.util.Map; import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY; import static org.apache.dubbo.common.constants.CommonConstants.URL_MERGE_PROCESSOR_KEY;
/** /**
* ClusterUtils * ClusterUtils
*/ */
public class ClusterUtils { public class ClusterUtils {
private ClusterUtils() { private ClusterUtils() {
} }
public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) { public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
String ump = localMap.get(URL_MERGE_PROCESSOR_KEY); String ump = localMap.get(URL_MERGE_PROCESSOR_KEY);
ProviderURLMergeProcessor providerURLMergeProcessor; ProviderURLMergeProcessor providerURLMergeProcessor;
if (StringUtils.isNotEmpty(ump)) { if (StringUtils.isNotEmpty(ump)) {
providerURLMergeProcessor = ExtensionLoader.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump); providerURLMergeProcessor = ExtensionLoader.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension(ump);
} else { } else {
providerURLMergeProcessor = ExtensionLoader.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default"); providerURLMergeProcessor = ExtensionLoader.getExtensionLoader(ProviderURLMergeProcessor.class).getExtension("default");
} }
return providerURLMergeProcessor.mergeUrl(remoteUrl, localMap); return providerURLMergeProcessor.mergeUrl(remoteUrl, localMap);
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* {@link FailbackClusterInvoker} * {@link FailbackClusterInvoker}
* *
*/ */
public class FailbackCluster extends AbstractCluster { public class FailbackCluster extends AbstractCluster {
public final static String NAME = "failback"; public final static String NAME = "failback";
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new FailbackClusterInvoker<>(directory); return new FailbackClusterInvoker<>(directory);
} }
} }

View File

@ -1,168 +1,168 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.timer.HashedWheelTimer; import org.apache.dubbo.common.timer.HashedWheelTimer;
import org.apache.dubbo.common.timer.Timeout; import org.apache.dubbo.common.timer.Timeout;
import org.apache.dubbo.common.timer.Timer; import org.apache.dubbo.common.timer.Timer;
import org.apache.dubbo.common.timer.TimerTask; import org.apache.dubbo.common.timer.TimerTask;
import org.apache.dubbo.common.utils.NamedThreadFactory; import org.apache.dubbo.common.utils.NamedThreadFactory;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_FAILBACK_TIMES; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_FAILBACK_TIMES;
import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY; import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_FAILBACK_TASKS; import static org.apache.dubbo.rpc.cluster.Constants.DEFAULT_FAILBACK_TASKS;
import static org.apache.dubbo.rpc.cluster.Constants.FAIL_BACK_TASKS_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FAIL_BACK_TASKS_KEY;
/** /**
* When fails, record failure requests and schedule for retry on a regular interval. * When fails, record failure requests and schedule for retry on a regular interval.
* Especially useful for services of notification. * Especially useful for services of notification.
* *
* <a href="http://en.wikipedia.org/wiki/Failback">Failback</a> * <a href="http://en.wikipedia.org/wiki/Failback">Failback</a>
*/ */
public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> { public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class); private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class);
private static final long RETRY_FAILED_PERIOD = 5; private static final long RETRY_FAILED_PERIOD = 5;
private final int retries; private final int retries;
private final int failbackTasks; private final int failbackTasks;
private volatile Timer failTimer; private volatile Timer failTimer;
public FailbackClusterInvoker(Directory<T> directory) { public FailbackClusterInvoker(Directory<T> directory) {
super(directory); super(directory);
int retriesConfig = getUrl().getParameter(RETRIES_KEY, DEFAULT_FAILBACK_TIMES); int retriesConfig = getUrl().getParameter(RETRIES_KEY, DEFAULT_FAILBACK_TIMES);
if (retriesConfig <= 0) { if (retriesConfig <= 0) {
retriesConfig = DEFAULT_FAILBACK_TIMES; retriesConfig = DEFAULT_FAILBACK_TIMES;
} }
int failbackTasksConfig = getUrl().getParameter(FAIL_BACK_TASKS_KEY, DEFAULT_FAILBACK_TASKS); int failbackTasksConfig = getUrl().getParameter(FAIL_BACK_TASKS_KEY, DEFAULT_FAILBACK_TASKS);
if (failbackTasksConfig <= 0) { if (failbackTasksConfig <= 0) {
failbackTasksConfig = DEFAULT_FAILBACK_TASKS; failbackTasksConfig = DEFAULT_FAILBACK_TASKS;
} }
retries = retriesConfig; retries = retriesConfig;
failbackTasks = failbackTasksConfig; failbackTasks = failbackTasksConfig;
} }
private void addFailed(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker) { private void addFailed(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker) {
if (failTimer == null) { if (failTimer == null) {
synchronized (this) { synchronized (this) {
if (failTimer == null) { if (failTimer == null) {
failTimer = new HashedWheelTimer( failTimer = new HashedWheelTimer(
new NamedThreadFactory("failback-cluster-timer", true), new NamedThreadFactory("failback-cluster-timer", true),
1, 1,
TimeUnit.SECONDS, 32, failbackTasks); TimeUnit.SECONDS, 32, failbackTasks);
} }
} }
} }
RetryTimerTask retryTimerTask = new RetryTimerTask(loadbalance, invocation, invokers, lastInvoker, retries, RETRY_FAILED_PERIOD); RetryTimerTask retryTimerTask = new RetryTimerTask(loadbalance, invocation, invokers, lastInvoker, retries, RETRY_FAILED_PERIOD);
try { try {
failTimer.newTimeout(retryTimerTask, RETRY_FAILED_PERIOD, TimeUnit.SECONDS); failTimer.newTimeout(retryTimerTask, RETRY_FAILED_PERIOD, TimeUnit.SECONDS);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("Failback background works error,invocation->" + invocation + ", exception: " + e.getMessage()); logger.error("Failback background works error,invocation->" + invocation + ", exception: " + e.getMessage());
} }
} }
@Override @Override
protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
Invoker<T> invoker = null; Invoker<T> invoker = null;
try { try {
checkInvokers(invokers, invocation); checkInvokers(invokers, invocation);
invoker = select(loadbalance, invocation, invokers, null); invoker = select(loadbalance, invocation, invokers, null);
return invokeWithContext(invoker, invocation); return invokeWithContext(invoker, invocation);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: " logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
+ e.getMessage() + ", ", e); + e.getMessage() + ", ", e);
addFailed(loadbalance, invocation, invokers, invoker); addFailed(loadbalance, invocation, invokers, invoker);
return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
} }
} }
@Override @Override
public void destroy() { public void destroy() {
super.destroy(); super.destroy();
if (failTimer != null) { if (failTimer != null) {
failTimer.stop(); failTimer.stop();
} }
} }
/** /**
* RetryTimerTask * RetryTimerTask
*/ */
private class RetryTimerTask implements TimerTask { private class RetryTimerTask implements TimerTask {
private final Invocation invocation; private final Invocation invocation;
private final LoadBalance loadbalance; private final LoadBalance loadbalance;
private final List<Invoker<T>> invokers; private final List<Invoker<T>> invokers;
private final int retries; private final int retries;
private final long tick; private final long tick;
private Invoker<T> lastInvoker; private Invoker<T> lastInvoker;
private int retryTimes = 0; private int retryTimes = 0;
RetryTimerTask(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker, int retries, long tick) { RetryTimerTask(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, Invoker<T> lastInvoker, int retries, long tick) {
this.loadbalance = loadbalance; this.loadbalance = loadbalance;
this.invocation = invocation; this.invocation = invocation;
this.invokers = invokers; this.invokers = invokers;
this.retries = retries; this.retries = retries;
this.tick = tick; this.tick = tick;
this.lastInvoker=lastInvoker; this.lastInvoker=lastInvoker;
} }
@Override @Override
public void run(Timeout timeout) { public void run(Timeout timeout) {
try { try {
Invoker<T> retryInvoker = select(loadbalance, invocation, invokers, Collections.singletonList(lastInvoker)); Invoker<T> retryInvoker = select(loadbalance, invocation, invokers, Collections.singletonList(lastInvoker));
lastInvoker = retryInvoker; lastInvoker = retryInvoker;
invokeWithContext(retryInvoker, invocation); invokeWithContext(retryInvoker, invocation);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e); logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e);
if ((++retryTimes) >= retries) { if ((++retryTimes) >= retries) {
logger.error("Failed retry times exceed threshold (" + retries + "), We have to abandon, invocation->" + invocation); logger.error("Failed retry times exceed threshold (" + retries + "), We have to abandon, invocation->" + invocation);
} else { } else {
rePut(timeout); rePut(timeout);
} }
} }
} }
private void rePut(Timeout timeout) { private void rePut(Timeout timeout) {
if (timeout == null) { if (timeout == null) {
return; return;
} }
Timer timer = timeout.timer(); Timer timer = timeout.timer();
if (timer.isStop() || timeout.isCancelled()) { if (timer.isStop() || timeout.isCancelled()) {
return; return;
} }
timer.newTimeout(timeout.task(), tick, TimeUnit.SECONDS); timer.newTimeout(timeout.task(), tick, TimeUnit.SECONDS);
} }
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* {@link FailfastClusterInvoker} * {@link FailfastClusterInvoker}
* *
*/ */
public class FailfastCluster extends AbstractCluster { public class FailfastCluster extends AbstractCluster {
public final static String NAME = "failfast"; public final static String NAME = "failfast";
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new FailfastClusterInvoker<>(directory); return new FailfastClusterInvoker<>(directory);
} }
} }

View File

@ -1,62 +1,62 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.Version; import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import java.util.List; import java.util.List;
/** /**
* Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error. * Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error.
* Usually used for non-idempotent write operations * Usually used for non-idempotent write operations
* *
* <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a> * <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
* *
*/ */
public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> { public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {
public FailfastClusterInvoker(Directory<T> directory) { public FailfastClusterInvoker(Directory<T> directory) {
super(directory); super(directory);
} }
@Override @Override
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
checkInvokers(invokers, invocation); checkInvokers(invokers, invocation);
Invoker<T> invoker = select(loadbalance, invocation, invokers, null); Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
try { try {
return invokeWithContext(invoker, invocation); return invokeWithContext(invoker, invocation);
} catch (Throwable e) { } catch (Throwable e) {
if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception. if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
throw (RpcException) e; throw (RpcException) e;
} }
throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0,
"Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName()
+ " select from all providers " + invokers + " for service " + getInterface().getName() + " select from all providers " + invokers + " for service " + getInterface().getName()
+ " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost()
+ " use dubbo version " + Version.getVersion() + " use dubbo version " + Version.getVersion()
+ ", but no luck to perform the invocation. Last error is: " + e.getMessage(), + ", but no luck to perform the invocation. Last error is: " + e.getMessage(),
e.getCause() != null ? e.getCause() : e); e.getCause() != null ? e.getCause() : e);
} }
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* {@link FailoverClusterInvoker} * {@link FailoverClusterInvoker}
* *
*/ */
public class FailoverCluster extends AbstractCluster { public class FailoverCluster extends AbstractCluster {
public final static String NAME = "failover"; public final static String NAME = "failover";
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new FailoverClusterInvoker<>(directory); return new FailoverClusterInvoker<>(directory);
} }
} }

View File

@ -1,128 +1,128 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.Version; import org.apache.dubbo.common.Version;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import org.apache.dubbo.rpc.support.RpcUtils; import org.apache.dubbo.rpc.support.RpcUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RETRIES; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_RETRIES;
import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY; import static org.apache.dubbo.common.constants.CommonConstants.RETRIES_KEY;
/** /**
* When invoke fails, log the initial error and retry other invokers (retry n times, which means at most n different invokers will be invoked) * When invoke fails, log the initial error and retry other invokers (retry n times, which means at most n different invokers will be invoked)
* Note that retry causes latency. * Note that retry causes latency.
* <p> * <p>
* <a href="http://en.wikipedia.org/wiki/Failover">Failover</a> * <a href="http://en.wikipedia.org/wiki/Failover">Failover</a>
* *
*/ */
public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> { public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class); private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);
public FailoverClusterInvoker(Directory<T> directory) { public FailoverClusterInvoker(Directory<T> directory) {
super(directory); super(directory);
} }
@Override @Override
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
List<Invoker<T>> copyInvokers = invokers; List<Invoker<T>> copyInvokers = invokers;
checkInvokers(copyInvokers, invocation); checkInvokers(copyInvokers, invocation);
String methodName = RpcUtils.getMethodName(invocation); String methodName = RpcUtils.getMethodName(invocation);
int len = calculateInvokeTimes(methodName); int len = calculateInvokeTimes(methodName);
// retry loop. // retry loop.
RpcException le = null; // last exception. RpcException le = null; // last exception.
List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers. List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
Set<String> providers = new HashSet<String>(len); Set<String> providers = new HashSet<String>(len);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
//Reselect before retry to avoid a change of candidate `invokers`. //Reselect before retry to avoid a change of candidate `invokers`.
//NOTE: if `invokers` changed, then `invoked` also lose accuracy. //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
if (i > 0) { if (i > 0) {
checkWhetherDestroyed(); checkWhetherDestroyed();
copyInvokers = list(invocation); copyInvokers = list(invocation);
// check again // check again
checkInvokers(copyInvokers, invocation); checkInvokers(copyInvokers, invocation);
} }
Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked); Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
invoked.add(invoker); invoked.add(invoker);
RpcContext.getServiceContext().setInvokers((List) invoked); RpcContext.getServiceContext().setInvokers((List) invoked);
try { try {
Result result = invokeWithContext(invoker, invocation); Result result = invokeWithContext(invoker, invocation);
if (le != null && logger.isWarnEnabled()) { if (le != null && logger.isWarnEnabled()) {
logger.warn("Although retry the method " + methodName logger.warn("Although retry the method " + methodName
+ " in the service " + getInterface().getName() + " in the service " + getInterface().getName()
+ " was successful by the provider " + invoker.getUrl().getAddress() + " was successful by the provider " + invoker.getUrl().getAddress()
+ ", but there have been failed providers " + providers + ", but there have been failed providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size() + " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress() + ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " on the consumer " + NetUtils.getLocalHost()
+ " using the dubbo version " + Version.getVersion() + ". Last error is: " + " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le); + le.getMessage(), le);
} }
return result; return result;
} catch (RpcException e) { } catch (RpcException e) {
if (e.isBiz()) { // biz exception. if (e.isBiz()) { // biz exception.
throw e; throw e;
} }
le = e; le = e;
} catch (Throwable e) { } catch (Throwable e) {
le = new RpcException(e.getMessage(), e); le = new RpcException(e.getMessage(), e);
} finally { } finally {
providers.add(invoker.getUrl().getAddress()); providers.add(invoker.getUrl().getAddress());
} }
} }
throw new RpcException(le.getCode(), "Failed to invoke the method " throw new RpcException(le.getCode(), "Failed to invoke the method "
+ methodName + " in the service " + getInterface().getName() + methodName + " in the service " + getInterface().getName()
+ ". Tried " + len + " times of the providers " + providers + ". Tried " + len + " times of the providers " + providers
+ " (" + providers.size() + "/" + copyInvokers.size() + " (" + providers.size() + "/" + copyInvokers.size()
+ ") from the registry " + directory.getUrl().getAddress() + ") from the registry " + directory.getUrl().getAddress()
+ " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version " + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ Version.getVersion() + ". Last error is: " + Version.getVersion() + ". Last error is: "
+ le.getMessage(), le.getCause() != null ? le.getCause() : le); + le.getMessage(), le.getCause() != null ? le.getCause() : le);
} }
private int calculateInvokeTimes(String methodName) { private int calculateInvokeTimes(String methodName) {
int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1; int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
RpcContext rpcContext = RpcContext.getClientAttachment(); RpcContext rpcContext = RpcContext.getClientAttachment();
Object retry = rpcContext.getObjectAttachment(RETRIES_KEY); Object retry = rpcContext.getObjectAttachment(RETRIES_KEY);
if (retry instanceof Number) { if (retry instanceof Number) {
len = ((Number) retry).intValue() + 1; len = ((Number) retry).intValue() + 1;
rpcContext.removeAttachment(RETRIES_KEY); rpcContext.removeAttachment(RETRIES_KEY);
} }
if (len <= 0) { if (len <= 0) {
len = 1; len = 1;
} }
return len; return len;
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* {@link FailsafeClusterInvoker} * {@link FailsafeClusterInvoker}
* *
*/ */
public class FailsafeCluster extends AbstractCluster { public class FailsafeCluster extends AbstractCluster {
public final static String NAME = "failsafe"; public final static String NAME = "failsafe";
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new FailsafeClusterInvoker<>(directory); return new FailsafeClusterInvoker<>(directory);
} }
} }

View File

@ -1,56 +1,56 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.LoadBalance; import org.apache.dubbo.rpc.cluster.LoadBalance;
import java.util.List; import java.util.List;
/** /**
* When invoke fails, log the error message and ignore this error by returning an empty Result. * When invoke fails, log the error message and ignore this error by returning an empty Result.
* Usually used to write audit logs and other operations * Usually used to write audit logs and other operations
* *
* <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a> * <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
* *
*/ */
public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> { public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class); private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class);
public FailsafeClusterInvoker(Directory<T> directory) { public FailsafeClusterInvoker(Directory<T> directory) {
super(directory); super(directory);
} }
@Override @Override
public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
try { try {
checkInvokers(invokers, invocation); checkInvokers(invokers, invocation);
Invoker<T> invoker = select(loadbalance, invocation, invokers, null); Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
return invokeWithContext(invoker, invocation); return invokeWithContext(invoker, invocation);
} catch (Throwable e) { } catch (Throwable e) {
logger.error("Failsafe ignore exception: " + e.getMessage(), e); logger.error("Failsafe ignore exception: " + e.getMessage(), e);
return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore return AsyncRpcResult.newDefaultAsyncResult(null, null, invocation); // ignore
} }
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster; import org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster;
/** /**
* {@link ForkingClusterInvoker} * {@link ForkingClusterInvoker}
* *
*/ */
public class ForkingCluster extends AbstractCluster { public class ForkingCluster extends AbstractCluster {
public final static String NAME = "forking"; public final static String NAME = "forking";
@Override @Override
public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException { public <T> AbstractClusterInvoker<T> doJoin(Directory<T> directory) throws RpcException {
return new ForkingClusterInvoker<>(directory); return new ForkingClusterInvoker<>(directory);
} }
} }

View File

@ -120,4 +120,4 @@ public class DefaultProviderURLMergeProcessor implements ProviderURLMergeProcess
return remoteUrl.clearParameters().addParameters(map); return remoteUrl.clearParameters().addParameters(map);
} }
} }

View File

@ -30,4 +30,4 @@ public class ZoneAwareCluster extends AbstractCluster {
return new ZoneAwareClusterInvoker<T>(directory); return new ZoneAwareClusterInvoker<T>(directory);
} }
} }

View File

@ -102,4 +102,4 @@ public class ZoneAwareClusterInvoker<T> extends AbstractClusterInvoker<T> {
return invokers.get(0).invoke(invocation); return invokers.get(0).invoke(invocation);
} }
} }

View File

@ -1,195 +1,195 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support.wrapper; package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.ClusterInvoker; import org.apache.dubbo.rpc.cluster.ClusterInvoker;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.support.MockInvoker; import org.apache.dubbo.rpc.support.MockInvoker;
import java.util.List; import java.util.List;
import static org.apache.dubbo.rpc.Constants.MOCK_KEY; import static org.apache.dubbo.rpc.Constants.MOCK_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK; import static org.apache.dubbo.rpc.cluster.Constants.INVOCATION_NEED_MOCK;
public class MockClusterInvoker<T> implements ClusterInvoker<T> { public class MockClusterInvoker<T> implements ClusterInvoker<T> {
private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class); private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);
private final Directory<T> directory; private final Directory<T> directory;
private final Invoker<T> invoker; private final Invoker<T> invoker;
public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) { public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
this.directory = directory; this.directory = directory;
this.invoker = invoker; this.invoker = invoker;
} }
@Override @Override
public URL getUrl() { public URL getUrl() {
return directory.getConsumerUrl(); return directory.getConsumerUrl();
} }
public URL getRegistryUrl() { public URL getRegistryUrl() {
return directory.getUrl(); return directory.getUrl();
} }
@Override @Override
public Directory<T> getDirectory() { public Directory<T> getDirectory() {
return directory; return directory;
} }
@Override @Override
public boolean isDestroyed() { public boolean isDestroyed() {
return directory.isDestroyed(); return directory.isDestroyed();
} }
@Override @Override
public boolean isAvailable() { public boolean isAvailable() {
return directory.isAvailable(); return directory.isAvailable();
} }
@Override @Override
public void destroy() { public void destroy() {
this.invoker.destroy(); this.invoker.destroy();
} }
@Override @Override
public Class<T> getInterface() { public Class<T> getInterface() {
return directory.getInterface(); return directory.getInterface();
} }
@Override @Override
public Result invoke(Invocation invocation) throws RpcException { public Result invoke(Invocation invocation) throws RpcException {
Result result = null; Result result = null;
String value = getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim(); String value = getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || "false".equalsIgnoreCase(value)) { if (value.length() == 0 || "false".equalsIgnoreCase(value)) {
//no mock //no mock
result = this.invoker.invoke(invocation); result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) { } else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + getUrl()); logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + getUrl());
} }
//force:direct mock //force:direct mock
result = doMockInvoke(invocation, null); result = doMockInvoke(invocation, null);
} else { } else {
//fail-mock //fail-mock
try { try {
result = this.invoker.invoke(invocation); result = this.invoker.invoke(invocation);
//fix:#4585 //fix:#4585
if(result.getException() != null && result.getException() instanceof RpcException){ if(result.getException() != null && result.getException() instanceof RpcException){
RpcException rpcException= (RpcException)result.getException(); RpcException rpcException= (RpcException)result.getException();
if(rpcException.isBiz()){ if(rpcException.isBiz()){
throw rpcException; throw rpcException;
}else { }else {
result = doMockInvoke(invocation, rpcException); result = doMockInvoke(invocation, rpcException);
} }
} }
} catch (RpcException e) { } catch (RpcException e) {
if (e.isBiz()) { if (e.isBiz()) {
throw e; throw e;
} }
if (logger.isWarnEnabled()) { if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + getUrl(), e); logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + getUrl(), e);
} }
result = doMockInvoke(invocation, e); result = doMockInvoke(invocation, e);
} }
} }
return result; return result;
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
private Result doMockInvoke(Invocation invocation, RpcException e) { private Result doMockInvoke(Invocation invocation, RpcException e) {
Result result = null; Result result = null;
Invoker<T> minvoker; Invoker<T> minvoker;
List<Invoker<T>> mockInvokers = selectMockInvoker(invocation); List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
if (CollectionUtils.isEmpty(mockInvokers)) { if (CollectionUtils.isEmpty(mockInvokers)) {
minvoker = (Invoker<T>) new MockInvoker(getUrl(), directory.getInterface()); minvoker = (Invoker<T>) new MockInvoker(getUrl(), directory.getInterface());
} else { } else {
minvoker = mockInvokers.get(0); minvoker = mockInvokers.get(0);
} }
try { try {
result = minvoker.invoke(invocation); result = minvoker.invoke(invocation);
} catch (RpcException me) { } catch (RpcException me) {
if (me.isBiz()) { if (me.isBiz()) {
result = AsyncRpcResult.newDefaultAsyncResult(me.getCause(), invocation); result = AsyncRpcResult.newDefaultAsyncResult(me.getCause(), invocation);
} else { } else {
throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause()); throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
} }
} catch (Throwable me) { } catch (Throwable me) {
throw new RpcException(getMockExceptionMessage(e, me), me.getCause()); throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
} }
return result; return result;
} }
private String getMockExceptionMessage(Throwable t, Throwable mt) { private String getMockExceptionMessage(Throwable t, Throwable mt) {
String msg = "mock error : " + mt.getMessage(); String msg = "mock error : " + mt.getMessage();
if (t != null) { if (t != null) {
msg = msg + ", invoke error is :" + StringUtils.toString(t); msg = msg + ", invoke error is :" + StringUtils.toString(t);
} }
return msg; return msg;
} }
/** /**
* Return MockInvoker * Return MockInvoker
* Contract * Contract
* directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return. * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
* if directory.list() returns more than one mock invoker, only one of them will be used. * if directory.list() returns more than one mock invoker, only one of them will be used.
* *
* @param invocation * @param invocation
* @return * @return
*/ */
private List<Invoker<T>> selectMockInvoker(Invocation invocation) { private List<Invoker<T>> selectMockInvoker(Invocation invocation) {
List<Invoker<T>> invokers = null; List<Invoker<T>> invokers = null;
//TODO generic invoker //TODO generic invoker
if (invocation instanceof RpcInvocation) { if (invocation instanceof RpcInvocation) {
//Note the implicit contract (although the description is added to the interface declaration, but extensibility is a problem. The practice placed in the attachment needs to be improved) //Note the implicit contract (although the description is added to the interface declaration, but extensibility is a problem. The practice placed in the attachment needs to be improved)
((RpcInvocation) invocation).setAttachment(INVOCATION_NEED_MOCK, Boolean.TRUE.toString()); ((RpcInvocation) invocation).setAttachment(INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
//directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return. //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is absent or not true in invocation, otherwise, a list of mock invokers will return.
try { try {
invokers = directory.list(invocation); invokers = directory.list(invocation);
} catch (RpcException e) { } catch (RpcException e) {
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info("Exception when try to invoke mock. Get mock invokers error for service:" logger.info("Exception when try to invoke mock. Get mock invokers error for service:"
+ getUrl().getServiceInterface() + ", method:" + invocation.getMethodName() + getUrl().getServiceInterface() + ", method:" + invocation.getMethodName()
+ ", will construct a new mock with 'new MockInvoker()'.", e); + ", will construct a new mock with 'new MockInvoker()'.", e);
} }
} }
} }
return invokers; return invokers;
} }
@Override @Override
public String toString() { public String toString() {
return "invoker :" + this.invoker + ",directory: " + this.directory; return "invoker :" + this.invoker + ",directory: " + this.directory;
} }
} }

View File

@ -1,42 +1,42 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support.wrapper; package org.apache.dubbo.rpc.cluster.support.wrapper;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.cluster.Cluster; import org.apache.dubbo.rpc.cluster.Cluster;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
/** /**
* mock impl * mock impl
* *
*/ */
public class MockClusterWrapper implements Cluster { public class MockClusterWrapper implements Cluster {
private Cluster cluster; private Cluster cluster;
public MockClusterWrapper(Cluster cluster) { public MockClusterWrapper(Cluster cluster) {
this.cluster = cluster; this.cluster = cluster;
} }
@Override @Override
public <T> Invoker<T> join(Directory<T> directory) throws RpcException { public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
return new MockClusterInvoker<T>(directory, return new MockClusterInvoker<T>(directory,
this.cluster.join(directory)); this.cluster.join(directory));
} }
} }

View File

@ -1,10 +1,10 @@
mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
available=org.apache.dubbo.rpc.cluster.support.AvailableCluster available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster

View File

@ -1,2 +1,2 @@
override=org.apache.dubbo.rpc.cluster.configurator.override.OverrideConfiguratorFactory override=org.apache.dubbo.rpc.cluster.configurator.override.OverrideConfiguratorFactory
absent=org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfiguratorFactory absent=org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfiguratorFactory

View File

@ -1,5 +1,5 @@
random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
shortestresponse=org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance shortestresponse=org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance

View File

@ -1,11 +1,11 @@
map=org.apache.dubbo.rpc.cluster.merger.MapMerger map=org.apache.dubbo.rpc.cluster.merger.MapMerger
set=org.apache.dubbo.rpc.cluster.merger.SetMerger set=org.apache.dubbo.rpc.cluster.merger.SetMerger
list=org.apache.dubbo.rpc.cluster.merger.ListMerger list=org.apache.dubbo.rpc.cluster.merger.ListMerger
byte=org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger byte=org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger
char=org.apache.dubbo.rpc.cluster.merger.CharArrayMerger char=org.apache.dubbo.rpc.cluster.merger.CharArrayMerger
short=org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger short=org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger
int=org.apache.dubbo.rpc.cluster.merger.IntArrayMerger int=org.apache.dubbo.rpc.cluster.merger.IntArrayMerger
long=org.apache.dubbo.rpc.cluster.merger.LongArrayMerger long=org.apache.dubbo.rpc.cluster.merger.LongArrayMerger
float=org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger float=org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger
double=org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger double=org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger
boolean=org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger boolean=org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger

View File

@ -1,7 +1,7 @@
file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
service=org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory service=org.apache.dubbo.rpc.cluster.router.condition.config.ServiceRouterFactory
app=org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory app=org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory
tag=org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory tag=org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory
mock=org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory mock=org.apache.dubbo.rpc.cluster.router.mock.MockRouterFactory
mesh-rule=org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleRouterFactory mesh-rule=org.apache.dubbo.rpc.cluster.router.mesh.route.MeshRuleRouterFactory

View File

@ -1,68 +1,68 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.absent; package org.apache.dubbo.rpc.cluster.configurator.absent;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant; import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* OverrideConfiguratorTest * OverrideConfiguratorTest
*/ */
public class AbsentConfiguratorTest { public class AbsentConfiguratorTest {
@Test @Test
public void testOverrideApplication() { public void testOverrideApplication() {
AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200")); AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200"));
URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER)); URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE)); url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11)); url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
Assertions.assertNull(url.getParameter("timeout")); Assertions.assertNull(url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11)); url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
} }
@Test @Test
public void testOverrideHost() { public void testOverrideHost() {
AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200")); AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER)); URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE)); url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf(UrlConstant.SERVICE_TIMEOUT_200)); AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf(UrlConstant.SERVICE_TIMEOUT_200));
url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10)); url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));
Assertions.assertNull(url.getParameter("timeout")); Assertions.assertNull(url.getParameter("timeout"));
url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10)); url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
} }
} }

View File

@ -1,68 +1,68 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.configurator.override; package org.apache.dubbo.rpc.cluster.configurator.override;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.NetUtils; import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator; import org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator;
import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant; import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
* OverrideConfiguratorTest * OverrideConfiguratorTest
*/ */
public class OverrideConfiguratorTest { public class OverrideConfiguratorTest {
@Test @Test
public void testOverride_Application() { public void testOverride_Application() {
OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200")); OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://foo@0.0.0.0/com.foo.BarService?timeout=200"));
URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER)); URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE)); url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11)); url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
Assertions.assertNull(url.getParameter("timeout")); Assertions.assertNull(url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11)); url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
} }
@Test @Test
public void testOverride_Host() { public void testOverride_Host() {
OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200")); OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER)); URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE)); url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
Assertions.assertEquals("200", url.getParameter("timeout")); Assertions.assertEquals("200", url.getParameter("timeout"));
AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200")); AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf("override://10.20.153.10/com.foo.BarService?timeout=200"));
url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10)); url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));
Assertions.assertNull(url.getParameter("timeout")); Assertions.assertNull(url.getParameter("timeout"));
url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10)); url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
Assertions.assertEquals("1000", url.getParameter("timeout")); Assertions.assertEquals("1000", url.getParameter("timeout"));
} }
} }

View File

@ -156,4 +156,4 @@ public class MockDirInvocation implements Invocation {
return result; return result;
} }
} }

View File

@ -1,27 +1,27 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.filter; package org.apache.dubbo.rpc.cluster.filter;
/** /**
* <code>TestService</code> * <code>TestService</code>
*/ */
public interface DemoService { public interface DemoService {
String sayHello(String name); String sayHello(String name);
int plus(int a, int b); int plus(int a, int b);
} }

View File

@ -1,43 +1,43 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.filter; package org.apache.dubbo.rpc.cluster.filter;
/** /**
* <code>TestService</code> * <code>TestService</code>
*/ */
public class DemoServiceLocal implements DemoService { public class DemoServiceLocal implements DemoService {
public DemoServiceLocal(DemoService demoService) { public DemoServiceLocal(DemoService demoService) {
} }
public String sayHello(String name) { public String sayHello(String name) {
return name; return name;
} }
public int plus(int a, int b) { public int plus(int a, int b) {
return a + b; return a + b;
} }
public void ondisconnect() { public void ondisconnect() {
} }
public void onconnect() { public void onconnect() {
} }
} }

View File

@ -1,31 +1,31 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.filter; package org.apache.dubbo.rpc.cluster.filter;
/** /**
* MockService.java * MockService.java
* *
*/ */
public class DemoServiceMock implements DemoService { public class DemoServiceMock implements DemoService {
public String sayHello(String name) { public String sayHello(String name) {
return name; return name;
} }
public int plus(int a, int b) { public int plus(int a, int b) {
return a + b; return a + b;
} }
} }

View File

@ -1,35 +1,35 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.filter; package org.apache.dubbo.rpc.cluster.filter;
/** /**
* <code>TestService</code> * <code>TestService</code>
*/ */
public class DemoServiceStub implements DemoService { public class DemoServiceStub implements DemoService {
public DemoServiceStub(DemoService demoService) { public DemoServiceStub(DemoService demoService) {
} }
public String sayHello(String name) { public String sayHello(String name) {
return name; return name;
} }
public int plus(int a, int b) { public int plus(int a, int b) {
return a + b; return a + b;
} }
} }

View File

@ -1,31 +1,31 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.filter; package org.apache.dubbo.rpc.cluster.filter;
/** /**
* MockService.java * MockService.java
* *
*/ */
public class MockService implements DemoService { public class MockService implements DemoService {
public String sayHello(String name) { public String sayHello(String name) {
return name; return name;
} }
public int plus(int a, int b) { public int plus(int a, int b) {
return a + b; return a + b;
} }
} }

View File

@ -1,348 +1,348 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.router.condition; package org.apache.dubbo.rpc.cluster.router.condition;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Router; import org.apache.dubbo.rpc.cluster.Router;
import org.apache.dubbo.rpc.cluster.router.MockInvoker; import org.apache.dubbo.rpc.cluster.router.MockInvoker;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.FORCE_KEY;
import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY; import static org.apache.dubbo.rpc.cluster.Constants.RULE_KEY;
public class ConditionRouterTest { public class ConditionRouterTest {
private static final String LOCAL_HOST = "127.0.0.1"; private static final String LOCAL_HOST = "127.0.0.1";
private URL SCRIPT_URL = URL.valueOf("condition://0.0.0.0/com.foo.BarService"); private URL SCRIPT_URL = URL.valueOf("condition://0.0.0.0/com.foo.BarService");
@BeforeAll @BeforeAll
public static void setUpBeforeClass() throws Exception { public static void setUpBeforeClass() throws Exception {
} }
@BeforeEach @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
} }
private URL getRouteUrl(String rule) { private URL getRouteUrl(String rule) {
return SCRIPT_URL.addParameterAndEncoded(RULE_KEY, rule); return SCRIPT_URL.addParameterAndEncoded(RULE_KEY, rule);
} }
@Test @Test
public void testRoute_matchWhen() { public void testRoute_matchWhen() {
Invocation invocation = new RpcInvocation(); Invocation invocation = new RpcInvocation();
Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => host = 1.2.3.4")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => host = 1.2.3.4"));
boolean matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); boolean matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.1,3.3.3.3 & host !=1.1.1.1 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertFalse(matchWhen); Assertions.assertFalse(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host !=4.4.4.4 & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host !=4.4.4.4 & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host !=4.4.4.* & host = 2.2.2.2,1.1.1.1,3.3.3.3 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.1 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.1 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertFalse(matchWhen); Assertions.assertFalse(matchWhen);
router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.2 => host = 1.2.3.4")); router = new ConditionRouterFactory().getRouter(getRouteUrl("host = 2.2.2.2,1.1.1.*,3.3.3.3 & host != 1.1.1.2 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation); matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
} }
@Test @Test
public void testRoute_matchFilter() { public void testRoute_matchFilter() {
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf( Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf(
"dubbo://10.20.3.3:20880/com.foo.BarService?serialization=fastjson")); "dubbo://10.20.3.3:20880/com.foo.BarService?serialization=fastjson"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST
+ ":20880/com.foo.BarService")); + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST
+ ":20880/com.foo.BarService")); + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
System.err.println("The localhost address: " + invoker2.getUrl().getAddress()); System.err.println("The localhost address: " + invoker2.getUrl().getAddress());
System.err.println(invoker3.getUrl().getAddress()); System.err.println(invoker3.getUrl().getAddress());
Router router1 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router1 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " host = 10.20.3.3").addParameter(FORCE_KEY, "host = " + LOCAL_HOST + " => " + " host = 10.20.3.3").addParameter(FORCE_KEY,
String.valueOf(true))); String.valueOf(true)));
Router router2 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router2 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " host = 10.20.3.* & host != 10.20.3.3").addParameter( "host = " + LOCAL_HOST + " => " + " host = 10.20.3.* & host != 10.20.3.3").addParameter(
FORCE_KEY, String.valueOf(true))); FORCE_KEY, String.valueOf(true)));
Router router3 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router3 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " host = 10.20.3.3 & host != 10.20.3.3").addParameter( "host = " + LOCAL_HOST + " => " + " host = 10.20.3.3 & host != 10.20.3.3").addParameter(
FORCE_KEY, String.valueOf(true))); FORCE_KEY, String.valueOf(true)));
Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " host = 10.20.3.2,10.20.3.3,10.20.3.4").addParameter( "host = " + LOCAL_HOST + " => " + " host = 10.20.3.2,10.20.3.3,10.20.3.4").addParameter(
FORCE_KEY, String.valueOf(true))); FORCE_KEY, String.valueOf(true)));
Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " host != 10.20.3.3").addParameter(FORCE_KEY, "host = " + LOCAL_HOST + " => " + " host != 10.20.3.3").addParameter(FORCE_KEY,
String.valueOf(true))); String.valueOf(true)));
Router router6 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router6 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " => " + " serialization = fastjson").addParameter( "host = " + LOCAL_HOST + " => " + " serialization = fastjson").addParameter(
FORCE_KEY, String.valueOf(true))); FORCE_KEY, String.valueOf(true)));
List<Invoker<String>> filteredInvokers1 = router1.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers1 = router1.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
List<Invoker<String>> filteredInvokers2 = router2.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers2 = router2.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
List<Invoker<String>> filteredInvokers3 = router3.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers3 = router3.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
List<Invoker<String>> filteredInvokers4 = router4.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers4 = router4.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
List<Invoker<String>> filteredInvokers5 = router5.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers5 = router5.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
List<Invoker<String>> filteredInvokers6 = router6.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers6 = router6.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(1, filteredInvokers1.size()); Assertions.assertEquals(1, filteredInvokers1.size());
Assertions.assertEquals(0, filteredInvokers2.size()); Assertions.assertEquals(0, filteredInvokers2.size());
Assertions.assertEquals(0, filteredInvokers3.size()); Assertions.assertEquals(0, filteredInvokers3.size());
Assertions.assertEquals(1, filteredInvokers4.size()); Assertions.assertEquals(1, filteredInvokers4.size());
Assertions.assertEquals(2, filteredInvokers5.size()); Assertions.assertEquals(2, filteredInvokers5.size());
Assertions.assertEquals(1, filteredInvokers6.size()); Assertions.assertEquals(1, filteredInvokers6.size());
} }
@Test @Test
public void testRoute_methodRoute() { public void testRoute_methodRoute() {
Invocation invocation = new RpcInvocation("getFoo", "com.foo.BarService", "", new Class<?>[0], new Object[0]); Invocation invocation = new RpcInvocation("getFoo", "com.foo.BarService", "", new Class<?>[0], new Object[0]);
// More than one methods, mismatch // More than one methods, mismatch
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("methods=getFoo => host = 1.2.3.4")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("methods=getFoo => host = 1.2.3.4"));
boolean matchWhen = ((ConditionRouter) router).matchWhen( boolean matchWhen = ((ConditionRouter) router).matchWhen(
URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo"), invocation); URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
// Exactly one method, match // Exactly one method, match
matchWhen = ((ConditionRouter) router).matchWhen( matchWhen = ((ConditionRouter) router).matchWhen(
URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation); URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
// Method routing and Other condition routing can work together // Method routing and Other condition routing can work together
Router router2 = new ConditionRouterFactory() Router router2 = new ConditionRouterFactory()
.getRouter(getRouteUrl("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4")); .getRouter(getRouteUrl("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router2).matchWhen( matchWhen = ((ConditionRouter) router2).matchWhen(
URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation); URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
Assertions.assertFalse(matchWhen); Assertions.assertFalse(matchWhen);
Router router3 = new ConditionRouterFactory() Router router3 = new ConditionRouterFactory()
.getRouter(getRouteUrl("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4")); .getRouter(getRouteUrl("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"));
matchWhen = ((ConditionRouter) router3).matchWhen( matchWhen = ((ConditionRouter) router3).matchWhen(
URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation); URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
Assertions.assertTrue(matchWhen); Assertions.assertTrue(matchWhen);
// Test filter condition // Test filter condition
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST
+ ":20880/com.foo.BarService")); + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST
+ ":20880/com.foo.BarService")); + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " & methods = getFoo => " + " host = 10.20.3.3").addParameter( "host = " + LOCAL_HOST + " & methods = getFoo => " + " host = 10.20.3.3").addParameter(
FORCE_KEY, String.valueOf(true))); FORCE_KEY, String.valueOf(true)));
List<Invoker<String>> filteredInvokers1 = router4.route(invokers, List<Invoker<String>> filteredInvokers1 = router4.route(invokers,
URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(1, filteredInvokers1.size()); Assertions.assertEquals(1, filteredInvokers1.size());
Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl( Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
"host = " + LOCAL_HOST + " & methods = unvalidmethod => " + " host = 10.20.3.3") "host = " + LOCAL_HOST + " & methods = unvalidmethod => " + " host = 10.20.3.3")
.addParameter(FORCE_KEY, String.valueOf(true))); .addParameter(FORCE_KEY, String.valueOf(true)));
List<Invoker<String>> filteredInvokers2 = router5.route(invokers, List<Invoker<String>> filteredInvokers2 = router5.route(invokers,
URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(3, filteredInvokers2.size()); Assertions.assertEquals(3, filteredInvokers2.size());
// Request a non-exists method // Request a non-exists method
} }
@Test @Test
public void testRoute_ReturnFalse() { public void testRoute_ReturnFalse() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => false")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => false"));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(0, filteredInvokers.size()); Assertions.assertEquals(0, filteredInvokers.size());
} }
@Test @Test
public void testRoute_ReturnEmpty() { public void testRoute_ReturnEmpty() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => ")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => "));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
invokers.add(new MockInvoker<String>()); invokers.add(new MockInvoker<String>());
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(0, filteredInvokers.size()); Assertions.assertEquals(0, filteredInvokers.size());
} }
@Test @Test
public void testRoute_ReturnAll() { public void testRoute_ReturnAll() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = " + LOCAL_HOST)); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = " + LOCAL_HOST));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"))); invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")));
invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"))); invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")));
invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"))); invokers.add(new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")));
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(invokers, filteredInvokers); Assertions.assertEquals(invokers, filteredInvokers);
} }
@Test @Test
public void testRoute_HostFilter() { public void testRoute_HostFilter() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = " + LOCAL_HOST)); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = " + LOCAL_HOST));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(2, filteredInvokers.size()); Assertions.assertEquals(2, filteredInvokers.size());
Assertions.assertEquals(invoker2, filteredInvokers.get(0)); Assertions.assertEquals(invoker2, filteredInvokers.get(0));
Assertions.assertEquals(invoker3, filteredInvokers.get(1)); Assertions.assertEquals(invoker3, filteredInvokers.get(1));
} }
@Test @Test
public void testRoute_Empty_HostFilter() { public void testRoute_Empty_HostFilter() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => " + " host = " + LOCAL_HOST)); Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => " + " host = " + LOCAL_HOST));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(2, filteredInvokers.size()); Assertions.assertEquals(2, filteredInvokers.size());
Assertions.assertEquals(invoker2, filteredInvokers.get(0)); Assertions.assertEquals(invoker2, filteredInvokers.get(0));
Assertions.assertEquals(invoker3, filteredInvokers.get(1)); Assertions.assertEquals(invoker3, filteredInvokers.get(1));
} }
@Test @Test
public void testRoute_False_HostFilter() { public void testRoute_False_HostFilter() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("true => " + " host = " + LOCAL_HOST)); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("true => " + " host = " + LOCAL_HOST));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(2, filteredInvokers.size()); Assertions.assertEquals(2, filteredInvokers.size());
Assertions.assertEquals(invoker2, filteredInvokers.get(0)); Assertions.assertEquals(invoker2, filteredInvokers.get(0));
Assertions.assertEquals(invoker3, filteredInvokers.get(1)); Assertions.assertEquals(invoker3, filteredInvokers.get(1));
} }
@Test @Test
public void testRoute_Placeholder() { public void testRoute_Placeholder() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = $host")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = $host"));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(2, filteredInvokers.size()); Assertions.assertEquals(2, filteredInvokers.size());
Assertions.assertEquals(invoker2, filteredInvokers.get(0)); Assertions.assertEquals(invoker2, filteredInvokers.get(0));
Assertions.assertEquals(invoker3, filteredInvokers.get(1)); Assertions.assertEquals(invoker3, filteredInvokers.get(1));
} }
@Test @Test
public void testRoute_NoForce() { public void testRoute_NoForce() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = 1.2.3.4")); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = 1.2.3.4"));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(invokers, filteredInvokers); Assertions.assertEquals(invokers, filteredInvokers);
} }
@Test @Test
public void testRoute_Force() { public void testRoute_Force() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true))); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + LOCAL_HOST + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
List<Invoker<String>> invokers = new ArrayList<Invoker<String>>(); List<Invoker<String>> invokers = new ArrayList<Invoker<String>>();
Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<String>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation()); List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), new RpcInvocation());
Assertions.assertEquals(0, filteredInvokers.size()); Assertions.assertEquals(0, filteredInvokers.size());
} }
@Test @Test
public void testRoute_Arguments() { public void testRoute_Arguments() {
Router router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0] = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true))); Router router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0] = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
List<Invoker<String>> invokers = new ArrayList<>(); List<Invoker<String>> invokers = new ArrayList<>();
Invoker<String> invoker1 = new MockInvoker<>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService")); Invoker<String> invoker1 = new MockInvoker<>(URL.valueOf("dubbo://10.20.3.3:20880/com.foo.BarService"));
Invoker<String> invoker2 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker2 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
Invoker<String> invoker3 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService")); Invoker<String> invoker3 = new MockInvoker<>(URL.valueOf("dubbo://" + LOCAL_HOST + ":20880/com.foo.BarService"));
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
invokers.add(invoker3); invokers.add(invoker3);
RpcInvocation invocation = new RpcInvocation(); RpcInvocation invocation = new RpcInvocation();
String p = "a"; String p = "a";
invocation.setArguments(new Object[]{null}); invocation.setArguments(new Object[]{null});
List<Invoker<String>> fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); List<Invoker<String>> fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(3, fileredInvokers.size()); Assertions.assertEquals(3, fileredInvokers.size());
invocation.setArguments(new Object[]{p}); invocation.setArguments(new Object[]{p});
fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(0, fileredInvokers.size()); Assertions.assertEquals(0, fileredInvokers.size());
router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments = b " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true))); router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments = b " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(3, fileredInvokers.size()); Assertions.assertEquals(3, fileredInvokers.size());
router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[10].inner = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true))); router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[10].inner = a " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(3, fileredInvokers.size()); Assertions.assertEquals(3, fileredInvokers.size());
int integer = 1; int integer = 1;
invocation.setArguments(new Object[]{integer}); invocation.setArguments(new Object[]{integer});
router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0].inner = 1 " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true))); router = new ConditionRouterFactory().getRouter(getRouteUrl("arguments[0].inner = 1 " + " => " + " host = 1.2.3.4").addParameter(FORCE_KEY, String.valueOf(true)));
fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation); fileredInvokers = router.route(invokers, URL.valueOf("consumer://" + LOCAL_HOST + "/com.foo.BarService"), invocation);
Assertions.assertEquals(0, fileredInvokers.size()); Assertions.assertEquals(0, fileredInvokers.size());
} }
} }

View File

@ -177,4 +177,4 @@ public class MeshAppRuleListenerTest {
assertTrue(vsDestinationGroup1.getVirtualServiceRuleList().size() == 0); assertTrue(vsDestinationGroup1.getVirtualServiceRuleList().size() == 0);
} }
} }

View File

@ -157,4 +157,4 @@ public class MeshRuleManagerTest {
ApplicationModel.getEnvironment().setDynamicConfiguration(before.orElse(null)); ApplicationModel.getEnvironment().setDynamicConfiguration(before.orElse(null));
} }
} }
} }

View File

@ -33,4 +33,4 @@ public class MeshRuleRouterFactoryTest {
when(url.getServiceKey()).thenReturn("demoService"); when(url.getServiceKey()).thenReturn("demoService");
ruleRouterFactory.getRouter(url); ruleRouterFactory.getRouter(url);
} }
} }

View File

@ -1404,4 +1404,4 @@ public class MeshRuleRouterTest {
assertNotNull(meshRuleRouter.route((List) inputInvokers, inputURL, invocation)); assertNotNull(meshRuleRouter.route((List) inputInvokers, inputURL, invocation));
} }
} }
} }

View File

@ -99,4 +99,4 @@ public class DestinationRuleTest {
} }
} }
} }

View File

@ -35,4 +35,4 @@ public class VirtualServiceRuleTest {
assertNotNull(virtualServiceRule); assertNotNull(virtualServiceRule);
} }
} }

View File

@ -137,4 +137,4 @@ public class DubboMatchRequestTest {
assertFalse(DubboMatchRequest.isMatch(dubboMatchRequest, "sayHello", new String[]{}, new Object[]{}, inputSourceLablesMap, invokeEagleEyeContextMap, invokeDubboContextMap2, new HashMap())); assertFalse(DubboMatchRequest.isMatch(dubboMatchRequest, "sayHello", new String[]{}, new Object[]{}, inputSourceLablesMap, invokeEagleEyeContextMap, invokeDubboContextMap2, new HashMap()));
} }
} }

View File

@ -39,4 +39,4 @@ public class BoolMatchTest {
assertTrue(BoolMatch.isMatch(boolMatch,false)); assertTrue(BoolMatch.isMatch(boolMatch,false));
} }
} }

View File

@ -98,4 +98,4 @@ public class DoubleMatchTest {
assertTrue(DoubleMatch.isMatch(doubleMatch, 3.0)); assertTrue(DoubleMatch.isMatch(doubleMatch, 3.0));
} }
} }

View File

@ -175,4 +175,4 @@ public class DubboAttachmentMatchTest {
assertFalse(DubboAttachmentMatch.isMatch(dubboAttachmentMatch, invokeEagleEyeContextMap2, invokeDubboContextMap2)); assertFalse(DubboAttachmentMatch.isMatch(dubboAttachmentMatch, invokeEagleEyeContextMap2, invokeDubboContextMap2));
} }
} }

View File

@ -153,4 +153,4 @@ public class DubboMethodMatchTest {
assertTrue(DubboMethodMatch.isMatch(dubboMethodMatch, "test", new String[]{"int", "java.lang.String", "boolean"}, new Object[]{10, "sayHello", true})); assertTrue(DubboMethodMatch.isMatch(dubboMethodMatch, "test", new String[]{"int", "java.lang.String", "boolean"}, new Object[]{10, "sayHello", true}));
assertFalse(DubboMethodMatch.isMatch(dubboMethodMatch, "test", new String[]{"int", "java.lang.String", "boolean"}, new Object[]{10, "sayHello", false})); assertFalse(DubboMethodMatch.isMatch(dubboMethodMatch, "test", new String[]{"int", "java.lang.String", "boolean"}, new Object[]{10, "sayHello", false}));
} }
} }

View File

@ -49,4 +49,4 @@ public class ListDoubleMatchTest {
assertTrue(ListDoubleMatch.isMatch(listDoubleMatch, 11.0)); assertTrue(ListDoubleMatch.isMatch(listDoubleMatch, 11.0));
assertFalse(ListDoubleMatch.isMatch(listDoubleMatch, 12.0)); assertFalse(ListDoubleMatch.isMatch(listDoubleMatch, 12.0));
} }
} }

View File

@ -51,4 +51,4 @@ public class ListStringMatchTest {
assertFalse(ListStringMatch.isMatch(listStringMatch, "3")); assertFalse(ListStringMatch.isMatch(listStringMatch, "3"));
} }
} }

View File

@ -78,4 +78,4 @@ public class StringMatchTest {
assertFalse(StringMatch.isMatch(stringMatch, "")); assertFalse(StringMatch.isMatch(stringMatch, ""));
assertFalse(StringMatch.isMatch(stringMatch, null)); assertFalse(StringMatch.isMatch(stringMatch, null));
} }
} }

View File

@ -71,4 +71,4 @@ class VsDestinationGroupRuleDispatcherTest {
verify(vsDestinationGroupRuleListener, times(1)).onRuleChange(anyObject()); verify(vsDestinationGroupRuleListener, times(1)).onRuleChange(anyObject());
} }
} }

View File

@ -96,15 +96,15 @@ public class ScriptRouterTest {
invokers.add(invoker3); invokers.add(invoker3);
String script = "function route(invokers, invocation, context){ " + String script = "function route(invokers, invocation, context){ " +
" var result = new java.util.ArrayList(invokers.size()); " + " var result = new java.util.ArrayList(invokers.size()); " +
" var targetHost = new java.util.ArrayList(); " + " var targetHost = new java.util.ArrayList(); " +
" targetHost.add(\"10.134.108.2\"); " + " targetHost.add(\"10.134.108.2\"); " +
" for (var i = 0; i < invokers.length; i++) { " + " for (var i = 0; i < invokers.length; i++) { " +
" if(targetHost.contains(invokers[i].getUrl().getHost())){ " + " if(targetHost.contains(invokers[i].getUrl().getHost())){ " +
" result.add(invokers[i]); " + " result.add(invokers[i]); " +
" } " + " } " +
" } " + " } " +
" return result; " + " return result; " +
"} " + "} " +
"route(invokers, invocation, context) "; "route(invokers, invocation, context) ";

View File

@ -1,122 +1,122 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.LogUtil; import org.apache.dubbo.common.utils.LogUtil;
import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.filter.DemoService; import org.apache.dubbo.rpc.cluster.filter.DemoService;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* FailfastClusterInvokerTest * FailfastClusterInvokerTest
* *
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class FailSafeClusterInvokerTest { public class FailSafeClusterInvokerTest {
List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>(); List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
URL url = URL.valueOf("test://test:11/test"); URL url = URL.valueOf("test://test:11/test");
Invoker<DemoService> invoker = mock(Invoker.class); Invoker<DemoService> invoker = mock(Invoker.class);
RpcInvocation invocation = new RpcInvocation(); RpcInvocation invocation = new RpcInvocation();
Directory<DemoService> dic; Directory<DemoService> dic;
Result result = new AppResponse(); Result result = new AppResponse();
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception
*/ */
@BeforeEach @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(invokers); given(dic.list(invocation)).willReturn(invokers);
given(dic.getInterface()).willReturn(DemoService.class); given(dic.getInterface()).willReturn(DemoService.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
invokers.add(invoker); invokers.add(invoker);
} }
private void resetInvokerToException() { private void resetInvokerToException() {
given(invoker.invoke(invocation)).willThrow(new RuntimeException()); given(invoker.invoke(invocation)).willThrow(new RuntimeException());
given(invoker.getUrl()).willReturn(url); given(invoker.getUrl()).willReturn(url);
given(invoker.getInterface()).willReturn(DemoService.class); given(invoker.getInterface()).willReturn(DemoService.class);
} }
private void resetInvokerToNoException() { private void resetInvokerToNoException() {
given(invoker.invoke(invocation)).willReturn(result); given(invoker.invoke(invocation)).willReturn(result);
given(invoker.getUrl()).willReturn(url); given(invoker.getUrl()).willReturn(url);
given(invoker.getInterface()).willReturn(DemoService.class); given(invoker.getInterface()).willReturn(DemoService.class);
} }
//TODO assert error log //TODO assert error log
@Test @Test
public void testInvokeExceptoin() { public void testInvokeExceptoin() {
resetInvokerToException(); resetInvokerToException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic); FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
invoker.invoke(invocation); invoker.invoke(invocation);
Assertions.assertNull(RpcContext.getServiceContext().getInvoker()); Assertions.assertNull(RpcContext.getServiceContext().getInvoker());
} }
@Test() @Test()
public void testInvokeNoExceptoin() { public void testInvokeNoExceptoin() {
resetInvokerToNoException(); resetInvokerToNoException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic); FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
Result ret = invoker.invoke(invocation); Result ret = invoker.invoke(invocation);
Assertions.assertSame(result, ret); Assertions.assertSame(result, ret);
} }
@Test() @Test()
public void testNoInvoke() { public void testNoInvoke() {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(null); given(dic.list(invocation)).willReturn(null);
given(dic.getInterface()).willReturn(DemoService.class); given(dic.getInterface()).willReturn(DemoService.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
resetInvokerToNoException(); resetInvokerToNoException();
FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic); FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
LogUtil.start(); LogUtil.start();
invoker.invoke(invocation); invoker.invoke(invocation);
assertTrue(LogUtil.findMessage("No provider") > 0); assertTrue(LogUtil.findMessage("No provider") > 0);
LogUtil.stop(); LogUtil.stop();
} }
} }

View File

@ -1,177 +1,177 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.utils.DubboAppender; import org.apache.dubbo.common.utils.DubboAppender;
import org.apache.dubbo.common.utils.LogUtil; import org.apache.dubbo.common.utils.LogUtil;
import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.log4j.Level; import org.apache.log4j.Level;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.TestMethodOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* FailbackClusterInvokerTest * FailbackClusterInvokerTest
* <p> * <p>
* add annotation @TestMethodOrder, the testARetryFailed Method must to first execution * add annotation @TestMethodOrder, the testARetryFailed Method must to first execution
*/ */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class) @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class FailbackClusterInvokerTest { public class FailbackClusterInvokerTest {
List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>(); List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
URL url = URL.valueOf("test://test:11/test?retries=2&failbacktasks=2"); URL url = URL.valueOf("test://test:11/test?retries=2&failbacktasks=2");
Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class); Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class);
RpcInvocation invocation = new RpcInvocation(); RpcInvocation invocation = new RpcInvocation();
Directory<FailbackClusterInvokerTest> dic; Directory<FailbackClusterInvokerTest> dic;
Result result = new AppResponse(); Result result = new AppResponse();
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception
*/ */
@BeforeEach @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(invokers); given(dic.list(invocation)).willReturn(invokers);
given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class); given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
invokers.add(invoker); invokers.add(invoker);
} }
@AfterEach @AfterEach
public void tearDown() { public void tearDown() {
dic = null; dic = null;
invocation = new RpcInvocation(); invocation = new RpcInvocation();
invokers.clear(); invokers.clear();
} }
private void resetInvokerToException() { private void resetInvokerToException() {
given(invoker.invoke(invocation)).willThrow(new RuntimeException()); given(invoker.invoke(invocation)).willThrow(new RuntimeException());
given(invoker.getUrl()).willReturn(url); given(invoker.getUrl()).willReturn(url);
given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class); given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
} }
private void resetInvokerToNoException() { private void resetInvokerToNoException() {
given(invoker.invoke(invocation)).willReturn(result); given(invoker.invoke(invocation)).willReturn(result);
given(invoker.getUrl()).willReturn(url); given(invoker.getUrl()).willReturn(url);
given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class); given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
} }
@Test @Test
@Order(1) @Order(1)
public void testInvokeException() { public void testInvokeException() {
resetInvokerToException(); resetInvokerToException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>( FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic); dic);
invoker.invoke(invocation); invoker.invoke(invocation);
Assertions.assertNull(RpcContext.getServiceContext().getInvoker()); Assertions.assertNull(RpcContext.getServiceContext().getInvoker());
DubboAppender.clear(); DubboAppender.clear();
} }
@Test @Test
@Order(2) @Order(2)
public void testInvokeNoException() { public void testInvokeNoException() {
resetInvokerToNoException(); resetInvokerToNoException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>( FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic); dic);
Result ret = invoker.invoke(invocation); Result ret = invoker.invoke(invocation);
Assertions.assertSame(result, ret); Assertions.assertSame(result, ret);
} }
@Test @Test
@Order(3) @Order(3)
public void testNoInvoke() { public void testNoInvoke() {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(null); given(dic.list(invocation)).willReturn(null);
given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class); given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
invokers.add(invoker); invokers.add(invoker);
resetInvokerToNoException(); resetInvokerToNoException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>( FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic); dic);
LogUtil.start(); LogUtil.start();
DubboAppender.clear(); DubboAppender.clear();
invoker.invoke(invocation); invoker.invoke(invocation);
assertEquals(1, LogUtil.findMessage("Failback to invoke")); assertEquals(1, LogUtil.findMessage("Failback to invoke"));
LogUtil.stop(); LogUtil.stop();
} }
@Disabled @Disabled
@Test @Test
@Order(4) @Order(4)
public void testARetryFailed() throws Exception { public void testARetryFailed() throws Exception {
//Test retries and //Test retries and
resetInvokerToException(); resetInvokerToException();
FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>( FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
dic); dic);
LogUtil.start(); LogUtil.start();
DubboAppender.clear(); DubboAppender.clear();
invoker.invoke(invocation); invoker.invoke(invocation);
invoker.invoke(invocation); invoker.invoke(invocation);
invoker.invoke(invocation); invoker.invoke(invocation);
Assertions.assertNull(RpcContext.getServiceContext().getInvoker()); Assertions.assertNull(RpcContext.getServiceContext().getInvoker());
// invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so // invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so
//Ensure that the main thread is online //Ensure that the main thread is online
CountDownLatch countDown = new CountDownLatch(1); CountDownLatch countDown = new CountDownLatch(1);
countDown.await(15000L, TimeUnit.MILLISECONDS); countDown.await(15000L, TimeUnit.MILLISECONDS);
LogUtil.stop(); LogUtil.stop();
Assertions.assertEquals(4, LogUtil.findMessage(Level.ERROR, "Failed retry to invoke method"), "must have four error message "); Assertions.assertEquals(4, LogUtil.findMessage(Level.ERROR, "Failed retry to invoke method"), "must have four error message ");
Assertions.assertEquals(2, LogUtil.findMessage(Level.ERROR, "Failed retry times exceed threshold"), "must have two error message "); Assertions.assertEquals(2, LogUtil.findMessage(Level.ERROR, "Failed retry times exceed threshold"), "must have two error message ");
Assertions.assertEquals(1, LogUtil.findMessage(Level.ERROR, "Failback background works error"), "must have one error message "); Assertions.assertEquals(1, LogUtil.findMessage(Level.ERROR, "Failback background works error"), "must have one error message ");
// it can be invoke successfully // it can be invoke successfully
} }
} }

View File

@ -124,4 +124,4 @@ public class FailfastClusterInvokerTest {
} }
} }
} }

View File

@ -1,290 +1,290 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support; package org.apache.dubbo.rpc.cluster.support;
import org.apache.dubbo.common.URL; import org.apache.dubbo.common.URL;
import org.apache.dubbo.rpc.AppResponse; import org.apache.dubbo.rpc.AppResponse;
import org.apache.dubbo.rpc.AsyncRpcResult; import org.apache.dubbo.rpc.AsyncRpcResult;
import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invocation;
import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Result;
import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.RpcException;
import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.RpcInvocation;
import org.apache.dubbo.rpc.cluster.Directory; import org.apache.dubbo.rpc.cluster.Directory;
import org.apache.dubbo.rpc.cluster.directory.StaticDirectory; import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
import org.apache.dubbo.rpc.protocol.AbstractInvoker; import org.apache.dubbo.rpc.protocol.AbstractInvoker;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
/** /**
* FailoverClusterInvokerTest * FailoverClusterInvokerTest
* *
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class FailoverClusterInvokerTest { public class FailoverClusterInvokerTest {
private List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>(); private List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>();
private int retries = 5; private int retries = 5;
private URL url = URL.valueOf("test://test:11/test?retries=" + retries); private URL url = URL.valueOf("test://test:11/test?retries=" + retries);
private Invoker<FailoverClusterInvokerTest> invoker1 = mock(Invoker.class); private Invoker<FailoverClusterInvokerTest> invoker1 = mock(Invoker.class);
private Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class); private Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class);
private RpcInvocation invocation = new RpcInvocation(); private RpcInvocation invocation = new RpcInvocation();
private Directory<FailoverClusterInvokerTest> dic; private Directory<FailoverClusterInvokerTest> dic;
private Result result = new AppResponse(); private Result result = new AppResponse();
/** /**
* @throws java.lang.Exception * @throws java.lang.Exception
*/ */
@BeforeEach @BeforeEach
public void setUp() throws Exception { public void setUp() throws Exception {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(invokers); given(dic.list(invocation)).willReturn(invokers);
given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
} }
@Test @Test
public void testInvokeWithRuntimeException() { public void testInvokeWithRuntimeException() {
given(invoker1.invoke(invocation)).willThrow(new RuntimeException()); given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
given(invoker1.isAvailable()).willReturn(true); given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getUrl()).willReturn(url); given(invoker1.getUrl()).willReturn(url);
given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willThrow(new RuntimeException()); given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
given(invoker2.isAvailable()).willReturn(true); given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getUrl()).willReturn(url); given(invoker2.getUrl()).willReturn(url);
given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try { try {
invoker.invoke(invocation); invoker.invoke(invocation);
fail(); fail();
} catch (RpcException expected) { } catch (RpcException expected) {
assertEquals(0, expected.getCode()); assertEquals(0, expected.getCode());
assertFalse(expected.getCause() instanceof RpcException); assertFalse(expected.getCause() instanceof RpcException);
} }
} }
@Test() @Test()
public void testInvokeWithRPCException() { public void testInvokeWithRPCException() {
given(invoker1.invoke(invocation)).willThrow(new RpcException()); given(invoker1.invoke(invocation)).willThrow(new RpcException());
given(invoker1.isAvailable()).willReturn(true); given(invoker1.isAvailable()).willReturn(true);
given(invoker1.getUrl()).willReturn(url); given(invoker1.getUrl()).willReturn(url);
given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willReturn(result); given(invoker2.invoke(invocation)).willReturn(result);
given(invoker2.isAvailable()).willReturn(true); given(invoker2.isAvailable()).willReturn(true);
given(invoker2.getUrl()).willReturn(url); given(invoker2.getUrl()).willReturn(url);
given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
Result ret = invoker.invoke(invocation); Result ret = invoker.invoke(invocation);
assertSame(result, ret); assertSame(result, ret);
} }
} }
@Test() @Test()
public void testInvoke_retryTimes() { public void testInvoke_retryTimes() {
given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION)); given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));
given(invoker1.isAvailable()).willReturn(false); given(invoker1.isAvailable()).willReturn(false);
given(invoker1.getUrl()).willReturn(url); given(invoker1.getUrl()).willReturn(url);
given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willThrow(new RpcException()); given(invoker2.invoke(invocation)).willThrow(new RpcException());
given(invoker2.isAvailable()).willReturn(false); given(invoker2.isAvailable()).willReturn(false);
given(invoker2.getUrl()).willReturn(url); given(invoker2.getUrl()).willReturn(url);
given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try { try {
Result ret = invoker.invoke(invocation); Result ret = invoker.invoke(invocation);
assertSame(result, ret); assertSame(result, ret);
fail(); fail();
} catch (RpcException expected) { } catch (RpcException expected) {
assertTrue((expected.isTimeout() || expected.getCode() == 0)); assertTrue((expected.isTimeout() || expected.getCode() == 0));
assertTrue(expected.getMessage().indexOf((retries + 1) + " times") > 0); assertTrue(expected.getMessage().indexOf((retries + 1) + " times") > 0);
} }
} }
@Test() @Test()
public void testInvoke_retryTimes2() { public void testInvoke_retryTimes2() {
int finalRetries = 1; int finalRetries = 1;
given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION)); given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));
given(invoker1.isAvailable()).willReturn(false); given(invoker1.isAvailable()).willReturn(false);
given(invoker1.getUrl()).willReturn(url); given(invoker1.getUrl()).willReturn(url);
given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
given(invoker2.invoke(invocation)).willThrow(new RpcException()); given(invoker2.invoke(invocation)).willThrow(new RpcException());
given(invoker2.isAvailable()).willReturn(false); given(invoker2.isAvailable()).willReturn(false);
given(invoker2.getUrl()).willReturn(url); given(invoker2.getUrl()).willReturn(url);
given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
RpcContext rpcContext = RpcContext.getContext(); RpcContext rpcContext = RpcContext.getContext();
rpcContext.setAttachment("retries", finalRetries); rpcContext.setAttachment("retries", finalRetries);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try { try {
Result ret = invoker.invoke(invocation); Result ret = invoker.invoke(invocation);
assertSame(result, ret); assertSame(result, ret);
fail(); fail();
} catch (RpcException expected) { } catch (RpcException expected) {
assertTrue((expected.isTimeout() || expected.getCode() == 0)); assertTrue((expected.isTimeout() || expected.getCode() == 0));
assertTrue(expected.getMessage().indexOf((finalRetries+1) + " times") > 0); assertTrue(expected.getMessage().indexOf((finalRetries+1) + " times") > 0);
} }
} }
@Test() @Test()
public void testNoInvoke() { public void testNoInvoke() {
dic = mock(Directory.class); dic = mock(Directory.class);
given(dic.getUrl()).willReturn(url); given(dic.getUrl()).willReturn(url);
given(dic.getConsumerUrl()).willReturn(url); given(dic.getConsumerUrl()).willReturn(url);
given(dic.list(invocation)).willReturn(null); given(dic.list(invocation)).willReturn(null);
given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class); given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
invocation.setMethodName("method1"); invocation.setMethodName("method1");
invokers.add(invoker1); invokers.add(invoker1);
FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic); FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
try { try {
invoker.invoke(invocation); invoker.invoke(invocation);
fail(); fail();
} catch (RpcException expected) { } catch (RpcException expected) {
assertFalse(expected.getCause() instanceof RpcException); assertFalse(expected.getCause() instanceof RpcException);
} }
} }
/** /**
* When invokers in directory changes after a failed request but just before a retry effort, * When invokers in directory changes after a failed request but just before a retry effort,
* then we should reselect from the latest invokers before retry. * then we should reselect from the latest invokers before retry.
*/ */
@Test @Test
public void testInvokerDestroyAndReList() { public void testInvokerDestroyAndReList() {
final URL url = URL.valueOf("test://localhost/" + Demo.class.getName() + "?loadbalance=roundrobin&retries=" + retries); final URL url = URL.valueOf("test://localhost/" + Demo.class.getName() + "?loadbalance=roundrobin&retries=" + retries);
RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION); RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);
MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url); MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url);
invoker1.setException(exception); invoker1.setException(exception);
MockInvoker<Demo> invoker2 = new MockInvoker<Demo>(Demo.class, url); MockInvoker<Demo> invoker2 = new MockInvoker<Demo>(Demo.class, url);
invoker2.setException(exception); invoker2.setException(exception);
final List<Invoker<Demo>> invokers = new ArrayList<Invoker<Demo>>(); final List<Invoker<Demo>> invokers = new ArrayList<Invoker<Demo>>();
invokers.add(invoker1); invokers.add(invoker1);
invokers.add(invoker2); invokers.add(invoker2);
Callable<Object> callable = () -> { Callable<Object> callable = () -> {
//Simulation: all invokers are destroyed //Simulation: all invokers are destroyed
for (Invoker<Demo> invoker : invokers) { for (Invoker<Demo> invoker : invokers) {
invoker.destroy(); invoker.destroy();
} }
invokers.clear(); invokers.clear();
MockInvoker<Demo> invoker3 = new MockInvoker<Demo>(Demo.class, url); MockInvoker<Demo> invoker3 = new MockInvoker<Demo>(Demo.class, url);
invoker3.setResult(AsyncRpcResult.newDefaultAsyncResult(null)); invoker3.setResult(AsyncRpcResult.newDefaultAsyncResult(null));
invokers.add(invoker3); invokers.add(invoker3);
return null; return null;
}; };
invoker1.setCallable(callable); invoker1.setCallable(callable);
invoker2.setCallable(callable); invoker2.setCallable(callable);
RpcInvocation inv = new RpcInvocation(); RpcInvocation inv = new RpcInvocation();
inv.setMethodName("test"); inv.setMethodName("test");
Directory<Demo> dic = new MockDirectory<Demo>(url, invokers); Directory<Demo> dic = new MockDirectory<Demo>(url, invokers);
FailoverClusterInvoker<Demo> clusterinvoker = new FailoverClusterInvoker<Demo>(dic); FailoverClusterInvoker<Demo> clusterinvoker = new FailoverClusterInvoker<Demo>(dic);
clusterinvoker.invoke(inv); clusterinvoker.invoke(inv);
} }
public interface Demo { public interface Demo {
} }
public static class MockInvoker<T> extends AbstractInvoker<T> { public static class MockInvoker<T> extends AbstractInvoker<T> {
URL url; URL url;
boolean available = true; boolean available = true;
boolean destoryed = false; boolean destoryed = false;
Result result; Result result;
RpcException exception; RpcException exception;
Callable<?> callable; Callable<?> callable;
public MockInvoker(Class<T> type, URL url) { public MockInvoker(Class<T> type, URL url) {
super(type, url); super(type, url);
} }
public void setResult(Result result) { public void setResult(Result result) {
this.result = result; this.result = result;
} }
public void setException(RpcException exception) { public void setException(RpcException exception) {
this.exception = exception; this.exception = exception;
} }
public void setCallable(Callable<?> callable) { public void setCallable(Callable<?> callable) {
this.callable = callable; this.callable = callable;
} }
@Override @Override
protected Result doInvoke(Invocation invocation) throws Throwable { protected Result doInvoke(Invocation invocation) throws Throwable {
if (callable != null) { if (callable != null) {
try { try {
callable.call(); callable.call();
} catch (Exception e) { } catch (Exception e) {
throw new RpcException(e); throw new RpcException(e);
} }
} }
if (exception != null) { if (exception != null) {
throw exception; throw exception;
} else { } else {
return result; return result;
} }
} }
} }
public class MockDirectory<T> extends StaticDirectory<T> { public class MockDirectory<T> extends StaticDirectory<T> {
public MockDirectory(URL url, List<Invoker<T>> invokers) { public MockDirectory(URL url, List<Invoker<T>> invokers) {
super(url, invokers); super(url, invokers);
} }
@Override @Override
protected List<Invoker<T>> doList(Invocation invocation) throws RpcException { protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
return new ArrayList<Invoker<T>>(super.doList(invocation)); return new ArrayList<Invoker<T>>(super.doList(invocation));
} }
} }
} }

View File

@ -154,4 +154,4 @@ public class ForkingClusterInvokerTest {
Assertions.assertSame(result, ret); Assertions.assertSame(result, ret);
} }
} }

View File

@ -1,28 +1,28 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.rpc.cluster.support.wrapper; package org.apache.dubbo.rpc.cluster.support.wrapper;
public class MyMockException extends RuntimeException { public class MyMockException extends RuntimeException {
private static final long serialVersionUID = 2851692379597990457L; private static final long serialVersionUID = 2851692379597990457L;
public MyMockException(String message) { public MyMockException(String message) {
super(message); super(message);
} }
} }

View File

@ -1 +1 @@
script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory

View File

@ -1,30 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- <!--
Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0 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 not use this file except in compliance with
the License. You may obtain a copy of the License at the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
<appender name="DUBBO" class="org.apache.dubbo.common.utils.DubboAppender"> <appender name="DUBBO" class="org.apache.dubbo.common.utils.DubboAppender">
<param name="File" value="../dubbo.log"/> <param name="File" value="../dubbo.log"/>
<layout class="org.apache.log4j.PatternLayout"> <layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n"/> <param name="ConversionPattern" value="[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n"/>
</layout> </layout>
</appender> </appender>
<root> <root>
<level value="INFO"/> <level value="INFO"/>
<appender-ref ref="DUBBO"/> <appender-ref ref="DUBBO"/>
</root> </root>
</log4j:configuration> </log4j:configuration>

View File

@ -42,4 +42,4 @@ public @interface Activate {
String[] after() default {}; String[] after() default {};
int order() default 0; int order() default 0;
} }

View File

@ -1,68 +1,68 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common; package org.apache.dubbo.common;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Marker for extension interface * Marker for extension interface
* <p/> * <p/>
* Changes on extension configuration file <br/> * Changes on extension configuration file <br/>
* Use <code>Protocol</code> as an example, its configuration file 'META-INF/dubbo/com.xxx.Protocol' is changes from: <br/> * Use <code>Protocol</code> as an example, its configuration file 'META-INF/dubbo/com.xxx.Protocol' is changes from: <br/>
* <pre> * <pre>
* com.foo.XxxProtocol * com.foo.XxxProtocol
* com.foo.YyyProtocol * com.foo.YyyProtocol
* </pre> * </pre>
* <p> * <p>
* to key-value pair <br/> * to key-value pair <br/>
* <pre> * <pre>
* xxx=com.foo.XxxProtocol * xxx=com.foo.XxxProtocol
* yyy=com.foo.YyyProtocol * yyy=com.foo.YyyProtocol
* </pre> * </pre>
* <br/> * <br/>
* The reason for this change is: * The reason for this change is:
* <p> * <p>
* If there's third party library referenced by static field or by method in extension implementation, its class will * If there's third party library referenced by static field or by method in extension implementation, its class will
* fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id * fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id
* therefore cannot be able to map the exception information with the extension, if the previous format is used. * therefore cannot be able to map the exception information with the extension, if the previous format is used.
* <p/> * <p/>
* For example: * For example:
* <p> * <p>
* Fails to load Extension("mina"). When user configure to use mina, dubbo will complain the extension cannot be loaded, * Fails to load Extension("mina"). When user configure to use mina, dubbo will complain the extension cannot be loaded,
* instead of reporting which extract extension implementation fails and the extract reason. * instead of reporting which extract extension implementation fails and the extract reason.
* </p> * </p>
* *
* @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI} * @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI}
*/ */
@Deprecated @Deprecated
@Documented @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE}) @Target({ElementType.TYPE})
public @interface Extension { public @interface Extension {
/** /**
* @deprecated * @deprecated
*/ */
@Deprecated @Deprecated
String value() default ""; String value() default "";
} }

View File

@ -1,43 +1,43 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common; package org.apache.dubbo.common;
/** /**
* Node. (API/SPI, Prototype, ThreadSafe) * Node. (API/SPI, Prototype, ThreadSafe)
*/ */
public interface Node { public interface Node {
/** /**
* get url. * get url.
* *
* @return url. * @return url.
*/ */
URL getUrl(); URL getUrl();
/** /**
* is available. * is available.
* *
* @return available. * @return available.
*/ */
boolean isAvailable(); boolean isAvailable();
/** /**
* destroy. * destroy.
*/ */
void destroy(); void destroy();
} }

View File

@ -1,263 +1,263 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common; package org.apache.dubbo.common;
import org.apache.dubbo.common.extension.ExtensionLoader; import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY_PREFIX;
import static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX; import static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;
/** /**
* Parameters for backward compatibility for version prior to 2.0.5 * Parameters for backward compatibility for version prior to 2.0.5
* *
* @deprecated * @deprecated
*/ */
@Deprecated @Deprecated
public class Parameters { public class Parameters {
protected static final Logger logger = LoggerFactory.getLogger(Parameters.class); protected static final Logger logger = LoggerFactory.getLogger(Parameters.class);
private final Map<String, String> parameters; private final Map<String, String> parameters;
public Parameters(String... pairs) { public Parameters(String... pairs) {
this(toMap(pairs)); this(toMap(pairs));
} }
public Parameters(Map<String, String> parameters) { public Parameters(Map<String, String> parameters) {
this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap<>(parameters) : new HashMap<>(0)); this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap<>(parameters) : new HashMap<>(0));
} }
private static Map<String, String> toMap(String... pairs) { private static Map<String, String> toMap(String... pairs) {
return CollectionUtils.toStringMap(pairs); return CollectionUtils.toStringMap(pairs);
} }
public static Parameters parseParameters(String query) { public static Parameters parseParameters(String query) {
return new Parameters(StringUtils.parseQueryString(query)); return new Parameters(StringUtils.parseQueryString(query));
} }
public Map<String, String> getParameters() { public Map<String, String> getParameters() {
return parameters; return parameters;
} }
public <T> T getExtension(Class<T> type, String key) { public <T> T getExtension(Class<T> type, String key) {
String name = getParameter(key); String name = getParameter(key);
return ExtensionLoader.getExtensionLoader(type).getExtension(name); return ExtensionLoader.getExtensionLoader(type).getExtension(name);
} }
public <T> T getExtension(Class<T> type, String key, String defaultValue) { public <T> T getExtension(Class<T> type, String key, String defaultValue) {
String name = getParameter(key, defaultValue); String name = getParameter(key, defaultValue);
return ExtensionLoader.getExtensionLoader(type).getExtension(name); return ExtensionLoader.getExtensionLoader(type).getExtension(name);
} }
public <T> T getMethodExtension(Class<T> type, String method, String key) { public <T> T getMethodExtension(Class<T> type, String method, String key) {
String name = getMethodParameter(method, key); String name = getMethodParameter(method, key);
return ExtensionLoader.getExtensionLoader(type).getExtension(name); return ExtensionLoader.getExtensionLoader(type).getExtension(name);
} }
public <T> T getMethodExtension(Class<T> type, String method, String key, String defaultValue) { public <T> T getMethodExtension(Class<T> type, String method, String key, String defaultValue) {
String name = getMethodParameter(method, key, defaultValue); String name = getMethodParameter(method, key, defaultValue);
return ExtensionLoader.getExtensionLoader(type).getExtension(name); return ExtensionLoader.getExtensionLoader(type).getExtension(name);
} }
public String getDecodedParameter(String key) { public String getDecodedParameter(String key) {
return getDecodedParameter(key, null); return getDecodedParameter(key, null);
} }
public String getDecodedParameter(String key, String defaultValue) { public String getDecodedParameter(String key, String defaultValue) {
String value = getParameter(key, defaultValue); String value = getParameter(key, defaultValue);
if (value != null && value.length() > 0) { if (value != null && value.length() > 0) {
try { try {
value = URLDecoder.decode(value, "UTF-8"); value = URLDecoder.decode(value, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
logger.error(e.getMessage(), e); logger.error(e.getMessage(), e);
} }
} }
return value; return value;
} }
public String getParameter(String key) { public String getParameter(String key) {
String value = parameters.get(key); String value = parameters.get(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
value = parameters.get(HIDE_KEY_PREFIX + key); value = parameters.get(HIDE_KEY_PREFIX + key);
} }
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
value = parameters.get(DEFAULT_KEY_PREFIX + key); value = parameters.get(DEFAULT_KEY_PREFIX + key);
} }
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
value = parameters.get(HIDE_KEY_PREFIX + DEFAULT_KEY_PREFIX + key); value = parameters.get(HIDE_KEY_PREFIX + DEFAULT_KEY_PREFIX + key);
} }
return value; return value;
} }
public String getParameter(String key, String defaultValue) { public String getParameter(String key, String defaultValue) {
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return value; return value;
} }
public int getIntParameter(String key) { public int getIntParameter(String key) {
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return 0; return 0;
} }
return Integer.parseInt(value); return Integer.parseInt(value);
} }
public int getIntParameter(String key, int defaultValue) { public int getIntParameter(String key, int defaultValue) {
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return Integer.parseInt(value); return Integer.parseInt(value);
} }
public int getPositiveIntParameter(String key, int defaultValue) { public int getPositiveIntParameter(String key, int defaultValue) {
if (defaultValue <= 0) { if (defaultValue <= 0) {
throw new IllegalArgumentException("defaultValue <= 0"); throw new IllegalArgumentException("defaultValue <= 0");
} }
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
int i = Integer.parseInt(value); int i = Integer.parseInt(value);
if (i > 0) { if (i > 0) {
return i; return i;
} }
return defaultValue; return defaultValue;
} }
public boolean getBooleanParameter(String key) { public boolean getBooleanParameter(String key) {
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return false; return false;
} }
return Boolean.parseBoolean(value); return Boolean.parseBoolean(value);
} }
public boolean getBooleanParameter(String key, boolean defaultValue) { public boolean getBooleanParameter(String key, boolean defaultValue) {
String value = getParameter(key); String value = getParameter(key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return Boolean.parseBoolean(value); return Boolean.parseBoolean(value);
} }
public boolean hasParameter(String key) { public boolean hasParameter(String key) {
String value = getParameter(key); String value = getParameter(key);
return value != null && value.length() > 0; return value != null && value.length() > 0;
} }
public String getMethodParameter(String method, String key) { public String getMethodParameter(String method, String key) {
String value = parameters.get(method + "." + key); String value = parameters.get(method + "." + key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
value = parameters.get(HIDE_KEY_PREFIX + method + "." + key); value = parameters.get(HIDE_KEY_PREFIX + method + "." + key);
} }
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return getParameter(key); return getParameter(key);
} }
return value; return value;
} }
public String getMethodParameter(String method, String key, String defaultValue) { public String getMethodParameter(String method, String key, String defaultValue) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return value; return value;
} }
public int getMethodIntParameter(String method, String key) { public int getMethodIntParameter(String method, String key) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return 0; return 0;
} }
return Integer.parseInt(value); return Integer.parseInt(value);
} }
public int getMethodIntParameter(String method, String key, int defaultValue) { public int getMethodIntParameter(String method, String key, int defaultValue) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return Integer.parseInt(value); return Integer.parseInt(value);
} }
public int getMethodPositiveIntParameter(String method, String key, int defaultValue) { public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {
if (defaultValue <= 0) { if (defaultValue <= 0) {
throw new IllegalArgumentException("defaultValue <= 0"); throw new IllegalArgumentException("defaultValue <= 0");
} }
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
int i = Integer.parseInt(value); int i = Integer.parseInt(value);
if (i > 0) { if (i > 0) {
return i; return i;
} }
return defaultValue; return defaultValue;
} }
public boolean getMethodBooleanParameter(String method, String key) { public boolean getMethodBooleanParameter(String method, String key) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return false; return false;
} }
return Boolean.parseBoolean(value); return Boolean.parseBoolean(value);
} }
public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) { public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return defaultValue; return defaultValue;
} }
return Boolean.parseBoolean(value); return Boolean.parseBoolean(value);
} }
public boolean hasMethodParameter(String method, String key) { public boolean hasMethodParameter(String method, String key) {
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
return value != null && value.length() > 0; return value != null && value.length() > 0;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
return true; return true;
} }
return parameters.equals(o); return parameters.equals(o);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return parameters.hashCode(); return parameters.hashCode();
} }
@Override @Override
public String toString() { public String toString() {
return StringUtils.toQueryString(getParameters()); return StringUtils.toQueryString(getParameters());
} }
} }

View File

@ -28,4 +28,4 @@ public interface Resetable {
*/ */
void reset(URL url); void reset(URL url);
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,436 +1,436 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common; package org.apache.dubbo.common;
import org.apache.dubbo.common.url.component.ServiceConfigURL; import org.apache.dubbo.common.url.component.ServiceConfigURL;
import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.common.utils.StringUtils;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
public final class URLBuilder extends ServiceConfigURL { public final class URLBuilder extends ServiceConfigURL {
private String protocol; private String protocol;
private String username; private String username;
private String password; private String password;
// by default, host to registry // by default, host to registry
private String host; private String host;
// by default, port to registry // by default, port to registry
private int port; private int port;
private String path; private String path;
private Map<String, String> parameters; private Map<String, String> parameters;
private Map<String, Object> attributes; private Map<String, Object> attributes;
private Map<String, Map<String, String>> methodParameters; private Map<String, Map<String, String>> methodParameters;
public URLBuilder() { public URLBuilder() {
protocol = null; protocol = null;
username = null; username = null;
password = null; password = null;
host = null; host = null;
port = 0; port = 0;
path = null; path = null;
parameters = new HashMap<>(); parameters = new HashMap<>();
attributes = new HashMap<>(); attributes = new HashMap<>();
methodParameters = new HashMap<>(); methodParameters = new HashMap<>();
} }
public URLBuilder(String protocol, String host, int port) { public URLBuilder(String protocol, String host, int port) {
this(protocol, null, null, host, port, null, null); this(protocol, null, null, host, port, null, null);
} }
public URLBuilder(String protocol, String host, int port, String[] pairs) { public URLBuilder(String protocol, String host, int port, String[] pairs) {
this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs)); this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));
} }
public URLBuilder(String protocol, String host, int port, Map<String, String> parameters) { public URLBuilder(String protocol, String host, int port, Map<String, String> parameters) {
this(protocol, null, null, host, port, null, parameters); this(protocol, null, null, host, port, null, parameters);
} }
public URLBuilder(String protocol, String host, int port, String path) { public URLBuilder(String protocol, String host, int port, String path) {
this(protocol, null, null, host, port, path, null); this(protocol, null, null, host, port, path, null);
} }
public URLBuilder(String protocol, String host, int port, String path, String... pairs) { public URLBuilder(String protocol, String host, int port, String path, String... pairs) {
this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs)); this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));
} }
public URLBuilder(String protocol, String host, int port, String path, Map<String, String> parameters) { public URLBuilder(String protocol, String host, int port, String path, Map<String, String> parameters) {
this(protocol, null, null, host, port, path, parameters); this(protocol, null, null, host, port, path, parameters);
} }
public URLBuilder(String protocol, public URLBuilder(String protocol,
String username, String username,
String password, String password,
String host, String host,
int port, int port,
String path, String path,
Map<String, String> parameters) { Map<String, String> parameters) {
this(protocol, username, password, host, port, path, parameters, null); this(protocol, username, password, host, port, path, parameters, null);
} }
public URLBuilder(String protocol, public URLBuilder(String protocol,
String username, String username,
String password, String password,
String host, String host,
int port, int port,
String path, String path,
Map<String, String> parameters, Map<String, String> parameters,
Map<String, Object> attributes) { Map<String, Object> attributes) {
this.protocol = protocol; this.protocol = protocol;
this.username = username; this.username = username;
this.password = password; this.password = password;
this.host = host; this.host = host;
this.port = port; this.port = port;
this.path = path; this.path = path;
this.parameters = parameters != null ? parameters : new HashMap<>(); this.parameters = parameters != null ? parameters : new HashMap<>();
this.attributes = attributes != null ? attributes : new HashMap<>(); this.attributes = attributes != null ? attributes : new HashMap<>();
} }
public static URLBuilder from(URL url) { public static URLBuilder from(URL url) {
String protocol = url.getProtocol(); String protocol = url.getProtocol();
String username = url.getUsername(); String username = url.getUsername();
String password = url.getPassword(); String password = url.getPassword();
String host = url.getHost(); String host = url.getHost();
int port = url.getPort(); int port = url.getPort();
String path = url.getPath(); String path = url.getPath();
Map<String, String> parameters = new HashMap<>(url.getParameters()); Map<String, String> parameters = new HashMap<>(url.getParameters());
Map<String, Object> attributes = new HashMap<>(url.getAttributes()); Map<String, Object> attributes = new HashMap<>(url.getAttributes());
return new URLBuilder( return new URLBuilder(
protocol, protocol,
username, username,
password, password,
host, host,
port, port,
path, path,
parameters, parameters,
attributes); attributes);
} }
public ServiceConfigURL build() { public ServiceConfigURL build() {
if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) { if (StringUtils.isEmpty(username) && StringUtils.isNotEmpty(password)) {
throw new IllegalArgumentException("Invalid url, password without username!"); throw new IllegalArgumentException("Invalid url, password without username!");
} }
port = Math.max(port, 0); port = Math.max(port, 0);
// trim the leading "/" // trim the leading "/"
int firstNonSlash = 0; int firstNonSlash = 0;
if (path != null) { if (path != null) {
while (firstNonSlash < path.length() && path.charAt(firstNonSlash) == '/') { while (firstNonSlash < path.length() && path.charAt(firstNonSlash) == '/') {
firstNonSlash++; firstNonSlash++;
} }
if (firstNonSlash >= path.length()) { if (firstNonSlash >= path.length()) {
path = ""; path = "";
} else if (firstNonSlash > 0) { } else if (firstNonSlash > 0) {
path = path.substring(firstNonSlash); path = path.substring(firstNonSlash);
} }
} }
return new ServiceConfigURL(protocol, username, password, host, port, path, parameters, attributes); return new ServiceConfigURL(protocol, username, password, host, port, path, parameters, attributes);
} }
@Override @Override
public URLBuilder putAttribute(String key, Object obj) { public URLBuilder putAttribute(String key, Object obj) {
attributes.put(key, obj); attributes.put(key, obj);
return this; return this;
} }
public URLBuilder setProtocol(String protocol) { public URLBuilder setProtocol(String protocol) {
this.protocol = protocol; this.protocol = protocol;
return this; return this;
} }
public URLBuilder setUsername(String username) { public URLBuilder setUsername(String username) {
this.username = username; this.username = username;
return this; return this;
} }
public URLBuilder setPassword(String password) { public URLBuilder setPassword(String password) {
this.password = password; this.password = password;
return this; return this;
} }
public URLBuilder setHost(String host) { public URLBuilder setHost(String host) {
this.host = host; this.host = host;
return this; return this;
} }
public URLBuilder setPort(int port) { public URLBuilder setPort(int port) {
this.port = port; this.port = port;
return this; return this;
} }
public URLBuilder setAddress(String address) { public URLBuilder setAddress(String address) {
int i = address.lastIndexOf(':'); int i = address.lastIndexOf(':');
String host; String host;
int port = this.port; int port = this.port;
if (i >= 0) { if (i >= 0) {
host = address.substring(0, i); host = address.substring(0, i);
port = Integer.parseInt(address.substring(i + 1)); port = Integer.parseInt(address.substring(i + 1));
} else { } else {
host = address; host = address;
} }
this.host = host; this.host = host;
this.port = port; this.port = port;
return this; return this;
} }
public URLBuilder setPath(String path) { public URLBuilder setPath(String path) {
this.path = path; this.path = path;
return this; return this;
} }
public URLBuilder addParameterAndEncoded(String key, String value) { public URLBuilder addParameterAndEncoded(String key, String value) {
if (StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(value)) {
return this; return this;
} }
return addParameter(key, URL.encode(value)); return addParameter(key, URL.encode(value));
} }
public URLBuilder addParameter(String key, boolean value) { public URLBuilder addParameter(String key, boolean value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, char value) { public URLBuilder addParameter(String key, char value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, byte value) { public URLBuilder addParameter(String key, byte value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, short value) { public URLBuilder addParameter(String key, short value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, int value) { public URLBuilder addParameter(String key, int value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, long value) { public URLBuilder addParameter(String key, long value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, float value) { public URLBuilder addParameter(String key, float value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, double value) { public URLBuilder addParameter(String key, double value) {
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, Enum<?> value) { public URLBuilder addParameter(String key, Enum<?> value) {
if (value == null) { if (value == null) {
return this; return this;
} }
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, Number value) { public URLBuilder addParameter(String key, Number value) {
if (value == null) { if (value == null) {
return this; return this;
} }
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, CharSequence value) { public URLBuilder addParameter(String key, CharSequence value) {
if (value == null || value.length() == 0) { if (value == null || value.length() == 0) {
return this; return this;
} }
return addParameter(key, String.valueOf(value)); return addParameter(key, String.valueOf(value));
} }
public URLBuilder addParameter(String key, String value) { public URLBuilder addParameter(String key, String value) {
if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return this; return this;
} }
parameters.put(key, value); parameters.put(key, value);
return this; return this;
} }
public URLBuilder addMethodParameter(String method, String key, String value) { public URLBuilder addMethodParameter(String method, String key, String value) {
if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return this; return this;
} }
URL.putMethodParameter(method, key, value, methodParameters); URL.putMethodParameter(method, key, value, methodParameters);
return this; return this;
} }
public URLBuilder addParameterIfAbsent(String key, String value) { public URLBuilder addParameterIfAbsent(String key, String value) {
if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return this; return this;
} }
if (hasParameter(key)) { if (hasParameter(key)) {
return this; return this;
} }
parameters.put(key, value); parameters.put(key, value);
return this; return this;
} }
public URLBuilder addMethodParameterIfAbsent(String method, String key, String value) { public URLBuilder addMethodParameterIfAbsent(String method, String key, String value) {
if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { if (StringUtils.isEmpty(method) || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
return this; return this;
} }
if (hasMethodParameter(method, key)) { if (hasMethodParameter(method, key)) {
return this; return this;
} }
URL.putMethodParameter(method, key, value, methodParameters); URL.putMethodParameter(method, key, value, methodParameters);
return this; return this;
} }
public URLBuilder addParameters(Map<String, String> parameters) { public URLBuilder addParameters(Map<String, String> parameters) {
if (CollectionUtils.isEmptyMap(parameters)) { if (CollectionUtils.isEmptyMap(parameters)) {
return this; return this;
} }
boolean hasAndEqual = true; boolean hasAndEqual = true;
for (Map.Entry<String, String> entry : parameters.entrySet()) { for (Map.Entry<String, String> entry : parameters.entrySet()) {
String oldValue = this.parameters.get(entry.getKey()); String oldValue = this.parameters.get(entry.getKey());
String newValue = entry.getValue(); String newValue = entry.getValue();
if (!Objects.equals(oldValue, newValue)) { if (!Objects.equals(oldValue, newValue)) {
hasAndEqual = false; hasAndEqual = false;
break; break;
} }
} }
// return immediately if there's no change // return immediately if there's no change
if (hasAndEqual) { if (hasAndEqual) {
return this; return this;
} }
this.parameters.putAll(parameters); this.parameters.putAll(parameters);
return this; return this;
} }
public URLBuilder addMethodParameters(Map<String, Map<String, String>> methodParameters) { public URLBuilder addMethodParameters(Map<String, Map<String, String>> methodParameters) {
if (CollectionUtils.isEmptyMap(methodParameters)) { if (CollectionUtils.isEmptyMap(methodParameters)) {
return this; return this;
} }
this.methodParameters.putAll(methodParameters); this.methodParameters.putAll(methodParameters);
return this; return this;
} }
public URLBuilder addParametersIfAbsent(Map<String, String> parameters) { public URLBuilder addParametersIfAbsent(Map<String, String> parameters) {
if (CollectionUtils.isEmptyMap(parameters)) { if (CollectionUtils.isEmptyMap(parameters)) {
return this; return this;
} }
for(Map.Entry<String, String> entry : parameters.entrySet()) { for(Map.Entry<String, String> entry : parameters.entrySet()) {
this.parameters.putIfAbsent(entry.getKey(), entry.getValue()); this.parameters.putIfAbsent(entry.getKey(), entry.getValue());
} }
return this; return this;
} }
public URLBuilder addParameters(String... pairs) { public URLBuilder addParameters(String... pairs) {
if (pairs == null || pairs.length == 0) { if (pairs == null || pairs.length == 0) {
return this; return this;
} }
if (pairs.length % 2 != 0) { if (pairs.length % 2 != 0) {
throw new IllegalArgumentException("Map pairs can not be odd number."); throw new IllegalArgumentException("Map pairs can not be odd number.");
} }
Map<String, String> map = new HashMap<>(); Map<String, String> map = new HashMap<>();
int len = pairs.length / 2; int len = pairs.length / 2;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
map.put(pairs[2 * i], pairs[2 * i + 1]); map.put(pairs[2 * i], pairs[2 * i + 1]);
} }
return addParameters(map); return addParameters(map);
} }
public URLBuilder addParameterString(String query) { public URLBuilder addParameterString(String query) {
if (StringUtils.isEmpty(query)) { if (StringUtils.isEmpty(query)) {
return this; return this;
} }
return addParameters(StringUtils.parseQueryString(query)); return addParameters(StringUtils.parseQueryString(query));
} }
public URLBuilder removeParameter(String key) { public URLBuilder removeParameter(String key) {
if (StringUtils.isEmpty(key)) { if (StringUtils.isEmpty(key)) {
return this; return this;
} }
return removeParameters(key); return removeParameters(key);
} }
public URLBuilder removeParameters(Collection<String> keys) { public URLBuilder removeParameters(Collection<String> keys) {
if (CollectionUtils.isEmpty(keys)) { if (CollectionUtils.isEmpty(keys)) {
return this; return this;
} }
return removeParameters(keys.toArray(new String[0])); return removeParameters(keys.toArray(new String[0]));
} }
public URLBuilder removeParameters(String... keys) { public URLBuilder removeParameters(String... keys) {
if (keys == null || keys.length == 0) { if (keys == null || keys.length == 0) {
return this; return this;
} }
for (String key : keys) { for (String key : keys) {
parameters.remove(key); parameters.remove(key);
} }
return this; return this;
} }
public URLBuilder clearParameters() { public URLBuilder clearParameters() {
parameters.clear(); parameters.clear();
return this; return this;
} }
public boolean hasParameter(String key) { public boolean hasParameter(String key) {
String value = getParameter(key); String value = getParameter(key);
return StringUtils.isNotEmpty(value); return StringUtils.isNotEmpty(value);
} }
public boolean hasMethodParameter(String method, String key) { public boolean hasMethodParameter(String method, String key) {
if (method == null) { if (method == null) {
String suffix = "." + key; String suffix = "." + key;
for (String fullKey : parameters.keySet()) { for (String fullKey : parameters.keySet()) {
if (fullKey.endsWith(suffix)) { if (fullKey.endsWith(suffix)) {
return true; return true;
} }
} }
return false; return false;
} }
if (key == null) { if (key == null) {
String prefix = method + "."; String prefix = method + ".";
for (String fullKey : parameters.keySet()) { for (String fullKey : parameters.keySet()) {
if (fullKey.startsWith(prefix)) { if (fullKey.startsWith(prefix)) {
return true; return true;
} }
} }
return false; return false;
} }
String value = getMethodParameter(method, key); String value = getMethodParameter(method, key);
return value != null && value.length() > 0; return value != null && value.length() > 0;
} }
public String getParameter(String key) { public String getParameter(String key) {
return parameters.get(key); return parameters.get(key);
} }
public String getMethodParameter(String method, String key) { public String getMethodParameter(String method, String key) {
Map<String, String> keyMap = methodParameters.get(method); Map<String, String> keyMap = methodParameters.get(method);
String value = null; String value = null;
if (keyMap != null) { if (keyMap != null) {
value = keyMap.get(key); value = keyMap.get(key);
} }
return value; return value;
} }
} }

View File

@ -385,4 +385,4 @@ public final class ClassGenerator {
public static interface DC { public static interface DC {
} // dynamic class tag interface. } // dynamic class tag interface.
} }

View File

@ -1,227 +1,227 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common.bytecode; package org.apache.dubbo.common.bytecode;
import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.ClassUtils;
import org.apache.dubbo.common.utils.ReflectUtils; import org.apache.dubbo.common.utils.ReflectUtils;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
* Mixin * Mixin
*/ */
public abstract class Mixin { public abstract class Mixin {
private static final String PACKAGE_NAME = Mixin.class.getPackage().getName(); private static final String PACKAGE_NAME = Mixin.class.getPackage().getName();
private static AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0); private static AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0);
protected Mixin() { protected Mixin() {
} }
/** /**
* mixin interface and delegates. * mixin interface and delegates.
* all class must be public. * all class must be public.
* *
* @param ics interface class array. * @param ics interface class array.
* @param dc delegate class. * @param dc delegate class.
* @return Mixin instance. * @return Mixin instance.
*/ */
public static Mixin mixin(Class<?>[] ics, Class<?> dc) { public static Mixin mixin(Class<?>[] ics, Class<?> dc) {
return mixin(ics, new Class[]{dc}); return mixin(ics, new Class[]{dc});
} }
/** /**
* mixin interface and delegates. * mixin interface and delegates.
* all class must be public. * all class must be public.
* *
* @param ics interface class array. * @param ics interface class array.
* @param dc delegate class. * @param dc delegate class.
* @param cl class loader. * @param cl class loader.
* @return Mixin instance. * @return Mixin instance.
*/ */
public static Mixin mixin(Class<?>[] ics, Class<?> dc, ClassLoader cl) { public static Mixin mixin(Class<?>[] ics, Class<?> dc, ClassLoader cl) {
return mixin(ics, new Class[]{dc}, cl); return mixin(ics, new Class[]{dc}, cl);
} }
/** /**
* mixin interface and delegates. * mixin interface and delegates.
* all class must be public. * all class must be public.
* *
* @param ics interface class array. * @param ics interface class array.
* @param dcs delegate class array. * @param dcs delegate class array.
* @return Mixin instance. * @return Mixin instance.
*/ */
public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs) { public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs) {
return mixin(ics, dcs, ClassUtils.getCallerClassLoader(Mixin.class)); return mixin(ics, dcs, ClassUtils.getCallerClassLoader(Mixin.class));
} }
/** /**
* mixin interface and delegates. * mixin interface and delegates.
* all class must be public. * all class must be public.
* *
* @param ics interface class array. * @param ics interface class array.
* @param dcs delegate class array. * @param dcs delegate class array.
* @param cl class loader. * @param cl class loader.
* @return Mixin instance. * @return Mixin instance.
*/ */
public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) { public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) {
assertInterfaceArray(ics); assertInterfaceArray(ics);
long id = MIXIN_CLASS_COUNTER.getAndIncrement(); long id = MIXIN_CLASS_COUNTER.getAndIncrement();
String pkg = null; String pkg = null;
ClassGenerator ccp = null, ccm = null; ClassGenerator ccp = null, ccm = null;
try { try {
ccp = ClassGenerator.newInstance(cl); ccp = ClassGenerator.newInstance(cl);
// impl constructor // impl constructor
StringBuilder code = new StringBuilder(); StringBuilder code = new StringBuilder();
for (int i = 0; i < dcs.length; i++) { for (int i = 0; i < dcs.length; i++) {
if (!Modifier.isPublic(dcs[i].getModifiers())) { if (!Modifier.isPublic(dcs[i].getModifiers())) {
String npkg = dcs[i].getPackage().getName(); String npkg = dcs[i].getPackage().getName();
if (pkg == null) { if (pkg == null) {
pkg = npkg; pkg = npkg;
} else { } else {
if (!pkg.equals(npkg)) { if (!pkg.equals(npkg)) {
throw new IllegalArgumentException("non-public interfaces class from different packages"); throw new IllegalArgumentException("non-public interfaces class from different packages");
} }
} }
} }
ccp.addField("private " + dcs[i].getName() + " d" + i + ";"); ccp.addField("private " + dcs[i].getName() + " d" + i + ";");
code.append("d").append(i).append(" = (").append(dcs[i].getName()).append(")$1[").append(i).append("];\n"); code.append("d").append(i).append(" = (").append(dcs[i].getName()).append(")$1[").append(i).append("];\n");
if (MixinAware.class.isAssignableFrom(dcs[i])) { if (MixinAware.class.isAssignableFrom(dcs[i])) {
code.append("d").append(i).append(".setMixinInstance(this);\n"); code.append("d").append(i).append(".setMixinInstance(this);\n");
} }
} }
ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{Object[].class}, code.toString()); ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{Object[].class}, code.toString());
// impl methods. // impl methods.
Set<String> worked = new HashSet<String>(); Set<String> worked = new HashSet<String>();
for (int i = 0; i < ics.length; i++) { for (int i = 0; i < ics.length; i++) {
if (!Modifier.isPublic(ics[i].getModifiers())) { if (!Modifier.isPublic(ics[i].getModifiers())) {
String npkg = ics[i].getPackage().getName(); String npkg = ics[i].getPackage().getName();
if (pkg == null) { if (pkg == null) {
pkg = npkg; pkg = npkg;
} else { } else {
if (!pkg.equals(npkg)) { if (!pkg.equals(npkg)) {
throw new IllegalArgumentException("non-public delegate class from different packages"); throw new IllegalArgumentException("non-public delegate class from different packages");
} }
} }
} }
ccp.addInterface(ics[i]); ccp.addInterface(ics[i]);
for (Method method : ics[i].getMethods()) { for (Method method : ics[i].getMethods()) {
if ("java.lang.Object".equals(method.getDeclaringClass().getName())) { if ("java.lang.Object".equals(method.getDeclaringClass().getName())) {
continue; continue;
} }
String desc = ReflectUtils.getDesc(method); String desc = ReflectUtils.getDesc(method);
if (worked.contains(desc)) { if (worked.contains(desc)) {
continue; continue;
} }
worked.add(desc); worked.add(desc);
int ix = findMethod(dcs, desc); int ix = findMethod(dcs, desc);
if (ix < 0) { if (ix < 0) {
throw new RuntimeException("Missing method [" + desc + "] implement."); throw new RuntimeException("Missing method [" + desc + "] implement.");
} }
Class<?> rt = method.getReturnType(); Class<?> rt = method.getReturnType();
String mn = method.getName(); String mn = method.getName();
if (Void.TYPE.equals(rt)) { if (Void.TYPE.equals(rt)) {
ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(), ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
"d" + ix + "." + mn + "($$);"); "d" + ix + "." + mn + "($$);");
} else { } else {
ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(), ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
"return ($r)d" + ix + "." + mn + "($$);"); "return ($r)d" + ix + "." + mn + "($$);");
} }
} }
} }
if (pkg == null) { if (pkg == null) {
pkg = PACKAGE_NAME; pkg = PACKAGE_NAME;
} }
// create MixinInstance class. // create MixinInstance class.
String micn = pkg + ".mixin" + id; String micn = pkg + ".mixin" + id;
ccp.setClassName(micn); ccp.setClassName(micn);
ccp.toClass(); ccp.toClass();
// create Mixin class. // create Mixin class.
String fcn = Mixin.class.getName() + id; String fcn = Mixin.class.getName() + id;
ccm = ClassGenerator.newInstance(cl); ccm = ClassGenerator.newInstance(cl);
ccm.setClassName(fcn); ccm.setClassName(fcn);
ccm.addDefaultConstructor(); ccm.addDefaultConstructor();
ccm.setSuperClass(Mixin.class.getName()); ccm.setSuperClass(Mixin.class.getName());
ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }"); ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
Class<?> mixin = ccm.toClass(); Class<?> mixin = ccm.toClass();
return (Mixin) mixin.getDeclaredConstructor().newInstance(); return (Mixin) mixin.getDeclaredConstructor().newInstance();
} catch (RuntimeException e) { } catch (RuntimeException e) {
throw e; throw e;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e.getMessage(), e); throw new RuntimeException(e.getMessage(), e);
} finally { } finally {
// release ClassGenerator // release ClassGenerator
if (ccp != null) { if (ccp != null) {
ccp.release(); ccp.release();
} }
if (ccm != null) { if (ccm != null) {
ccm.release(); ccm.release();
} }
} }
} }
private static int findMethod(Class<?>[] dcs, String desc) { private static int findMethod(Class<?>[] dcs, String desc) {
Class<?> cl; Class<?> cl;
Method[] methods; Method[] methods;
for (int i = 0; i < dcs.length; i++) { for (int i = 0; i < dcs.length; i++) {
cl = dcs[i]; cl = dcs[i];
methods = cl.getMethods(); methods = cl.getMethods();
for (Method method : methods) { for (Method method : methods) {
if (desc.equals(ReflectUtils.getDesc(method))) { if (desc.equals(ReflectUtils.getDesc(method))) {
return i; return i;
} }
} }
} }
return -1; return -1;
} }
private static void assertInterfaceArray(Class<?>[] ics) { private static void assertInterfaceArray(Class<?>[] ics) {
for (int i = 0; i < ics.length; i++) { for (int i = 0; i < ics.length; i++) {
if (!ics[i].isInterface()) { if (!ics[i].isInterface()) {
throw new RuntimeException("Class " + ics[i].getName() + " is not a interface."); throw new RuntimeException("Class " + ics[i].getName() + " is not a interface.");
} }
} }
} }
/** /**
* new Mixin instance. * new Mixin instance.
* *
* @param ds delegates instance. * @param ds delegates instance.
* @return instance. * @return instance.
*/ */
abstract public Object newInstance(Object[] ds); abstract public Object newInstance(Object[] ds);
public static interface MixinAware { public static interface MixinAware {
void setMixinInstance(Object instance); void setMixinInstance(Object instance);
} }
} }

View File

@ -1,33 +1,33 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common.bytecode; package org.apache.dubbo.common.bytecode;
/** /**
* NoSuchMethodException. * NoSuchMethodException.
*/ */
public class NoSuchMethodException extends RuntimeException { public class NoSuchMethodException extends RuntimeException {
private static final long serialVersionUID = -2725364246023268766L; private static final long serialVersionUID = -2725364246023268766L;
public NoSuchMethodException() { public NoSuchMethodException() {
super(); super();
} }
public NoSuchMethodException(String msg) { public NoSuchMethodException(String msg) {
super(msg); super(msg);
} }
} }

View File

@ -1,33 +1,33 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * 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 not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.dubbo.common.bytecode; package org.apache.dubbo.common.bytecode;
/** /**
* NoSuchPropertyException. * NoSuchPropertyException.
*/ */
public class NoSuchPropertyException extends RuntimeException { public class NoSuchPropertyException extends RuntimeException {
private static final long serialVersionUID = -2725364246023268766L; private static final long serialVersionUID = -2725364246023268766L;
public NoSuchPropertyException() { public NoSuchPropertyException() {
super(); super();
} }
public NoSuchPropertyException(String msg) { public NoSuchPropertyException(String msg) {
super(msg); super(msg);
} }
} }

Some files were not shown because too many files have changed in this diff Show More