You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by GitBox <gi...@apache.org> on 2018/08/16 05:50:09 UTC
[GitHub] diecui1202 closed pull request #2014: redis注册中心的监控修改
diecui1202 closed pull request #2014: redis注册中心的监控修改
URL: https://github.com/apache/incubator-dubbo/pull/2014
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
old mode 100755
new mode 100644
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
old mode 100755
new mode 100644
diff --git a/dubbo-cluster/pom.xml b/dubbo-cluster/pom.xml
index 42941d4db6..e81499e539 100644
--- a/dubbo-cluster/pom.xml
+++ b/dubbo-cluster/pom.xml
@@ -1,38 +1,38 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.dubbo</groupId>
- <artifactId>dubbo-parent</artifactId>
- <version>2.7.0-SNAPSHOT</version>
- </parent>
- <artifactId>dubbo-cluster</artifactId>
- <packaging>jar</packaging>
- <name>${project.artifactId}</name>
- <description>The cluster module of dubbo project</description>
- <properties>
- <skip_maven_deploy>false</skip_maven_deploy>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.apache.dubbo</groupId>
- <artifactId>dubbo-rpc-api</artifactId>
- <version>${project.parent.version}</version>
- </dependency>
- </dependencies>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-parent</artifactId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>dubbo-cluster</artifactId>
+ <packaging>jar</packaging>
+ <name>${project.artifactId}</name>
+ <description>The cluster module of dubbo project</description>
+ <properties>
+ <skip_maven_deploy>false</skip_maven_deploy>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-rpc-api</artifactId>
+ <version>${project.parent.version}</version>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
index e5ecb157c0..62fd149cd6 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Cluster.java
@@ -1,46 +1,46 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.support.FailoverCluster;
-
-/**
- * Cluster. (SPI, Singleton, ThreadSafe)
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a>
- * <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
- *
- */
-@SPI(FailoverCluster.NAME)
-public interface Cluster {
-
- /**
- * Merge the directory invokers to a virtual invoker.
- *
- * @param <T>
- * @param directory
- * @return cluster invoker
- * @throws RpcException
- */
- @Adaptive
- <T> Invoker<T> join(Directory<T> directory) throws RpcException;
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.support.FailoverCluster;
+
+/**
+ * Cluster. (SPI, Singleton, ThreadSafe)
+ * <p>
+ * <a href="http://en.wikipedia.org/wiki/Computer_cluster">Cluster</a>
+ * <a href="http://en.wikipedia.org/wiki/Fault-tolerant_system">Fault-Tolerant</a>
+ *
+ */
+@SPI(FailoverCluster.NAME)
+public interface Cluster {
+
+ /**
+ * Merge the directory invokers to a virtual invoker.
+ *
+ * @param <T>
+ * @param directory
+ * @return cluster invoker
+ * @throws RpcException
+ */
+ @Adaptive
+ <T> Invoker<T> join(Directory<T> directory) throws RpcException;
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
index aa229fabc5..91e839e1df 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Configurator.java
@@ -1,43 +1,43 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-
-/**
- * Configurator. (SPI, Prototype, ThreadSafe)
- *
- */
-public interface Configurator extends Comparable<Configurator> {
-
- /**
- * get the configurator url.
- *
- * @return configurator url.
- */
- URL getUrl();
-
- /**
- * Configure the provider url.
- * O
- *
- * @param url - old rovider url.
- * @return new provider url.
- */
- URL configure(URL url);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+
+/**
+ * Configurator. (SPI, Prototype, ThreadSafe)
+ *
+ */
+public interface Configurator extends Comparable<Configurator> {
+
+ /**
+ * get the configurator url.
+ *
+ * @return configurator url.
+ */
+ URL getUrl();
+
+ /**
+ * Configure the provider url.
+ * O
+ *
+ * @param url - old rovider url.
+ * @return new provider url.
+ */
+ URL configure(URL url);
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
index 026d6f54ed..8b2722c29f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/ConfiguratorFactory.java
@@ -1,39 +1,39 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-
-/**
- * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)
- *
- */
-@SPI
-public interface ConfiguratorFactory {
-
- /**
- * get the configurator instance.
- *
- * @param url - configurator url.
- * @return configurator instance.
- */
- @Adaptive("protocol")
- Configurator getConfigurator(URL url);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ * ConfiguratorFactory. (SPI, Singleton, ThreadSafe)
+ *
+ */
+@SPI
+public interface ConfiguratorFactory {
+
+ /**
+ * get the configurator instance.
+ *
+ * @param url - configurator url.
+ * @return configurator instance.
+ */
+ @Adaptive("protocol")
+ Configurator getConfigurator(URL url);
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
index 67f021659e..498e7a8f5b 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Directory.java
@@ -1,49 +1,49 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.Node;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-
-import java.util.List;
-
-/**
- * Directory. (SPI, Prototype, ThreadSafe)
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a>
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- */
-public interface Directory<T> extends Node {
-
- /**
- * get service type.
- *
- * @return service type.
- */
- Class<T> getInterface();
-
- /**
- * list invokers.
- *
- * @return invokers
- */
- List<Invoker<T>> list(Invocation invocation) throws RpcException;
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.Node;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.List;
+
+/**
+ * Directory. (SPI, Prototype, ThreadSafe)
+ * <p>
+ * <a href="http://en.wikipedia.org/wiki/Directory_service">Directory Service</a>
+ *
+ * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
+ */
+public interface Directory<T> extends Node {
+
+ /**
+ * get service type.
+ *
+ * @return service type.
+ */
+ Class<T> getInterface();
+
+ /**
+ * list invokers.
+ *
+ * @return invokers
+ */
+ List<Invoker<T>> list(Invocation invocation) throws RpcException;
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
index 4e6ced18a0..ccf00a5522 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/LoadBalance.java
@@ -1,50 +1,50 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
-
-import java.util.List;
-
-/**
- * LoadBalance. (SPI, Singleton, ThreadSafe)
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a>
- *
- * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
- */
-@SPI(RandomLoadBalance.NAME)
-public interface LoadBalance {
-
- /**
- * select one invoker in list.
- *
- * @param invokers invokers.
- * @param url refer url
- * @param invocation invocation.
- * @return selected invoker.
- */
- @Adaptive("loadbalance")
- <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance;
+
+import java.util.List;
+
+/**
+ * LoadBalance. (SPI, Singleton, ThreadSafe)
+ * <p>
+ * <a href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load-Balancing</a>
+ *
+ * @see org.apache.dubbo.rpc.cluster.Cluster#join(Directory)
+ */
+@SPI(RandomLoadBalance.NAME)
+public interface LoadBalance {
+
+ /**
+ * select one invoker in list.
+ *
+ * @param invokers invokers.
+ * @param url refer url
+ * @param invocation invocation.
+ * @return selected invoker.
+ */
+ @Adaptive("loadbalance")
+ <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
index 47aa2515a3..bbbcfa3c37 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/Router.java
@@ -1,54 +1,54 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-
-import java.util.List;
-
-/**
- * Router. (SPI, Prototype, ThreadSafe)
- * <p>
- * <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.Directory#list(Invocation)
- */
-public interface Router extends Comparable<Router> {
-
- /**
- * get the router url.
- *
- * @return url
- */
- URL getUrl();
-
- /**
- * route.
- *
- * @param invokers
- * @param url refer url
- * @param invocation
- * @return routed invokers
- * @throws RpcException
- */
- <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+
+import java.util.List;
+
+/**
+ * Router. (SPI, Prototype, ThreadSafe)
+ * <p>
+ * <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.Directory#list(Invocation)
+ */
+public interface Router extends Comparable<Router> {
+
+ /**
+ * get the router url.
+ *
+ * @return url
+ */
+ URL getUrl();
+
+ /**
+ * route.
+ *
+ * @param invokers
+ * @param url refer url
+ * @param invocation
+ * @return routed invokers
+ * @throws RpcException
+ */
+ <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
index 679b9fe589..291ef07bbf 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/RouterFactory.java
@@ -1,44 +1,44 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.rpc.Invocation;
-
-/**
- * RouterFactory. (SPI, Singleton, ThreadSafe)
- * <p>
- * <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.Directory#list(Invocation)
- */
-@SPI
-public interface RouterFactory {
-
- /**
- * Create router.
- *
- * @param url
- * @return router
- */
- @Adaptive("protocol")
- Router getRouter(URL url);
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.SPI;
+import org.apache.dubbo.rpc.Invocation;
+
+/**
+ * RouterFactory. (SPI, Singleton, ThreadSafe)
+ * <p>
+ * <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.Directory#list(Invocation)
+ */
+@SPI
+public interface RouterFactory {
+
+ /**
+ * Create router.
+ *
+ * @param url
+ * @return router
+ */
+ @Adaptive("protocol")
+ Router getRouter(URL url);
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
index bf8ba2a571..05a1868414 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/AbstractConfigurator.java
@@ -1,128 +1,128 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.cluster.Configurator;
-
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * AbstractOverrideConfigurator
- *
- */
-public abstract class AbstractConfigurator implements Configurator {
-
- private final URL configuratorUrl;
-
- public AbstractConfigurator(URL url) {
- if (url == null) {
- throw new IllegalArgumentException("configurator url == null");
- }
- this.configuratorUrl = url;
- }
-
- @Override
- public URL getUrl() {
- return configuratorUrl;
- }
-
- @Override
- public URL configure(URL url) {
- if (configuratorUrl == null || configuratorUrl.getHost() == null
- || url == null || url.getHost() == null) {
- return 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 (configuratorUrl.getPort() != 0) {
- if (url.getPort() == configuratorUrl.getPort()) {
- return configureIfMatch(url.getHost(), url);
- }
- } else {// 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;
- // 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.getParameter(Constants.SIDE_KEY, Constants.PROVIDER).equals(Constants.CONSUMER)) {
- return configureIfMatch(NetUtils.getLocalHost(), url);// NetUtils.getLocalHost is the ip address consumer registered to registry.
- } else if (url.getParameter(Constants.SIDE_KEY, Constants.CONSUMER).equals(Constants.PROVIDER)) {
- return configureIfMatch(Constants.ANYHOST_VALUE, url);// take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
- }
- }
- return url;
- }
-
- private URL configureIfMatch(String host, URL url) {
- if (Constants.ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
- String configApplication = configuratorUrl.getParameter(Constants.APPLICATION_KEY,
- configuratorUrl.getUsername());
- String currentApplication = url.getParameter(Constants.APPLICATION_KEY, url.getUsername());
- if (configApplication == null || Constants.ANY_VALUE.equals(configApplication)
- || configApplication.equals(currentApplication)) {
- Set<String> conditionKeys = new HashSet<String>();
- conditionKeys.add(Constants.CATEGORY_KEY);
- conditionKeys.add(Constants.CHECK_KEY);
- conditionKeys.add(Constants.DYNAMIC_KEY);
- conditionKeys.add(Constants.ENABLED_KEY);
- for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- if (key.startsWith("~") || Constants.APPLICATION_KEY.equals(key) || Constants.SIDE_KEY.equals(key)) {
- conditionKeys.add(key);
- if (value != null && !Constants.ANY_VALUE.equals(value)
- && !value.equals(url.getParameter(key.startsWith("~") ? key.substring(1) : key))) {
- return url;
- }
- }
- }
- return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
- }
- }
- return url;
- }
-
- /**
- * Sort by host, priority
- * 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;
- *
- * @param o
- * @return
- */
- @Override
- public int compareTo(Configurator o) {
- if (o == null) {
- return -1;
- }
-
- int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());
- if (ipCompare == 0) {//host is the same, sort by priority
- int i = getUrl().getParameter(Constants.PRIORITY_KEY, 0),
- j = o.getUrl().getParameter(Constants.PRIORITY_KEY, 0);
- return i < j ? -1 : (i == j ? 0 : 1);
- } else {
- return ipCompare;
- }
-
-
- }
-
- protected abstract URL doConfigure(URL currentUrl, URL configUrl);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.cluster.Configurator;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * AbstractOverrideConfigurator
+ *
+ */
+public abstract class AbstractConfigurator implements Configurator {
+
+ private final URL configuratorUrl;
+
+ public AbstractConfigurator(URL url) {
+ if (url == null) {
+ throw new IllegalArgumentException("configurator url == null");
+ }
+ this.configuratorUrl = url;
+ }
+
+ @Override
+ public URL getUrl() {
+ return configuratorUrl;
+ }
+
+ @Override
+ public URL configure(URL url) {
+ if (configuratorUrl == null || configuratorUrl.getHost() == null
+ || url == null || url.getHost() == null) {
+ return 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 (configuratorUrl.getPort() != 0) {
+ if (url.getPort() == configuratorUrl.getPort()) {
+ return configureIfMatch(url.getHost(), url);
+ }
+ } else {// 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;
+ // 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.getParameter(Constants.SIDE_KEY, Constants.PROVIDER).equals(Constants.CONSUMER)) {
+ return configureIfMatch(NetUtils.getLocalHost(), url);// NetUtils.getLocalHost is the ip address consumer registered to registry.
+ } else if (url.getParameter(Constants.SIDE_KEY, Constants.CONSUMER).equals(Constants.PROVIDER)) {
+ return configureIfMatch(Constants.ANYHOST_VALUE, url);// take effect on all providers, so address must be 0.0.0.0, otherwise it won't flow to this if branch
+ }
+ }
+ return url;
+ }
+
+ private URL configureIfMatch(String host, URL url) {
+ if (Constants.ANYHOST_VALUE.equals(configuratorUrl.getHost()) || host.equals(configuratorUrl.getHost())) {
+ String configApplication = configuratorUrl.getParameter(Constants.APPLICATION_KEY,
+ configuratorUrl.getUsername());
+ String currentApplication = url.getParameter(Constants.APPLICATION_KEY, url.getUsername());
+ if (configApplication == null || Constants.ANY_VALUE.equals(configApplication)
+ || configApplication.equals(currentApplication)) {
+ Set<String> conditionKeys = new HashSet<String>();
+ conditionKeys.add(Constants.CATEGORY_KEY);
+ conditionKeys.add(Constants.CHECK_KEY);
+ conditionKeys.add(Constants.DYNAMIC_KEY);
+ conditionKeys.add(Constants.ENABLED_KEY);
+ for (Map.Entry<String, String> entry : configuratorUrl.getParameters().entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (key.startsWith("~") || Constants.APPLICATION_KEY.equals(key) || Constants.SIDE_KEY.equals(key)) {
+ conditionKeys.add(key);
+ if (value != null && !Constants.ANY_VALUE.equals(value)
+ && !value.equals(url.getParameter(key.startsWith("~") ? key.substring(1) : key))) {
+ return url;
+ }
+ }
+ }
+ return doConfigure(url, configuratorUrl.removeParameters(conditionKeys));
+ }
+ }
+ return url;
+ }
+
+ /**
+ * Sort by host, priority
+ * 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;
+ *
+ * @param o
+ * @return
+ */
+ @Override
+ public int compareTo(Configurator o) {
+ if (o == null) {
+ return -1;
+ }
+
+ int ipCompare = getUrl().getHost().compareTo(o.getUrl().getHost());
+ if (ipCompare == 0) {//host is the same, sort by priority
+ int i = getUrl().getParameter(Constants.PRIORITY_KEY, 0),
+ j = o.getUrl().getParameter(Constants.PRIORITY_KEY, 0);
+ return i < j ? -1 : (i == j ? 0 : 1);
+ } else {
+ return ipCompare;
+ }
+
+
+ }
+
+ protected abstract URL doConfigure(URL currentUrl, URL configUrl);
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
index c81d9b8f1d..cb83b8b854 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfigurator.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.absent;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
-
-/**
- * AbsentConfigurator
- *
- */
-public class AbsentConfigurator extends AbstractConfigurator {
-
- public AbsentConfigurator(URL url) {
- super(url);
- }
-
- @Override
- public URL doConfigure(URL currentUrl, URL configUrl) {
- return currentUrl.addParametersIfAbsent(configUrl.getParameters());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.absent;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
+
+/**
+ * AbsentConfigurator
+ *
+ */
+public class AbsentConfigurator extends AbstractConfigurator {
+
+ public AbsentConfigurator(URL url) {
+ super(url);
+ }
+
+ @Override
+ public URL doConfigure(URL currentUrl, URL configUrl) {
+ return currentUrl.addParametersIfAbsent(configUrl.getParameters());
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
index 86b0e708b4..479eb5082a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorFactory.java
@@ -1,34 +1,34 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.absent;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Configurator;
-import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
-
-/**
- * AbsentConfiguratorFactory
- *
- */
-public class AbsentConfiguratorFactory implements ConfiguratorFactory {
-
- @Override
- public Configurator getConfigurator(URL url) {
- return new AbsentConfigurator(url);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.absent;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+
+/**
+ * AbsentConfiguratorFactory
+ *
+ */
+public class AbsentConfiguratorFactory implements ConfiguratorFactory {
+
+ @Override
+ public Configurator getConfigurator(URL url) {
+ return new AbsentConfigurator(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
index 1d57773edb..a83cf2ea51 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfigurator.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.override;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
-
-/**
- * AbsentConfigurator
- *
- */
-public class OverrideConfigurator extends AbstractConfigurator {
-
- public OverrideConfigurator(URL url) {
- super(url);
- }
-
- @Override
- public URL doConfigure(URL currentUrl, URL configUrl) {
- return currentUrl.addParameters(configUrl.getParameters());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.override;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.configurator.AbstractConfigurator;
+
+/**
+ * AbsentConfigurator
+ *
+ */
+public class OverrideConfigurator extends AbstractConfigurator {
+
+ public OverrideConfigurator(URL url) {
+ super(url);
+ }
+
+ @Override
+ public URL doConfigure(URL currentUrl, URL configUrl) {
+ return currentUrl.addParameters(configUrl.getParameters());
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
index 051b4bd82f..310b6f0c04 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorFactory.java
@@ -1,34 +1,34 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.override;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Configurator;
-import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
-
-/**
- * AbsentConfiguratorFactory
- *
- */
-public class OverrideConfiguratorFactory implements ConfiguratorFactory {
-
- @Override
- public Configurator getConfigurator(URL url) {
- return new OverrideConfigurator(url);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.override;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Configurator;
+import org.apache.dubbo.rpc.cluster.ConfiguratorFactory;
+
+/**
+ * AbsentConfiguratorFactory
+ *
+ */
+public class OverrideConfiguratorFactory implements ConfiguratorFactory {
+
+ @Override
+ public Configurator getConfigurator(URL url) {
+ return new OverrideConfigurator(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
index 47a0d12bc7..7ca52f9081 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/directory/StaticDirectory.java
@@ -1,90 +1,90 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.directory;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Router;
-
-import java.util.List;
-
-/**
- * StaticDirectory
- *
- */
-public class StaticDirectory<T> extends AbstractDirectory<T> {
-
- private final List<Invoker<T>> invokers;
-
- public StaticDirectory(List<Invoker<T>> invokers) {
- this(null, invokers, null);
- }
-
- public StaticDirectory(List<Invoker<T>> invokers, List<Router> routers) {
- this(null, invokers, routers);
- }
-
- public StaticDirectory(URL url, List<Invoker<T>> invokers) {
- this(url, invokers, null);
- }
-
- public StaticDirectory(URL url, List<Invoker<T>> invokers, List<Router> routers) {
- super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routers);
- if (invokers == null || invokers.isEmpty())
- throw new IllegalArgumentException("invokers == null");
- this.invokers = invokers;
- }
-
- @Override
- public Class<T> getInterface() {
- return invokers.get(0).getInterface();
- }
-
- @Override
- public boolean isAvailable() {
- if (isDestroyed()) {
- return false;
- }
- for (Invoker<T> invoker : invokers) {
- if (invoker.isAvailable()) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void destroy() {
- if (isDestroyed()) {
- return;
- }
- super.destroy();
- for (Invoker<T> invoker : invokers) {
- invoker.destroy();
- }
- invokers.clear();
- }
-
- @Override
- protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
-
- return invokers;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.directory;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+
+import java.util.List;
+
+/**
+ * StaticDirectory
+ *
+ */
+public class StaticDirectory<T> extends AbstractDirectory<T> {
+
+ private final List<Invoker<T>> invokers;
+
+ public StaticDirectory(List<Invoker<T>> invokers) {
+ this(null, invokers, null);
+ }
+
+ public StaticDirectory(List<Invoker<T>> invokers, List<Router> routers) {
+ this(null, invokers, routers);
+ }
+
+ public StaticDirectory(URL url, List<Invoker<T>> invokers) {
+ this(url, invokers, null);
+ }
+
+ public StaticDirectory(URL url, List<Invoker<T>> invokers, List<Router> routers) {
+ super(url == null && invokers != null && !invokers.isEmpty() ? invokers.get(0).getUrl() : url, routers);
+ if (invokers == null || invokers.isEmpty())
+ throw new IllegalArgumentException("invokers == null");
+ this.invokers = invokers;
+ }
+
+ @Override
+ public Class<T> getInterface() {
+ return invokers.get(0).getInterface();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (isDestroyed()) {
+ return false;
+ }
+ for (Invoker<T> invoker : invokers) {
+ if (invoker.isAvailable()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void destroy() {
+ if (isDestroyed()) {
+ return;
+ }
+ super.destroy();
+ for (Invoker<T> invoker : invokers) {
+ invoker.destroy();
+ }
+ invokers.clear();
+ }
+
+ @Override
+ protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
+
+ return invokers;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
index ff94b3cf57..b4842944bc 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/AbstractLoadBalance.java
@@ -1,64 +1,64 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-/**
- * AbstractLoadBalance
- *
- */
-public abstract class AbstractLoadBalance implements LoadBalance {
-
- static int calculateWarmupWeight(int uptime, int warmup, int weight) {
- int ww = (int) ((float) uptime / ((float) warmup / (float) weight));
- return ww < 1 ? 1 : (ww > weight ? weight : ww);
- }
-
- @Override
- public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
- if (invokers == null || invokers.isEmpty())
- return null;
- if (invokers.size() == 1)
- return invokers.get(0);
- return doSelect(invokers, url, invocation);
- }
-
- protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
-
- protected int getWeight(Invoker<?> invoker, Invocation invocation) {
- int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
- if (weight > 0) {
- long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
- if (timestamp > 0L) {
- int uptime = (int) (System.currentTimeMillis() - timestamp);
- int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
- if (uptime > 0 && uptime < warmup) {
- weight = calculateWarmupWeight(uptime, warmup, weight);
- }
- }
- }
- return weight;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ * AbstractLoadBalance
+ *
+ */
+public abstract class AbstractLoadBalance implements LoadBalance {
+
+ static int calculateWarmupWeight(int uptime, int warmup, int weight) {
+ int ww = (int) ((float) uptime / ((float) warmup / (float) weight));
+ return ww < 1 ? 1 : (ww > weight ? weight : ww);
+ }
+
+ @Override
+ public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+ if (invokers == null || invokers.isEmpty())
+ return null;
+ if (invokers.size() == 1)
+ return invokers.get(0);
+ return doSelect(invokers, url, invocation);
+ }
+
+ protected abstract <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation);
+
+ protected int getWeight(Invoker<?> invoker, Invocation invocation) {
+ int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT);
+ if (weight > 0) {
+ long timestamp = invoker.getUrl().getParameter(Constants.REMOTE_TIMESTAMP_KEY, 0L);
+ if (timestamp > 0L) {
+ int uptime = (int) (System.currentTimeMillis() - timestamp);
+ int warmup = invoker.getUrl().getParameter(Constants.WARMUP_KEY, Constants.DEFAULT_WARMUP);
+ if (uptime > 0 && uptime < warmup) {
+ weight = calculateWarmupWeight(uptime, warmup, weight);
+ }
+ }
+ }
+ return weight;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
index 31749b287a..132a11c4f7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/ConsistentHashLoadBalance.java
@@ -1,141 +1,141 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.support.RpcUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * ConsistentHashLoadBalance
- *
- */
-public class ConsistentHashLoadBalance extends AbstractLoadBalance {
- public static final String NAME = "consistenthash";
-
- private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
-
- @SuppressWarnings("unchecked")
- @Override
- protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
- String methodName = RpcUtils.getMethodName(invocation);
- String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;
- int identityHashCode = System.identityHashCode(invokers);
- ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key);
- if (selector == null || selector.identityHashCode != identityHashCode) {
- selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, identityHashCode));
- selector = (ConsistentHashSelector<T>) selectors.get(key);
- }
- return selector.select(invocation);
- }
-
- private static final class ConsistentHashSelector<T> {
-
- private final TreeMap<Long, Invoker<T>> virtualInvokers;
-
- private final int replicaNumber;
-
- private final int identityHashCode;
-
- private final int[] argumentIndex;
-
- ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {
- this.virtualInvokers = new TreeMap<Long, Invoker<T>>();
- this.identityHashCode = identityHashCode;
- URL url = invokers.get(0).getUrl();
- this.replicaNumber = url.getMethodParameter(methodName, "hash.nodes", 160);
- String[] index = Constants.COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, "hash.arguments", "0"));
- argumentIndex = new int[index.length];
- for (int i = 0; i < index.length; i++) {
- argumentIndex[i] = Integer.parseInt(index[i]);
- }
- for (Invoker<T> invoker : invokers) {
- String address = invoker.getUrl().getAddress();
- for (int i = 0; i < replicaNumber / 4; i++) {
- byte[] digest = md5(address + i);
- for (int h = 0; h < 4; h++) {
- long m = hash(digest, h);
- virtualInvokers.put(m, invoker);
- }
- }
- }
- }
-
- public Invoker<T> select(Invocation invocation) {
- String key = toKey(invocation.getArguments());
- byte[] digest = md5(key);
- return selectForKey(hash(digest, 0));
- }
-
- private String toKey(Object[] args) {
- StringBuilder buf = new StringBuilder();
- for (int i : argumentIndex) {
- if (i >= 0 && i < args.length) {
- buf.append(args[i]);
- }
- }
- return buf.toString();
- }
-
- private Invoker<T> selectForKey(long hash) {
- Map.Entry<Long, Invoker<T>> entry = virtualInvokers.tailMap(hash, true).firstEntry();
- if (entry == null) {
- entry = virtualInvokers.firstEntry();
- }
- return entry.getValue();
- }
-
- private long hash(byte[] digest, int number) {
- return (((long) (digest[3 + number * 4] & 0xFF) << 24)
- | ((long) (digest[2 + number * 4] & 0xFF) << 16)
- | ((long) (digest[1 + number * 4] & 0xFF) << 8)
- | (digest[number * 4] & 0xFF))
- & 0xFFFFFFFFL;
- }
-
- private byte[] md5(String value) {
- MessageDigest md5;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- md5.reset();
- byte[] bytes;
- try {
- bytes = value.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- md5.update(bytes);
- return md5.digest();
- }
-
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.support.RpcUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * ConsistentHashLoadBalance
+ *
+ */
+public class ConsistentHashLoadBalance extends AbstractLoadBalance {
+ public static final String NAME = "consistenthash";
+
+ private final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+ String methodName = RpcUtils.getMethodName(invocation);
+ String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;
+ int identityHashCode = System.identityHashCode(invokers);
+ ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key);
+ if (selector == null || selector.identityHashCode != identityHashCode) {
+ selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, identityHashCode));
+ selector = (ConsistentHashSelector<T>) selectors.get(key);
+ }
+ return selector.select(invocation);
+ }
+
+ private static final class ConsistentHashSelector<T> {
+
+ private final TreeMap<Long, Invoker<T>> virtualInvokers;
+
+ private final int replicaNumber;
+
+ private final int identityHashCode;
+
+ private final int[] argumentIndex;
+
+ ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {
+ this.virtualInvokers = new TreeMap<Long, Invoker<T>>();
+ this.identityHashCode = identityHashCode;
+ URL url = invokers.get(0).getUrl();
+ this.replicaNumber = url.getMethodParameter(methodName, "hash.nodes", 160);
+ String[] index = Constants.COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, "hash.arguments", "0"));
+ argumentIndex = new int[index.length];
+ for (int i = 0; i < index.length; i++) {
+ argumentIndex[i] = Integer.parseInt(index[i]);
+ }
+ for (Invoker<T> invoker : invokers) {
+ String address = invoker.getUrl().getAddress();
+ for (int i = 0; i < replicaNumber / 4; i++) {
+ byte[] digest = md5(address + i);
+ for (int h = 0; h < 4; h++) {
+ long m = hash(digest, h);
+ virtualInvokers.put(m, invoker);
+ }
+ }
+ }
+ }
+
+ public Invoker<T> select(Invocation invocation) {
+ String key = toKey(invocation.getArguments());
+ byte[] digest = md5(key);
+ return selectForKey(hash(digest, 0));
+ }
+
+ private String toKey(Object[] args) {
+ StringBuilder buf = new StringBuilder();
+ for (int i : argumentIndex) {
+ if (i >= 0 && i < args.length) {
+ buf.append(args[i]);
+ }
+ }
+ return buf.toString();
+ }
+
+ private Invoker<T> selectForKey(long hash) {
+ Map.Entry<Long, Invoker<T>> entry = virtualInvokers.tailMap(hash, true).firstEntry();
+ if (entry == null) {
+ entry = virtualInvokers.firstEntry();
+ }
+ return entry.getValue();
+ }
+
+ private long hash(byte[] digest, int number) {
+ return (((long) (digest[3 + number * 4] & 0xFF) << 24)
+ | ((long) (digest[2 + number * 4] & 0xFF) << 16)
+ | ((long) (digest[1 + number * 4] & 0xFF) << 8)
+ | (digest[number * 4] & 0xFF))
+ & 0xFFFFFFFFL;
+ }
+
+ private byte[] md5(String value) {
+ MessageDigest md5;
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ md5.reset();
+ byte[] bytes;
+ try {
+ bytes = value.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ md5.update(bytes);
+ return md5.digest();
+ }
+
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
index 7a8eb3dbd0..a3258ef94c 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/LeastActiveLoadBalance.java
@@ -1,87 +1,87 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcStatus;
-
-import java.util.List;
-import java.util.Random;
-
-/**
- * LeastActiveLoadBalance
- *
- */
-public class LeastActiveLoadBalance extends AbstractLoadBalance {
-
- public static final String NAME = "leastactive";
-
- private final Random random = new Random();
-
- @Override
- protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
- int length = invokers.size(); // Number of invokers
- int leastActive = -1; // The least active value of all invokers
- int leastCount = 0; // The number of invokers having the same least active value (leastActive)
- int[] leastIndexs = new int[length]; // The index of invokers having the same least active value (leastActive)
- int totalWeight = 0; // The sum of weights
- int firstWeight = 0; // Initial value, used for comparision
- boolean sameWeight = true; // Every invoker has the same weight value?
- for (int i = 0; i < length; i++) {
- Invoker<T> invoker = invokers.get(i);
- int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // Active number
- int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // Weight
- if (leastActive == -1 || active < leastActive) { // Restart, when find a invoker having smaller least active value.
- leastActive = active; // Record the current least active value
- leastCount = 1; // Reset leastCount, count again based on current leastCount
- leastIndexs[0] = i; // Reset
- totalWeight = weight; // Reset
- firstWeight = weight; // Record the weight the first invoker
- sameWeight = true; // Reset, every invoker has the same weight value?
- } else if (active == leastActive) { // If current invoker's active value equals with leaseActive, then accumulating.
- leastIndexs[leastCount++] = i; // Record index number of this invoker
- totalWeight += weight; // Add this invoker's weight to totalWeight.
- // If every invoker has the same weight?
- if (sameWeight && i > 0
- && weight != firstWeight) {
- sameWeight = false;
- }
- }
- }
- // assert(leastCount > 0)
- if (leastCount == 1) {
- // If we got exactly one invoker having the least active value, return this invoker directly.
- return invokers.get(leastIndexs[0]);
- }
- if (!sameWeight && totalWeight > 0) {
- // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
- int offsetWeight = random.nextInt(totalWeight);
- // Return a invoker based on the random value.
- for (int i = 0; i < leastCount; i++) {
- int leastIndex = leastIndexs[i];
- offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
- if (offsetWeight <= 0)
- return invokers.get(leastIndex);
- }
- }
- // If all invokers have the same weight value or totalWeight=0, return evenly.
- return invokers.get(leastIndexs[random.nextInt(leastCount)]);
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcStatus;
+
+import java.util.List;
+import java.util.Random;
+
+/**
+ * LeastActiveLoadBalance
+ *
+ */
+public class LeastActiveLoadBalance extends AbstractLoadBalance {
+
+ public static final String NAME = "leastactive";
+
+ private final Random random = new Random();
+
+ @Override
+ protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+ int length = invokers.size(); // Number of invokers
+ int leastActive = -1; // The least active value of all invokers
+ int leastCount = 0; // The number of invokers having the same least active value (leastActive)
+ int[] leastIndexs = new int[length]; // The index of invokers having the same least active value (leastActive)
+ int totalWeight = 0; // The sum of weights
+ int firstWeight = 0; // Initial value, used for comparision
+ boolean sameWeight = true; // Every invoker has the same weight value?
+ for (int i = 0; i < length; i++) {
+ Invoker<T> invoker = invokers.get(i);
+ int active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive(); // Active number
+ int weight = invoker.getUrl().getMethodParameter(invocation.getMethodName(), Constants.WEIGHT_KEY, Constants.DEFAULT_WEIGHT); // Weight
+ if (leastActive == -1 || active < leastActive) { // Restart, when find a invoker having smaller least active value.
+ leastActive = active; // Record the current least active value
+ leastCount = 1; // Reset leastCount, count again based on current leastCount
+ leastIndexs[0] = i; // Reset
+ totalWeight = weight; // Reset
+ firstWeight = weight; // Record the weight the first invoker
+ sameWeight = true; // Reset, every invoker has the same weight value?
+ } else if (active == leastActive) { // If current invoker's active value equals with leaseActive, then accumulating.
+ leastIndexs[leastCount++] = i; // Record index number of this invoker
+ totalWeight += weight; // Add this invoker's weight to totalWeight.
+ // If every invoker has the same weight?
+ if (sameWeight && i > 0
+ && weight != firstWeight) {
+ sameWeight = false;
+ }
+ }
+ }
+ // assert(leastCount > 0)
+ if (leastCount == 1) {
+ // If we got exactly one invoker having the least active value, return this invoker directly.
+ return invokers.get(leastIndexs[0]);
+ }
+ if (!sameWeight && totalWeight > 0) {
+ // If (not every invoker has the same weight & at least one invoker's weight>0), select randomly based on totalWeight.
+ int offsetWeight = random.nextInt(totalWeight);
+ // Return a invoker based on the random value.
+ for (int i = 0; i < leastCount; i++) {
+ int leastIndex = leastIndexs[i];
+ offsetWeight -= getWeight(invokers.get(leastIndex), invocation);
+ if (offsetWeight <= 0)
+ return invokers.get(leastIndex);
+ }
+ }
+ // If all invokers have the same weight value or totalWeight=0, return evenly.
+ return invokers.get(leastIndexs[random.nextInt(leastCount)]);
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
index c2bf0b8c89..3c5e438dc2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/loadbalance/RoundRobinLoadBalance.java
@@ -1,103 +1,103 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.loadbalance;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.AtomicPositiveInteger;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * Round robin load balance.
- *
- */
-public class RoundRobinLoadBalance extends AbstractLoadBalance {
-
- public static final String NAME = "roundrobin";
-
- private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
-
- @Override
- protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
- String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
- int length = invokers.size(); // Number of invokers
- int maxWeight = 0; // The maximum weight
- int minWeight = Integer.MAX_VALUE; // The minimum weight
- final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = new LinkedHashMap<Invoker<T>, IntegerWrapper>();
- int weightSum = 0;
- for (int i = 0; i < length; i++) {
- int weight = getWeight(invokers.get(i), invocation);
- maxWeight = Math.max(maxWeight, weight); // Choose the maximum weight
- minWeight = Math.min(minWeight, weight); // Choose the minimum weight
- if (weight > 0) {
- invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
- weightSum += weight;
- }
- }
- AtomicPositiveInteger sequence = sequences.get(key);
- if (sequence == null) {
- sequences.putIfAbsent(key, new AtomicPositiveInteger());
- sequence = sequences.get(key);
- }
- int currentSequence = sequence.getAndIncrement();
- if (maxWeight > 0 && minWeight < maxWeight) {
- int mod = currentSequence % weightSum;
- for (int i = 0; i < maxWeight; i++) {
- for (Map.Entry<Invoker<T>, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
- final Invoker<T> k = each.getKey();
- final IntegerWrapper v = each.getValue();
- if (mod == 0 && v.getValue() > 0) {
- return k;
- }
- if (v.getValue() > 0) {
- v.decrement();
- mod--;
- }
- }
- }
- }
- // Round robin
- return invokers.get(currentSequence % length);
- }
-
- private static final class IntegerWrapper {
- private int value;
-
- public IntegerWrapper(int value) {
- this.value = value;
- }
-
- public int getValue() {
- return value;
- }
-
- public void setValue(int value) {
- this.value = value;
- }
-
- public void decrement() {
- this.value--;
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.loadbalance;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.AtomicPositiveInteger;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Round robin load balance.
+ *
+ */
+public class RoundRobinLoadBalance extends AbstractLoadBalance {
+
+ public static final String NAME = "roundrobin";
+
+ private final ConcurrentMap<String, AtomicPositiveInteger> sequences = new ConcurrentHashMap<String, AtomicPositiveInteger>();
+
+ @Override
+ protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
+ String key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();
+ int length = invokers.size(); // Number of invokers
+ int maxWeight = 0; // The maximum weight
+ int minWeight = Integer.MAX_VALUE; // The minimum weight
+ final LinkedHashMap<Invoker<T>, IntegerWrapper> invokerToWeightMap = new LinkedHashMap<Invoker<T>, IntegerWrapper>();
+ int weightSum = 0;
+ for (int i = 0; i < length; i++) {
+ int weight = getWeight(invokers.get(i), invocation);
+ maxWeight = Math.max(maxWeight, weight); // Choose the maximum weight
+ minWeight = Math.min(minWeight, weight); // Choose the minimum weight
+ if (weight > 0) {
+ invokerToWeightMap.put(invokers.get(i), new IntegerWrapper(weight));
+ weightSum += weight;
+ }
+ }
+ AtomicPositiveInteger sequence = sequences.get(key);
+ if (sequence == null) {
+ sequences.putIfAbsent(key, new AtomicPositiveInteger());
+ sequence = sequences.get(key);
+ }
+ int currentSequence = sequence.getAndIncrement();
+ if (maxWeight > 0 && minWeight < maxWeight) {
+ int mod = currentSequence % weightSum;
+ for (int i = 0; i < maxWeight; i++) {
+ for (Map.Entry<Invoker<T>, IntegerWrapper> each : invokerToWeightMap.entrySet()) {
+ final Invoker<T> k = each.getKey();
+ final IntegerWrapper v = each.getValue();
+ if (mod == 0 && v.getValue() > 0) {
+ return k;
+ }
+ if (v.getValue() > 0) {
+ v.decrement();
+ mod--;
+ }
+ }
+ }
+ }
+ // Round robin
+ return invokers.get(currentSequence % length);
+ }
+
+ private static final class IntegerWrapper {
+ private int value;
+
+ public IntegerWrapper(int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ public void decrement() {
+ this.value--;
+ }
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
index 0ca2a4997d..8bab09b5c7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/MockInvokersSelector.java
@@ -1,100 +1,100 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Router;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A specific Router designed to realize mock feature.
- * If a request is configured to use mock, then this router guarantees that only the invokers with protocol MOCK appear in final the invoker list, all other invokers will be excluded.
- *
- */
-public class MockInvokersSelector implements Router {
-
- @Override
- public <T> List<Invoker<T>> route(final List<Invoker<T>> invokers,
- URL url, final Invocation invocation) throws RpcException {
- if (invocation.getAttachments() == null) {
- return getNormalInvokers(invokers);
- } else {
- String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
- if (value == null)
- return getNormalInvokers(invokers);
- else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
- return getMockedInvokers(invokers);
- }
- }
- return invokers;
- }
-
- private <T> List<Invoker<T>> getMockedInvokers(final List<Invoker<T>> invokers) {
- if (!hasMockProviders(invokers)) {
- return null;
- }
- List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(1);
- for (Invoker<T> invoker : invokers) {
- if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
- sInvokers.add(invoker);
- }
- }
- return sInvokers;
- }
-
- private <T> List<Invoker<T>> getNormalInvokers(final List<Invoker<T>> invokers) {
- if (!hasMockProviders(invokers)) {
- return invokers;
- } else {
- List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(invokers.size());
- for (Invoker<T> invoker : invokers) {
- if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
- sInvokers.add(invoker);
- }
- }
- return sInvokers;
- }
- }
-
- private <T> boolean hasMockProviders(final List<Invoker<T>> invokers) {
- boolean hasMockProvider = false;
- for (Invoker<T> invoker : invokers) {
- if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
- hasMockProvider = true;
- break;
- }
- }
- return hasMockProvider;
- }
-
- @Override
- public URL getUrl() {
- return null;
- }
-
- @Override
- public int compareTo(Router o) {
- return 1;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A specific Router designed to realize mock feature.
+ * If a request is configured to use mock, then this router guarantees that only the invokers with protocol MOCK appear in final the invoker list, all other invokers will be excluded.
+ *
+ */
+public class MockInvokersSelector implements Router {
+
+ @Override
+ public <T> List<Invoker<T>> route(final List<Invoker<T>> invokers,
+ URL url, final Invocation invocation) throws RpcException {
+ if (invocation.getAttachments() == null) {
+ return getNormalInvokers(invokers);
+ } else {
+ String value = invocation.getAttachments().get(Constants.INVOCATION_NEED_MOCK);
+ if (value == null)
+ return getNormalInvokers(invokers);
+ else if (Boolean.TRUE.toString().equalsIgnoreCase(value)) {
+ return getMockedInvokers(invokers);
+ }
+ }
+ return invokers;
+ }
+
+ private <T> List<Invoker<T>> getMockedInvokers(final List<Invoker<T>> invokers) {
+ if (!hasMockProviders(invokers)) {
+ return null;
+ }
+ List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(1);
+ for (Invoker<T> invoker : invokers) {
+ if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+ sInvokers.add(invoker);
+ }
+ }
+ return sInvokers;
+ }
+
+ private <T> List<Invoker<T>> getNormalInvokers(final List<Invoker<T>> invokers) {
+ if (!hasMockProviders(invokers)) {
+ return invokers;
+ } else {
+ List<Invoker<T>> sInvokers = new ArrayList<Invoker<T>>(invokers.size());
+ for (Invoker<T> invoker : invokers) {
+ if (!invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+ sInvokers.add(invoker);
+ }
+ }
+ return sInvokers;
+ }
+ }
+
+ private <T> boolean hasMockProviders(final List<Invoker<T>> invokers) {
+ boolean hasMockProvider = false;
+ for (Invoker<T> invoker : invokers) {
+ if (invoker.getUrl().getProtocol().equals(Constants.MOCK_PROTOCOL)) {
+ hasMockProvider = true;
+ break;
+ }
+ }
+ return hasMockProvider;
+ }
+
+ @Override
+ public URL getUrl() {
+ return null;
+ }
+
+ @Override
+ public int compareTo(Router o) {
+ return 1;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
index af36757028..da1849c0b3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouter.java
@@ -1,272 +1,272 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router.condition;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.common.utils.UrlUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Router;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * ConditionRouter
- *
- */
-public class ConditionRouter implements Router, Comparable<Router> {
-
- private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
- private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
- private final URL url;
- private final int priority;
- private final boolean force;
- private final Map<String, MatchPair> whenCondition;
- private final Map<String, MatchPair> thenCondition;
-
- public ConditionRouter(URL url) {
- this.url = url;
- this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
- this.force = url.getParameter(Constants.FORCE_KEY, false);
- try {
- String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
- if (rule == null || rule.trim().length() == 0) {
- throw new IllegalArgumentException("Illegal route rule!");
- }
- rule = rule.replace("consumer.", "").replace("provider.", "");
- int i = rule.indexOf("=>");
- String whenRule = i < 0 ? null : rule.substring(0, i).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> 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.
- this.whenCondition = when;
- this.thenCondition = then;
- } catch (ParseException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- private static Map<String, MatchPair> parseRule(String rule)
- throws ParseException {
- Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
- if (StringUtils.isBlank(rule)) {
- return condition;
- }
- // Key-Value pair, stores both match and mismatch conditions
- MatchPair pair = null;
- // Multiple values
- Set<String> values = null;
- final Matcher matcher = ROUTE_PATTERN.matcher(rule);
- while (matcher.find()) { // Try to match one by one
- String separator = matcher.group(1);
- String content = matcher.group(2);
- // Start part of the condition expression.
- if (separator == null || separator.length() == 0) {
- pair = new MatchPair();
- condition.put(content, pair);
- }
- // The KV part of the condition expression
- else if ("&".equals(separator)) {
- if (condition.get(content) == null) {
- pair = new MatchPair();
- condition.put(content, pair);
- } else {
- pair = condition.get(content);
- }
- }
- // The Value in the KV part.
- else if ("=".equals(separator)) {
- if (pair == null)
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
-
- values = pair.matches;
- values.add(content);
- }
- // The Value in the KV part.
- else if ("!=".equals(separator)) {
- if (pair == null)
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
-
- values = pair.mismatches;
- values.add(content);
- }
- // The Value in the KV part, if Value have more than one items.
- else if (",".equals(separator)) { // Should be seperateed by ','
- if (values == null || values.isEmpty())
- throw new ParseException("Illegal route rule \""
- + rule + "\", The error char '" + separator
- + "' at index " + matcher.start() + " before \""
- + content + "\".", matcher.start());
- values.add(content);
- } else {
- throw new ParseException("Illegal route rule \"" + rule
- + "\", The error char '" + separator + "' at index "
- + matcher.start() + " before \"" + content + "\".", matcher.start());
- }
- }
- return condition;
- }
-
- @Override
- public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation)
- throws RpcException {
- if (invokers == null || invokers.isEmpty()) {
- return invokers;
- }
- try {
- if (!matchWhen(url, invocation)) {
- return invokers;
- }
- List<Invoker<T>> result = new ArrayList<Invoker<T>>();
- if (thenCondition == null) {
- logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
- return result;
- }
- for (Invoker<T> invoker : invokers) {
- if (matchThen(invoker.getUrl(), url)) {
- result.add(invoker);
- }
- }
- if (!result.isEmpty()) {
- return result;
- } else if (force) {
- logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(Constants.RULE_KEY));
- return result;
- }
- } catch (Throwable t) {
- logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
- }
- return invokers;
- }
-
- @Override
- public URL getUrl() {
- return url;
- }
-
- @Override
- public int compareTo(Router o) {
- if (o == null || o.getClass() != ConditionRouter.class) {
- return 1;
- }
- ConditionRouter c = (ConditionRouter) o;
- return this.priority == c.priority ? url.toFullString().compareTo(c.url.toFullString()) : (this.priority > c.priority ? 1 : -1);
- }
-
- boolean matchWhen(URL url, Invocation invocation) {
- return whenCondition == null || whenCondition.isEmpty() || matchCondition(whenCondition, url, null, invocation);
- }
-
- private boolean matchThen(URL url, URL param) {
- return !(thenCondition == null || thenCondition.isEmpty()) && matchCondition(thenCondition, url, param, null);
- }
-
- private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) {
- Map<String, String> sample = url.toMap();
- boolean result = false;
- for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) {
- String key = matchPair.getKey();
- String sampleValue;
- //get real invoked method name from invocation
- if (invocation != null && (Constants.METHOD_KEY.equals(key) || Constants.METHODS_KEY.equals(key))) {
- sampleValue = invocation.getMethodName();
- } else {
- sampleValue = sample.get(key);
- if (sampleValue == null) {
- sampleValue = sample.get(Constants.DEFAULT_KEY_PREFIX + key);
- }
- }
- if (sampleValue != null) {
- if (!matchPair.getValue().isMatch(sampleValue, param)) {
- return false;
- } else {
- result = true;
- }
- } else {
- //not pass the condition
- if (!matchPair.getValue().matches.isEmpty()) {
- return false;
- } else {
- result = true;
- }
- }
- }
- return result;
- }
-
- private static final class MatchPair {
- final Set<String> matches = new HashSet<String>();
- final Set<String> mismatches = new HashSet<String>();
-
- private boolean isMatch(String value, URL param) {
- if (!matches.isEmpty() && mismatches.isEmpty()) {
- for (String match : matches) {
- if (UrlUtils.isMatchGlobPattern(match, value, param)) {
- return true;
- }
- }
- return false;
- }
-
- if (!mismatches.isEmpty() && matches.isEmpty()) {
- for (String mismatch : mismatches) {
- if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
- return false;
- }
- }
- return true;
- }
-
- if (!matches.isEmpty() && !mismatches.isEmpty()) {
- //when both mismatches and matches contain the same value, then using mismatches first
- for (String mismatch : mismatches) {
- if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
- return false;
- }
- }
- for (String match : matches) {
- if (UrlUtils.isMatchGlobPattern(match, value, param)) {
- return true;
- }
- }
- return false;
- }
- return false;
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router.condition;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.UrlUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * ConditionRouter
+ *
+ */
+public class ConditionRouter implements Router, Comparable<Router> {
+
+ private static final Logger logger = LoggerFactory.getLogger(ConditionRouter.class);
+ private static Pattern ROUTE_PATTERN = Pattern.compile("([&!=,]*)\\s*([^&!=,\\s]+)");
+ private final URL url;
+ private final int priority;
+ private final boolean force;
+ private final Map<String, MatchPair> whenCondition;
+ private final Map<String, MatchPair> thenCondition;
+
+ public ConditionRouter(URL url) {
+ this.url = url;
+ this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
+ this.force = url.getParameter(Constants.FORCE_KEY, false);
+ try {
+ String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
+ if (rule == null || rule.trim().length() == 0) {
+ throw new IllegalArgumentException("Illegal route rule!");
+ }
+ rule = rule.replace("consumer.", "").replace("provider.", "");
+ int i = rule.indexOf("=>");
+ String whenRule = i < 0 ? null : rule.substring(0, i).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> 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.
+ this.whenCondition = when;
+ this.thenCondition = then;
+ } catch (ParseException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ private static Map<String, MatchPair> parseRule(String rule)
+ throws ParseException {
+ Map<String, MatchPair> condition = new HashMap<String, MatchPair>();
+ if (StringUtils.isBlank(rule)) {
+ return condition;
+ }
+ // Key-Value pair, stores both match and mismatch conditions
+ MatchPair pair = null;
+ // Multiple values
+ Set<String> values = null;
+ final Matcher matcher = ROUTE_PATTERN.matcher(rule);
+ while (matcher.find()) { // Try to match one by one
+ String separator = matcher.group(1);
+ String content = matcher.group(2);
+ // Start part of the condition expression.
+ if (separator == null || separator.length() == 0) {
+ pair = new MatchPair();
+ condition.put(content, pair);
+ }
+ // The KV part of the condition expression
+ else if ("&".equals(separator)) {
+ if (condition.get(content) == null) {
+ pair = new MatchPair();
+ condition.put(content, pair);
+ } else {
+ pair = condition.get(content);
+ }
+ }
+ // The Value in the KV part.
+ else if ("=".equals(separator)) {
+ if (pair == null)
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+
+ values = pair.matches;
+ values.add(content);
+ }
+ // The Value in the KV part.
+ else if ("!=".equals(separator)) {
+ if (pair == null)
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+
+ values = pair.mismatches;
+ values.add(content);
+ }
+ // The Value in the KV part, if Value have more than one items.
+ else if (",".equals(separator)) { // Should be seperateed by ','
+ if (values == null || values.isEmpty())
+ throw new ParseException("Illegal route rule \""
+ + rule + "\", The error char '" + separator
+ + "' at index " + matcher.start() + " before \""
+ + content + "\".", matcher.start());
+ values.add(content);
+ } else {
+ throw new ParseException("Illegal route rule \"" + rule
+ + "\", The error char '" + separator + "' at index "
+ + matcher.start() + " before \"" + content + "\".", matcher.start());
+ }
+ }
+ return condition;
+ }
+
+ @Override
+ public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation)
+ throws RpcException {
+ if (invokers == null || invokers.isEmpty()) {
+ return invokers;
+ }
+ try {
+ if (!matchWhen(url, invocation)) {
+ return invokers;
+ }
+ List<Invoker<T>> result = new ArrayList<Invoker<T>>();
+ if (thenCondition == null) {
+ logger.warn("The current consumer in the service blacklist. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey());
+ return result;
+ }
+ for (Invoker<T> invoker : invokers) {
+ if (matchThen(invoker.getUrl(), url)) {
+ result.add(invoker);
+ }
+ }
+ if (!result.isEmpty()) {
+ return result;
+ } else if (force) {
+ logger.warn("The route result is empty and force execute. consumer: " + NetUtils.getLocalHost() + ", service: " + url.getServiceKey() + ", router: " + url.getParameterAndDecoded(Constants.RULE_KEY));
+ return result;
+ }
+ } catch (Throwable t) {
+ logger.error("Failed to execute condition router rule: " + getUrl() + ", invokers: " + invokers + ", cause: " + t.getMessage(), t);
+ }
+ return invokers;
+ }
+
+ @Override
+ public URL getUrl() {
+ return url;
+ }
+
+ @Override
+ public int compareTo(Router o) {
+ if (o == null || o.getClass() != ConditionRouter.class) {
+ return 1;
+ }
+ ConditionRouter c = (ConditionRouter) o;
+ return this.priority == c.priority ? url.toFullString().compareTo(c.url.toFullString()) : (this.priority > c.priority ? 1 : -1);
+ }
+
+ boolean matchWhen(URL url, Invocation invocation) {
+ return whenCondition == null || whenCondition.isEmpty() || matchCondition(whenCondition, url, null, invocation);
+ }
+
+ private boolean matchThen(URL url, URL param) {
+ return !(thenCondition == null || thenCondition.isEmpty()) && matchCondition(thenCondition, url, param, null);
+ }
+
+ private boolean matchCondition(Map<String, MatchPair> condition, URL url, URL param, Invocation invocation) {
+ Map<String, String> sample = url.toMap();
+ boolean result = false;
+ for (Map.Entry<String, MatchPair> matchPair : condition.entrySet()) {
+ String key = matchPair.getKey();
+ String sampleValue;
+ //get real invoked method name from invocation
+ if (invocation != null && (Constants.METHOD_KEY.equals(key) || Constants.METHODS_KEY.equals(key))) {
+ sampleValue = invocation.getMethodName();
+ } else {
+ sampleValue = sample.get(key);
+ if (sampleValue == null) {
+ sampleValue = sample.get(Constants.DEFAULT_KEY_PREFIX + key);
+ }
+ }
+ if (sampleValue != null) {
+ if (!matchPair.getValue().isMatch(sampleValue, param)) {
+ return false;
+ } else {
+ result = true;
+ }
+ } else {
+ //not pass the condition
+ if (!matchPair.getValue().matches.isEmpty()) {
+ return false;
+ } else {
+ result = true;
+ }
+ }
+ }
+ return result;
+ }
+
+ private static final class MatchPair {
+ final Set<String> matches = new HashSet<String>();
+ final Set<String> mismatches = new HashSet<String>();
+
+ private boolean isMatch(String value, URL param) {
+ if (!matches.isEmpty() && mismatches.isEmpty()) {
+ for (String match : matches) {
+ if (UrlUtils.isMatchGlobPattern(match, value, param)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (!mismatches.isEmpty() && matches.isEmpty()) {
+ for (String mismatch : mismatches) {
+ if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (!matches.isEmpty() && !mismatches.isEmpty()) {
+ //when both mismatches and matches contain the same value, then using mismatches first
+ for (String mismatch : mismatches) {
+ if (UrlUtils.isMatchGlobPattern(mismatch, value, param)) {
+ return false;
+ }
+ }
+ for (String match : matches) {
+ if (UrlUtils.isMatchGlobPattern(match, value, param)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return false;
+ }
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
index a616d8d015..bf8614e986 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterFactory.java
@@ -1,36 +1,36 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router.condition;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Router;
-import org.apache.dubbo.rpc.cluster.RouterFactory;
-
-/**
- * ConditionRouterFactory
- *
- */
-public class ConditionRouterFactory implements RouterFactory {
-
- public static final String NAME = "condition";
-
- @Override
- public Router getRouter(URL url) {
- return new ConditionRouter(url);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router.condition;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+
+/**
+ * ConditionRouterFactory
+ *
+ */
+public class ConditionRouterFactory implements RouterFactory {
+
+ public static final String NAME = "condition";
+
+ @Override
+ public Router getRouter(URL url) {
+ return new ConditionRouter(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
index 616432254a..53fcf647af 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouter.java
@@ -1,126 +1,126 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router.script;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Router;
-
-import javax.script.Bindings;
-import javax.script.Compilable;
-import javax.script.CompiledScript;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * ScriptRouter
- *
- */
-public class ScriptRouter implements Router {
-
- private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class);
-
- private static final Map<String, ScriptEngine> engines = new ConcurrentHashMap<String, ScriptEngine>();
-
- private final ScriptEngine engine;
-
- private final int priority;
-
- private final String rule;
-
- private final URL url;
-
- public ScriptRouter(URL url) {
- this.url = url;
- String type = url.getParameter(Constants.TYPE_KEY);
- this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
- String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
- if (type == null || type.length() == 0) {
- type = Constants.DEFAULT_SCRIPT_TYPE_KEY;
- }
- if (rule == null || rule.length() == 0) {
- throw new IllegalStateException(new IllegalStateException("route rule can not be empty. rule:" + rule));
- }
- ScriptEngine engine = engines.get(type);
- if (engine == null) {
- engine = new ScriptEngineManager().getEngineByName(type);
- if (engine == null) {
- throw new IllegalStateException(new IllegalStateException("Unsupported route rule type: " + type + ", rule: " + rule));
- }
- engines.put(type, engine);
- }
- this.engine = engine;
- this.rule = rule;
- }
-
- @Override
- public URL getUrl() {
- return url;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
- try {
- List<Invoker<T>> invokersCopy = new ArrayList<Invoker<T>>(invokers);
- Compilable compilable = (Compilable) engine;
- Bindings bindings = engine.createBindings();
- bindings.put("invokers", invokersCopy);
- bindings.put("invocation", invocation);
- bindings.put("context", RpcContext.getContext());
- CompiledScript function = compilable.compile(rule);
- Object obj = function.eval(bindings);
- if (obj instanceof Invoker[]) {
- invokersCopy = Arrays.asList((Invoker<T>[]) obj);
- } else if (obj instanceof Object[]) {
- invokersCopy = new ArrayList<Invoker<T>>();
- for (Object inv : (Object[]) obj) {
- invokersCopy.add((Invoker<T>) inv);
- }
- } else {
- invokersCopy = (List<Invoker<T>>) obj;
- }
- return invokersCopy;
- } catch (ScriptException e) {
- //fail then ignore rule .invokers.
- logger.error("route error , rule has been ignored. rule: " + rule + ", method:" + invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e);
- return invokers;
- }
- }
-
- @Override
- public int compareTo(Router o) {
- if (o == null || o.getClass() != ScriptRouter.class) {
- return 1;
- }
- ScriptRouter c = (ScriptRouter) o;
- return this.priority == c.priority ? rule.compareTo(c.rule) : (this.priority > c.priority ? 1 : -1);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router.script;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Router;
+
+import javax.script.Bindings;
+import javax.script.Compilable;
+import javax.script.CompiledScript;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * ScriptRouter
+ *
+ */
+public class ScriptRouter implements Router {
+
+ private static final Logger logger = LoggerFactory.getLogger(ScriptRouter.class);
+
+ private static final Map<String, ScriptEngine> engines = new ConcurrentHashMap<String, ScriptEngine>();
+
+ private final ScriptEngine engine;
+
+ private final int priority;
+
+ private final String rule;
+
+ private final URL url;
+
+ public ScriptRouter(URL url) {
+ this.url = url;
+ String type = url.getParameter(Constants.TYPE_KEY);
+ this.priority = url.getParameter(Constants.PRIORITY_KEY, 0);
+ String rule = url.getParameterAndDecoded(Constants.RULE_KEY);
+ if (type == null || type.length() == 0) {
+ type = Constants.DEFAULT_SCRIPT_TYPE_KEY;
+ }
+ if (rule == null || rule.length() == 0) {
+ throw new IllegalStateException(new IllegalStateException("route rule can not be empty. rule:" + rule));
+ }
+ ScriptEngine engine = engines.get(type);
+ if (engine == null) {
+ engine = new ScriptEngineManager().getEngineByName(type);
+ if (engine == null) {
+ throw new IllegalStateException(new IllegalStateException("Unsupported route rule type: " + type + ", rule: " + rule));
+ }
+ engines.put(type, engine);
+ }
+ this.engine = engine;
+ this.rule = rule;
+ }
+
+ @Override
+ public URL getUrl() {
+ return url;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <T> List<Invoker<T>> route(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
+ try {
+ List<Invoker<T>> invokersCopy = new ArrayList<Invoker<T>>(invokers);
+ Compilable compilable = (Compilable) engine;
+ Bindings bindings = engine.createBindings();
+ bindings.put("invokers", invokersCopy);
+ bindings.put("invocation", invocation);
+ bindings.put("context", RpcContext.getContext());
+ CompiledScript function = compilable.compile(rule);
+ Object obj = function.eval(bindings);
+ if (obj instanceof Invoker[]) {
+ invokersCopy = Arrays.asList((Invoker<T>[]) obj);
+ } else if (obj instanceof Object[]) {
+ invokersCopy = new ArrayList<Invoker<T>>();
+ for (Object inv : (Object[]) obj) {
+ invokersCopy.add((Invoker<T>) inv);
+ }
+ } else {
+ invokersCopy = (List<Invoker<T>>) obj;
+ }
+ return invokersCopy;
+ } catch (ScriptException e) {
+ //fail then ignore rule .invokers.
+ logger.error("route error , rule has been ignored. rule: " + rule + ", method:" + invocation.getMethodName() + ", url: " + RpcContext.getContext().getUrl(), e);
+ return invokers;
+ }
+ }
+
+ @Override
+ public int compareTo(Router o) {
+ if (o == null || o.getClass() != ScriptRouter.class) {
+ return 1;
+ }
+ ScriptRouter c = (ScriptRouter) o;
+ return this.priority == c.priority ? rule.compareTo(c.rule) : (this.priority > c.priority ? 1 : -1);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouterFactory.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouterFactory.java
index 56976ed731..8043d27d1f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouterFactory.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/router/script/ScriptRouterFactory.java
@@ -1,45 +1,45 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router.script;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.cluster.Router;
-import org.apache.dubbo.rpc.cluster.RouterFactory;
-
-/**
- * ScriptRouterFactory
- * <p>
- * Example URLS used by Script Router Factory:
- * <ol>
- * <li> script://registyAddress?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://C:/path/to/routerfile.js?type=js&rule=xxxx
- * </ol>
- * The host value in URL points out the address of the source content of the Script Router,Registry、File etc
- *
- */
-public class ScriptRouterFactory implements RouterFactory {
-
- public static final String NAME = "script";
-
- @Override
- public Router getRouter(URL url) {
- return new ScriptRouter(url);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router.script;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+
+/**
+ * ScriptRouterFactory
+ * <p>
+ * Example URLS used by Script Router Factory:
+ * <ol>
+ * <li> script://registyAddress?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://C:/path/to/routerfile.js?type=js&rule=xxxx
+ * </ol>
+ * The host value in URL points out the address of the source content of the Script Router,Registry、File etc
+ *
+ */
+public class ScriptRouterFactory implements RouterFactory {
+
+ public static final String NAME = "script";
+
+ @Override
+ public Router getRouter(URL url) {
+ return new ScriptRouter(url);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
index a4a1905cf2..5a7c3392a7 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AbstractClusterInvoker.java
@@ -1,270 +1,270 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-import org.apache.dubbo.rpc.support.RpcUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * AbstractClusterInvoker
- *
- */
-public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
-
- private static final Logger logger = LoggerFactory
- .getLogger(AbstractClusterInvoker.class);
- protected final Directory<T> directory;
-
- protected final boolean availablecheck;
-
- private AtomicBoolean destroyed = new AtomicBoolean(false);
-
- private volatile Invoker<T> stickyInvoker = null;
-
- public AbstractClusterInvoker(Directory<T> directory) {
- this(directory, directory.getUrl());
- }
-
- public AbstractClusterInvoker(Directory<T> directory, URL url) {
- if (directory == null)
- throw new IllegalArgumentException("service directory == null");
-
- this.directory = directory;
- //sticky: invoker.isAvailable() should always be checked before using when availablecheck is true.
- this.availablecheck = url.getParameter(Constants.CLUSTER_AVAILABLE_CHECK_KEY, Constants.DEFAULT_CLUSTER_AVAILABLE_CHECK);
- }
-
- @Override
- public Class<T> getInterface() {
- return directory.getInterface();
- }
-
- @Override
- public URL getUrl() {
- return directory.getUrl();
- }
-
- @Override
- public boolean isAvailable() {
- Invoker<T> invoker = stickyInvoker;
- if (invoker != null) {
- return invoker.isAvailable();
- }
- return directory.isAvailable();
- }
-
- @Override
- public void destroy() {
- if (destroyed.compareAndSet(false, true)) {
- directory.destroy();
- }
- }
-
- /**
- * Select a invoker using loadbalance policy.</br>
- * a)Firstly, select an invoker using loadbalance. If this invoker is in previously selected list, or,
- * if this invoker is unavailable, then continue step b (reselect), otherwise return the first selected invoker</br>
- * b)Reslection, the validation rule for reselection: selected > available. This rule guarantees that
- * the selected invoker has the minimum chance to be one in the previously selected list, and also
- * guarantees this invoker is available.
- *
- * @param loadbalance load balance policy
- * @param invocation
- * @param invokers invoker candidates
- * @param selected exclude selected invokers or not
- * @return
- * @throws RpcException
- */
- protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
- if (invokers == null || invokers.isEmpty())
- return null;
- String methodName = invocation == null ? "" : invocation.getMethodName();
-
- boolean sticky = invokers.get(0).getUrl().getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY);
- {
- //ignore overloaded method
- if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {
- stickyInvoker = null;
- }
- //ignore concurrency problem
- if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
- if (availablecheck && stickyInvoker.isAvailable()) {
- return stickyInvoker;
- }
- }
- }
- Invoker<T> invoker = doSelect(loadbalance, invocation, invokers, selected);
-
- if (sticky) {
- stickyInvoker = invoker;
- }
- return invoker;
- }
-
- private Invoker<T> doSelect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
- if (invokers == null || invokers.isEmpty())
- return null;
- if (invokers.size() == 1)
- return invokers.get(0);
- if (loadbalance == null) {
- loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
- }
- Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);
-
- //If the `invoker` is in the `selected` or invoker is unavailable && availablecheck is true, reselect.
- if ((selected != null && selected.contains(invoker))
- || (!invoker.isAvailable() && getUrl() != null && availablecheck)) {
- try {
- Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
- if (rinvoker != null) {
- invoker = rinvoker;
- } else {
- //Check the index of current selected invoker, if it's not the last one, choose the one at index+1.
- int index = invokers.indexOf(invoker);
- try {
- //Avoid collision
- invoker = index < invokers.size() - 1 ? invokers.get(index + 1) : invokers.get(0);
- } catch (Exception e) {
- logger.warn(e.getMessage() + " may because invokers list dynamic change, ignore.", e);
- }
- }
- } catch (Throwable t) {
- logger.error("cluster reselect fail reason is :" + t.getMessage() + " if can not solve, you can set cluster.availablecheck=false in url", t);
- }
- }
- return invoker;
- }
-
- /**
- * Reselect, use invokers not in `selected` first, if all invokers are in `selected`, just pick an available one using loadbalance policy.
- *
- * @param loadbalance
- * @param invocation
- * @param invokers
- * @param selected
- * @return
- * @throws RpcException
- */
- private Invoker<T> reselect(LoadBalance loadbalance, Invocation invocation,
- List<Invoker<T>> invokers, List<Invoker<T>> selected, boolean availablecheck)
- throws RpcException {
-
- //Allocating one in advance, this list is certain to be used.
- List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size() > 1 ? (invokers.size() - 1) : invokers.size());
-
- //First, try picking a invoker not in `selected`.
- if (availablecheck) { // invoker.isAvailable() should be checked
- for (Invoker<T> invoker : invokers) {
- if (invoker.isAvailable()) {
- if (selected == null || !selected.contains(invoker)) {
- reselectInvokers.add(invoker);
- }
- }
- }
- if (!reselectInvokers.isEmpty()) {
- return loadbalance.select(reselectInvokers, getUrl(), invocation);
- }
- } else { // do not check invoker.isAvailable()
- for (Invoker<T> invoker : invokers) {
- if (selected == null || !selected.contains(invoker)) {
- reselectInvokers.add(invoker);
- }
- }
- if (!reselectInvokers.isEmpty()) {
- return loadbalance.select(reselectInvokers, getUrl(), invocation);
- }
- }
- // Just pick an available invoker using loadbalance policy
- {
- if (selected != null) {
- for (Invoker<T> invoker : selected) {
- if ((invoker.isAvailable()) // available first
- && !reselectInvokers.contains(invoker)) {
- reselectInvokers.add(invoker);
- }
- }
- }
- if (!reselectInvokers.isEmpty()) {
- return loadbalance.select(reselectInvokers, getUrl(), invocation);
- }
- }
- return null;
- }
-
- @Override
- public Result invoke(final Invocation invocation) throws RpcException {
- checkWhetherDestroyed();
- LoadBalance loadbalance = null;
- List<Invoker<T>> invokers = list(invocation);
- if (invokers != null && !invokers.isEmpty()) {
- loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
- .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
- }
- RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
- return doInvoke(invocation, invokers, loadbalance);
- }
-
- protected void checkWhetherDestroyed() {
-
- if (destroyed.get()) {
- throw new RpcException("Rpc cluster invoker for " + getInterface() + " on consumer " + NetUtils.getLocalHost()
- + " use dubbo version " + Version.getVersion()
- + " is now destroyed! Can not invoke any more.");
- }
- }
-
- @Override
- public String toString() {
- return getInterface() + " -> " + getUrl().toString();
- }
-
- protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {
- if (invokers == null || invokers.isEmpty()) {
- throw new RpcException("Failed to invoke the method "
- + invocation.getMethodName() + " in the service " + getInterface().getName()
- + ". No provider available for the service " + directory.getUrl().getServiceKey()
- + " from registry " + directory.getUrl().getAddress()
- + " on the consumer " + NetUtils.getLocalHost()
- + " using the dubbo version " + Version.getVersion()
- + ". Please check if the providers have been started and registered.");
- }
- }
-
- protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
- LoadBalance loadbalance) throws RpcException;
-
- protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
- List<Invoker<T>> invokers = directory.list(invocation);
- return invokers;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+import org.apache.dubbo.rpc.support.RpcUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * AbstractClusterInvoker
+ *
+ */
+public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
+
+ private static final Logger logger = LoggerFactory
+ .getLogger(AbstractClusterInvoker.class);
+ protected final Directory<T> directory;
+
+ protected final boolean availablecheck;
+
+ private AtomicBoolean destroyed = new AtomicBoolean(false);
+
+ private volatile Invoker<T> stickyInvoker = null;
+
+ public AbstractClusterInvoker(Directory<T> directory) {
+ this(directory, directory.getUrl());
+ }
+
+ public AbstractClusterInvoker(Directory<T> directory, URL url) {
+ if (directory == null)
+ throw new IllegalArgumentException("service directory == null");
+
+ this.directory = directory;
+ //sticky: invoker.isAvailable() should always be checked before using when availablecheck is true.
+ this.availablecheck = url.getParameter(Constants.CLUSTER_AVAILABLE_CHECK_KEY, Constants.DEFAULT_CLUSTER_AVAILABLE_CHECK);
+ }
+
+ @Override
+ public Class<T> getInterface() {
+ return directory.getInterface();
+ }
+
+ @Override
+ public URL getUrl() {
+ return directory.getUrl();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ Invoker<T> invoker = stickyInvoker;
+ if (invoker != null) {
+ return invoker.isAvailable();
+ }
+ return directory.isAvailable();
+ }
+
+ @Override
+ public void destroy() {
+ if (destroyed.compareAndSet(false, true)) {
+ directory.destroy();
+ }
+ }
+
+ /**
+ * Select a invoker using loadbalance policy.</br>
+ * a)Firstly, select an invoker using loadbalance. If this invoker is in previously selected list, or,
+ * if this invoker is unavailable, then continue step b (reselect), otherwise return the first selected invoker</br>
+ * b)Reslection, the validation rule for reselection: selected > available. This rule guarantees that
+ * the selected invoker has the minimum chance to be one in the previously selected list, and also
+ * guarantees this invoker is available.
+ *
+ * @param loadbalance load balance policy
+ * @param invocation
+ * @param invokers invoker candidates
+ * @param selected exclude selected invokers or not
+ * @return
+ * @throws RpcException
+ */
+ protected Invoker<T> select(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
+ if (invokers == null || invokers.isEmpty())
+ return null;
+ String methodName = invocation == null ? "" : invocation.getMethodName();
+
+ boolean sticky = invokers.get(0).getUrl().getMethodParameter(methodName, Constants.CLUSTER_STICKY_KEY, Constants.DEFAULT_CLUSTER_STICKY);
+ {
+ //ignore overloaded method
+ if (stickyInvoker != null && !invokers.contains(stickyInvoker)) {
+ stickyInvoker = null;
+ }
+ //ignore concurrency problem
+ if (sticky && stickyInvoker != null && (selected == null || !selected.contains(stickyInvoker))) {
+ if (availablecheck && stickyInvoker.isAvailable()) {
+ return stickyInvoker;
+ }
+ }
+ }
+ Invoker<T> invoker = doSelect(loadbalance, invocation, invokers, selected);
+
+ if (sticky) {
+ stickyInvoker = invoker;
+ }
+ return invoker;
+ }
+
+ private Invoker<T> doSelect(LoadBalance loadbalance, Invocation invocation, List<Invoker<T>> invokers, List<Invoker<T>> selected) throws RpcException {
+ if (invokers == null || invokers.isEmpty())
+ return null;
+ if (invokers.size() == 1)
+ return invokers.get(0);
+ if (loadbalance == null) {
+ loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
+ }
+ Invoker<T> invoker = loadbalance.select(invokers, getUrl(), invocation);
+
+ //If the `invoker` is in the `selected` or invoker is unavailable && availablecheck is true, reselect.
+ if ((selected != null && selected.contains(invoker))
+ || (!invoker.isAvailable() && getUrl() != null && availablecheck)) {
+ try {
+ Invoker<T> rinvoker = reselect(loadbalance, invocation, invokers, selected, availablecheck);
+ if (rinvoker != null) {
+ invoker = rinvoker;
+ } else {
+ //Check the index of current selected invoker, if it's not the last one, choose the one at index+1.
+ int index = invokers.indexOf(invoker);
+ try {
+ //Avoid collision
+ invoker = index < invokers.size() - 1 ? invokers.get(index + 1) : invokers.get(0);
+ } catch (Exception e) {
+ logger.warn(e.getMessage() + " may because invokers list dynamic change, ignore.", e);
+ }
+ }
+ } catch (Throwable t) {
+ logger.error("cluster reselect fail reason is :" + t.getMessage() + " if can not solve, you can set cluster.availablecheck=false in url", t);
+ }
+ }
+ return invoker;
+ }
+
+ /**
+ * Reselect, use invokers not in `selected` first, if all invokers are in `selected`, just pick an available one using loadbalance policy.
+ *
+ * @param loadbalance
+ * @param invocation
+ * @param invokers
+ * @param selected
+ * @return
+ * @throws RpcException
+ */
+ private Invoker<T> reselect(LoadBalance loadbalance, Invocation invocation,
+ List<Invoker<T>> invokers, List<Invoker<T>> selected, boolean availablecheck)
+ throws RpcException {
+
+ //Allocating one in advance, this list is certain to be used.
+ List<Invoker<T>> reselectInvokers = new ArrayList<Invoker<T>>(invokers.size() > 1 ? (invokers.size() - 1) : invokers.size());
+
+ //First, try picking a invoker not in `selected`.
+ if (availablecheck) { // invoker.isAvailable() should be checked
+ for (Invoker<T> invoker : invokers) {
+ if (invoker.isAvailable()) {
+ if (selected == null || !selected.contains(invoker)) {
+ reselectInvokers.add(invoker);
+ }
+ }
+ }
+ if (!reselectInvokers.isEmpty()) {
+ return loadbalance.select(reselectInvokers, getUrl(), invocation);
+ }
+ } else { // do not check invoker.isAvailable()
+ for (Invoker<T> invoker : invokers) {
+ if (selected == null || !selected.contains(invoker)) {
+ reselectInvokers.add(invoker);
+ }
+ }
+ if (!reselectInvokers.isEmpty()) {
+ return loadbalance.select(reselectInvokers, getUrl(), invocation);
+ }
+ }
+ // Just pick an available invoker using loadbalance policy
+ {
+ if (selected != null) {
+ for (Invoker<T> invoker : selected) {
+ if ((invoker.isAvailable()) // available first
+ && !reselectInvokers.contains(invoker)) {
+ reselectInvokers.add(invoker);
+ }
+ }
+ }
+ if (!reselectInvokers.isEmpty()) {
+ return loadbalance.select(reselectInvokers, getUrl(), invocation);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Result invoke(final Invocation invocation) throws RpcException {
+ checkWhetherDestroyed();
+ LoadBalance loadbalance = null;
+ List<Invoker<T>> invokers = list(invocation);
+ if (invokers != null && !invokers.isEmpty()) {
+ loadbalance = ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
+ .getMethodParameter(RpcUtils.getMethodName(invocation), Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
+ }
+ RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
+ return doInvoke(invocation, invokers, loadbalance);
+ }
+
+ protected void checkWhetherDestroyed() {
+
+ if (destroyed.get()) {
+ throw new RpcException("Rpc cluster invoker for " + getInterface() + " on consumer " + NetUtils.getLocalHost()
+ + " use dubbo version " + Version.getVersion()
+ + " is now destroyed! Can not invoke any more.");
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getInterface() + " -> " + getUrl().toString();
+ }
+
+ protected void checkInvokers(List<Invoker<T>> invokers, Invocation invocation) {
+ if (invokers == null || invokers.isEmpty()) {
+ throw new RpcException("Failed to invoke the method "
+ + invocation.getMethodName() + " in the service " + getInterface().getName()
+ + ". No provider available for the service " + directory.getUrl().getServiceKey()
+ + " from registry " + directory.getUrl().getAddress()
+ + " on the consumer " + NetUtils.getLocalHost()
+ + " using the dubbo version " + Version.getVersion()
+ + ". Please check if the providers have been started and registered.");
+ }
+ }
+
+ protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers,
+ LoadBalance loadbalance) throws RpcException;
+
+ protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
+ List<Invoker<T>> invokers = directory.list(invocation);
+ return invokers;
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
index 85e91e0527..42227d7e84 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/AvailableCluster.java
@@ -1,54 +1,54 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-/**
- * AvailableCluster
- *
- */
-public class AvailableCluster implements Cluster {
-
- public static final String NAME = "available";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
-
- return new AbstractClusterInvoker<T>(directory) {
- @Override
- public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- for (Invoker<T> invoker : invokers) {
- if (invoker.isAvailable()) {
- return invoker.invoke(invocation);
- }
- }
- throw new RpcException("No provider available in " + invokers);
- }
- };
-
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ * AvailableCluster
+ *
+ */
+public class AvailableCluster implements Cluster {
+
+ public static final String NAME = "available";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+
+ return new AbstractClusterInvoker<T>(directory) {
+ @Override
+ public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ for (Invoker<T> invoker : invokers) {
+ if (invoker.isAvailable()) {
+ return invoker.invoke(invocation);
+ }
+ }
+ throw new RpcException("No provider available in " + invokers);
+ }
+ };
+
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastCluster.java
index c0cbdf763e..73beb729a2 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastCluster.java
@@ -1,35 +1,35 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * BroadcastCluster
- *
- */
-public class BroadcastCluster implements Cluster {
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new BroadcastClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * BroadcastCluster
+ *
+ */
+public class BroadcastCluster implements Cluster {
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new BroadcastClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
index ab0623ea4a..ec0d279ae0 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/BroadcastClusterInvoker.java
@@ -1,67 +1,67 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-/**
- * BroadcastClusterInvoker
- *
- */
-public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
-
- private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
-
- public BroadcastClusterInvoker(Directory<T> directory) {
- super(directory);
- }
-
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- checkInvokers(invokers, invocation);
- RpcContext.getContext().setInvokers((List) invokers);
- RpcException exception = null;
- Result result = null;
- for (Invoker<T> invoker : invokers) {
- try {
- result = invoker.invoke(invocation);
- } catch (RpcException e) {
- exception = e;
- logger.warn(e.getMessage(), e);
- } catch (Throwable e) {
- exception = new RpcException(e.getMessage(), e);
- logger.warn(e.getMessage(), e);
- }
- }
- if (exception != null) {
- throw exception;
- }
- return result;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ * BroadcastClusterInvoker
+ *
+ */
+public class BroadcastClusterInvoker<T> extends AbstractClusterInvoker<T> {
+
+ private static final Logger logger = LoggerFactory.getLogger(BroadcastClusterInvoker.class);
+
+ public BroadcastClusterInvoker(Directory<T> directory) {
+ super(directory);
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public Result doInvoke(final Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ checkInvokers(invokers, invocation);
+ RpcContext.getContext().setInvokers((List) invokers);
+ RpcException exception = null;
+ Result result = null;
+ for (Invoker<T> invoker : invokers) {
+ try {
+ result = invoker.invoke(invocation);
+ } catch (RpcException e) {
+ exception = e;
+ logger.warn(e.getMessage(), e);
+ } catch (Throwable e) {
+ exception = new RpcException(e.getMessage(), e);
+ logger.warn(e.getMessage(), e);
+ }
+ }
+ if (exception != null) {
+ throw exception;
+ }
+ return result;
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
index 2b875552d7..f4ee2a9daa 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ClusterUtils.java
@@ -1,112 +1,112 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * ClusterUtils
- *
- */
-public class ClusterUtils {
-
- private ClusterUtils() {
- }
-
- public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
- Map<String, String> map = new HashMap<String, String>();
- Map<String, String> remoteMap = remoteUrl.getParameters();
-
-
- if (remoteMap != null && remoteMap.size() > 0) {
- map.putAll(remoteMap);
-
- // Remove configurations from provider, some items should be affected by provider.
- map.remove(Constants.THREAD_NAME_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREAD_NAME_KEY);
-
- map.remove(Constants.THREADPOOL_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADPOOL_KEY);
-
- map.remove(Constants.CORE_THREADS_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.CORE_THREADS_KEY);
-
- map.remove(Constants.THREADS_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADS_KEY);
-
- map.remove(Constants.QUEUES_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.QUEUES_KEY);
-
- map.remove(Constants.ALIVE_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ALIVE_KEY);
-
- map.remove(Constants.TRANSPORTER_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY);
-
- map.remove(Constants.ASYNC_KEY);
- map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ASYNC_KEY);
- }
-
- if (localMap != null && localMap.size() > 0) {
- map.putAll(localMap);
- }
- if (remoteMap != null && remoteMap.size() > 0) {
- // Use version passed from provider side
- String dubbo = remoteMap.get(Constants.DUBBO_VERSION_KEY);
- if (dubbo != null && dubbo.length() > 0) {
- map.put(Constants.DUBBO_VERSION_KEY, dubbo);
- }
- String version = remoteMap.get(Constants.VERSION_KEY);
- if (version != null && version.length() > 0) {
- map.put(Constants.VERSION_KEY, version);
- }
- String group = remoteMap.get(Constants.GROUP_KEY);
- if (group != null && group.length() > 0) {
- map.put(Constants.GROUP_KEY, group);
- }
- String methods = remoteMap.get(Constants.METHODS_KEY);
- if (methods != null && methods.length() > 0) {
- map.put(Constants.METHODS_KEY, methods);
- }
- // Reserve timestamp of provider url.
- String remoteTimestamp = remoteMap.get(Constants.TIMESTAMP_KEY);
- if (remoteTimestamp != null && remoteTimestamp.length() > 0) {
- map.put(Constants.REMOTE_TIMESTAMP_KEY, remoteMap.get(Constants.TIMESTAMP_KEY));
- }
- // Combine filters and listeners on Provider and Consumer
- String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY);
- String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY);
- if (remoteFilter != null && remoteFilter.length() > 0
- && localFilter != null && localFilter.length() > 0) {
- localMap.put(Constants.REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter);
- }
- String remoteListener = remoteMap.get(Constants.INVOKER_LISTENER_KEY);
- String localListener = localMap.get(Constants.INVOKER_LISTENER_KEY);
- if (remoteListener != null && remoteListener.length() > 0
- && localListener != null && localListener.length() > 0) {
- localMap.put(Constants.INVOKER_LISTENER_KEY, remoteListener + "," + localListener);
- }
- }
-
- return remoteUrl.clearParameters().addParameters(map);
- }
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ClusterUtils
+ *
+ */
+public class ClusterUtils {
+
+ private ClusterUtils() {
+ }
+
+ public static URL mergeUrl(URL remoteUrl, Map<String, String> localMap) {
+ Map<String, String> map = new HashMap<String, String>();
+ Map<String, String> remoteMap = remoteUrl.getParameters();
+
+
+ if (remoteMap != null && remoteMap.size() > 0) {
+ map.putAll(remoteMap);
+
+ // Remove configurations from provider, some items should be affected by provider.
+ map.remove(Constants.THREAD_NAME_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREAD_NAME_KEY);
+
+ map.remove(Constants.THREADPOOL_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADPOOL_KEY);
+
+ map.remove(Constants.CORE_THREADS_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.CORE_THREADS_KEY);
+
+ map.remove(Constants.THREADS_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.THREADS_KEY);
+
+ map.remove(Constants.QUEUES_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.QUEUES_KEY);
+
+ map.remove(Constants.ALIVE_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ALIVE_KEY);
+
+ map.remove(Constants.TRANSPORTER_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.TRANSPORTER_KEY);
+
+ map.remove(Constants.ASYNC_KEY);
+ map.remove(Constants.DEFAULT_KEY_PREFIX + Constants.ASYNC_KEY);
+ }
+
+ if (localMap != null && localMap.size() > 0) {
+ map.putAll(localMap);
+ }
+ if (remoteMap != null && remoteMap.size() > 0) {
+ // Use version passed from provider side
+ String dubbo = remoteMap.get(Constants.DUBBO_VERSION_KEY);
+ if (dubbo != null && dubbo.length() > 0) {
+ map.put(Constants.DUBBO_VERSION_KEY, dubbo);
+ }
+ String version = remoteMap.get(Constants.VERSION_KEY);
+ if (version != null && version.length() > 0) {
+ map.put(Constants.VERSION_KEY, version);
+ }
+ String group = remoteMap.get(Constants.GROUP_KEY);
+ if (group != null && group.length() > 0) {
+ map.put(Constants.GROUP_KEY, group);
+ }
+ String methods = remoteMap.get(Constants.METHODS_KEY);
+ if (methods != null && methods.length() > 0) {
+ map.put(Constants.METHODS_KEY, methods);
+ }
+ // Reserve timestamp of provider url.
+ String remoteTimestamp = remoteMap.get(Constants.TIMESTAMP_KEY);
+ if (remoteTimestamp != null && remoteTimestamp.length() > 0) {
+ map.put(Constants.REMOTE_TIMESTAMP_KEY, remoteMap.get(Constants.TIMESTAMP_KEY));
+ }
+ // Combine filters and listeners on Provider and Consumer
+ String remoteFilter = remoteMap.get(Constants.REFERENCE_FILTER_KEY);
+ String localFilter = localMap.get(Constants.REFERENCE_FILTER_KEY);
+ if (remoteFilter != null && remoteFilter.length() > 0
+ && localFilter != null && localFilter.length() > 0) {
+ localMap.put(Constants.REFERENCE_FILTER_KEY, remoteFilter + "," + localFilter);
+ }
+ String remoteListener = remoteMap.get(Constants.INVOKER_LISTENER_KEY);
+ String localListener = localMap.get(Constants.INVOKER_LISTENER_KEY);
+ if (remoteListener != null && remoteListener.length() > 0
+ && localListener != null && localListener.length() > 0) {
+ localMap.put(Constants.INVOKER_LISTENER_KEY, remoteListener + "," + localListener);
+ }
+ }
+
+ return remoteUrl.clearParameters().addParameters(map);
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackCluster.java
index 34c0199e79..1608d9733f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackCluster.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * {@link FailbackClusterInvoker}
- *
- */
-public class FailbackCluster implements Cluster {
-
- public final static String NAME = "failback";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new FailbackClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * {@link FailbackClusterInvoker}
+ *
+ */
+public class FailbackCluster implements Cluster {
+
+ public final static String NAME = "failback";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new FailbackClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
index 55a4180f60..a5e984d698 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvoker.java
@@ -1,121 +1,121 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-/**
- * When fails, record failure requests and schedule for retry on a regular interval.
- * Especially useful for services of notification.
- *
- * <a href="http://en.wikipedia.org/wiki/Failback">Failback</a>
- *
- */
-public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
-
- private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class);
-
- private static final long RETRY_FAILED_PERIOD = 5 * 1000;
-
- /**
- * Use {@link NamedInternalThreadFactory} to produce {@link org.apache.dubbo.common.threadlocal.InternalThread}
- * which with the use of {@link org.apache.dubbo.common.threadlocal.InternalThreadLocal} in {@link RpcContext}.
- */
- private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2,
- new NamedInternalThreadFactory("failback-cluster-timer", true));
-
- private final ConcurrentMap<Invocation, AbstractClusterInvoker<?>> failed = new ConcurrentHashMap<Invocation, AbstractClusterInvoker<?>>();
- private volatile ScheduledFuture<?> retryFuture;
-
- public FailbackClusterInvoker(Directory<T> directory) {
- super(directory);
- }
-
- private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) {
- if (retryFuture == null) {
- synchronized (this) {
- if (retryFuture == null) {
- retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
-
- @Override
- public void run() {
- // collect retry statistics
- try {
- retryFailed();
- } catch (Throwable t) { // Defensive fault tolerance
- logger.error("Unexpected error occur at collect statistic", t);
- }
- }
- }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS);
- }
- }
- }
- failed.put(invocation, router);
- }
-
- void retryFailed() {
- if (failed.size() == 0) {
- return;
- }
- for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>(
- failed).entrySet()) {
- Invocation invocation = entry.getKey();
- Invoker<?> invoker = entry.getValue();
- try {
- invoker.invoke(invocation);
- failed.remove(invocation);
- } catch (Throwable e) {
- logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e);
- }
- }
- }
-
- @Override
- protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- try {
- checkInvokers(invokers, invocation);
- Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
- return invoker.invoke(invocation);
- } catch (Throwable e) {
- logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
- + e.getMessage() + ", ", e);
- addFailed(invocation, this);
- return new RpcResult(); // ignore
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.threadlocal.NamedInternalThreadFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * When fails, record failure requests and schedule for retry on a regular interval.
+ * Especially useful for services of notification.
+ *
+ * <a href="http://en.wikipedia.org/wiki/Failback">Failback</a>
+ *
+ */
+public class FailbackClusterInvoker<T> extends AbstractClusterInvoker<T> {
+
+ private static final Logger logger = LoggerFactory.getLogger(FailbackClusterInvoker.class);
+
+ private static final long RETRY_FAILED_PERIOD = 5 * 1000;
+
+ /**
+ * Use {@link NamedInternalThreadFactory} to produce {@link org.apache.dubbo.common.threadlocal.InternalThread}
+ * which with the use of {@link org.apache.dubbo.common.threadlocal.InternalThreadLocal} in {@link RpcContext}.
+ */
+ private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2,
+ new NamedInternalThreadFactory("failback-cluster-timer", true));
+
+ private final ConcurrentMap<Invocation, AbstractClusterInvoker<?>> failed = new ConcurrentHashMap<Invocation, AbstractClusterInvoker<?>>();
+ private volatile ScheduledFuture<?> retryFuture;
+
+ public FailbackClusterInvoker(Directory<T> directory) {
+ super(directory);
+ }
+
+ private void addFailed(Invocation invocation, AbstractClusterInvoker<?> router) {
+ if (retryFuture == null) {
+ synchronized (this) {
+ if (retryFuture == null) {
+ retryFuture = scheduledExecutorService.scheduleWithFixedDelay(new Runnable() {
+
+ @Override
+ public void run() {
+ // collect retry statistics
+ try {
+ retryFailed();
+ } catch (Throwable t) { // Defensive fault tolerance
+ logger.error("Unexpected error occur at collect statistic", t);
+ }
+ }
+ }, RETRY_FAILED_PERIOD, RETRY_FAILED_PERIOD, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+ failed.put(invocation, router);
+ }
+
+ void retryFailed() {
+ if (failed.size() == 0) {
+ return;
+ }
+ for (Map.Entry<Invocation, AbstractClusterInvoker<?>> entry : new HashMap<Invocation, AbstractClusterInvoker<?>>(
+ failed).entrySet()) {
+ Invocation invocation = entry.getKey();
+ Invoker<?> invoker = entry.getValue();
+ try {
+ invoker.invoke(invocation);
+ failed.remove(invocation);
+ } catch (Throwable e) {
+ logger.error("Failed retry to invoke method " + invocation.getMethodName() + ", waiting again.", e);
+ }
+ }
+ }
+
+ @Override
+ protected Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ try {
+ checkInvokers(invokers, invocation);
+ Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
+ return invoker.invoke(invocation);
+ } catch (Throwable e) {
+ logger.error("Failback to invoke method " + invocation.getMethodName() + ", wait for retry in background. Ignored exception: "
+ + e.getMessage() + ", ", e);
+ addFailed(invocation, this);
+ return new RpcResult(); // ignore
+ }
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastCluster.java
index 5633603f0b..be19e05cfe 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastCluster.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * {@link FailfastClusterInvoker}
- *
- */
-public class FailfastCluster implements Cluster {
-
- public final static String NAME = "failfast";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new FailfastClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * {@link FailfastClusterInvoker}
+ *
+ */
+public class FailfastCluster implements Cluster {
+
+ public final static String NAME = "failfast";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new FailfastClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
index 4122e8c9fe..1d467e82dc 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailfastClusterInvoker.java
@@ -1,56 +1,56 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-/**
- * 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
- *
- * <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
- *
- */
-public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {
-
- public FailfastClusterInvoker(Directory<T> directory) {
- super(directory);
- }
-
- @Override
- public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- checkInvokers(invokers, invocation);
- Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
- try {
- return invoker.invoke(invocation);
- } catch (Throwable e) {
- if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
- throw (RpcException) e;
- }
- throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ * 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
+ *
+ * <a href="http://en.wikipedia.org/wiki/Fail-fast">Fail-fast</a>
+ *
+ */
+public class FailfastClusterInvoker<T> extends AbstractClusterInvoker<T> {
+
+ public FailfastClusterInvoker(Directory<T> directory) {
+ super(directory);
+ }
+
+ @Override
+ public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ checkInvokers(invokers, invocation);
+ Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
+ try {
+ return invoker.invoke(invocation);
+ } catch (Throwable e) {
+ if (e instanceof RpcException && ((RpcException) e).isBiz()) { // biz exception.
+ throw (RpcException) e;
+ }
+ throw new RpcException(e instanceof RpcException ? ((RpcException) e).getCode() : 0, "Failfast invoke providers " + invoker.getUrl() + " " + loadbalance.getClass().getSimpleName() + " select from all providers " + invokers + " for service " + getInterface().getName() + " method " + invocation.getMethodName() + " on consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", but no luck to perform the invocation. Last error is: " + e.getMessage(), e.getCause() != null ? e.getCause() : e);
+ }
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverCluster.java
index 38d0f58991..5f0d1f390a 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverCluster.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * {@link FailoverClusterInvoker}
- *
- */
-public class FailoverCluster implements Cluster {
-
- public final static String NAME = "failover";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new FailoverClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * {@link FailoverClusterInvoker}
+ *
+ */
+public class FailoverCluster implements Cluster {
+
+ public final static String NAME = "failover";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new FailoverClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
index 00b981fd20..e8f5fd3fe3 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvoker.java
@@ -1,112 +1,112 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.Version;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * 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.
- * <p>
- * <a href="http://en.wikipedia.org/wiki/Failover">Failover</a>
- *
- */
-public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
-
- private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);
-
- public FailoverClusterInvoker(Directory<T> directory) {
- super(directory);
- }
-
- @Override
- @SuppressWarnings({"unchecked", "rawtypes"})
- public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- List<Invoker<T>> copyinvokers = invokers;
- checkInvokers(copyinvokers, invocation);
- int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
- if (len <= 0) {
- len = 1;
- }
- // retry loop.
- RpcException le = null; // last exception.
- List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
- Set<String> providers = new HashSet<String>(len);
- for (int i = 0; i < len; i++) {
- //Reselect before retry to avoid a change of candidate `invokers`.
- //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
- if (i > 0) {
- checkWhetherDestroyed();
- copyinvokers = list(invocation);
- // check again
- checkInvokers(copyinvokers, invocation);
- }
- Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
- invoked.add(invoker);
- RpcContext.getContext().setInvokers((List) invoked);
- try {
- Result result = invoker.invoke(invocation);
- if (le != null && logger.isWarnEnabled()) {
- logger.warn("Although retry the method " + invocation.getMethodName()
- + " in the service " + getInterface().getName()
- + " was successful by the provider " + invoker.getUrl().getAddress()
- + ", but there have been failed providers " + providers
- + " (" + providers.size() + "/" + copyinvokers.size()
- + ") from the registry " + directory.getUrl().getAddress()
- + " on the consumer " + NetUtils.getLocalHost()
- + " using the dubbo version " + Version.getVersion() + ". Last error is: "
- + le.getMessage(), le);
- }
- return result;
- } catch (RpcException e) {
- if (e.isBiz()) { // biz exception.
- throw e;
- }
- le = e;
- } catch (Throwable e) {
- le = new RpcException(e.getMessage(), e);
- } finally {
- providers.add(invoker.getUrl().getAddress());
- }
- }
- throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
- + invocation.getMethodName() + " in the service " + getInterface().getName()
- + ". Tried " + len + " times of the providers " + providers
- + " (" + providers.size() + "/" + copyinvokers.size()
- + ") from the registry " + directory.getUrl().getAddress()
- + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
- + Version.getVersion() + ". Last error is: "
- + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.Version;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 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.
+ * <p>
+ * <a href="http://en.wikipedia.org/wiki/Failover">Failover</a>
+ *
+ */
+public class FailoverClusterInvoker<T> extends AbstractClusterInvoker<T> {
+
+ private static final Logger logger = LoggerFactory.getLogger(FailoverClusterInvoker.class);
+
+ public FailoverClusterInvoker(Directory<T> directory) {
+ super(directory);
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ List<Invoker<T>> copyinvokers = invokers;
+ checkInvokers(copyinvokers, invocation);
+ int len = getUrl().getMethodParameter(invocation.getMethodName(), Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
+ if (len <= 0) {
+ len = 1;
+ }
+ // retry loop.
+ RpcException le = null; // last exception.
+ List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyinvokers.size()); // invoked invokers.
+ Set<String> providers = new HashSet<String>(len);
+ for (int i = 0; i < len; i++) {
+ //Reselect before retry to avoid a change of candidate `invokers`.
+ //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
+ if (i > 0) {
+ checkWhetherDestroyed();
+ copyinvokers = list(invocation);
+ // check again
+ checkInvokers(copyinvokers, invocation);
+ }
+ Invoker<T> invoker = select(loadbalance, invocation, copyinvokers, invoked);
+ invoked.add(invoker);
+ RpcContext.getContext().setInvokers((List) invoked);
+ try {
+ Result result = invoker.invoke(invocation);
+ if (le != null && logger.isWarnEnabled()) {
+ logger.warn("Although retry the method " + invocation.getMethodName()
+ + " in the service " + getInterface().getName()
+ + " was successful by the provider " + invoker.getUrl().getAddress()
+ + ", but there have been failed providers " + providers
+ + " (" + providers.size() + "/" + copyinvokers.size()
+ + ") from the registry " + directory.getUrl().getAddress()
+ + " on the consumer " + NetUtils.getLocalHost()
+ + " using the dubbo version " + Version.getVersion() + ". Last error is: "
+ + le.getMessage(), le);
+ }
+ return result;
+ } catch (RpcException e) {
+ if (e.isBiz()) { // biz exception.
+ throw e;
+ }
+ le = e;
+ } catch (Throwable e) {
+ le = new RpcException(e.getMessage(), e);
+ } finally {
+ providers.add(invoker.getUrl().getAddress());
+ }
+ }
+ throw new RpcException(le != null ? le.getCode() : 0, "Failed to invoke the method "
+ + invocation.getMethodName() + " in the service " + getInterface().getName()
+ + ". Tried " + len + " times of the providers " + providers
+ + " (" + providers.size() + "/" + copyinvokers.size()
+ + ") from the registry " + directory.getUrl().getAddress()
+ + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
+ + Version.getVersion() + ". Last error is: "
+ + (le != null ? le.getMessage() : ""), le != null && le.getCause() != null ? le.getCause() : le);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeCluster.java
index eed0b5bdc8..48fdde7a40 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeCluster.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * {@link FailsafeClusterInvoker}
- *
- */
-public class FailsafeCluster implements Cluster {
-
- public final static String NAME = "failsafe";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new FailsafeClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * {@link FailsafeClusterInvoker}
+ *
+ */
+public class FailsafeCluster implements Cluster {
+
+ public final static String NAME = "failsafe";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new FailsafeClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
index 0f5378a19a..2ea4e1f1b4 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/FailsafeClusterInvoker.java
@@ -1,56 +1,56 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-
-import java.util.List;
-
-/**
- * When invoke fails, log the error message and ignore this error by returning an empty RpcResult.
- * Usually used to write audit logs and other operations
- *
- * <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
- *
- */
-public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {
- private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class);
-
- public FailsafeClusterInvoker(Directory<T> directory) {
- super(directory);
- }
-
- @Override
- public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
- try {
- checkInvokers(invokers, invocation);
- Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
- return invoker.invoke(invocation);
- } catch (Throwable e) {
- logger.error("Failsafe ignore exception: " + e.getMessage(), e);
- return new RpcResult(); // ignore
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+/**
+ * When invoke fails, log the error message and ignore this error by returning an empty RpcResult.
+ * Usually used to write audit logs and other operations
+ *
+ * <a href="http://en.wikipedia.org/wiki/Fail-safe">Fail-safe</a>
+ *
+ */
+public class FailsafeClusterInvoker<T> extends AbstractClusterInvoker<T> {
+ private static final Logger logger = LoggerFactory.getLogger(FailsafeClusterInvoker.class);
+
+ public FailsafeClusterInvoker(Directory<T> directory) {
+ super(directory);
+ }
+
+ @Override
+ public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
+ try {
+ checkInvokers(invokers, invocation);
+ Invoker<T> invoker = select(loadbalance, invocation, invokers, null);
+ return invoker.invoke(invocation);
+ } catch (Throwable e) {
+ logger.error("Failsafe ignore exception: " + e.getMessage(), e);
+ return new RpcResult(); // ignore
+ }
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingCluster.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingCluster.java
index 3701d64011..9a10e20214 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingCluster.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/ForkingCluster.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * {@link ForkingClusterInvoker}
- *
- */
-public class ForkingCluster implements Cluster {
-
- public final static String NAME = "forking";
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new ForkingClusterInvoker<T>(directory);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * {@link ForkingClusterInvoker}
+ *
+ */
+public class ForkingCluster implements Cluster {
+
+ public final static String NAME = "forking";
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new ForkingClusterInvoker<T>(directory);
+ }
+
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
index 7e3b4e7df8..84045d046f 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvoker.java
@@ -1,166 +1,166 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support.wrapper;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.support.MockInvoker;
-
-import java.util.List;
-
-public class MockClusterInvoker<T> implements Invoker<T> {
-
- private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);
-
- private final Directory<T> directory;
-
- private final Invoker<T> invoker;
-
- public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
- this.directory = directory;
- this.invoker = invoker;
- }
-
- @Override
- public URL getUrl() {
- return directory.getUrl();
- }
-
- @Override
- public boolean isAvailable() {
- return directory.isAvailable();
- }
-
- @Override
- public void destroy() {
- this.invoker.destroy();
- }
-
- @Override
- public Class<T> getInterface() {
- return directory.getInterface();
- }
-
- @Override
- public Result invoke(Invocation invocation) throws RpcException {
- Result result = null;
-
- String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
- if (value.length() == 0 || value.equalsIgnoreCase("false")) {
- //no mock
- result = this.invoker.invoke(invocation);
- } else if (value.startsWith("force")) {
- if (logger.isWarnEnabled()) {
- logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
- }
- //force:direct mock
- result = doMockInvoke(invocation, null);
- } else {
- //fail-mock
- try {
- result = this.invoker.invoke(invocation);
- } catch (RpcException e) {
- if (e.isBiz()) {
- throw e;
- } else {
- if (logger.isWarnEnabled()) {
- logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
- }
- result = doMockInvoke(invocation, e);
- }
- }
- }
- return result;
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private Result doMockInvoke(Invocation invocation, RpcException e) {
- Result result = null;
- Invoker<T> minvoker;
-
- List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
- if (mockInvokers == null || mockInvokers.isEmpty()) {
- minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
- } else {
- minvoker = mockInvokers.get(0);
- }
- try {
- result = minvoker.invoke(invocation);
- } catch (RpcException me) {
- if (me.isBiz()) {
- result = new RpcResult(me.getCause());
- } else {
- throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
- }
- } catch (Throwable me) {
- throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
- }
- return result;
- }
-
- private String getMockExceptionMessage(Throwable t, Throwable mt) {
- String msg = "mock error : " + mt.getMessage();
- if (t != null) {
- msg = msg + ", invoke error is :" + StringUtils.toString(t);
- }
- return msg;
- }
-
- /**
- * Return MockInvoker
- * Contract:
- * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present 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.
- *
- * @param invocation
- * @return
- */
- private List<Invoker<T>> selectMockInvoker(Invocation invocation) {
- List<Invoker<T>> invokers = null;
- //TODO generic invoker?
- 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 attachement needs to be improved)
- ((RpcInvocation) invocation).setAttachment(Constants.INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
- //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
- try {
- invokers = directory.list(invocation);
- } catch (RpcException e) {
- if (logger.isInfoEnabled()) {
- logger.info("Exception when try to invoke mock. Get mock invokers error for service:"
- + directory.getUrl().getServiceInterface() + ", method:" + invocation.getMethodName()
- + ", will contruct a new mock with 'new MockInvoker()'.", e);
- }
- }
- }
- return invokers;
- }
-
- @Override
- public String toString() {
- return "invoker :" + this.invoker + ",directory: " + this.directory;
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support.wrapper;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.support.MockInvoker;
+
+import java.util.List;
+
+public class MockClusterInvoker<T> implements Invoker<T> {
+
+ private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);
+
+ private final Directory<T> directory;
+
+ private final Invoker<T> invoker;
+
+ public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
+ this.directory = directory;
+ this.invoker = invoker;
+ }
+
+ @Override
+ public URL getUrl() {
+ return directory.getUrl();
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return directory.isAvailable();
+ }
+
+ @Override
+ public void destroy() {
+ this.invoker.destroy();
+ }
+
+ @Override
+ public Class<T> getInterface() {
+ return directory.getInterface();
+ }
+
+ @Override
+ public Result invoke(Invocation invocation) throws RpcException {
+ Result result = null;
+
+ String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
+ if (value.length() == 0 || value.equalsIgnoreCase("false")) {
+ //no mock
+ result = this.invoker.invoke(invocation);
+ } else if (value.startsWith("force")) {
+ if (logger.isWarnEnabled()) {
+ logger.info("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
+ }
+ //force:direct mock
+ result = doMockInvoke(invocation, null);
+ } else {
+ //fail-mock
+ try {
+ result = this.invoker.invoke(invocation);
+ } catch (RpcException e) {
+ if (e.isBiz()) {
+ throw e;
+ } else {
+ if (logger.isWarnEnabled()) {
+ logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
+ }
+ result = doMockInvoke(invocation, e);
+ }
+ }
+ }
+ return result;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private Result doMockInvoke(Invocation invocation, RpcException e) {
+ Result result = null;
+ Invoker<T> minvoker;
+
+ List<Invoker<T>> mockInvokers = selectMockInvoker(invocation);
+ if (mockInvokers == null || mockInvokers.isEmpty()) {
+ minvoker = (Invoker<T>) new MockInvoker(directory.getUrl());
+ } else {
+ minvoker = mockInvokers.get(0);
+ }
+ try {
+ result = minvoker.invoke(invocation);
+ } catch (RpcException me) {
+ if (me.isBiz()) {
+ result = new RpcResult(me.getCause());
+ } else {
+ throw new RpcException(me.getCode(), getMockExceptionMessage(e, me), me.getCause());
+ }
+ } catch (Throwable me) {
+ throw new RpcException(getMockExceptionMessage(e, me), me.getCause());
+ }
+ return result;
+ }
+
+ private String getMockExceptionMessage(Throwable t, Throwable mt) {
+ String msg = "mock error : " + mt.getMessage();
+ if (t != null) {
+ msg = msg + ", invoke error is :" + StringUtils.toString(t);
+ }
+ return msg;
+ }
+
+ /**
+ * Return MockInvoker
+ * Contract:
+ * directory.list() will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present 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.
+ *
+ * @param invocation
+ * @return
+ */
+ private List<Invoker<T>> selectMockInvoker(Invocation invocation) {
+ List<Invoker<T>> invokers = null;
+ //TODO generic invoker?
+ 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 attachement needs to be improved)
+ ((RpcInvocation) invocation).setAttachment(Constants.INVOCATION_NEED_MOCK, Boolean.TRUE.toString());
+ //directory will return a list of normal invokers if Constants.INVOCATION_NEED_MOCK is present in invocation, otherwise, a list of mock invokers will return.
+ try {
+ invokers = directory.list(invocation);
+ } catch (RpcException e) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Exception when try to invoke mock. Get mock invokers error for service:"
+ + directory.getUrl().getServiceInterface() + ", method:" + invocation.getMethodName()
+ + ", will contruct a new mock with 'new MockInvoker()'.", e);
+ }
+ }
+ }
+ return invokers;
+ }
+
+ @Override
+ public String toString() {
+ return "invoker :" + this.invoker + ",directory: " + this.directory;
+ }
+}
diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
index cfe8cece56..8aa23065c0 100644
--- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
+++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterWrapper.java
@@ -1,42 +1,42 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support.wrapper;
-
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.cluster.Cluster;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-/**
- * mock impl
- *
- */
-public class MockClusterWrapper implements Cluster {
-
- private Cluster cluster;
-
- public MockClusterWrapper(Cluster cluster) {
- this.cluster = cluster;
- }
-
- @Override
- public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
- return new MockClusterInvoker<T>(directory,
- this.cluster.join(directory));
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support.wrapper;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+/**
+ * mock impl
+ *
+ */
+public class MockClusterWrapper implements Cluster {
+
+ private Cluster cluster;
+
+ public MockClusterWrapper(Cluster cluster) {
+ this.cluster = cluster;
+ }
+
+ @Override
+ public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+ return new MockClusterInvoker<T>(directory,
+ this.cluster.join(directory));
+ }
+
+}
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
index ef212d70e8..257510748d 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Cluster
@@ -1,9 +1,9 @@
-mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
-failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
-failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
-failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
-failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
-forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
-available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
-mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
+mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
+failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
+failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
+failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
+failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
+forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
+available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
+mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory
index 000018773f..38597bd4c2 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.ConfiguratorFactory
@@ -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
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance
index 69e1cff2dc..b36a448c0f 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance
@@ -1,4 +1,4 @@
-random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
-roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
-leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
+random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
+roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
+leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
\ No newline at end of file
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger
index 699decf96f..e3aeabb6d4 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.Merger
@@ -1,11 +1,11 @@
-map=org.apache.dubbo.rpc.cluster.merger.MapMerger
-set=org.apache.dubbo.rpc.cluster.merger.SetMerger
-list=org.apache.dubbo.rpc.cluster.merger.ListMerger
-byte=org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger
-char=org.apache.dubbo.rpc.cluster.merger.CharArrayMerger
-short=org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger
-int=org.apache.dubbo.rpc.cluster.merger.IntArrayMerger
-long=org.apache.dubbo.rpc.cluster.merger.LongArrayMerger
-float=org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger
-double=org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger
-boolean=org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger
+map=org.apache.dubbo.rpc.cluster.merger.MapMerger
+set=org.apache.dubbo.rpc.cluster.merger.SetMerger
+list=org.apache.dubbo.rpc.cluster.merger.ListMerger
+byte=org.apache.dubbo.rpc.cluster.merger.ByteArrayMerger
+char=org.apache.dubbo.rpc.cluster.merger.CharArrayMerger
+short=org.apache.dubbo.rpc.cluster.merger.ShortArrayMerger
+int=org.apache.dubbo.rpc.cluster.merger.IntArrayMerger
+long=org.apache.dubbo.rpc.cluster.merger.LongArrayMerger
+float=org.apache.dubbo.rpc.cluster.merger.FloatArrayMerger
+double=org.apache.dubbo.rpc.cluster.merger.DoubleArrayMerger
+boolean=org.apache.dubbo.rpc.cluster.merger.BooleanArrayMerger
diff --git a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
index 0ada9c3be9..a1f6050d15 100644
--- a/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
+++ b/dubbo-cluster/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.RouterFactory
@@ -1,3 +1,3 @@
-file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
-script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
+file=org.apache.dubbo.rpc.cluster.router.file.FileRouterFactory
+script=org.apache.dubbo.rpc.cluster.router.script.ScriptRouterFactory
condition=org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java
index 9b3789d382..6520a94694 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/absent/AbsentConfiguratorTest.java
@@ -1,68 +1,68 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.absent;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * OverrideConfiguratorTest
- */
-public class AbsentConfiguratorTest {
-
-
- @Test
- public void testOverrideApplication() {
- 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));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
- Assert.assertEquals("1000", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
- Assert.assertNull(url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
- Assert.assertEquals("1000", url.getParameter("timeout"));
- }
-
- @Test
- public void testOverrideHost() {
- AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
-
- URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
- Assert.assertEquals("1000", url.getParameter("timeout"));
-
- AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf(UrlConstant.SERVICE_TIMEOUT_200));
-
- url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));
- Assert.assertNull(url.getParameter("timeout"));
-
- url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
- Assert.assertEquals("1000", url.getParameter("timeout"));
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.absent;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * OverrideConfiguratorTest
+ */
+public class AbsentConfiguratorTest {
+
+
+ @Test
+ public void testOverrideApplication() {
+ 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));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
+ Assert.assertNull(url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+ }
+
+ @Test
+ public void testOverrideHost() {
+ AbsentConfigurator configurator = new AbsentConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
+
+ URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+
+ AbsentConfigurator configurator1 = new AbsentConfigurator(URL.valueOf(UrlConstant.SERVICE_TIMEOUT_200));
+
+ url = configurator1.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_10));
+ Assert.assertNull(url.getParameter("timeout"));
+
+ url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+ }
+
+}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java
index 1f665ba4d1..29811df20c 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/configurator/override/OverrideConfiguratorTest.java
@@ -1,68 +1,68 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.configurator.override;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator;
-import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-/**
- * OverrideConfiguratorTest
- */
-public class OverrideConfiguratorTest {
-
- @Test
- public void testOverride_Application() {
- 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));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
- Assert.assertNull(url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
- Assert.assertEquals("1000", url.getParameter("timeout"));
- }
-
- @Test
- public void testOverride_Host() {
- OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
-
- URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
- Assert.assertEquals("200", url.getParameter("timeout"));
-
- 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));
- Assert.assertNull(url.getParameter("timeout"));
-
- url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
- Assert.assertEquals("1000", url.getParameter("timeout"));
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.configurator.override;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.cluster.configurator.absent.AbsentConfigurator;
+import org.apache.dubbo.rpc.cluster.configurator.consts.UrlConstant;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * OverrideConfiguratorTest
+ */
+public class OverrideConfiguratorTest {
+
+ @Test
+ public void testOverride_Application() {
+ 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));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.APPLICATION_BAR_SIDE_CONSUMER_11));
+ Assert.assertNull(url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_11));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+ }
+
+ @Test
+ public void testOverride_Host() {
+ OverrideConfigurator configurator = new OverrideConfigurator(URL.valueOf("override://" + NetUtils.getLocalHost() + "/com.foo.BarService?timeout=200"));
+
+ URL url = configurator.configure(URL.valueOf(UrlConstant.URL_CONSUMER));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ url = configurator.configure(URL.valueOf(UrlConstant.URL_ONE));
+ Assert.assertEquals("200", url.getParameter("timeout"));
+
+ 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));
+ Assert.assertNull(url.getParameter("timeout"));
+
+ url = configurator1.configure(URL.valueOf(UrlConstant.TIMEOUT_1000_SIDE_CONSUMER_10));
+ Assert.assertEquals("1000", url.getParameter("timeout"));
+ }
+
+}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoService.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoService.java
index 258b8c8b77..5d02e54f3b 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoService.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoService.java
@@ -1,27 +1,27 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.filter;
-
-/**
- * <code>TestService</code>
- */
-
-public interface DemoService {
- String sayHello(String name);
-
- int plus(int a, int b);
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.filter;
+
+/**
+ * <code>TestService</code>
+ */
+
+public interface DemoService {
+ String sayHello(String name);
+
+ int plus(int a, int b);
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceLocal.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceLocal.java
index e715ae6517..0652e723f9 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceLocal.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceLocal.java
@@ -1,43 +1,43 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.filter;
-
-/**
- * <code>TestService</code>
- */
-
-public class DemoServiceLocal implements DemoService {
-
- public DemoServiceLocal(DemoService demoService) {
- }
-
- public String sayHello(String name) {
- return name;
- }
-
- public int plus(int a, int b) {
- return a + b;
- }
-
- public void ondisconnect() {
-
- }
-
- public void onconnect() {
-
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.filter;
+
+/**
+ * <code>TestService</code>
+ */
+
+public class DemoServiceLocal implements DemoService {
+
+ public DemoServiceLocal(DemoService demoService) {
+ }
+
+ public String sayHello(String name) {
+ return name;
+ }
+
+ public int plus(int a, int b) {
+ return a + b;
+ }
+
+ public void ondisconnect() {
+
+ }
+
+ public void onconnect() {
+
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceMock.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceMock.java
index f888a1c02f..53d4f2dc6f 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceMock.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceMock.java
@@ -1,31 +1,31 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.filter;
-
-/**
- * MockService.java
- *
- */
-public class DemoServiceMock implements DemoService {
- public String sayHello(String name) {
- return name;
- }
-
- public int plus(int a, int b) {
- return a + b;
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.filter;
+
+/**
+ * MockService.java
+ *
+ */
+public class DemoServiceMock implements DemoService {
+ public String sayHello(String name) {
+ return name;
+ }
+
+ public int plus(int a, int b) {
+ return a + b;
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceStub.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceStub.java
index 02fda0aa0f..3a834b9621 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceStub.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/DemoServiceStub.java
@@ -1,35 +1,35 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.filter;
-
-/**
- * <code>TestService</code>
- */
-
-public class DemoServiceStub implements DemoService {
-
- public DemoServiceStub(DemoService demoService) {
- }
-
- public String sayHello(String name) {
- return name;
- }
-
- public int plus(int a, int b) {
- return a + b;
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.filter;
+
+/**
+ * <code>TestService</code>
+ */
+
+public class DemoServiceStub implements DemoService {
+
+ public DemoServiceStub(DemoService demoService) {
+ }
+
+ public String sayHello(String name) {
+ return name;
+ }
+
+ public int plus(int a, int b) {
+ return a + b;
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockService.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockService.java
index e01d9a4fff..4546a641ed 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockService.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/filter/MockService.java
@@ -1,31 +1,31 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.filter;
-
-/**
- * MockService.java
- *
- */
-public class MockService implements DemoService {
- public String sayHello(String name) {
- return name;
- }
-
- public int plus(int a, int b) {
- return a + b;
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.filter;
+
+/**
+ * MockService.java
+ *
+ */
+public class MockService implements DemoService {
+ public String sayHello(String name) {
+ return name;
+ }
+
+ public int plus(int a, int b) {
+ return a + b;
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
index 0a4ba90243..c0c200cc71 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/router/condition/ConditionRouterTest.java
@@ -1,308 +1,308 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.router.condition;
-
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.cluster.Router;
-import org.apache.dubbo.rpc.cluster.router.MockInvoker;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class ConditionRouterTest {
-
- private URL SCRIPT_URL = URL.valueOf("condition://0.0.0.0/com.foo.BarService");
-
- @BeforeClass
- public static void setUpBeforeClass() throws Exception {
- }
-
- @Before
- public void setUp() throws Exception {
- }
-
- private URL getRouteUrl(String rule) {
- return SCRIPT_URL.addParameterAndEncoded(Constants.RULE_KEY, rule);
- }
-
- @Test
- public void testRoute_matchWhen() {
- Invocation invocation = new RpcInvocation();
-
- 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);
- Assert.assertEquals(true, matchWhen);
-
- 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);
- Assert.assertEquals(true, 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"));
- matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
- Assert.assertEquals(false, 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"));
- matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
- Assert.assertEquals(true, 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"));
- matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
- Assert.assertEquals(true, 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"));
- matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
- Assert.assertEquals(false, 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"));
- matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
- Assert.assertEquals(true, matchWhen);
- }
-
- @Test
- public void testRoute_matchFilter() {
- 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?default.serialization=fastjson"));
- Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
- + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
- + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
-
- Router router1 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.3").addParameter(Constants.FORCE_KEY,
- String.valueOf(true)));
- Router router2 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.* & host != 10.20.3.3").addParameter(
- Constants.FORCE_KEY, String.valueOf(true)));
- Router router3 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.3 & host != 10.20.3.3").addParameter(
- Constants.FORCE_KEY, String.valueOf(true)));
- Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.2,10.20.3.3,10.20.3.4").addParameter(
- Constants.FORCE_KEY, String.valueOf(true)));
- Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " host != 10.20.3.3").addParameter(Constants.FORCE_KEY,
- String.valueOf(true)));
- Router router6 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " => " + " serialization = fastjson").addParameter(
- Constants.FORCE_KEY, String.valueOf(true)));
-
- List<Invoker<String>> filteredInvokers1 = router1.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- List<Invoker<String>> filteredInvokers2 = router2.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- List<Invoker<String>> filteredInvokers3 = router3.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- List<Invoker<String>> filteredInvokers4 = router4.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- List<Invoker<String>> filteredInvokers5 = router5.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- List<Invoker<String>> filteredInvokers6 = router6.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(1, filteredInvokers1.size());
- Assert.assertEquals(0, filteredInvokers2.size());
- Assert.assertEquals(0, filteredInvokers3.size());
- Assert.assertEquals(1, filteredInvokers4.size());
- Assert.assertEquals(2, filteredInvokers5.size());
- Assert.assertEquals(1, filteredInvokers6.size());
- }
-
- @Test
- public void testRoute_methodRoute() {
- Invocation invocation = new RpcInvocation("getFoo", new Class<?>[0], new Object[0]);
- // More than one methods, mismatch
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("methods=getFoo => host = 1.2.3.4"));
- boolean matchWhen = ((ConditionRouter) router).matchWhen(
- URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo"), invocation);
- Assert.assertEquals(true, matchWhen);
- // Exactly one method, match
- matchWhen = ((ConditionRouter) router).matchWhen(
- URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
- Assert.assertEquals(true, matchWhen);
- // Method routing and Other condition routing can work together
- Router router2 = new ConditionRouterFactory()
- .getRouter(getRouteUrl("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"));
- matchWhen = ((ConditionRouter) router2).matchWhen(
- URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
- Assert.assertEquals(false, matchWhen);
-
- Router router3 = new ConditionRouterFactory()
- .getRouter(getRouteUrl("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"));
- matchWhen = ((ConditionRouter) router3).matchWhen(
- URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
- Assert.assertEquals(true, matchWhen);
- // Test filter condition
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
- + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
- + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
-
- Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " & methods = getFoo => " + " host = 10.20.3.3").addParameter(
- Constants.FORCE_KEY, String.valueOf(true)));
- List<Invoker<String>> filteredInvokers1 = router4.route(invokers,
- URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), invocation);
- Assert.assertEquals(1, filteredInvokers1.size());
-
- Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
- "host = " + NetUtils.getLocalHost() + " & methods = unvalidmethod => " + " host = 10.20.3.3")
- .addParameter(Constants.FORCE_KEY, String.valueOf(true)));
- List<Invoker<String>> filteredInvokers2 = router5.route(invokers,
- URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), invocation);
- Assert.assertEquals(3, filteredInvokers2.size());
- // Request a non-exists method
- }
-
- @Test
- public void testRoute_ReturnFalse() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => false"));
- List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(0, filteredInvokers.size());
- }
-
- @Test
- public void testRoute_ReturnEmpty() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => "));
- List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(0, filteredInvokers.size());
- }
-
- @Test
- public void testRoute_ReturnAll() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = " + NetUtils.getLocalHost()));
- List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(invokers, filteredInvokers);
- }
-
- @Test
- public void testRoute_HostFilter() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = " + NetUtils.getLocalHost()));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(2, filteredInvokers.size());
- Assert.assertEquals(invoker2, filteredInvokers.get(0));
- Assert.assertEquals(invoker3, filteredInvokers.get(1));
- }
-
- @Test
- public void testRoute_Empty_HostFilter() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => " + " host = " + NetUtils.getLocalHost()));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(2, filteredInvokers.size());
- Assert.assertEquals(invoker2, filteredInvokers.get(0));
- Assert.assertEquals(invoker3, filteredInvokers.get(1));
- }
-
- @Test
- public void testRoute_False_HostFilter() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("true => " + " host = " + NetUtils.getLocalHost()));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(2, filteredInvokers.size());
- Assert.assertEquals(invoker2, filteredInvokers.get(0));
- Assert.assertEquals(invoker3, filteredInvokers.get(1));
- }
-
- @Test
- public void testRoute_Placeholder() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = $host"));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(2, filteredInvokers.size());
- Assert.assertEquals(invoker2, filteredInvokers.get(0));
- Assert.assertEquals(invoker3, filteredInvokers.get(1));
- }
-
- @Test
- public void testRoute_NoForce() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = 1.2.3.4"));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(invokers, filteredInvokers);
- }
-
- @Test
- public void testRoute_Force() {
- Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = 1.2.3.4").addParameter(Constants.FORCE_KEY, String.valueOf(true)));
- 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
- List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
- Assert.assertEquals(0, filteredInvokers.size());
- }
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.router.condition;
+
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.cluster.Router;
+import org.apache.dubbo.rpc.cluster.router.MockInvoker;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConditionRouterTest {
+
+ private URL SCRIPT_URL = URL.valueOf("condition://0.0.0.0/com.foo.BarService");
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ private URL getRouteUrl(String rule) {
+ return SCRIPT_URL.addParameterAndEncoded(Constants.RULE_KEY, rule);
+ }
+
+ @Test
+ public void testRoute_matchWhen() {
+ Invocation invocation = new RpcInvocation();
+
+ 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);
+ Assert.assertEquals(true, matchWhen);
+
+ 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);
+ Assert.assertEquals(true, 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"));
+ matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
+ Assert.assertEquals(false, 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"));
+ matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
+ Assert.assertEquals(true, 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"));
+ matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
+ Assert.assertEquals(true, 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"));
+ matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
+ Assert.assertEquals(false, 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"));
+ matchWhen = ((ConditionRouter) router).matchWhen(URL.valueOf("consumer://1.1.1.1/com.foo.BarService"), invocation);
+ Assert.assertEquals(true, matchWhen);
+ }
+
+ @Test
+ public void testRoute_matchFilter() {
+ 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?default.serialization=fastjson"));
+ Invoker<String> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
+ + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
+ + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+
+ Router router1 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.3").addParameter(Constants.FORCE_KEY,
+ String.valueOf(true)));
+ Router router2 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.* & host != 10.20.3.3").addParameter(
+ Constants.FORCE_KEY, String.valueOf(true)));
+ Router router3 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.3 & host != 10.20.3.3").addParameter(
+ Constants.FORCE_KEY, String.valueOf(true)));
+ Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " host = 10.20.3.2,10.20.3.3,10.20.3.4").addParameter(
+ Constants.FORCE_KEY, String.valueOf(true)));
+ Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " host != 10.20.3.3").addParameter(Constants.FORCE_KEY,
+ String.valueOf(true)));
+ Router router6 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " => " + " serialization = fastjson").addParameter(
+ Constants.FORCE_KEY, String.valueOf(true)));
+
+ List<Invoker<String>> filteredInvokers1 = router1.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ List<Invoker<String>> filteredInvokers2 = router2.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ List<Invoker<String>> filteredInvokers3 = router3.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ List<Invoker<String>> filteredInvokers4 = router4.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ List<Invoker<String>> filteredInvokers5 = router5.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ List<Invoker<String>> filteredInvokers6 = router6.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(1, filteredInvokers1.size());
+ Assert.assertEquals(0, filteredInvokers2.size());
+ Assert.assertEquals(0, filteredInvokers3.size());
+ Assert.assertEquals(1, filteredInvokers4.size());
+ Assert.assertEquals(2, filteredInvokers5.size());
+ Assert.assertEquals(1, filteredInvokers6.size());
+ }
+
+ @Test
+ public void testRoute_methodRoute() {
+ Invocation invocation = new RpcInvocation("getFoo", new Class<?>[0], new Object[0]);
+ // More than one methods, mismatch
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("methods=getFoo => host = 1.2.3.4"));
+ boolean matchWhen = ((ConditionRouter) router).matchWhen(
+ URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=setFoo,getFoo,findFoo"), invocation);
+ Assert.assertEquals(true, matchWhen);
+ // Exactly one method, match
+ matchWhen = ((ConditionRouter) router).matchWhen(
+ URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
+ Assert.assertEquals(true, matchWhen);
+ // Method routing and Other condition routing can work together
+ Router router2 = new ConditionRouterFactory()
+ .getRouter(getRouteUrl("methods=getFoo & host!=1.1.1.1 => host = 1.2.3.4"));
+ matchWhen = ((ConditionRouter) router2).matchWhen(
+ URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
+ Assert.assertEquals(false, matchWhen);
+
+ Router router3 = new ConditionRouterFactory()
+ .getRouter(getRouteUrl("methods=getFoo & host=1.1.1.1 => host = 1.2.3.4"));
+ matchWhen = ((ConditionRouter) router3).matchWhen(
+ URL.valueOf("consumer://1.1.1.1/com.foo.BarService?methods=getFoo"), invocation);
+ Assert.assertEquals(true, matchWhen);
+ // Test filter condition
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
+ + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost()
+ + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+
+ Router router4 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " & methods = getFoo => " + " host = 10.20.3.3").addParameter(
+ Constants.FORCE_KEY, String.valueOf(true)));
+ List<Invoker<String>> filteredInvokers1 = router4.route(invokers,
+ URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), invocation);
+ Assert.assertEquals(1, filteredInvokers1.size());
+
+ Router router5 = new ConditionRouterFactory().getRouter(getRouteUrl(
+ "host = " + NetUtils.getLocalHost() + " & methods = unvalidmethod => " + " host = 10.20.3.3")
+ .addParameter(Constants.FORCE_KEY, String.valueOf(true)));
+ List<Invoker<String>> filteredInvokers2 = router5.route(invokers,
+ URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), invocation);
+ Assert.assertEquals(3, filteredInvokers2.size());
+ // Request a non-exists method
+ }
+
+ @Test
+ public void testRoute_ReturnFalse() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => false"));
+ List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(0, filteredInvokers.size());
+ }
+
+ @Test
+ public void testRoute_ReturnEmpty() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => "));
+ List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(0, filteredInvokers.size());
+ }
+
+ @Test
+ public void testRoute_ReturnAll() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = " + NetUtils.getLocalHost()));
+ List<Invoker<String>> invokers = new ArrayList<Invoker<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://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(invokers, filteredInvokers);
+ }
+
+ @Test
+ public void testRoute_HostFilter() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = " + NetUtils.getLocalHost()));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(2, filteredInvokers.size());
+ Assert.assertEquals(invoker2, filteredInvokers.get(0));
+ Assert.assertEquals(invoker3, filteredInvokers.get(1));
+ }
+
+ @Test
+ public void testRoute_Empty_HostFilter() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl(" => " + " host = " + NetUtils.getLocalHost()));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(2, filteredInvokers.size());
+ Assert.assertEquals(invoker2, filteredInvokers.get(0));
+ Assert.assertEquals(invoker3, filteredInvokers.get(1));
+ }
+
+ @Test
+ public void testRoute_False_HostFilter() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("true => " + " host = " + NetUtils.getLocalHost()));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(2, filteredInvokers.size());
+ Assert.assertEquals(invoker2, filteredInvokers.get(0));
+ Assert.assertEquals(invoker3, filteredInvokers.get(1));
+ }
+
+ @Test
+ public void testRoute_Placeholder() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = $host"));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(2, filteredInvokers.size());
+ Assert.assertEquals(invoker2, filteredInvokers.get(0));
+ Assert.assertEquals(invoker3, filteredInvokers.get(1));
+ }
+
+ @Test
+ public void testRoute_NoForce() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = 1.2.3.4"));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(invokers, filteredInvokers);
+ }
+
+ @Test
+ public void testRoute_Force() {
+ Router router = new ConditionRouterFactory().getRouter(getRouteUrl("host = " + NetUtils.getLocalHost() + " => " + " host = 1.2.3.4").addParameter(Constants.FORCE_KEY, String.valueOf(true)));
+ 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> invoker2 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ Invoker<String> invoker3 = new MockInvoker<String>(URL.valueOf("dubbo://" + NetUtils.getLocalHost() + ":20880/com.foo.BarService"));
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+ List<Invoker<String>> filteredInvokers = router.route(invokers, URL.valueOf("consumer://" + NetUtils.getLocalHost() + "/com.foo.BarService"), new RpcInvocation());
+ Assert.assertEquals(0, filteredInvokers.size());
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
index fa9ac1a868..7b0c8bb57e 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailSafeClusterInvokerTest.java
@@ -1,120 +1,120 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.LogUtil;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.filter.DemoService;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-/**
- * FailfastClusterInvokerTest
- *
- */
-@SuppressWarnings("unchecked")
-public class FailSafeClusterInvokerTest {
- List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
- URL url = URL.valueOf("test://test:11/test");
- Invoker<DemoService> invoker = mock(Invoker.class);
- RpcInvocation invocation = new RpcInvocation();
- Directory<DemoService> dic;
- Result result = new RpcResult();
-
- /**
- * @throws java.lang.Exception
- */
-
- @Before
- public void setUp() throws Exception {
-
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(invokers);
- given(dic.getInterface()).willReturn(DemoService.class);
- invocation.setMethodName("method1");
-
- invokers.add(invoker);
- }
-
- private void resetInvokerToException() {
- given(invoker.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker.getUrl()).willReturn(url);
- given(invoker.getInterface()).willReturn(DemoService.class);
- }
-
- private void resetInvokerToNoException() {
- given(invoker.invoke(invocation)).willReturn(result);
- given(invoker.getUrl()).willReturn(url);
- given(invoker.getInterface()).willReturn(DemoService.class);
- }
-
- //TODO assert error log
- @Test
- public void testInvokeExceptoin() {
- resetInvokerToException();
- FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
- invoker.invoke(invocation);
- Assert.assertNull(RpcContext.getContext().getInvoker());
- }
-
- @Test()
- public void testInvokeNoExceptoin() {
-
- resetInvokerToNoException();
-
- FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
- Result ret = invoker.invoke(invocation);
- Assert.assertSame(result, ret);
- }
-
- @Test()
- public void testNoInvoke() {
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(null);
- given(dic.getInterface()).willReturn(DemoService.class);
-
- invocation.setMethodName("method1");
-
- resetInvokerToNoException();
-
- FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
- LogUtil.start();
- invoker.invoke(invocation);
- assertTrue(LogUtil.findMessage("No provider") > 0);
- LogUtil.stop();
- }
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.LogUtil;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.filter.DemoService;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * FailfastClusterInvokerTest
+ *
+ */
+@SuppressWarnings("unchecked")
+public class FailSafeClusterInvokerTest {
+ List<Invoker<DemoService>> invokers = new ArrayList<Invoker<DemoService>>();
+ URL url = URL.valueOf("test://test:11/test");
+ Invoker<DemoService> invoker = mock(Invoker.class);
+ RpcInvocation invocation = new RpcInvocation();
+ Directory<DemoService> dic;
+ Result result = new RpcResult();
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @Before
+ public void setUp() throws Exception {
+
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(invokers);
+ given(dic.getInterface()).willReturn(DemoService.class);
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker);
+ }
+
+ private void resetInvokerToException() {
+ given(invoker.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker.getUrl()).willReturn(url);
+ given(invoker.getInterface()).willReturn(DemoService.class);
+ }
+
+ private void resetInvokerToNoException() {
+ given(invoker.invoke(invocation)).willReturn(result);
+ given(invoker.getUrl()).willReturn(url);
+ given(invoker.getInterface()).willReturn(DemoService.class);
+ }
+
+ //TODO assert error log
+ @Test
+ public void testInvokeExceptoin() {
+ resetInvokerToException();
+ FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
+ invoker.invoke(invocation);
+ Assert.assertNull(RpcContext.getContext().getInvoker());
+ }
+
+ @Test()
+ public void testInvokeNoExceptoin() {
+
+ resetInvokerToNoException();
+
+ FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
+ Result ret = invoker.invoke(invocation);
+ Assert.assertSame(result, ret);
+ }
+
+ @Test()
+ public void testNoInvoke() {
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(null);
+ given(dic.getInterface()).willReturn(DemoService.class);
+
+ invocation.setMethodName("method1");
+
+ resetInvokerToNoException();
+
+ FailsafeClusterInvoker<DemoService> invoker = new FailsafeClusterInvoker<DemoService>(dic);
+ LogUtil.start();
+ invoker.invoke(invocation);
+ assertTrue(LogUtil.findMessage("No provider") > 0);
+ LogUtil.stop();
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
index 42a4ec6eba..9f6c83f0fd 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java
@@ -1,132 +1,132 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.utils.LogUtil;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcContext;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-@SuppressWarnings("unchecked")
-public class FailbackClusterInvokerTest {
-
- List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
- URL url = URL.valueOf("test://test:11/test");
- Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class);
- RpcInvocation invocation = new RpcInvocation();
- Directory<FailbackClusterInvokerTest> dic;
- Result result = new RpcResult();
-
- /**
- * @throws java.lang.Exception
- */
-
- @Before
- public void setUp() throws Exception {
-
- dic = mock(Directory.class);
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(invokers);
- given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
-
- invocation.setMethodName("method1");
-
- invokers.add(invoker);
- }
-
- private void resetInvokerToException() {
- given(invoker.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker.getUrl()).willReturn(url);
- given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
- }
-
- private void resetInvokerToNoException() {
- given(invoker.invoke(invocation)).willReturn(result);
- given(invoker.getUrl()).willReturn(url);
- given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
- }
-
- @Test
- public void testInvokeExceptoin() {
- resetInvokerToException();
- FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
- dic);
- invoker.invoke(invocation);
- Assert.assertNull(RpcContext.getContext().getInvoker());
- }
-
- @Test()
- public void testInvokeNoExceptoin() {
-
- resetInvokerToNoException();
-
- FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
- dic);
- Result ret = invoker.invoke(invocation);
- Assert.assertSame(result, ret);
- }
-
- @Test()
- public void testNoInvoke() {
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(null);
- given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
-
- invocation.setMethodName("method1");
-
- invokers.add(invoker);
-
- resetInvokerToNoException();
-
- FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
- dic);
- LogUtil.start();
- invoker.invoke(invocation);
- assertEquals(1, LogUtil.findMessage("Failback to invoke"));
- LogUtil.stop();
- }
-
- @Test()
- public void testRetryFailed() {
-
- resetInvokerToException();
-
- FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
- dic);
- invoker.invoke(invocation);
- Assert.assertNull(RpcContext.getContext().getInvoker());
- invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so
- // it can be invoke successfully
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.LogUtil;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+@SuppressWarnings("unchecked")
+public class FailbackClusterInvokerTest {
+
+ List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
+ URL url = URL.valueOf("test://test:11/test");
+ Invoker<FailbackClusterInvokerTest> invoker = mock(Invoker.class);
+ RpcInvocation invocation = new RpcInvocation();
+ Directory<FailbackClusterInvokerTest> dic;
+ Result result = new RpcResult();
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @Before
+ public void setUp() throws Exception {
+
+ dic = mock(Directory.class);
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(invokers);
+ given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
+
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker);
+ }
+
+ private void resetInvokerToException() {
+ given(invoker.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker.getUrl()).willReturn(url);
+ given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
+ }
+
+ private void resetInvokerToNoException() {
+ given(invoker.invoke(invocation)).willReturn(result);
+ given(invoker.getUrl()).willReturn(url);
+ given(invoker.getInterface()).willReturn(FailbackClusterInvokerTest.class);
+ }
+
+ @Test
+ public void testInvokeExceptoin() {
+ resetInvokerToException();
+ FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
+ dic);
+ invoker.invoke(invocation);
+ Assert.assertNull(RpcContext.getContext().getInvoker());
+ }
+
+ @Test()
+ public void testInvokeNoExceptoin() {
+
+ resetInvokerToNoException();
+
+ FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
+ dic);
+ Result ret = invoker.invoke(invocation);
+ Assert.assertSame(result, ret);
+ }
+
+ @Test()
+ public void testNoInvoke() {
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(null);
+ given(dic.getInterface()).willReturn(FailbackClusterInvokerTest.class);
+
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker);
+
+ resetInvokerToNoException();
+
+ FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
+ dic);
+ LogUtil.start();
+ invoker.invoke(invocation);
+ assertEquals(1, LogUtil.findMessage("Failback to invoke"));
+ LogUtil.stop();
+ }
+
+ @Test()
+ public void testRetryFailed() {
+
+ resetInvokerToException();
+
+ FailbackClusterInvoker<FailbackClusterInvokerTest> invoker = new FailbackClusterInvoker<FailbackClusterInvokerTest>(
+ dic);
+ invoker.invoke(invocation);
+ Assert.assertNull(RpcContext.getContext().getInvoker());
+ invoker.retryFailed();// when retry the invoker which get from failed map already is not the mocked invoker,so
+ // it can be invoke successfully
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
index 28ba182974..7fcc30c262 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailoverClusterInvokerTest.java
@@ -1,260 +1,260 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.protocol.AbstractInvoker;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-/**
- * FailoverClusterInvokerTest
- *
- */
-@SuppressWarnings("unchecked")
-public class FailoverClusterInvokerTest {
- private List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>();
- private int retries = 5;
- private URL url = URL.valueOf("test://test:11/test?retries=" + retries);
- private Invoker<FailoverClusterInvokerTest> invoker1 = mock(Invoker.class);
- private Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class);
- private RpcInvocation invocation = new RpcInvocation();
- private Directory<FailoverClusterInvokerTest> dic;
- private Result result = new RpcResult();
-
- /**
- * @throws java.lang.Exception
- */
-
- @Before
- public void setUp() throws Exception {
-
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(invokers);
- given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
- invocation.setMethodName("method1");
-
- invokers.add(invoker1);
- invokers.add(invoker2);
- }
-
-
- @Test
- public void testInvokeWithRuntimeException() {
- given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker1.isAvailable()).willReturn(true);
- given(invoker1.getUrl()).willReturn(url);
- given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker2.isAvailable()).willReturn(true);
- given(invoker2.getUrl()).willReturn(url);
- given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
- try {
- invoker.invoke(invocation);
- fail();
- } catch (RpcException expected) {
- assertEquals(0, expected.getCode());
- assertFalse(expected.getCause() instanceof RpcException);
- }
- }
-
- @Test()
- public void testInvokeWithRPCException() {
- given(invoker1.invoke(invocation)).willThrow(new RpcException());
- given(invoker1.isAvailable()).willReturn(true);
- given(invoker1.getUrl()).willReturn(url);
- given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- given(invoker2.invoke(invocation)).willReturn(result);
- given(invoker2.isAvailable()).willReturn(true);
- given(invoker2.getUrl()).willReturn(url);
- given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
- for (int i = 0; i < 100; i++) {
- Result ret = invoker.invoke(invocation);
- assertSame(result, ret);
- }
- }
-
- @Test()
- public void testInvoke_retryTimes() {
- given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));
- given(invoker1.isAvailable()).willReturn(false);
- given(invoker1.getUrl()).willReturn(url);
- given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- given(invoker2.invoke(invocation)).willThrow(new RpcException());
- given(invoker2.isAvailable()).willReturn(false);
- given(invoker2.getUrl()).willReturn(url);
- given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
-
- FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
- try {
- Result ret = invoker.invoke(invocation);
- assertSame(result, ret);
- fail();
- } catch (RpcException expected) {
- assertTrue((expected.isTimeout() || expected.getCode() == 0));
- assertTrue(expected.getMessage().indexOf((retries + 1) + " times") > 0);
- }
- }
-
- @Test()
- public void testNoInvoke() {
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(null);
- given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
- invocation.setMethodName("method1");
-
- invokers.add(invoker1);
-
-
- FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
- try {
- invoker.invoke(invocation);
- fail();
- } catch (RpcException expected) {
- assertFalse(expected.getCause() instanceof RpcException);
- }
- }
-
- /**
- * 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.
- */
- @Test
- public void testInvokerDestoryAndReList() {
- final URL url = URL.valueOf("test://localhost/" + Demo.class.getName() + "?loadbalance=roundrobin&retries=" + retries);
- RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);
- MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url);
- invoker1.setException(exception);
-
- MockInvoker<Demo> invoker2 = new MockInvoker<Demo>(Demo.class, url);
- invoker2.setException(exception);
-
- final List<Invoker<Demo>> invokers = new ArrayList<Invoker<Demo>>();
- invokers.add(invoker1);
- invokers.add(invoker2);
-
- Callable<Object> callable = new Callable<Object>() {
- public Object call() throws Exception {
- //Simulation: all invokers are destroyed
- for (Invoker<Demo> invoker : invokers) {
- invoker.destroy();
- }
- invokers.clear();
- MockInvoker<Demo> invoker3 = new MockInvoker<Demo>(Demo.class, url);
- invokers.add(invoker3);
- return null;
- }
- };
- invoker1.setCallable(callable);
- invoker2.setCallable(callable);
-
- RpcInvocation inv = new RpcInvocation();
- inv.setMethodName("test");
-
- Directory<Demo> dic = new MockDirectory<Demo>(url, invokers);
-
- FailoverClusterInvoker<Demo> clusterinvoker = new FailoverClusterInvoker<Demo>(dic);
- clusterinvoker.invoke(inv);
- }
-
- public static interface Demo {
- }
-
- public static class MockInvoker<T> extends AbstractInvoker<T> {
- URL url;
- boolean available = true;
- boolean destoryed = false;
- Result result;
- RpcException exception;
- Callable<?> callable;
-
- public MockInvoker(Class<T> type, URL url) {
- super(type, url);
- }
-
- public void setResult(Result result) {
- this.result = result;
- }
-
- public void setException(RpcException exception) {
- this.exception = exception;
- }
-
- public void setCallable(Callable<?> callable) {
- this.callable = callable;
- }
-
- @Override
- protected Result doInvoke(Invocation invocation) throws Throwable {
- if (callable != null) {
- try {
- callable.call();
- } catch (Exception e) {
- throw new RpcException(e);
- }
- }
- if (exception != null) {
- throw exception;
- } else {
- return result;
- }
- }
- }
-
- public class MockDirectory<T> extends StaticDirectory<T> {
- public MockDirectory(URL url, List<Invoker<T>> invokers) {
- super(url, invokers);
- }
-
- @Override
- protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
- return new ArrayList<Invoker<T>>(super.doList(invocation));
- }
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
+import org.apache.dubbo.rpc.protocol.AbstractInvoker;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * FailoverClusterInvokerTest
+ *
+ */
+@SuppressWarnings("unchecked")
+public class FailoverClusterInvokerTest {
+ private List<Invoker<FailoverClusterInvokerTest>> invokers = new ArrayList<Invoker<FailoverClusterInvokerTest>>();
+ private int retries = 5;
+ private URL url = URL.valueOf("test://test:11/test?retries=" + retries);
+ private Invoker<FailoverClusterInvokerTest> invoker1 = mock(Invoker.class);
+ private Invoker<FailoverClusterInvokerTest> invoker2 = mock(Invoker.class);
+ private RpcInvocation invocation = new RpcInvocation();
+ private Directory<FailoverClusterInvokerTest> dic;
+ private Result result = new RpcResult();
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @Before
+ public void setUp() throws Exception {
+
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(invokers);
+ given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ }
+
+
+ @Test
+ public void testInvokeWithRuntimeException() {
+ given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker1.isAvailable()).willReturn(true);
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker2.isAvailable()).willReturn(true);
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
+ try {
+ invoker.invoke(invocation);
+ fail();
+ } catch (RpcException expected) {
+ assertEquals(0, expected.getCode());
+ assertFalse(expected.getCause() instanceof RpcException);
+ }
+ }
+
+ @Test()
+ public void testInvokeWithRPCException() {
+ given(invoker1.invoke(invocation)).willThrow(new RpcException());
+ given(invoker1.isAvailable()).willReturn(true);
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willReturn(result);
+ given(invoker2.isAvailable()).willReturn(true);
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
+ for (int i = 0; i < 100; i++) {
+ Result ret = invoker.invoke(invocation);
+ assertSame(result, ret);
+ }
+ }
+
+ @Test()
+ public void testInvoke_retryTimes() {
+ given(invoker1.invoke(invocation)).willThrow(new RpcException(RpcException.TIMEOUT_EXCEPTION));
+ given(invoker1.isAvailable()).willReturn(false);
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willThrow(new RpcException());
+ given(invoker2.isAvailable()).willReturn(false);
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+
+ FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
+ try {
+ Result ret = invoker.invoke(invocation);
+ assertSame(result, ret);
+ fail();
+ } catch (RpcException expected) {
+ assertTrue((expected.isTimeout() || expected.getCode() == 0));
+ assertTrue(expected.getMessage().indexOf((retries + 1) + " times") > 0);
+ }
+ }
+
+ @Test()
+ public void testNoInvoke() {
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(null);
+ given(dic.getInterface()).willReturn(FailoverClusterInvokerTest.class);
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker1);
+
+
+ FailoverClusterInvoker<FailoverClusterInvokerTest> invoker = new FailoverClusterInvoker<FailoverClusterInvokerTest>(dic);
+ try {
+ invoker.invoke(invocation);
+ fail();
+ } catch (RpcException expected) {
+ assertFalse(expected.getCause() instanceof RpcException);
+ }
+ }
+
+ /**
+ * 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.
+ */
+ @Test
+ public void testInvokerDestoryAndReList() {
+ final URL url = URL.valueOf("test://localhost/" + Demo.class.getName() + "?loadbalance=roundrobin&retries=" + retries);
+ RpcException exception = new RpcException(RpcException.TIMEOUT_EXCEPTION);
+ MockInvoker<Demo> invoker1 = new MockInvoker<Demo>(Demo.class, url);
+ invoker1.setException(exception);
+
+ MockInvoker<Demo> invoker2 = new MockInvoker<Demo>(Demo.class, url);
+ invoker2.setException(exception);
+
+ final List<Invoker<Demo>> invokers = new ArrayList<Invoker<Demo>>();
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+
+ Callable<Object> callable = new Callable<Object>() {
+ public Object call() throws Exception {
+ //Simulation: all invokers are destroyed
+ for (Invoker<Demo> invoker : invokers) {
+ invoker.destroy();
+ }
+ invokers.clear();
+ MockInvoker<Demo> invoker3 = new MockInvoker<Demo>(Demo.class, url);
+ invokers.add(invoker3);
+ return null;
+ }
+ };
+ invoker1.setCallable(callable);
+ invoker2.setCallable(callable);
+
+ RpcInvocation inv = new RpcInvocation();
+ inv.setMethodName("test");
+
+ Directory<Demo> dic = new MockDirectory<Demo>(url, invokers);
+
+ FailoverClusterInvoker<Demo> clusterinvoker = new FailoverClusterInvoker<Demo>(dic);
+ clusterinvoker.invoke(inv);
+ }
+
+ public static interface Demo {
+ }
+
+ public static class MockInvoker<T> extends AbstractInvoker<T> {
+ URL url;
+ boolean available = true;
+ boolean destoryed = false;
+ Result result;
+ RpcException exception;
+ Callable<?> callable;
+
+ public MockInvoker(Class<T> type, URL url) {
+ super(type, url);
+ }
+
+ public void setResult(Result result) {
+ this.result = result;
+ }
+
+ public void setException(RpcException exception) {
+ this.exception = exception;
+ }
+
+ public void setCallable(Callable<?> callable) {
+ this.callable = callable;
+ }
+
+ @Override
+ protected Result doInvoke(Invocation invocation) throws Throwable {
+ if (callable != null) {
+ try {
+ callable.call();
+ } catch (Exception e) {
+ throw new RpcException(e);
+ }
+ }
+ if (exception != null) {
+ throw exception;
+ } else {
+ return result;
+ }
+ }
+ }
+
+ public class MockDirectory<T> extends StaticDirectory<T> {
+ public MockDirectory(URL url, List<Invoker<T>> invokers) {
+ super(url, invokers);
+ }
+
+ @Override
+ protected List<Invoker<T>> doList(Invocation invocation) throws RpcException {
+ return new ArrayList<Invoker<T>>(super.doList(invocation));
+ }
+ }
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
index 97dcbcd764..9f933caf90 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/ForkingClusterInvokerTest.java
@@ -1,134 +1,134 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support;
-
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.RpcResult;
-import org.apache.dubbo.rpc.cluster.Directory;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.junit.Assert.assertFalse;
-import static org.mockito.BDDMockito.given;
-import static org.mockito.Mockito.mock;
-
-/**
- * ForkingClusterInvokerTest
- *
- */
-@SuppressWarnings("unchecked")
-public class ForkingClusterInvokerTest {
-
- List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
- URL url = URL.valueOf("test://test:11/test?forks=2");
- Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
- Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
- Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
- RpcInvocation invocation = new RpcInvocation();
- Directory<ForkingClusterInvokerTest> dic;
- Result result = new RpcResult();
-
- /**
- * @throws java.lang.Exception
- */
-
- @Before
- public void setUp() throws Exception {
-
- dic = mock(Directory.class);
-
- given(dic.getUrl()).willReturn(url);
- given(dic.list(invocation)).willReturn(invokers);
- given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
-
- invocation.setMethodName("method1");
-
- invokers.add(invoker1);
- invokers.add(invoker2);
- invokers.add(invoker3);
-
- }
- private void resetInvokerToException() {
- given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker1.getUrl()).willReturn(url);
- given(invoker1.isAvailable()).willReturn(true);
- given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
-
- given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker2.getUrl()).willReturn(url);
- given(invoker2.isAvailable()).willReturn(true);
- given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
-
- given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
- given(invoker3.getUrl()).willReturn(url);
- given(invoker3.isAvailable()).willReturn(true);
- given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
- }
-
- private void resetInvokerToNoException() {
- given(invoker1.invoke(invocation)).willReturn(result);
- given(invoker1.getUrl()).willReturn(url);
- given(invoker1.isAvailable()).willReturn(true);
- given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
-
- given(invoker2.invoke(invocation)).willReturn(result);
- given(invoker2.getUrl()).willReturn(url);
- given(invoker2.isAvailable()).willReturn(true);
- given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
-
- given(invoker3.invoke(invocation)).willReturn(result);
- given(invoker3.getUrl()).willReturn(url);
- given(invoker3.isAvailable()).willReturn(true);
- given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
- }
-
- @Test
- public void testInvokeExceptoin() {
- resetInvokerToException();
- ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
- dic);
-
- try {
- invoker.invoke(invocation);
- Assert.fail();
- } catch (RpcException expected) {
- Assert.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
- assertFalse(expected.getCause() instanceof RpcException);
- }
- }
-
- @Test()
- public void testInvokeNoExceptoin() {
-
- resetInvokerToNoException();
-
- ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
- dic);
- Result ret = invoker.invoke(invocation);
- Assert.assertSame(result, ret);
- }
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.RpcResult;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+/**
+ * ForkingClusterInvokerTest
+ *
+ */
+@SuppressWarnings("unchecked")
+public class ForkingClusterInvokerTest {
+
+ List<Invoker<ForkingClusterInvokerTest>> invokers = new ArrayList<Invoker<ForkingClusterInvokerTest>>();
+ URL url = URL.valueOf("test://test:11/test?forks=2");
+ Invoker<ForkingClusterInvokerTest> invoker1 = mock(Invoker.class);
+ Invoker<ForkingClusterInvokerTest> invoker2 = mock(Invoker.class);
+ Invoker<ForkingClusterInvokerTest> invoker3 = mock(Invoker.class);
+ RpcInvocation invocation = new RpcInvocation();
+ Directory<ForkingClusterInvokerTest> dic;
+ Result result = new RpcResult();
+
+ /**
+ * @throws java.lang.Exception
+ */
+
+ @Before
+ public void setUp() throws Exception {
+
+ dic = mock(Directory.class);
+
+ given(dic.getUrl()).willReturn(url);
+ given(dic.list(invocation)).willReturn(invokers);
+ given(dic.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+
+ invocation.setMethodName("method1");
+
+ invokers.add(invoker1);
+ invokers.add(invoker2);
+ invokers.add(invoker3);
+
+ }
+ private void resetInvokerToException() {
+ given(invoker1.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.isAvailable()).willReturn(true);
+ given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.isAvailable()).willReturn(true);
+ given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+
+ given(invoker3.invoke(invocation)).willThrow(new RuntimeException());
+ given(invoker3.getUrl()).willReturn(url);
+ given(invoker3.isAvailable()).willReturn(true);
+ given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+ }
+
+ private void resetInvokerToNoException() {
+ given(invoker1.invoke(invocation)).willReturn(result);
+ given(invoker1.getUrl()).willReturn(url);
+ given(invoker1.isAvailable()).willReturn(true);
+ given(invoker1.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+
+ given(invoker2.invoke(invocation)).willReturn(result);
+ given(invoker2.getUrl()).willReturn(url);
+ given(invoker2.isAvailable()).willReturn(true);
+ given(invoker2.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+
+ given(invoker3.invoke(invocation)).willReturn(result);
+ given(invoker3.getUrl()).willReturn(url);
+ given(invoker3.isAvailable()).willReturn(true);
+ given(invoker3.getInterface()).willReturn(ForkingClusterInvokerTest.class);
+ }
+
+ @Test
+ public void testInvokeExceptoin() {
+ resetInvokerToException();
+ ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
+ dic);
+
+ try {
+ invoker.invoke(invocation);
+ Assert.fail();
+ } catch (RpcException expected) {
+ Assert.assertTrue(expected.getMessage().contains("Failed to forking invoke provider"));
+ assertFalse(expected.getCause() instanceof RpcException);
+ }
+ }
+
+ @Test()
+ public void testInvokeNoExceptoin() {
+
+ resetInvokerToNoException();
+
+ ForkingClusterInvoker<ForkingClusterInvokerTest> invoker = new ForkingClusterInvoker<ForkingClusterInvokerTest>(
+ dic);
+ Result ret = invoker.invoke(invocation);
+ Assert.assertSame(result, ret);
+ }
+
}
\ No newline at end of file
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
index 4893dc7337..6852244940 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MockClusterInvokerTest.java
@@ -1,799 +1,799 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support.wrapper;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.rpc.Invocation;
-import org.apache.dubbo.rpc.Invoker;
-import org.apache.dubbo.rpc.Protocol;
-import org.apache.dubbo.rpc.ProxyFactory;
-import org.apache.dubbo.rpc.Result;
-import org.apache.dubbo.rpc.RpcException;
-import org.apache.dubbo.rpc.RpcInvocation;
-import org.apache.dubbo.rpc.cluster.Directory;
-import org.apache.dubbo.rpc.cluster.LoadBalance;
-import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
-import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
-import org.apache.dubbo.rpc.support.MockProtocol;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class MockClusterInvokerTest {
-
- List<Invoker<IHelloService>> invokers = new ArrayList<Invoker<IHelloService>>();
-
- @Before
- public void beforeMethod() {
- invokers.clear();
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerInvoke_normal() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
- url = url.addParameter(Constants.MOCK_KEY, "fail");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
- + "?getSomething.mock=return aa");
-
- Protocol protocol = new MockProtocol();
- Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
- invokers.add(mInvoker1);
-
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("something", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerInvoke_failmock() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter(Constants.MOCK_KEY, "fail:return null")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
- + "?getSomething.mock=return aa").addParameters(url.getParameters());
-
- Protocol protocol = new MockProtocol();
- Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
- invokers.add(mInvoker1);
-
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("aa", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
-
- /**
- * Test if mock policy works fine: force-mock
- */
- @Test
- public void testMockInvokerInvoke_forcemock() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
- url = url.addParameter(Constants.MOCK_KEY, "force:return null");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
- + "?getSomething.mock=return aa&getSomething3xx.mock=return xx")
- .addParameters(url.getParameters());
-
- Protocol protocol = new MockProtocol();
- Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
- invokers.add(mInvoker1);
-
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("aa", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
- @Test
- public void testMockInvokerInvoke_forcemock_defaultreturn() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
- url = url.addParameter(Constants.MOCK_KEY, "force");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
- + "?getSomething.mock=return aa&getSomething3xx.mock=return xx&sayHello.mock=return ")
- .addParameters(url.getParameters());
-
- Protocol protocol = new MockProtocol();
- Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
- invokers.add(mInvoker1);
-
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_someMethods() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getSomething.mock", "fail:return x")
- .addParameter("getSomething2.mock", "force:return y");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("something", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("y", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("something3", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_WithOutDefault() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getSomething.mock", "fail:return x")
- .addParameter("getSomething2.mock", "force:return y")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("y", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- try {
- ret = cluster.invoke(invocation);
- Assert.fail();
- } catch (RpcException e) {
-
- }
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_WithDefault() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "fail:return null")
- .addParameter("getSomething.mock", "fail:return x")
- .addParameter("getSomething2.mock", "force:return y")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("y", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals(null, ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_WithFailDefault() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "fail:return z")
- .addParameter("getSomething.mock", "fail:return x")
- .addParameter("getSomething2.mock", "force:return y")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("y", ret.getValue());
-
- // If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("z", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("z", ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_WithForceDefault() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "force:return z")
- .addParameter("getSomething.mock", "fail:return x")
- .addParameter("getSomething2.mock", "force:return y")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("y", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("z", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("z", ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_Fock_Default() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "fail:return x")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething2");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("sayHello");
- ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_checkCompatible_return() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getSomething.mock", "return x")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("x", ret.getValue());
-
- //If no mock was configured, return null directly
- invocation = new RpcInvocation();
- invocation.setMethodName("getSomething3");
- try {
- ret = cluster.invoke(invocation);
- Assert.fail("fail invoke");
- } catch (RpcException e) {
-
- }
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "true")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("somethingmock", ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock2() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "fail")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("somethingmock", ret.getValue());
- }
-
- /**
- * Test if mock policy works fine: fail-mock
- */
- @Test
- public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock3() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "force");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals("somethingmock", ret.getValue());
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_check_String() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getSomething.mock", "force:return 1688")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getSomething");
- Result ret = cluster.invoke(invocation);
- Assert.assertTrue("result type must be String but was : " + ret.getValue().getClass(), ret.getValue() instanceof String);
- Assert.assertEquals("1688", (String) ret.getValue());
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_check_int() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getInt1.mock", "force:return 1688")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getInt1");
- Result ret = cluster.invoke(invocation);
- Assert.assertTrue("result type must be integer but was : " + ret.getValue().getClass(), ret.getValue() instanceof Integer);
- Assert.assertEquals(new Integer(1688), (Integer) ret.getValue());
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_check_boolean() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getBoolean1.mock", "force:return true")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean1");
- Result ret = cluster.invoke(invocation);
- Assert.assertTrue("result type must be Boolean but was : " + ret.getValue().getClass(), ret.getValue() instanceof Boolean);
- Assert.assertEquals(true, Boolean.parseBoolean(ret.getValue().toString()));
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_check_Boolean() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getBoolean2.mock", "force:return true")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean2");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals(true, Boolean.parseBoolean(ret.getValue().toString()));
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testMockInvokerFromOverride_Invoke_check_ListString_empty() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getListString.mock", "force:return empty")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getListString");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals(0, ((List<String>) ret.getValue()).size());
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testMockInvokerFromOverride_Invoke_check_ListString() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getListString.mock", "force:return [\"hi\",\"hi2\"]")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getListString");
- Result ret = cluster.invoke(invocation);
- List<String> rl = (List<String>) ret.getValue();
- Assert.assertEquals(2, rl.size());
- Assert.assertEquals("hi", rl.get(0));
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testMockInvokerFromOverride_Invoke_check_ListPojo_empty() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getUsers.mock", "force:return empty")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getUsers");
- Result ret = cluster.invoke(invocation);
- Assert.assertEquals(0, ((List<User>) ret.getValue()).size());
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void testMockInvokerFromOverride_Invoke_check_ListPojo() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getUsers.mock", "force:return [{id:1, name:\"hi1\"}, {id:2, name:\"hi2\"}]")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getUsers");
- Result ret = cluster.invoke(invocation);
- List<User> rl = (List<User>) ret.getValue();
- System.out.println(rl);
- Assert.assertEquals(2, rl.size());
- Assert.assertEquals("hi1", ((User) rl.get(0)).getName());
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_check_ListPojo_error() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getUsers.mock", "force:return [{id:x, name:\"hi1\"}]")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getUsers");
- try {
- cluster.invoke(invocation);
- } catch (RpcException e) {
- }
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_force_throw() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getBoolean2.mock", "force:throw ")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean2");
- try {
- cluster.invoke(invocation);
- Assert.fail();
- } catch (RpcException e) {
- Assert.assertFalse("not custem exception", e.isBiz());
- }
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_force_throwCustemException() throws Throwable {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getBoolean2.mock", "force:throw org.apache.dubbo.rpc.cluster.support.wrapper.MyMockException")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean2");
- try {
- cluster.invoke(invocation).recreate();
- Assert.fail();
- } catch (MyMockException e) {
-
- }
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_force_throwCustemExceptionNotFound() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("getBoolean2.mock", "force:throw java.lang.RuntimeException2")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean2");
- try {
- cluster.invoke(invocation);
- Assert.fail();
- } catch (Exception e) {
- Assert.assertTrue(e.getCause() instanceof IllegalStateException);
- }
- }
-
- @Test
- public void testMockInvokerFromOverride_Invoke_mock_false() {
- URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
- .addParameter("mock", "false")
- .addParameter("invoke_return_error", "true");
- Invoker<IHelloService> cluster = getClusterInvoker(url);
- //Configured with mock
- RpcInvocation invocation = new RpcInvocation();
- invocation.setMethodName("getBoolean2");
- try {
- cluster.invoke(invocation);
- Assert.fail();
- } catch (RpcException e) {
- Assert.assertTrue(e.isTimeout());
- }
- }
-
- @SuppressWarnings({"unchecked", "rawtypes"})
- private Invoker<IHelloService> getClusterInvoker(URL url) {
- // As `javassist` have a strict restriction of argument types, request will fail if Invocation do not contains complete parameter type information
- final URL durl = url.addParameter("proxy", "jdk");
- invokers.clear();
- ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension("jdk");
- Invoker<IHelloService> invoker1 = proxy.getInvoker(new HelloService(), IHelloService.class, durl);
- invokers.add(invoker1);
-
- Directory<IHelloService> dic = new StaticDirectory<IHelloService>(durl, invokers, null);
- AbstractClusterInvoker<IHelloService> cluster = new AbstractClusterInvoker(dic) {
- @Override
- protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
- throws RpcException {
- if (durl.getParameter("invoke_return_error", false)) {
- throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "test rpc exception");
- } else {
- return ((Invoker<?>) invokers.get(0)).invoke(invocation);
- }
- }
- };
- return new MockClusterInvoker<IHelloService>(dic, cluster);
- }
-
- public static interface IHelloService {
- String getSomething();
-
- String getSomething2();
-
- String getSomething3();
-
- int getInt1();
-
- boolean getBoolean1();
-
- Boolean getBoolean2();
-
- public List<String> getListString();
-
- public List<User> getUsers();
-
- void sayHello();
- }
-
- public static class HelloService implements IHelloService {
- public String getSomething() {
- return "something";
- }
-
- public String getSomething2() {
- return "something2";
- }
-
- public String getSomething3() {
- return "something3";
- }
-
- public int getInt1() {
- return 1;
- }
-
- public boolean getBoolean1() {
- return false;
- }
-
- public Boolean getBoolean2() {
- return Boolean.FALSE;
- }
-
- public List<String> getListString() {
- return Arrays.asList(new String[]{"Tom", "Jerry"});
- }
-
- public List<User> getUsers() {
- return Arrays.asList(new User[]{new User(1, "Tom"), new User(2, "Jerry")});
- }
-
- public void sayHello() {
- System.out.println("hello prety");
- }
- }
-
- public static class IHelloServiceMock implements IHelloService {
- public IHelloServiceMock() {
-
- }
-
- public String getSomething() {
- return "somethingmock";
- }
-
- public String getSomething2() {
- return "something2mock";
- }
-
- public String getSomething3() {
- return "something3mock";
- }
-
- public List<String> getListString() {
- return Arrays.asList(new String[]{"Tommock", "Jerrymock"});
- }
-
- public List<User> getUsers() {
- return Arrays.asList(new User[]{new User(1, "Tommock"), new User(2, "Jerrymock")});
- }
-
- public int getInt1() {
- return 1;
- }
-
- public boolean getBoolean1() {
- return false;
- }
-
- public Boolean getBoolean2() {
- return Boolean.FALSE;
- }
-
- public void sayHello() {
- System.out.println("hello prety");
- }
- }
-
- public static class User {
- private int id;
- private String name;
-
- public User() {
- }
-
- public User(int id, String name) {
- super();
- this.id = id;
- this.name = name;
- }
-
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support.wrapper;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.RpcInvocation;
+import org.apache.dubbo.rpc.cluster.Directory;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+import org.apache.dubbo.rpc.cluster.directory.StaticDirectory;
+import org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker;
+import org.apache.dubbo.rpc.support.MockProtocol;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MockClusterInvokerTest {
+
+ List<Invoker<IHelloService>> invokers = new ArrayList<Invoker<IHelloService>>();
+
+ @Before
+ public void beforeMethod() {
+ invokers.clear();
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerInvoke_normal() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
+ url = url.addParameter(Constants.MOCK_KEY, "fail");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
+ + "?getSomething.mock=return aa");
+
+ Protocol protocol = new MockProtocol();
+ Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
+ invokers.add(mInvoker1);
+
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("something", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerInvoke_failmock() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter(Constants.MOCK_KEY, "fail:return null")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
+ + "?getSomething.mock=return aa").addParameters(url.getParameters());
+
+ Protocol protocol = new MockProtocol();
+ Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
+ invokers.add(mInvoker1);
+
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("aa", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+
+ /**
+ * Test if mock policy works fine: force-mock
+ */
+ @Test
+ public void testMockInvokerInvoke_forcemock() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
+ url = url.addParameter(Constants.MOCK_KEY, "force:return null");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
+ + "?getSomething.mock=return aa&getSomething3xx.mock=return xx")
+ .addParameters(url.getParameters());
+
+ Protocol protocol = new MockProtocol();
+ Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
+ invokers.add(mInvoker1);
+
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("aa", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+ @Test
+ public void testMockInvokerInvoke_forcemock_defaultreturn() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName());
+ url = url.addParameter(Constants.MOCK_KEY, "force");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ URL mockUrl = URL.valueOf("mock://localhost/" + IHelloService.class.getName()
+ + "?getSomething.mock=return aa&getSomething3xx.mock=return xx&sayHello.mock=return ")
+ .addParameters(url.getParameters());
+
+ Protocol protocol = new MockProtocol();
+ Invoker<IHelloService> mInvoker1 = protocol.refer(IHelloService.class, mockUrl);
+ invokers.add(mInvoker1);
+
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_someMethods() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getSomething.mock", "fail:return x")
+ .addParameter("getSomething2.mock", "force:return y");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("something", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("y", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("something3", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_WithOutDefault() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getSomething.mock", "fail:return x")
+ .addParameter("getSomething2.mock", "force:return y")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("y", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ try {
+ ret = cluster.invoke(invocation);
+ Assert.fail();
+ } catch (RpcException e) {
+
+ }
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_WithDefault() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "fail:return null")
+ .addParameter("getSomething.mock", "fail:return x")
+ .addParameter("getSomething2.mock", "force:return y")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("y", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals(null, ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_WithFailDefault() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "fail:return z")
+ .addParameter("getSomething.mock", "fail:return x")
+ .addParameter("getSomething2.mock", "force:return y")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("y", ret.getValue());
+
+ // If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("z", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("z", ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_WithForceDefault() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "force:return z")
+ .addParameter("getSomething.mock", "fail:return x")
+ .addParameter("getSomething2.mock", "force:return y")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("y", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("z", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("z", ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_Fock_Default() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "fail:return x")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething2");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("sayHello");
+ ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_checkCompatible_return() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getSomething.mock", "return x")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("x", ret.getValue());
+
+ //If no mock was configured, return null directly
+ invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething3");
+ try {
+ ret = cluster.invoke(invocation);
+ Assert.fail("fail invoke");
+ } catch (RpcException e) {
+
+ }
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "true")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("somethingmock", ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock2() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "fail")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("somethingmock", ret.getValue());
+ }
+
+ /**
+ * Test if mock policy works fine: fail-mock
+ */
+ @Test
+ public void testMockInvokerFromOverride_Invoke_checkCompatible_ImplMock3() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "force");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals("somethingmock", ret.getValue());
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_String() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getSomething.mock", "force:return 1688")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getSomething");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertTrue("result type must be String but was : " + ret.getValue().getClass(), ret.getValue() instanceof String);
+ Assert.assertEquals("1688", (String) ret.getValue());
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_int() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getInt1.mock", "force:return 1688")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getInt1");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertTrue("result type must be integer but was : " + ret.getValue().getClass(), ret.getValue() instanceof Integer);
+ Assert.assertEquals(new Integer(1688), (Integer) ret.getValue());
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_boolean() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getBoolean1.mock", "force:return true")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean1");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertTrue("result type must be Boolean but was : " + ret.getValue().getClass(), ret.getValue() instanceof Boolean);
+ Assert.assertEquals(true, Boolean.parseBoolean(ret.getValue().toString()));
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_Boolean() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getBoolean2.mock", "force:return true")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean2");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals(true, Boolean.parseBoolean(ret.getValue().toString()));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_ListString_empty() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getListString.mock", "force:return empty")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getListString");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals(0, ((List<String>) ret.getValue()).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_ListString() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getListString.mock", "force:return [\"hi\",\"hi2\"]")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getListString");
+ Result ret = cluster.invoke(invocation);
+ List<String> rl = (List<String>) ret.getValue();
+ Assert.assertEquals(2, rl.size());
+ Assert.assertEquals("hi", rl.get(0));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_ListPojo_empty() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getUsers.mock", "force:return empty")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getUsers");
+ Result ret = cluster.invoke(invocation);
+ Assert.assertEquals(0, ((List<User>) ret.getValue()).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_ListPojo() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getUsers.mock", "force:return [{id:1, name:\"hi1\"}, {id:2, name:\"hi2\"}]")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getUsers");
+ Result ret = cluster.invoke(invocation);
+ List<User> rl = (List<User>) ret.getValue();
+ System.out.println(rl);
+ Assert.assertEquals(2, rl.size());
+ Assert.assertEquals("hi1", ((User) rl.get(0)).getName());
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_check_ListPojo_error() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getUsers.mock", "force:return [{id:x, name:\"hi1\"}]")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getUsers");
+ try {
+ cluster.invoke(invocation);
+ } catch (RpcException e) {
+ }
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_force_throw() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getBoolean2.mock", "force:throw ")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean2");
+ try {
+ cluster.invoke(invocation);
+ Assert.fail();
+ } catch (RpcException e) {
+ Assert.assertFalse("not custem exception", e.isBiz());
+ }
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_force_throwCustemException() throws Throwable {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getBoolean2.mock", "force:throw org.apache.dubbo.rpc.cluster.support.wrapper.MyMockException")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean2");
+ try {
+ cluster.invoke(invocation).recreate();
+ Assert.fail();
+ } catch (MyMockException e) {
+
+ }
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_force_throwCustemExceptionNotFound() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("getBoolean2.mock", "force:throw java.lang.RuntimeException2")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean2");
+ try {
+ cluster.invoke(invocation);
+ Assert.fail();
+ } catch (Exception e) {
+ Assert.assertTrue(e.getCause() instanceof IllegalStateException);
+ }
+ }
+
+ @Test
+ public void testMockInvokerFromOverride_Invoke_mock_false() {
+ URL url = URL.valueOf("remote://1.2.3.4/" + IHelloService.class.getName())
+ .addParameter("mock", "false")
+ .addParameter("invoke_return_error", "true");
+ Invoker<IHelloService> cluster = getClusterInvoker(url);
+ //Configured with mock
+ RpcInvocation invocation = new RpcInvocation();
+ invocation.setMethodName("getBoolean2");
+ try {
+ cluster.invoke(invocation);
+ Assert.fail();
+ } catch (RpcException e) {
+ Assert.assertTrue(e.isTimeout());
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ private Invoker<IHelloService> getClusterInvoker(URL url) {
+ // As `javassist` have a strict restriction of argument types, request will fail if Invocation do not contains complete parameter type information
+ final URL durl = url.addParameter("proxy", "jdk");
+ invokers.clear();
+ ProxyFactory proxy = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getExtension("jdk");
+ Invoker<IHelloService> invoker1 = proxy.getInvoker(new HelloService(), IHelloService.class, durl);
+ invokers.add(invoker1);
+
+ Directory<IHelloService> dic = new StaticDirectory<IHelloService>(durl, invokers, null);
+ AbstractClusterInvoker<IHelloService> cluster = new AbstractClusterInvoker(dic) {
+ @Override
+ protected Result doInvoke(Invocation invocation, List invokers, LoadBalance loadbalance)
+ throws RpcException {
+ if (durl.getParameter("invoke_return_error", false)) {
+ throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "test rpc exception");
+ } else {
+ return ((Invoker<?>) invokers.get(0)).invoke(invocation);
+ }
+ }
+ };
+ return new MockClusterInvoker<IHelloService>(dic, cluster);
+ }
+
+ public static interface IHelloService {
+ String getSomething();
+
+ String getSomething2();
+
+ String getSomething3();
+
+ int getInt1();
+
+ boolean getBoolean1();
+
+ Boolean getBoolean2();
+
+ public List<String> getListString();
+
+ public List<User> getUsers();
+
+ void sayHello();
+ }
+
+ public static class HelloService implements IHelloService {
+ public String getSomething() {
+ return "something";
+ }
+
+ public String getSomething2() {
+ return "something2";
+ }
+
+ public String getSomething3() {
+ return "something3";
+ }
+
+ public int getInt1() {
+ return 1;
+ }
+
+ public boolean getBoolean1() {
+ return false;
+ }
+
+ public Boolean getBoolean2() {
+ return Boolean.FALSE;
+ }
+
+ public List<String> getListString() {
+ return Arrays.asList(new String[]{"Tom", "Jerry"});
+ }
+
+ public List<User> getUsers() {
+ return Arrays.asList(new User[]{new User(1, "Tom"), new User(2, "Jerry")});
+ }
+
+ public void sayHello() {
+ System.out.println("hello prety");
+ }
+ }
+
+ public static class IHelloServiceMock implements IHelloService {
+ public IHelloServiceMock() {
+
+ }
+
+ public String getSomething() {
+ return "somethingmock";
+ }
+
+ public String getSomething2() {
+ return "something2mock";
+ }
+
+ public String getSomething3() {
+ return "something3mock";
+ }
+
+ public List<String> getListString() {
+ return Arrays.asList(new String[]{"Tommock", "Jerrymock"});
+ }
+
+ public List<User> getUsers() {
+ return Arrays.asList(new User[]{new User(1, "Tommock"), new User(2, "Jerrymock")});
+ }
+
+ public int getInt1() {
+ return 1;
+ }
+
+ public boolean getBoolean1() {
+ return false;
+ }
+
+ public Boolean getBoolean2() {
+ return Boolean.FALSE;
+ }
+
+ public void sayHello() {
+ System.out.println("hello prety");
+ }
+ }
+
+ public static class User {
+ private int id;
+ private String name;
+
+ public User() {
+ }
+
+ public User(int id, String name) {
+ super();
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ }
+}
diff --git a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MyMockException.java b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MyMockException.java
index d9a59cfb90..f353745cc7 100644
--- a/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MyMockException.java
+++ b/dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/wrapper/MyMockException.java
@@ -1,28 +1,28 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.rpc.cluster.support.wrapper;
-
-
-public class MyMockException extends RuntimeException {
-
- private static final long serialVersionUID = 2851692379597990457L;
-
- public MyMockException(String message) {
- super(message);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.cluster.support.wrapper;
+
+
+public class MyMockException extends RuntimeException {
+
+ private static final long serialVersionUID = 2851692379597990457L;
+
+ public MyMockException(String message) {
+ super(message);
+ }
+
+}
diff --git a/dubbo-common/pom.xml b/dubbo-common/pom.xml
index 72d43da6f5..9c04632cb3 100644
--- a/dubbo-common/pom.xml
+++ b/dubbo-common/pom.xml
@@ -1,71 +1,71 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.dubbo</groupId>
- <artifactId>dubbo-parent</artifactId>
- <version>2.7.0-SNAPSHOT</version>
- </parent>
- <artifactId>dubbo-common</artifactId>
- <packaging>jar</packaging>
- <name>${project.artifactId}</name>
- <description>The common module of dubbo project</description>
- <properties>
- <skip_maven_deploy>false</skip_maven_deploy>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- </dependency>
- <dependency>
- <groupId>org.javassist</groupId>
- <artifactId>javassist</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>hessian-lite</artifactId>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- </dependency>
- <dependency>
- <groupId>com.esotericsoftware</groupId>
- <artifactId>kryo</artifactId>
- </dependency>
- <dependency>
- <groupId>de.javakaffee</groupId>
- <artifactId>kryo-serializers</artifactId>
- </dependency>
- <dependency>
- <groupId>de.ruedigermoeller</groupId>
- <artifactId>fst</artifactId>
- </dependency>
- </dependencies>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.dubbo</groupId>
+ <artifactId>dubbo-parent</artifactId>
+ <version>2.7.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>dubbo-common</artifactId>
+ <packaging>jar</packaging>
+ <name>${project.artifactId}</name>
+ <description>The common module of dubbo project</description>
+ <properties>
+ <skip_maven_deploy>false</skip_maven_deploy>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>hessian-lite</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.esotericsoftware</groupId>
+ <artifactId>kryo</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>de.javakaffee</groupId>
+ <artifactId>kryo-serializers</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>de.ruedigermoeller</groupId>
+ <artifactId>fst</artifactId>
+ </dependency>
+ </dependencies>
</project>
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Extension.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Extension.java
index 724a0d7dcd..0f9e6c1e49 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Extension.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Extension.java
@@ -1,68 +1,68 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.dubbo.common;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Marker for extension interface
- * <p/>
- * 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/>
- * <pre>
- * com.foo.XxxProtocol
- * com.foo.YyyProtocol
- * </pre>
- * <p>
- * to key-value pair <br/>
- * <pre>
- * xxx=com.foo.XxxProtocol
- * yyy=com.foo.YyyProtocol
- * </pre>
- * <br/>
- * The reason for this change is:
- * <p>
- * 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
- * therefore cannot be able to map the exception information with the extension, if the previous format is used.
- * <p/>
- * For example:
- * <p>
- * 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.
- * </p>
- *
- * @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI}
- */
-@Deprecated
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Extension {
-
- /**
- * @deprecated
- */
- @Deprecated
- String value() default "";
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.common;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marker for extension interface
+ * <p/>
+ * 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/>
+ * <pre>
+ * com.foo.XxxProtocol
+ * com.foo.YyyProtocol
+ * </pre>
+ * <p>
+ * to key-value pair <br/>
+ * <pre>
+ * xxx=com.foo.XxxProtocol
+ * yyy=com.foo.YyyProtocol
+ * </pre>
+ * <br/>
+ * The reason for this change is:
+ * <p>
+ * 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
+ * therefore cannot be able to map the exception information with the extension, if the previous format is used.
+ * <p/>
+ * For example:
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @deprecated because it's too general, switch to use {@link org.apache.dubbo.common.extension.SPI}
+ */
+@Deprecated
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface Extension {
+
+ /**
+ * @deprecated
+ */
+ @Deprecated
+ String value() default "";
+
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Node.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Node.java
index 7b097f72b2..608a0939ac 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Node.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Node.java
@@ -1,43 +1,43 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common;
-
-/**
- * Node. (API/SPI, Prototype, ThreadSafe)
- */
-public interface Node {
-
- /**
- * get url.
- *
- * @return url.
- */
- URL getUrl();
-
- /**
- * is available.
- *
- * @return available.
- */
- boolean isAvailable();
-
- /**
- * destroy.
- */
- void destroy();
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common;
+
+/**
+ * Node. (API/SPI, Prototype, ThreadSafe)
+ */
+public interface Node {
+
+ /**
+ * get url.
+ *
+ * @return url.
+ */
+ URL getUrl();
+
+ /**
+ * is available.
+ *
+ * @return available.
+ */
+ boolean isAvailable();
+
+ /**
+ * destroy.
+ */
+ void destroy();
+
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
index 39999279ec..9c572f3aef 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Parameters.java
@@ -1,265 +1,265 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common;
-
-import org.apache.dubbo.common.extension.ExtensionLoader;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.StringUtils;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Parameters for backward compatibility for version prior to 2.0.5
- *
- * @deprecated
- */
-@Deprecated
-public class Parameters {
- protected static final Logger logger = LoggerFactory.getLogger(Parameters.class);
- private final Map<String, String> parameters;
-
- public Parameters(String... pairs) {
- this(toMap(pairs));
- }
-
- public Parameters(Map<String, String> parameters) {
- this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap<String, String>(parameters) : new HashMap<String, String>(0));
- }
-
- private static Map<String, String> toMap(String... pairs) {
- Map<String, String> parameters = new HashMap<String, String>();
- if (pairs.length > 0) {
- if (pairs.length % 2 != 0) {
- throw new IllegalArgumentException("pairs must be even.");
- }
- for (int i = 0; i < pairs.length; i = i + 2) {
- parameters.put(pairs[i], pairs[i + 1]);
- }
- }
- return parameters;
- }
-
- public static Parameters parseParameters(String query) {
- return new Parameters(StringUtils.parseQueryString(query));
- }
-
- public Map<String, String> getParameters() {
- return parameters;
- }
-
- public <T> T getExtension(Class<T> type, String key) {
- String name = getParameter(key);
- return ExtensionLoader.getExtensionLoader(type).getExtension(name);
- }
-
- public <T> T getExtension(Class<T> type, String key, String defaultValue) {
- String name = getParameter(key, defaultValue);
- return ExtensionLoader.getExtensionLoader(type).getExtension(name);
- }
-
- public <T> T getMethodExtension(Class<T> type, String method, String key) {
- String name = getMethodParameter(method, key);
- return ExtensionLoader.getExtensionLoader(type).getExtension(name);
- }
-
- public <T> T getMethodExtension(Class<T> type, String method, String key, String defaultValue) {
- String name = getMethodParameter(method, key, defaultValue);
- return ExtensionLoader.getExtensionLoader(type).getExtension(name);
- }
-
- public String getDecodedParameter(String key) {
- return getDecodedParameter(key, null);
- }
-
- public String getDecodedParameter(String key, String defaultValue) {
- String value = getParameter(key, defaultValue);
- if (value != null && value.length() > 0) {
- try {
- value = URLDecoder.decode(value, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- logger.error(e.getMessage(), e);
- }
- }
- return value;
- }
-
- public String getParameter(String key) {
- String value = parameters.get(key);
- if (value == null || value.length() == 0) {
- value = parameters.get(Constants.HIDE_KEY_PREFIX + key);
- }
- if (value == null || value.length() == 0) {
- value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key);
- }
- if (value == null || value.length() == 0) {
- value = parameters.get(Constants.HIDE_KEY_PREFIX + Constants.DEFAULT_KEY_PREFIX + key);
- }
- return value;
- }
-
- public String getParameter(String key, String defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value;
- }
-
- public int getIntParameter(String key) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return 0;
- }
- return Integer.parseInt(value);
- }
-
- public int getIntParameter(String key, int defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Integer.parseInt(value);
- }
-
- public int getPositiveIntParameter(String key, int defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- int i = Integer.parseInt(value);
- if (i > 0) {
- return i;
- }
- return defaultValue;
- }
-
- public boolean getBooleanParameter(String key) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return false;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean getBooleanParameter(String key, boolean defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean hasParamter(String key) {
- String value = getParameter(key);
- return value != null && value.length() > 0;
- }
-
- public String getMethodParameter(String method, String key) {
- String value = parameters.get(method + "." + key);
- if (value == null || value.length() == 0) {
- value = parameters.get(Constants.HIDE_KEY_PREFIX + method + "." + key);
- }
- if (value == null || value.length() == 0) {
- return getParameter(key);
- }
- return value;
- }
-
- public String getMethodParameter(String method, String key, String defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value;
- }
-
- public int getMethodIntParameter(String method, String key) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return 0;
- }
- return Integer.parseInt(value);
- }
-
- public int getMethodIntParameter(String method, String key, int defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Integer.parseInt(value);
- }
-
- public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- int i = Integer.parseInt(value);
- if (i > 0) {
- return i;
- }
- return defaultValue;
- }
-
- public boolean getMethodBooleanParameter(String method, String key) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return false;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean hasMethodParamter(String method, String key) {
- String value = getMethodParameter(method, key);
- return value != null && value.length() > 0;
- }
-
- @Override
- public boolean equals(Object o) {
- return parameters.equals(o);
- }
-
- @Override
- public int hashCode() {
- return parameters.hashCode();
- }
-
- @Override
- public String toString() {
- return StringUtils.toQueryString(getParameters());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common;
+
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parameters for backward compatibility for version prior to 2.0.5
+ *
+ * @deprecated
+ */
+@Deprecated
+public class Parameters {
+ protected static final Logger logger = LoggerFactory.getLogger(Parameters.class);
+ private final Map<String, String> parameters;
+
+ public Parameters(String... pairs) {
+ this(toMap(pairs));
+ }
+
+ public Parameters(Map<String, String> parameters) {
+ this.parameters = Collections.unmodifiableMap(parameters != null ? new HashMap<String, String>(parameters) : new HashMap<String, String>(0));
+ }
+
+ private static Map<String, String> toMap(String... pairs) {
+ Map<String, String> parameters = new HashMap<String, String>();
+ if (pairs.length > 0) {
+ if (pairs.length % 2 != 0) {
+ throw new IllegalArgumentException("pairs must be even.");
+ }
+ for (int i = 0; i < pairs.length; i = i + 2) {
+ parameters.put(pairs[i], pairs[i + 1]);
+ }
+ }
+ return parameters;
+ }
+
+ public static Parameters parseParameters(String query) {
+ return new Parameters(StringUtils.parseQueryString(query));
+ }
+
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ public <T> T getExtension(Class<T> type, String key) {
+ String name = getParameter(key);
+ return ExtensionLoader.getExtensionLoader(type).getExtension(name);
+ }
+
+ public <T> T getExtension(Class<T> type, String key, String defaultValue) {
+ String name = getParameter(key, defaultValue);
+ return ExtensionLoader.getExtensionLoader(type).getExtension(name);
+ }
+
+ public <T> T getMethodExtension(Class<T> type, String method, String key) {
+ String name = getMethodParameter(method, key);
+ return ExtensionLoader.getExtensionLoader(type).getExtension(name);
+ }
+
+ public <T> T getMethodExtension(Class<T> type, String method, String key, String defaultValue) {
+ String name = getMethodParameter(method, key, defaultValue);
+ return ExtensionLoader.getExtensionLoader(type).getExtension(name);
+ }
+
+ public String getDecodedParameter(String key) {
+ return getDecodedParameter(key, null);
+ }
+
+ public String getDecodedParameter(String key, String defaultValue) {
+ String value = getParameter(key, defaultValue);
+ if (value != null && value.length() > 0) {
+ try {
+ value = URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ return value;
+ }
+
+ public String getParameter(String key) {
+ String value = parameters.get(key);
+ if (value == null || value.length() == 0) {
+ value = parameters.get(Constants.HIDE_KEY_PREFIX + key);
+ }
+ if (value == null || value.length() == 0) {
+ value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key);
+ }
+ if (value == null || value.length() == 0) {
+ value = parameters.get(Constants.HIDE_KEY_PREFIX + Constants.DEFAULT_KEY_PREFIX + key);
+ }
+ return value;
+ }
+
+ public String getParameter(String key, String defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public int getIntParameter(String key) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return 0;
+ }
+ return Integer.parseInt(value);
+ }
+
+ public int getIntParameter(String key, int defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Integer.parseInt(value);
+ }
+
+ public int getPositiveIntParameter(String key, int defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ int i = Integer.parseInt(value);
+ if (i > 0) {
+ return i;
+ }
+ return defaultValue;
+ }
+
+ public boolean getBooleanParameter(String key) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return false;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean getBooleanParameter(String key, boolean defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean hasParamter(String key) {
+ String value = getParameter(key);
+ return value != null && value.length() > 0;
+ }
+
+ public String getMethodParameter(String method, String key) {
+ String value = parameters.get(method + "." + key);
+ if (value == null || value.length() == 0) {
+ value = parameters.get(Constants.HIDE_KEY_PREFIX + method + "." + key);
+ }
+ if (value == null || value.length() == 0) {
+ return getParameter(key);
+ }
+ return value;
+ }
+
+ public String getMethodParameter(String method, String key, String defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public int getMethodIntParameter(String method, String key) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return 0;
+ }
+ return Integer.parseInt(value);
+ }
+
+ public int getMethodIntParameter(String method, String key, int defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Integer.parseInt(value);
+ }
+
+ public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ int i = Integer.parseInt(value);
+ if (i > 0) {
+ return i;
+ }
+ return defaultValue;
+ }
+
+ public boolean getMethodBooleanParameter(String method, String key) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return false;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean hasMethodParamter(String method, String key) {
+ String value = getMethodParameter(method, key);
+ return value != null && value.length() > 0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return parameters.equals(o);
+ }
+
+ @Override
+ public int hashCode() {
+ return parameters.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return StringUtils.toQueryString(getParameters());
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/Resetable.java b/dubbo-common/src/main/java/org/apache/dubbo/common/Resetable.java
index f2eb8da4ed..021cfbf257 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/Resetable.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/Resetable.java
@@ -1,31 +1,31 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common;
-
-/**
- * Resetable.
- */
-public interface Resetable {
-
- /**
- * reset.
- *
- * @param url
- */
- void reset(URL url);
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common;
+
+/**
+ * Resetable.
+ */
+public interface Resetable {
+
+ /**
+ * reset.
+ *
+ * @param url
+ */
+ void reset(URL url);
+
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
index 45d776ab32..8cca809bc2 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/URL.java
@@ -1,1397 +1,1397 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common;
-
-import org.apache.dubbo.common.utils.CollectionUtils;
-import org.apache.dubbo.common.utils.NetUtils;
-import org.apache.dubbo.common.utils.StringUtils;
-
-import java.io.Serializable;
-import java.io.UnsupportedEncodingException;
-import java.net.InetSocketAddress;
-import java.net.MalformedURLException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * URL - Uniform Resource Locator (Immutable, ThreadSafe)
- * <p>
- * url example:
- * <ul>
- * <li>http://www.facebook.com/friends?param1=value1&param2=value2
- * <li>http://username:password@10.20.130.230:8080/list?version=1.0.0
- * <li>ftp://username:password@192.168.1.7:21/1/read.txt
- * <li>registry://192.168.1.7:9090/org.apache.dubbo.service1?param1=value1&param2=value2
- * </ul>
- * <p>
- * Some strange example below:
- * <ul>
- * <li>192.168.1.3:20880<br>
- * for this case, url protocol = null, url host = 192.168.1.3, port = 20880, url path = null
- * <li>file:///home/user1/router.js?type=script<br>
- * for this case, url protocol = file, url host = null, url path = home/user1/router.js
- * <li>file://home/user1/router.js?type=script<br>
- * for this case, url protocol = file, url host = home, url path = user1/router.js
- * <li>file:///D:/1/router.js?type=script<br>
- * for this case, url protocol = file, url host = null, url path = D:/1/router.js
- * <li>file:/D:/1/router.js?type=script<br>
- * same as above file:///D:/1/router.js?type=script
- * <li>/home/user1/router.js?type=script <br>
- * for this case, url protocol = null, url host = null, url path = home/user1/router.js
- * <li>home/user1/router.js?type=script <br>
- * for this case, url protocol = null, url host = home, url path = user1/router.js
- * </ul>
- *
- * @see java.net.URL
- * @see java.net.URI
- */
-public /**final**/ class URL implements Serializable {
-
- private static final long serialVersionUID = -1985165475234910535L;
-
- private final String protocol;
-
- private final String username;
-
- private final String password;
-
- // by default, host to registry
- private final String host;
-
- // by default, port to registry
- private final int port;
-
- private final String path;
-
- private final Map<String, String> parameters;
-
- // ==== cache ====
-
- private volatile transient Map<String, Number> numbers;
-
- private volatile transient Map<String, URL> urls;
-
- private volatile transient String ip;
-
- private volatile transient String full;
-
- private volatile transient String identity;
-
- private volatile transient String parameter;
-
- private volatile transient String string;
-
- protected URL() {
- this.protocol = null;
- this.username = null;
- this.password = null;
- this.host = null;
- this.port = 0;
- this.path = null;
- this.parameters = null;
- }
-
- public URL(String protocol, String host, int port) {
- this(protocol, null, null, host, port, null, (Map<String, String>) null);
- }
-
- public URL(String protocol, String host, int port, String[] pairs) { // varargs ... confilict with the following path argument, use array instead.
- this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));
- }
-
- public URL(String protocol, String host, int port, Map<String, String> parameters) {
- this(protocol, null, null, host, port, null, parameters);
- }
-
- public URL(String protocol, String host, int port, String path) {
- this(protocol, null, null, host, port, path, (Map<String, String>) null);
- }
-
- public URL(String protocol, String host, int port, String path, String... pairs) {
- this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));
- }
-
- public URL(String protocol, String host, int port, String path, Map<String, String> parameters) {
- this(protocol, null, null, host, port, path, parameters);
- }
-
- public URL(String protocol, String username, String password, String host, int port, String path) {
- this(protocol, username, password, host, port, path, (Map<String, String>) null);
- }
-
- public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) {
- this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));
- }
-
- public URL(String protocol, String username, String password, String host, int port, String path, Map<String, String> parameters) {
- if ((username == null || username.length() == 0)
- && password != null && password.length() > 0) {
- throw new IllegalArgumentException("Invalid url, password without username!");
- }
- this.protocol = protocol;
- this.username = username;
- this.password = password;
- this.host = host;
- this.port = (port < 0 ? 0 : port);
- // trim the beginning "/"
- while (path != null && path.startsWith("/")) {
- path = path.substring(1);
- }
- this.path = path;
- if (parameters == null) {
- parameters = new HashMap<String, String>();
- } else {
- parameters = new HashMap<String, String>(parameters);
- }
- this.parameters = Collections.unmodifiableMap(parameters);
- }
-
- /**
- * Parse url string
- *
- * @param url URL string
- * @return URL instance
- * @see URL
- */
- public static URL valueOf(String url) {
- if (url == null || (url = url.trim()).length() == 0) {
- throw new IllegalArgumentException("url == null");
- }
- String protocol = null;
- String username = null;
- String password = null;
- String host = null;
- int port = 0;
- String path = null;
- Map<String, String> parameters = null;
- int i = url.indexOf("?"); // seperator between body and parameters
- if (i >= 0) {
- String[] parts = url.substring(i + 1).split("\\&");
- parameters = new HashMap<String, String>();
- for (String part : parts) {
- part = part.trim();
- if (part.length() > 0) {
- int j = part.indexOf('=');
- if (j >= 0) {
- parameters.put(part.substring(0, j), part.substring(j + 1));
- } else {
- parameters.put(part, part);
- }
- }
- }
- url = url.substring(0, i);
- }
- i = url.indexOf("://");
- if (i >= 0) {
- if (i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
- protocol = url.substring(0, i);
- url = url.substring(i + 3);
- } else {
- // case: file:/path/to/file.txt
- i = url.indexOf(":/");
- if (i >= 0) {
- if (i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
- protocol = url.substring(0, i);
- url = url.substring(i + 1);
- }
- }
-
- i = url.indexOf("/");
- if (i >= 0) {
- path = url.substring(i + 1);
- url = url.substring(0, i);
- }
- i = url.lastIndexOf("@");
- if (i >= 0) {
- username = url.substring(0, i);
- int j = username.indexOf(":");
- if (j >= 0) {
- password = username.substring(j + 1);
- username = username.substring(0, j);
- }
- url = url.substring(i + 1);
- }
- i = url.indexOf(":");
- if (i >= 0 && i < url.length() - 1) {
- port = Integer.parseInt(url.substring(i + 1));
- url = url.substring(0, i);
- }
- if (url.length() > 0) host = url;
- return new URL(protocol, username, password, host, port, path, parameters);
- }
-
- public static String encode(String value) {
- if (value == null || value.length() == 0) {
- return "";
- }
- try {
- return URLEncoder.encode(value, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- public static String decode(String value) {
- if (value == null || value.length() == 0) {
- return "";
- }
- try {
- return URLDecoder.decode(value, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- public String getProtocol() {
- return protocol;
- }
-
- public URL setProtocol(String protocol) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public String getUsername() {
- return username;
- }
-
- public URL setUsername(String username) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public String getPassword() {
- return password;
- }
-
- public URL setPassword(String password) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public String getAuthority() {
- if ((username == null || username.length() == 0)
- && (password == null || password.length() == 0)) {
- return null;
- }
- return (username == null ? "" : username)
- + ":" + (password == null ? "" : password);
- }
-
- public String getHost() {
- return host;
- }
-
- public URL setHost(String host) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- /**
- * Fetch IP address for this URL.
- *
- * Pls. note that IP should be used instead of Host when to compare with socket's address or to search in a map
- * which use address as its key.
- *
- * @return ip in string format
- */
- public String getIp() {
- if (ip == null) {
- ip = NetUtils.getIpByHost(host);
- }
- return ip;
- }
-
- public int getPort() {
- return port;
- }
-
- public URL setPort(int port) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public int getPort(int defaultPort) {
- return port <= 0 ? defaultPort : port;
- }
-
- public String getAddress() {
- return port <= 0 ? host : host + ":" + port;
- }
-
- public URL setAddress(String address) {
- int i = address.lastIndexOf(':');
- String host;
- int port = this.port;
- if (i >= 0) {
- host = address.substring(0, i);
- port = Integer.parseInt(address.substring(i + 1));
- } else {
- host = address;
- }
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public String getBackupAddress() {
- return getBackupAddress(0);
- }
-
- public String getBackupAddress(int defaultPort) {
- StringBuilder address = new StringBuilder(appendDefaultPort(getAddress(), defaultPort));
- String[] backups = getParameter(Constants.BACKUP_KEY, new String[0]);
- if (backups != null && backups.length > 0) {
- for (String backup : backups) {
- address.append(",");
- address.append(appendDefaultPort(backup, defaultPort));
- }
- }
- return address.toString();
- }
-
- public List<URL> getBackupUrls() {
- List<URL> urls = new ArrayList<URL>();
- urls.add(this);
- String[] backups = getParameter(Constants.BACKUP_KEY, new String[0]);
- if (backups != null && backups.length > 0) {
- for (String backup : backups) {
- urls.add(this.setAddress(backup));
- }
- }
- return urls;
- }
-
- private String appendDefaultPort(String address, int defaultPort) {
- if (address != null && address.length() > 0
- && defaultPort > 0) {
- int i = address.indexOf(':');
- if (i < 0) {
- return address + ":" + defaultPort;
- } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
- return address.substring(0, i + 1) + defaultPort;
- }
- }
- return address;
- }
-
- public String getPath() {
- return path;
- }
-
- public URL setPath(String path) {
- return new URL(protocol, username, password, host, port, path, getParameters());
- }
-
- public String getAbsolutePath() {
- if (path != null && !path.startsWith("/")) {
- return "/" + path;
- }
- return path;
- }
-
- public Map<String, String> getParameters() {
- return parameters;
- }
-
- public String getParameterAndDecoded(String key) {
- return getParameterAndDecoded(key, null);
- }
-
- public String getParameterAndDecoded(String key, String defaultValue) {
- return decode(getParameter(key, defaultValue));
- }
-
- public String getParameter(String key) {
- String value = parameters.get(key);
- if (value == null || value.length() == 0) {
- value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key);
- }
- return value;
- }
-
- public String getParameter(String key, String defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value;
- }
-
- public String[] getParameter(String key, String[] defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Constants.COMMA_SPLIT_PATTERN.split(value);
- }
-
- private Map<String, Number> getNumbers() {
- if (numbers == null) { // concurrent initialization is tolerant
- numbers = new ConcurrentHashMap<String, Number>();
- }
- return numbers;
- }
-
- private Map<String, URL> getUrls() {
- if (urls == null) { // concurrent initialization is tolerant
- urls = new ConcurrentHashMap<String, URL>();
- }
- return urls;
- }
-
- public URL getUrlParameter(String key) {
- URL u = getUrls().get(key);
- if (u != null) {
- return u;
- }
- String value = getParameterAndDecoded(key);
- if (value == null || value.length() == 0) {
- return null;
- }
- u = URL.valueOf(value);
- getUrls().put(key, u);
- return u;
- }
-
- public double getParameter(String key, double defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.doubleValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- double d = Double.parseDouble(value);
- getNumbers().put(key, d);
- return d;
- }
-
- public float getParameter(String key, float defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.floatValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- float f = Float.parseFloat(value);
- getNumbers().put(key, f);
- return f;
- }
-
- public long getParameter(String key, long defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.longValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- long l = Long.parseLong(value);
- getNumbers().put(key, l);
- return l;
- }
-
- public int getParameter(String key, int defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.intValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- int i = Integer.parseInt(value);
- getNumbers().put(key, i);
- return i;
- }
-
- public short getParameter(String key, short defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.shortValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- short s = Short.parseShort(value);
- getNumbers().put(key, s);
- return s;
- }
-
- public byte getParameter(String key, byte defaultValue) {
- Number n = getNumbers().get(key);
- if (n != null) {
- return n.byteValue();
- }
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- byte b = Byte.parseByte(value);
- getNumbers().put(key, b);
- return b;
- }
-
- public float getPositiveParameter(String key, float defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- float value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public double getPositiveParameter(String key, double defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- double value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public long getPositiveParameter(String key, long defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- long value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public int getPositiveParameter(String key, int defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- int value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public short getPositiveParameter(String key, short defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- short value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public byte getPositiveParameter(String key, byte defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- byte value = getParameter(key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public char getParameter(String key, char defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value.charAt(0);
- }
-
- public boolean getParameter(String key, boolean defaultValue) {
- String value = getParameter(key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean hasParameter(String key) {
- String value = getParameter(key);
- return value != null && value.length() > 0;
- }
-
- public String getMethodParameterAndDecoded(String method, String key) {
- return URL.decode(getMethodParameter(method, key));
- }
-
- public String getMethodParameterAndDecoded(String method, String key, String defaultValue) {
- return URL.decode(getMethodParameter(method, key, defaultValue));
- }
-
- public String getMethodParameter(String method, String key) {
- String value = parameters.get(method + "." + key);
- if (value == null || value.length() == 0) {
- return getParameter(key);
- }
- return value;
- }
-
- public String getMethodParameter(String method, String key, String defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value;
- }
-
- public double getMethodParameter(String method, String key, double defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.intValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- double d = Double.parseDouble(value);
- getNumbers().put(methodKey, d);
- return d;
- }
-
- public float getMethodParameter(String method, String key, float defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.intValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- float f = Float.parseFloat(value);
- getNumbers().put(methodKey, f);
- return f;
- }
-
- public long getMethodParameter(String method, String key, long defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.intValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- long l = Long.parseLong(value);
- getNumbers().put(methodKey, l);
- return l;
- }
-
- public int getMethodParameter(String method, String key, int defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.intValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- int i = Integer.parseInt(value);
- getNumbers().put(methodKey, i);
- return i;
- }
-
- public short getMethodParameter(String method, String key, short defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.shortValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- short s = Short.parseShort(value);
- getNumbers().put(methodKey, s);
- return s;
- }
-
- public byte getMethodParameter(String method, String key, byte defaultValue) {
- String methodKey = method + "." + key;
- Number n = getNumbers().get(methodKey);
- if (n != null) {
- return n.byteValue();
- }
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- byte b = Byte.parseByte(value);
- getNumbers().put(methodKey, b);
- return b;
- }
-
- public double getMethodPositiveParameter(String method, String key, double defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- double value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public float getMethodPositiveParameter(String method, String key, float defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- float value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public long getMethodPositiveParameter(String method, String key, long defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- long value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public int getMethodPositiveParameter(String method, String key, int defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- int value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public short getMethodPositiveParameter(String method, String key, short defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- short value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public byte getMethodPositiveParameter(String method, String key, byte defaultValue) {
- if (defaultValue <= 0) {
- throw new IllegalArgumentException("defaultValue <= 0");
- }
- byte value = getMethodParameter(method, key, defaultValue);
- if (value <= 0) {
- return defaultValue;
- }
- return value;
- }
-
- public char getMethodParameter(String method, String key, char defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return value.charAt(0);
- }
-
- public boolean getMethodParameter(String method, String key, boolean defaultValue) {
- String value = getMethodParameter(method, key);
- if (value == null || value.length() == 0) {
- return defaultValue;
- }
- return Boolean.parseBoolean(value);
- }
-
- public boolean hasMethodParameter(String method, String key) {
- if (method == null) {
- String suffix = "." + key;
- for (String fullKey : parameters.keySet()) {
- if (fullKey.endsWith(suffix)) {
- return true;
- }
- }
- return false;
- }
- if (key == null) {
- String prefix = method + ".";
- for (String fullKey : parameters.keySet()) {
- if (fullKey.startsWith(prefix)) {
- return true;
- }
- }
- return false;
- }
- String value = getMethodParameter(method, key);
- return value != null && value.length() > 0;
- }
-
- public boolean isLocalHost() {
- return NetUtils.isLocalHost(host) || getParameter(Constants.LOCALHOST_KEY, false);
- }
-
- public boolean isAnyHost() {
- return Constants.ANYHOST_VALUE.equals(host) || getParameter(Constants.ANYHOST_KEY, false);
- }
-
- public URL addParameterAndEncoded(String key, String value) {
- if (value == null || value.length() == 0) {
- return this;
- }
- return addParameter(key, encode(value));
- }
-
- public URL addParameter(String key, boolean value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, char value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, byte value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, short value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, int value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, long value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, float value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, double value) {
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, Enum<?> value) {
- if (value == null) return this;
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, Number value) {
- if (value == null) return this;
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, CharSequence value) {
- if (value == null || value.length() == 0) return this;
- return addParameter(key, String.valueOf(value));
- }
-
- public URL addParameter(String key, String value) {
- if (key == null || key.length() == 0
- || value == null || value.length() == 0) {
- return this;
- }
- // if value doesn't change, return immediately
- if (value.equals(getParameters().get(key))) { // value != null
- return this;
- }
-
- Map<String, String> map = new HashMap<String, String>(getParameters());
- map.put(key, value);
- return new URL(protocol, username, password, host, port, path, map);
- }
-
- public URL addParameterIfAbsent(String key, String value) {
- if (key == null || key.length() == 0
- || value == null || value.length() == 0) {
- return this;
- }
- if (hasParameter(key)) {
- return this;
- }
- Map<String, String> map = new HashMap<String, String>(getParameters());
- map.put(key, value);
- return new URL(protocol, username, password, host, port, path, map);
- }
-
- /**
- * Add parameters to a new url.
- *
- * @param parameters parameters in key-value pairs
- * @return A new URL
- */
- public URL addParameters(Map<String, String> parameters) {
- if (parameters == null || parameters.size() == 0) {
- return this;
- }
-
- boolean hasAndEqual = true;
- for (Map.Entry<String, String> entry : parameters.entrySet()) {
- String value = getParameters().get(entry.getKey());
- if (value == null) {
- if (entry.getValue() != null) {
- hasAndEqual = false;
- break;
- }
- } else {
- if (!value.equals(entry.getValue())) {
- hasAndEqual = false;
- break;
- }
- }
- }
- // return immediately if there's no change
- if (hasAndEqual) return this;
-
- Map<String, String> map = new HashMap<String, String>(getParameters());
- map.putAll(parameters);
- return new URL(protocol, username, password, host, port, path, map);
- }
-
- public URL addParametersIfAbsent(Map<String, String> parameters) {
- if (parameters == null || parameters.size() == 0) {
- return this;
- }
- Map<String, String> map = new HashMap<String, String>(parameters);
- map.putAll(getParameters());
- return new URL(protocol, username, password, host, port, path, map);
- }
-
- public URL addParameters(String... pairs) {
- if (pairs == null || pairs.length == 0) {
- return this;
- }
- if (pairs.length % 2 != 0) {
- throw new IllegalArgumentException("Map pairs can not be odd number.");
- }
- Map<String, String> map = new HashMap<String, String>();
- int len = pairs.length / 2;
- for (int i = 0; i < len; i++) {
- map.put(pairs[2 * i], pairs[2 * i + 1]);
- }
- return addParameters(map);
- }
-
- public URL addParameterString(String query) {
- if (query == null || query.length() == 0) {
- return this;
- }
- return addParameters(StringUtils.parseQueryString(query));
- }
-
- public URL removeParameter(String key) {
- if (key == null || key.length() == 0) {
- return this;
- }
- return removeParameters(key);
- }
-
- public URL removeParameters(Collection<String> keys) {
- if (keys == null || keys.isEmpty()) {
- return this;
- }
- return removeParameters(keys.toArray(new String[0]));
- }
-
- public URL removeParameters(String... keys) {
- if (keys == null || keys.length == 0) {
- return this;
- }
- Map<String, String> map = new HashMap<String, String>(getParameters());
- for (String key : keys) {
- map.remove(key);
- }
- if (map.size() == getParameters().size()) {
- return this;
- }
- return new URL(protocol, username, password, host, port, path, map);
- }
-
- public URL clearParameters() {
- return new URL(protocol, username, password, host, port, path, new HashMap<String, String>());
- }
-
- public String getRawParameter(String key) {
- if ("protocol".equals(key))
- return protocol;
- if ("username".equals(key))
- return username;
- if ("password".equals(key))
- return password;
- if ("host".equals(key))
- return host;
- if ("port".equals(key))
- return String.valueOf(port);
- if ("path".equals(key))
- return path;
- return getParameter(key);
- }
-
- public Map<String, String> toMap() {
- Map<String, String> map = new HashMap<String, String>(parameters);
- if (protocol != null)
- map.put("protocol", protocol);
- if (username != null)
- map.put("username", username);
- if (password != null)
- map.put("password", password);
- if (host != null)
- map.put("host", host);
- if (port > 0)
- map.put("port", String.valueOf(port));
- if (path != null)
- map.put("path", path);
- return map;
- }
-
- @Override
- public String toString() {
- if (string != null) {
- return string;
- }
- return string = buildString(false, true); // no show username and password
- }
-
- public String toString(String... parameters) {
- return buildString(false, true, parameters); // no show username and password
- }
-
- public String toIdentityString() {
- if (identity != null) {
- return identity;
- }
- return identity = buildString(true, false); // only return identity message, see the method "equals" and "hashCode"
- }
-
- public String toIdentityString(String... parameters) {
- return buildString(true, false, parameters); // only return identity message, see the method "equals" and "hashCode"
- }
-
- public String toFullString() {
- if (full != null) {
- return full;
- }
- return full = buildString(true, true);
- }
-
- public String toFullString(String... parameters) {
- return buildString(true, true, parameters);
- }
-
- public String toParameterString() {
- if (parameter != null) {
- return parameter;
- }
- return parameter = toParameterString(new String[0]);
- }
-
- public String toParameterString(String... parameters) {
- StringBuilder buf = new StringBuilder();
- buildParameters(buf, false, parameters);
- return buf.toString();
- }
-
- private void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {
- if (getParameters() != null && getParameters().size() > 0) {
- List<String> includes = (parameters == null || parameters.length == 0 ? null : Arrays.asList(parameters));
- boolean first = true;
- for (Map.Entry<String, String> entry : new TreeMap<String, String>(getParameters()).entrySet()) {
- if (entry.getKey() != null && entry.getKey().length() > 0
- && (includes == null || includes.contains(entry.getKey()))) {
- if (first) {
- if (concat) {
- buf.append("?");
- }
- first = false;
- } else {
- buf.append("&");
- }
- buf.append(entry.getKey());
- buf.append("=");
- buf.append(entry.getValue() == null ? "" : entry.getValue().trim());
- }
- }
- }
- }
-
- private String buildString(boolean appendUser, boolean appendParameter, String... parameters) {
- return buildString(appendUser, appendParameter, false, false, parameters);
- }
-
- private String buildString(boolean appendUser, boolean appendParameter, boolean useIP, boolean useService, String... parameters) {
- StringBuilder buf = new StringBuilder();
- if (protocol != null && protocol.length() > 0) {
- buf.append(protocol);
- buf.append("://");
- }
- if (appendUser && username != null && username.length() > 0) {
- buf.append(username);
- if (password != null && password.length() > 0) {
- buf.append(":");
- buf.append(password);
- }
- buf.append("@");
- }
- String host;
- if (useIP) {
- host = getIp();
- } else {
- host = getHost();
- }
- if (host != null && host.length() > 0) {
- buf.append(host);
- if (port > 0) {
- buf.append(":");
- buf.append(port);
- }
- }
- String path;
- if (useService) {
- path = getServiceKey();
- } else {
- path = getPath();
- }
- if (path != null && path.length() > 0) {
- buf.append("/");
- buf.append(path);
- }
- if (appendParameter) {
- buildParameters(buf, true, parameters);
- }
- return buf.toString();
- }
-
- public java.net.URL toJavaURL() {
- try {
- return new java.net.URL(toString());
- } catch (MalformedURLException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- public InetSocketAddress toInetSocketAddress() {
- return new InetSocketAddress(host, port);
- }
-
- public String getServiceKey() {
- String inf = getServiceInterface();
- if (inf == null) return null;
- StringBuilder buf = new StringBuilder();
- String group = getParameter(Constants.GROUP_KEY);
- if (group != null && group.length() > 0) {
- buf.append(group).append("/");
- }
- buf.append(inf);
- String version = getParameter(Constants.VERSION_KEY);
- if (version != null && version.length() > 0) {
- buf.append(":").append(version);
- }
- return buf.toString();
- }
-
- public String toServiceStringWithoutResolving() {
- return buildString(true, false, false, true);
- }
-
- public String toServiceString() {
- return buildString(true, false, true, true);
- }
-
- @Deprecated
- public String getServiceName() {
- return getServiceInterface();
- }
-
- public String getServiceInterface() {
- return getParameter(Constants.INTERFACE_KEY, path);
- }
-
- public URL setServiceInterface(String service) {
- return addParameter(Constants.INTERFACE_KEY, service);
- }
-
- /**
- * @see #getParameter(String, int)
- * @deprecated Replace to <code>getParameter(String, int)</code>
- */
- @Deprecated
- public int getIntParameter(String key) {
- return getParameter(key, 0);
- }
-
- /**
- * @see #getParameter(String, int)
- * @deprecated Replace to <code>getParameter(String, int)</code>
- */
- @Deprecated
- public int getIntParameter(String key, int defaultValue) {
- return getParameter(key, defaultValue);
- }
-
- /**
- * @see #getPositiveParameter(String, int)
- * @deprecated Replace to <code>getPositiveParameter(String, int)</code>
- */
- @Deprecated
- public int getPositiveIntParameter(String key, int defaultValue) {
- return getPositiveParameter(key, defaultValue);
- }
-
- /**
- * @see #getParameter(String, boolean)
- * @deprecated Replace to <code>getParameter(String, boolean)</code>
- */
- @Deprecated
- public boolean getBooleanParameter(String key) {
- return getParameter(key, false);
- }
-
- /**
- * @see #getParameter(String, boolean)
- * @deprecated Replace to <code>getParameter(String, boolean)</code>
- */
- @Deprecated
- public boolean getBooleanParameter(String key, boolean defaultValue) {
- return getParameter(key, defaultValue);
- }
-
- /**
- * @see #getMethodParameter(String, String, int)
- * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>
- */
- @Deprecated
- public int getMethodIntParameter(String method, String key) {
- return getMethodParameter(method, key, 0);
- }
-
- /**
- * @see #getMethodParameter(String, String, int)
- * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>
- */
- @Deprecated
- public int getMethodIntParameter(String method, String key, int defaultValue) {
- return getMethodParameter(method, key, defaultValue);
- }
-
- /**
- * @see #getMethodPositiveParameter(String, String, int)
- * @deprecated Replace to <code>getMethodPositiveParameter(String, String, int)</code>
- */
- @Deprecated
- public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {
- return getMethodPositiveParameter(method, key, defaultValue);
- }
-
- /**
- * @see #getMethodParameter(String, String, boolean)
- * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>
- */
- @Deprecated
- public boolean getMethodBooleanParameter(String method, String key) {
- return getMethodParameter(method, key, false);
- }
-
- /**
- * @see #getMethodParameter(String, String, boolean)
- * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>
- */
- @Deprecated
- public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {
- return getMethodParameter(method, key, defaultValue);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((host == null) ? 0 : host.hashCode());
- result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
- result = prime * result + ((password == null) ? 0 : password.hashCode());
- result = prime * result + ((path == null) ? 0 : path.hashCode());
- result = prime * result + port;
- result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
- result = prime * result + ((username == null) ? 0 : username.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- URL other = (URL) obj;
- if (host == null) {
- if (other.host != null)
- return false;
- } else if (!host.equals(other.host))
- return false;
- if (parameters == null) {
- if (other.parameters != null)
- return false;
- } else if (!parameters.equals(other.parameters))
- return false;
- if (password == null) {
- if (other.password != null)
- return false;
- } else if (!password.equals(other.password))
- return false;
- if (path == null) {
- if (other.path != null)
- return false;
- } else if (!path.equals(other.path))
- return false;
- if (port != other.port)
- return false;
- if (protocol == null) {
- if (other.protocol != null)
- return false;
- } else if (!protocol.equals(other.protocol))
- return false;
- if (username == null) {
- if (other.username != null)
- return false;
- } else if (!username.equals(other.username))
- return false;
- return true;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common;
+
+import org.apache.dubbo.common.utils.CollectionUtils;
+import org.apache.dubbo.common.utils.NetUtils;
+import org.apache.dubbo.common.utils.StringUtils;
+
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.net.MalformedURLException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * URL - Uniform Resource Locator (Immutable, ThreadSafe)
+ * <p>
+ * url example:
+ * <ul>
+ * <li>http://www.facebook.com/friends?param1=value1&param2=value2
+ * <li>http://username:password@10.20.130.230:8080/list?version=1.0.0
+ * <li>ftp://username:password@192.168.1.7:21/1/read.txt
+ * <li>registry://192.168.1.7:9090/org.apache.dubbo.service1?param1=value1&param2=value2
+ * </ul>
+ * <p>
+ * Some strange example below:
+ * <ul>
+ * <li>192.168.1.3:20880<br>
+ * for this case, url protocol = null, url host = 192.168.1.3, port = 20880, url path = null
+ * <li>file:///home/user1/router.js?type=script<br>
+ * for this case, url protocol = file, url host = null, url path = home/user1/router.js
+ * <li>file://home/user1/router.js?type=script<br>
+ * for this case, url protocol = file, url host = home, url path = user1/router.js
+ * <li>file:///D:/1/router.js?type=script<br>
+ * for this case, url protocol = file, url host = null, url path = D:/1/router.js
+ * <li>file:/D:/1/router.js?type=script<br>
+ * same as above file:///D:/1/router.js?type=script
+ * <li>/home/user1/router.js?type=script <br>
+ * for this case, url protocol = null, url host = null, url path = home/user1/router.js
+ * <li>home/user1/router.js?type=script <br>
+ * for this case, url protocol = null, url host = home, url path = user1/router.js
+ * </ul>
+ *
+ * @see java.net.URL
+ * @see java.net.URI
+ */
+public /**final**/ class URL implements Serializable {
+
+ private static final long serialVersionUID = -1985165475234910535L;
+
+ private final String protocol;
+
+ private final String username;
+
+ private final String password;
+
+ // by default, host to registry
+ private final String host;
+
+ // by default, port to registry
+ private final int port;
+
+ private final String path;
+
+ private final Map<String, String> parameters;
+
+ // ==== cache ====
+
+ private volatile transient Map<String, Number> numbers;
+
+ private volatile transient Map<String, URL> urls;
+
+ private volatile transient String ip;
+
+ private volatile transient String full;
+
+ private volatile transient String identity;
+
+ private volatile transient String parameter;
+
+ private volatile transient String string;
+
+ protected URL() {
+ this.protocol = null;
+ this.username = null;
+ this.password = null;
+ this.host = null;
+ this.port = 0;
+ this.path = null;
+ this.parameters = null;
+ }
+
+ public URL(String protocol, String host, int port) {
+ this(protocol, null, null, host, port, null, (Map<String, String>) null);
+ }
+
+ public URL(String protocol, String host, int port, String[] pairs) { // varargs ... confilict with the following path argument, use array instead.
+ this(protocol, null, null, host, port, null, CollectionUtils.toStringMap(pairs));
+ }
+
+ public URL(String protocol, String host, int port, Map<String, String> parameters) {
+ this(protocol, null, null, host, port, null, parameters);
+ }
+
+ public URL(String protocol, String host, int port, String path) {
+ this(protocol, null, null, host, port, path, (Map<String, String>) null);
+ }
+
+ public URL(String protocol, String host, int port, String path, String... pairs) {
+ this(protocol, null, null, host, port, path, CollectionUtils.toStringMap(pairs));
+ }
+
+ public URL(String protocol, String host, int port, String path, Map<String, String> parameters) {
+ this(protocol, null, null, host, port, path, parameters);
+ }
+
+ public URL(String protocol, String username, String password, String host, int port, String path) {
+ this(protocol, username, password, host, port, path, (Map<String, String>) null);
+ }
+
+ public URL(String protocol, String username, String password, String host, int port, String path, String... pairs) {
+ this(protocol, username, password, host, port, path, CollectionUtils.toStringMap(pairs));
+ }
+
+ public URL(String protocol, String username, String password, String host, int port, String path, Map<String, String> parameters) {
+ if ((username == null || username.length() == 0)
+ && password != null && password.length() > 0) {
+ throw new IllegalArgumentException("Invalid url, password without username!");
+ }
+ this.protocol = protocol;
+ this.username = username;
+ this.password = password;
+ this.host = host;
+ this.port = (port < 0 ? 0 : port);
+ // trim the beginning "/"
+ while (path != null && path.startsWith("/")) {
+ path = path.substring(1);
+ }
+ this.path = path;
+ if (parameters == null) {
+ parameters = new HashMap<String, String>();
+ } else {
+ parameters = new HashMap<String, String>(parameters);
+ }
+ this.parameters = Collections.unmodifiableMap(parameters);
+ }
+
+ /**
+ * Parse url string
+ *
+ * @param url URL string
+ * @return URL instance
+ * @see URL
+ */
+ public static URL valueOf(String url) {
+ if (url == null || (url = url.trim()).length() == 0) {
+ throw new IllegalArgumentException("url == null");
+ }
+ String protocol = null;
+ String username = null;
+ String password = null;
+ String host = null;
+ int port = 0;
+ String path = null;
+ Map<String, String> parameters = null;
+ int i = url.indexOf("?"); // seperator between body and parameters
+ if (i >= 0) {
+ String[] parts = url.substring(i + 1).split("\\&");
+ parameters = new HashMap<String, String>();
+ for (String part : parts) {
+ part = part.trim();
+ if (part.length() > 0) {
+ int j = part.indexOf('=');
+ if (j >= 0) {
+ parameters.put(part.substring(0, j), part.substring(j + 1));
+ } else {
+ parameters.put(part, part);
+ }
+ }
+ }
+ url = url.substring(0, i);
+ }
+ i = url.indexOf("://");
+ if (i >= 0) {
+ if (i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
+ protocol = url.substring(0, i);
+ url = url.substring(i + 3);
+ } else {
+ // case: file:/path/to/file.txt
+ i = url.indexOf(":/");
+ if (i >= 0) {
+ if (i == 0) throw new IllegalStateException("url missing protocol: \"" + url + "\"");
+ protocol = url.substring(0, i);
+ url = url.substring(i + 1);
+ }
+ }
+
+ i = url.indexOf("/");
+ if (i >= 0) {
+ path = url.substring(i + 1);
+ url = url.substring(0, i);
+ }
+ i = url.lastIndexOf("@");
+ if (i >= 0) {
+ username = url.substring(0, i);
+ int j = username.indexOf(":");
+ if (j >= 0) {
+ password = username.substring(j + 1);
+ username = username.substring(0, j);
+ }
+ url = url.substring(i + 1);
+ }
+ i = url.indexOf(":");
+ if (i >= 0 && i < url.length() - 1) {
+ port = Integer.parseInt(url.substring(i + 1));
+ url = url.substring(0, i);
+ }
+ if (url.length() > 0) host = url;
+ return new URL(protocol, username, password, host, port, path, parameters);
+ }
+
+ public static String encode(String value) {
+ if (value == null || value.length() == 0) {
+ return "";
+ }
+ try {
+ return URLEncoder.encode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ public static String decode(String value) {
+ if (value == null || value.length() == 0) {
+ return "";
+ }
+ try {
+ return URLDecoder.decode(value, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ public String getProtocol() {
+ return protocol;
+ }
+
+ public URL setProtocol(String protocol) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public URL setUsername(String username) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public URL setPassword(String password) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public String getAuthority() {
+ if ((username == null || username.length() == 0)
+ && (password == null || password.length() == 0)) {
+ return null;
+ }
+ return (username == null ? "" : username)
+ + ":" + (password == null ? "" : password);
+ }
+
+ public String getHost() {
+ return host;
+ }
+
+ public URL setHost(String host) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ /**
+ * Fetch IP address for this URL.
+ *
+ * Pls. note that IP should be used instead of Host when to compare with socket's address or to search in a map
+ * which use address as its key.
+ *
+ * @return ip in string format
+ */
+ public String getIp() {
+ if (ip == null) {
+ ip = NetUtils.getIpByHost(host);
+ }
+ return ip;
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public URL setPort(int port) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public int getPort(int defaultPort) {
+ return port <= 0 ? defaultPort : port;
+ }
+
+ public String getAddress() {
+ return port <= 0 ? host : host + ":" + port;
+ }
+
+ public URL setAddress(String address) {
+ int i = address.lastIndexOf(':');
+ String host;
+ int port = this.port;
+ if (i >= 0) {
+ host = address.substring(0, i);
+ port = Integer.parseInt(address.substring(i + 1));
+ } else {
+ host = address;
+ }
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public String getBackupAddress() {
+ return getBackupAddress(0);
+ }
+
+ public String getBackupAddress(int defaultPort) {
+ StringBuilder address = new StringBuilder(appendDefaultPort(getAddress(), defaultPort));
+ String[] backups = getParameter(Constants.BACKUP_KEY, new String[0]);
+ if (backups != null && backups.length > 0) {
+ for (String backup : backups) {
+ address.append(",");
+ address.append(appendDefaultPort(backup, defaultPort));
+ }
+ }
+ return address.toString();
+ }
+
+ public List<URL> getBackupUrls() {
+ List<URL> urls = new ArrayList<URL>();
+ urls.add(this);
+ String[] backups = getParameter(Constants.BACKUP_KEY, new String[0]);
+ if (backups != null && backups.length > 0) {
+ for (String backup : backups) {
+ urls.add(this.setAddress(backup));
+ }
+ }
+ return urls;
+ }
+
+ private String appendDefaultPort(String address, int defaultPort) {
+ if (address != null && address.length() > 0
+ && defaultPort > 0) {
+ int i = address.indexOf(':');
+ if (i < 0) {
+ return address + ":" + defaultPort;
+ } else if (Integer.parseInt(address.substring(i + 1)) == 0) {
+ return address.substring(0, i + 1) + defaultPort;
+ }
+ }
+ return address;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public URL setPath(String path) {
+ return new URL(protocol, username, password, host, port, path, getParameters());
+ }
+
+ public String getAbsolutePath() {
+ if (path != null && !path.startsWith("/")) {
+ return "/" + path;
+ }
+ return path;
+ }
+
+ public Map<String, String> getParameters() {
+ return parameters;
+ }
+
+ public String getParameterAndDecoded(String key) {
+ return getParameterAndDecoded(key, null);
+ }
+
+ public String getParameterAndDecoded(String key, String defaultValue) {
+ return decode(getParameter(key, defaultValue));
+ }
+
+ public String getParameter(String key) {
+ String value = parameters.get(key);
+ if (value == null || value.length() == 0) {
+ value = parameters.get(Constants.DEFAULT_KEY_PREFIX + key);
+ }
+ return value;
+ }
+
+ public String getParameter(String key, String defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public String[] getParameter(String key, String[] defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Constants.COMMA_SPLIT_PATTERN.split(value);
+ }
+
+ private Map<String, Number> getNumbers() {
+ if (numbers == null) { // concurrent initialization is tolerant
+ numbers = new ConcurrentHashMap<String, Number>();
+ }
+ return numbers;
+ }
+
+ private Map<String, URL> getUrls() {
+ if (urls == null) { // concurrent initialization is tolerant
+ urls = new ConcurrentHashMap<String, URL>();
+ }
+ return urls;
+ }
+
+ public URL getUrlParameter(String key) {
+ URL u = getUrls().get(key);
+ if (u != null) {
+ return u;
+ }
+ String value = getParameterAndDecoded(key);
+ if (value == null || value.length() == 0) {
+ return null;
+ }
+ u = URL.valueOf(value);
+ getUrls().put(key, u);
+ return u;
+ }
+
+ public double getParameter(String key, double defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.doubleValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ double d = Double.parseDouble(value);
+ getNumbers().put(key, d);
+ return d;
+ }
+
+ public float getParameter(String key, float defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.floatValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ float f = Float.parseFloat(value);
+ getNumbers().put(key, f);
+ return f;
+ }
+
+ public long getParameter(String key, long defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.longValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ long l = Long.parseLong(value);
+ getNumbers().put(key, l);
+ return l;
+ }
+
+ public int getParameter(String key, int defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.intValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ int i = Integer.parseInt(value);
+ getNumbers().put(key, i);
+ return i;
+ }
+
+ public short getParameter(String key, short defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.shortValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ short s = Short.parseShort(value);
+ getNumbers().put(key, s);
+ return s;
+ }
+
+ public byte getParameter(String key, byte defaultValue) {
+ Number n = getNumbers().get(key);
+ if (n != null) {
+ return n.byteValue();
+ }
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ byte b = Byte.parseByte(value);
+ getNumbers().put(key, b);
+ return b;
+ }
+
+ public float getPositiveParameter(String key, float defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ float value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public double getPositiveParameter(String key, double defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ double value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public long getPositiveParameter(String key, long defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ long value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public int getPositiveParameter(String key, int defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ int value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public short getPositiveParameter(String key, short defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ short value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public byte getPositiveParameter(String key, byte defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ byte value = getParameter(key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public char getParameter(String key, char defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value.charAt(0);
+ }
+
+ public boolean getParameter(String key, boolean defaultValue) {
+ String value = getParameter(key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean hasParameter(String key) {
+ String value = getParameter(key);
+ return value != null && value.length() > 0;
+ }
+
+ public String getMethodParameterAndDecoded(String method, String key) {
+ return URL.decode(getMethodParameter(method, key));
+ }
+
+ public String getMethodParameterAndDecoded(String method, String key, String defaultValue) {
+ return URL.decode(getMethodParameter(method, key, defaultValue));
+ }
+
+ public String getMethodParameter(String method, String key) {
+ String value = parameters.get(method + "." + key);
+ if (value == null || value.length() == 0) {
+ return getParameter(key);
+ }
+ return value;
+ }
+
+ public String getMethodParameter(String method, String key, String defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public double getMethodParameter(String method, String key, double defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.intValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ double d = Double.parseDouble(value);
+ getNumbers().put(methodKey, d);
+ return d;
+ }
+
+ public float getMethodParameter(String method, String key, float defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.intValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ float f = Float.parseFloat(value);
+ getNumbers().put(methodKey, f);
+ return f;
+ }
+
+ public long getMethodParameter(String method, String key, long defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.intValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ long l = Long.parseLong(value);
+ getNumbers().put(methodKey, l);
+ return l;
+ }
+
+ public int getMethodParameter(String method, String key, int defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.intValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ int i = Integer.parseInt(value);
+ getNumbers().put(methodKey, i);
+ return i;
+ }
+
+ public short getMethodParameter(String method, String key, short defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.shortValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ short s = Short.parseShort(value);
+ getNumbers().put(methodKey, s);
+ return s;
+ }
+
+ public byte getMethodParameter(String method, String key, byte defaultValue) {
+ String methodKey = method + "." + key;
+ Number n = getNumbers().get(methodKey);
+ if (n != null) {
+ return n.byteValue();
+ }
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ byte b = Byte.parseByte(value);
+ getNumbers().put(methodKey, b);
+ return b;
+ }
+
+ public double getMethodPositiveParameter(String method, String key, double defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ double value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public float getMethodPositiveParameter(String method, String key, float defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ float value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public long getMethodPositiveParameter(String method, String key, long defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ long value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public int getMethodPositiveParameter(String method, String key, int defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ int value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public short getMethodPositiveParameter(String method, String key, short defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ short value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public byte getMethodPositiveParameter(String method, String key, byte defaultValue) {
+ if (defaultValue <= 0) {
+ throw new IllegalArgumentException("defaultValue <= 0");
+ }
+ byte value = getMethodParameter(method, key, defaultValue);
+ if (value <= 0) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ public char getMethodParameter(String method, String key, char defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return value.charAt(0);
+ }
+
+ public boolean getMethodParameter(String method, String key, boolean defaultValue) {
+ String value = getMethodParameter(method, key);
+ if (value == null || value.length() == 0) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(value);
+ }
+
+ public boolean hasMethodParameter(String method, String key) {
+ if (method == null) {
+ String suffix = "." + key;
+ for (String fullKey : parameters.keySet()) {
+ if (fullKey.endsWith(suffix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ if (key == null) {
+ String prefix = method + ".";
+ for (String fullKey : parameters.keySet()) {
+ if (fullKey.startsWith(prefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ String value = getMethodParameter(method, key);
+ return value != null && value.length() > 0;
+ }
+
+ public boolean isLocalHost() {
+ return NetUtils.isLocalHost(host) || getParameter(Constants.LOCALHOST_KEY, false);
+ }
+
+ public boolean isAnyHost() {
+ return Constants.ANYHOST_VALUE.equals(host) || getParameter(Constants.ANYHOST_KEY, false);
+ }
+
+ public URL addParameterAndEncoded(String key, String value) {
+ if (value == null || value.length() == 0) {
+ return this;
+ }
+ return addParameter(key, encode(value));
+ }
+
+ public URL addParameter(String key, boolean value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, char value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, byte value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, short value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, int value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, long value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, float value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, double value) {
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, Enum<?> value) {
+ if (value == null) return this;
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, Number value) {
+ if (value == null) return this;
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, CharSequence value) {
+ if (value == null || value.length() == 0) return this;
+ return addParameter(key, String.valueOf(value));
+ }
+
+ public URL addParameter(String key, String value) {
+ if (key == null || key.length() == 0
+ || value == null || value.length() == 0) {
+ return this;
+ }
+ // if value doesn't change, return immediately
+ if (value.equals(getParameters().get(key))) { // value != null
+ return this;
+ }
+
+ Map<String, String> map = new HashMap<String, String>(getParameters());
+ map.put(key, value);
+ return new URL(protocol, username, password, host, port, path, map);
+ }
+
+ public URL addParameterIfAbsent(String key, String value) {
+ if (key == null || key.length() == 0
+ || value == null || value.length() == 0) {
+ return this;
+ }
+ if (hasParameter(key)) {
+ return this;
+ }
+ Map<String, String> map = new HashMap<String, String>(getParameters());
+ map.put(key, value);
+ return new URL(protocol, username, password, host, port, path, map);
+ }
+
+ /**
+ * Add parameters to a new url.
+ *
+ * @param parameters parameters in key-value pairs
+ * @return A new URL
+ */
+ public URL addParameters(Map<String, String> parameters) {
+ if (parameters == null || parameters.size() == 0) {
+ return this;
+ }
+
+ boolean hasAndEqual = true;
+ for (Map.Entry<String, String> entry : parameters.entrySet()) {
+ String value = getParameters().get(entry.getKey());
+ if (value == null) {
+ if (entry.getValue() != null) {
+ hasAndEqual = false;
+ break;
+ }
+ } else {
+ if (!value.equals(entry.getValue())) {
+ hasAndEqual = false;
+ break;
+ }
+ }
+ }
+ // return immediately if there's no change
+ if (hasAndEqual) return this;
+
+ Map<String, String> map = new HashMap<String, String>(getParameters());
+ map.putAll(parameters);
+ return new URL(protocol, username, password, host, port, path, map);
+ }
+
+ public URL addParametersIfAbsent(Map<String, String> parameters) {
+ if (parameters == null || parameters.size() == 0) {
+ return this;
+ }
+ Map<String, String> map = new HashMap<String, String>(parameters);
+ map.putAll(getParameters());
+ return new URL(protocol, username, password, host, port, path, map);
+ }
+
+ public URL addParameters(String... pairs) {
+ if (pairs == null || pairs.length == 0) {
+ return this;
+ }
+ if (pairs.length % 2 != 0) {
+ throw new IllegalArgumentException("Map pairs can not be odd number.");
+ }
+ Map<String, String> map = new HashMap<String, String>();
+ int len = pairs.length / 2;
+ for (int i = 0; i < len; i++) {
+ map.put(pairs[2 * i], pairs[2 * i + 1]);
+ }
+ return addParameters(map);
+ }
+
+ public URL addParameterString(String query) {
+ if (query == null || query.length() == 0) {
+ return this;
+ }
+ return addParameters(StringUtils.parseQueryString(query));
+ }
+
+ public URL removeParameter(String key) {
+ if (key == null || key.length() == 0) {
+ return this;
+ }
+ return removeParameters(key);
+ }
+
+ public URL removeParameters(Collection<String> keys) {
+ if (keys == null || keys.isEmpty()) {
+ return this;
+ }
+ return removeParameters(keys.toArray(new String[0]));
+ }
+
+ public URL removeParameters(String... keys) {
+ if (keys == null || keys.length == 0) {
+ return this;
+ }
+ Map<String, String> map = new HashMap<String, String>(getParameters());
+ for (String key : keys) {
+ map.remove(key);
+ }
+ if (map.size() == getParameters().size()) {
+ return this;
+ }
+ return new URL(protocol, username, password, host, port, path, map);
+ }
+
+ public URL clearParameters() {
+ return new URL(protocol, username, password, host, port, path, new HashMap<String, String>());
+ }
+
+ public String getRawParameter(String key) {
+ if ("protocol".equals(key))
+ return protocol;
+ if ("username".equals(key))
+ return username;
+ if ("password".equals(key))
+ return password;
+ if ("host".equals(key))
+ return host;
+ if ("port".equals(key))
+ return String.valueOf(port);
+ if ("path".equals(key))
+ return path;
+ return getParameter(key);
+ }
+
+ public Map<String, String> toMap() {
+ Map<String, String> map = new HashMap<String, String>(parameters);
+ if (protocol != null)
+ map.put("protocol", protocol);
+ if (username != null)
+ map.put("username", username);
+ if (password != null)
+ map.put("password", password);
+ if (host != null)
+ map.put("host", host);
+ if (port > 0)
+ map.put("port", String.valueOf(port));
+ if (path != null)
+ map.put("path", path);
+ return map;
+ }
+
+ @Override
+ public String toString() {
+ if (string != null) {
+ return string;
+ }
+ return string = buildString(false, true); // no show username and password
+ }
+
+ public String toString(String... parameters) {
+ return buildString(false, true, parameters); // no show username and password
+ }
+
+ public String toIdentityString() {
+ if (identity != null) {
+ return identity;
+ }
+ return identity = buildString(true, false); // only return identity message, see the method "equals" and "hashCode"
+ }
+
+ public String toIdentityString(String... parameters) {
+ return buildString(true, false, parameters); // only return identity message, see the method "equals" and "hashCode"
+ }
+
+ public String toFullString() {
+ if (full != null) {
+ return full;
+ }
+ return full = buildString(true, true);
+ }
+
+ public String toFullString(String... parameters) {
+ return buildString(true, true, parameters);
+ }
+
+ public String toParameterString() {
+ if (parameter != null) {
+ return parameter;
+ }
+ return parameter = toParameterString(new String[0]);
+ }
+
+ public String toParameterString(String... parameters) {
+ StringBuilder buf = new StringBuilder();
+ buildParameters(buf, false, parameters);
+ return buf.toString();
+ }
+
+ private void buildParameters(StringBuilder buf, boolean concat, String[] parameters) {
+ if (getParameters() != null && getParameters().size() > 0) {
+ List<String> includes = (parameters == null || parameters.length == 0 ? null : Arrays.asList(parameters));
+ boolean first = true;
+ for (Map.Entry<String, String> entry : new TreeMap<String, String>(getParameters()).entrySet()) {
+ if (entry.getKey() != null && entry.getKey().length() > 0
+ && (includes == null || includes.contains(entry.getKey()))) {
+ if (first) {
+ if (concat) {
+ buf.append("?");
+ }
+ first = false;
+ } else {
+ buf.append("&");
+ }
+ buf.append(entry.getKey());
+ buf.append("=");
+ buf.append(entry.getValue() == null ? "" : entry.getValue().trim());
+ }
+ }
+ }
+ }
+
+ private String buildString(boolean appendUser, boolean appendParameter, String... parameters) {
+ return buildString(appendUser, appendParameter, false, false, parameters);
+ }
+
+ private String buildString(boolean appendUser, boolean appendParameter, boolean useIP, boolean useService, String... parameters) {
+ StringBuilder buf = new StringBuilder();
+ if (protocol != null && protocol.length() > 0) {
+ buf.append(protocol);
+ buf.append("://");
+ }
+ if (appendUser && username != null && username.length() > 0) {
+ buf.append(username);
+ if (password != null && password.length() > 0) {
+ buf.append(":");
+ buf.append(password);
+ }
+ buf.append("@");
+ }
+ String host;
+ if (useIP) {
+ host = getIp();
+ } else {
+ host = getHost();
+ }
+ if (host != null && host.length() > 0) {
+ buf.append(host);
+ if (port > 0) {
+ buf.append(":");
+ buf.append(port);
+ }
+ }
+ String path;
+ if (useService) {
+ path = getServiceKey();
+ } else {
+ path = getPath();
+ }
+ if (path != null && path.length() > 0) {
+ buf.append("/");
+ buf.append(path);
+ }
+ if (appendParameter) {
+ buildParameters(buf, true, parameters);
+ }
+ return buf.toString();
+ }
+
+ public java.net.URL toJavaURL() {
+ try {
+ return new java.net.URL(toString());
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ public InetSocketAddress toInetSocketAddress() {
+ return new InetSocketAddress(host, port);
+ }
+
+ public String getServiceKey() {
+ String inf = getServiceInterface();
+ if (inf == null) return null;
+ StringBuilder buf = new StringBuilder();
+ String group = getParameter(Constants.GROUP_KEY);
+ if (group != null && group.length() > 0) {
+ buf.append(group).append("/");
+ }
+ buf.append(inf);
+ String version = getParameter(Constants.VERSION_KEY);
+ if (version != null && version.length() > 0) {
+ buf.append(":").append(version);
+ }
+ return buf.toString();
+ }
+
+ public String toServiceStringWithoutResolving() {
+ return buildString(true, false, false, true);
+ }
+
+ public String toServiceString() {
+ return buildString(true, false, true, true);
+ }
+
+ @Deprecated
+ public String getServiceName() {
+ return getServiceInterface();
+ }
+
+ public String getServiceInterface() {
+ return getParameter(Constants.INTERFACE_KEY, path);
+ }
+
+ public URL setServiceInterface(String service) {
+ return addParameter(Constants.INTERFACE_KEY, service);
+ }
+
+ /**
+ * @see #getParameter(String, int)
+ * @deprecated Replace to <code>getParameter(String, int)</code>
+ */
+ @Deprecated
+ public int getIntParameter(String key) {
+ return getParameter(key, 0);
+ }
+
+ /**
+ * @see #getParameter(String, int)
+ * @deprecated Replace to <code>getParameter(String, int)</code>
+ */
+ @Deprecated
+ public int getIntParameter(String key, int defaultValue) {
+ return getParameter(key, defaultValue);
+ }
+
+ /**
+ * @see #getPositiveParameter(String, int)
+ * @deprecated Replace to <code>getPositiveParameter(String, int)</code>
+ */
+ @Deprecated
+ public int getPositiveIntParameter(String key, int defaultValue) {
+ return getPositiveParameter(key, defaultValue);
+ }
+
+ /**
+ * @see #getParameter(String, boolean)
+ * @deprecated Replace to <code>getParameter(String, boolean)</code>
+ */
+ @Deprecated
+ public boolean getBooleanParameter(String key) {
+ return getParameter(key, false);
+ }
+
+ /**
+ * @see #getParameter(String, boolean)
+ * @deprecated Replace to <code>getParameter(String, boolean)</code>
+ */
+ @Deprecated
+ public boolean getBooleanParameter(String key, boolean defaultValue) {
+ return getParameter(key, defaultValue);
+ }
+
+ /**
+ * @see #getMethodParameter(String, String, int)
+ * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>
+ */
+ @Deprecated
+ public int getMethodIntParameter(String method, String key) {
+ return getMethodParameter(method, key, 0);
+ }
+
+ /**
+ * @see #getMethodParameter(String, String, int)
+ * @deprecated Replace to <code>getMethodParameter(String, String, int)</code>
+ */
+ @Deprecated
+ public int getMethodIntParameter(String method, String key, int defaultValue) {
+ return getMethodParameter(method, key, defaultValue);
+ }
+
+ /**
+ * @see #getMethodPositiveParameter(String, String, int)
+ * @deprecated Replace to <code>getMethodPositiveParameter(String, String, int)</code>
+ */
+ @Deprecated
+ public int getMethodPositiveIntParameter(String method, String key, int defaultValue) {
+ return getMethodPositiveParameter(method, key, defaultValue);
+ }
+
+ /**
+ * @see #getMethodParameter(String, String, boolean)
+ * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>
+ */
+ @Deprecated
+ public boolean getMethodBooleanParameter(String method, String key) {
+ return getMethodParameter(method, key, false);
+ }
+
+ /**
+ * @see #getMethodParameter(String, String, boolean)
+ * @deprecated Replace to <code>getMethodParameter(String, String, boolean)</code>
+ */
+ @Deprecated
+ public boolean getMethodBooleanParameter(String method, String key, boolean defaultValue) {
+ return getMethodParameter(method, key, defaultValue);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((host == null) ? 0 : host.hashCode());
+ result = prime * result + ((parameters == null) ? 0 : parameters.hashCode());
+ result = prime * result + ((password == null) ? 0 : password.hashCode());
+ result = prime * result + ((path == null) ? 0 : path.hashCode());
+ result = prime * result + port;
+ result = prime * result + ((protocol == null) ? 0 : protocol.hashCode());
+ result = prime * result + ((username == null) ? 0 : username.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ URL other = (URL) obj;
+ if (host == null) {
+ if (other.host != null)
+ return false;
+ } else if (!host.equals(other.host))
+ return false;
+ if (parameters == null) {
+ if (other.parameters != null)
+ return false;
+ } else if (!parameters.equals(other.parameters))
+ return false;
+ if (password == null) {
+ if (other.password != null)
+ return false;
+ } else if (!password.equals(other.password))
+ return false;
+ if (path == null) {
+ if (other.path != null)
+ return false;
+ } else if (!path.equals(other.path))
+ return false;
+ if (port != other.port)
+ return false;
+ if (protocol == null) {
+ if (other.protocol != null)
+ return false;
+ } else if (!protocol.equals(other.protocol))
+ return false;
+ if (username == null) {
+ if (other.username != null)
+ return false;
+ } else if (!username.equals(other.username))
+ return false;
+ return true;
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
index 685ad177cb..7eab119b83 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/ClassGenerator.java
@@ -1,333 +1,333 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-import javassist.CannotCompileException;
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.CtConstructor;
-import javassist.CtField;
-import javassist.CtMethod;
-import javassist.CtNewConstructor;
-import javassist.CtNewMethod;
-import javassist.LoaderClassPath;
-import javassist.NotFoundException;
-import org.apache.dubbo.common.utils.ClassHelper;
-import org.apache.dubbo.common.utils.ReflectUtils;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.security.ProtectionDomain;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * ClassGenerator
- */
-public final class ClassGenerator {
- private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(0);
- private static final String SIMPLE_NAME_TAG = "<init>";
- private static final Map<ClassLoader, ClassPool> POOL_MAP = new ConcurrentHashMap<ClassLoader, ClassPool>(); //ClassLoader - ClassPool
- private ClassPool mPool;
- private CtClass mCtc;
- private String mClassName, mSuperClass;
- private Set<String> mInterfaces;
- private List<String> mFields, mConstructors, mMethods;
- private Map<String, Method> mCopyMethods; // <method desc,method instance>
- private Map<String, Constructor<?>> mCopyConstructors; // <constructor desc,constructor instance>
- private boolean mDefaultConstructor = false;
-
- private ClassGenerator() {
- }
-
- private ClassGenerator(ClassPool pool) {
- mPool = pool;
- }
-
- public static ClassGenerator newInstance() {
- return new ClassGenerator(getClassPool(Thread.currentThread().getContextClassLoader()));
- }
-
- public static ClassGenerator newInstance(ClassLoader loader) {
- return new ClassGenerator(getClassPool(loader));
- }
-
- public static boolean isDynamicClass(Class<?> cl) {
- return ClassGenerator.DC.class.isAssignableFrom(cl);
- }
-
- public static ClassPool getClassPool(ClassLoader loader) {
- if (loader == null)
- return ClassPool.getDefault();
-
- ClassPool pool = POOL_MAP.get(loader);
- if (pool == null) {
- pool = new ClassPool(true);
- pool.appendClassPath(new LoaderClassPath(loader));
- POOL_MAP.put(loader, pool);
- }
- return pool;
- }
-
- private static String modifier(int mod) {
- StringBuilder modifier = new StringBuilder();
- if (Modifier.isPublic(mod)) modifier.append("public");
- if (Modifier.isProtected(mod)) modifier.append("protected");
- if (Modifier.isPrivate(mod)) modifier.append("private");
-
- if (Modifier.isStatic(mod)) modifier.append(" static");
- if (Modifier.isVolatile(mod)) modifier.append(" volatile");
-
- return modifier.toString();
- }
-
- public String getClassName() {
- return mClassName;
- }
-
- public ClassGenerator setClassName(String name) {
- mClassName = name;
- return this;
- }
-
- public ClassGenerator addInterface(String cn) {
- if (mInterfaces == null)
- mInterfaces = new HashSet<String>();
- mInterfaces.add(cn);
- return this;
- }
-
- public ClassGenerator addInterface(Class<?> cl) {
- return addInterface(cl.getName());
- }
-
- public ClassGenerator setSuperClass(String cn) {
- mSuperClass = cn;
- return this;
- }
-
- public ClassGenerator setSuperClass(Class<?> cl) {
- mSuperClass = cl.getName();
- return this;
- }
-
- public ClassGenerator addField(String code) {
- if (mFields == null)
- mFields = new ArrayList<String>();
- mFields.add(code);
- return this;
- }
-
- public ClassGenerator addField(String name, int mod, Class<?> type) {
- return addField(name, mod, type, null);
- }
-
- public ClassGenerator addField(String name, int mod, Class<?> type, String def) {
- StringBuilder sb = new StringBuilder();
- sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(type)).append(' ');
- sb.append(name);
- if (def != null && def.length() > 0) {
- sb.append('=');
- sb.append(def);
- }
- sb.append(';');
- return addField(sb.toString());
- }
-
- public ClassGenerator addMethod(String code) {
- if (mMethods == null)
- mMethods = new ArrayList<String>();
- mMethods.add(code);
- return this;
- }
-
- public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, String body) {
- return addMethod(name, mod, rt, pts, null, body);
- }
-
- public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, Class<?>[] ets, String body) {
- StringBuilder sb = new StringBuilder();
- sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(rt)).append(' ').append(name);
- sb.append('(');
- for (int i = 0; i < pts.length; i++) {
- if (i > 0)
- sb.append(',');
- sb.append(ReflectUtils.getName(pts[i]));
- sb.append(" arg").append(i);
- }
- sb.append(')');
- if (ets != null && ets.length > 0) {
- sb.append(" throws ");
- for (int i = 0; i < ets.length; i++) {
- if (i > 0)
- sb.append(',');
- sb.append(ReflectUtils.getName(ets[i]));
- }
- }
- sb.append('{').append(body).append('}');
- return addMethod(sb.toString());
- }
-
- public ClassGenerator addMethod(Method m) {
- addMethod(m.getName(), m);
- return this;
- }
-
- public ClassGenerator addMethod(String name, Method m) {
- String desc = name + ReflectUtils.getDescWithoutMethodName(m);
- addMethod(':' + desc);
- if (mCopyMethods == null)
- mCopyMethods = new ConcurrentHashMap<String, Method>(8);
- mCopyMethods.put(desc, m);
- return this;
- }
-
- public ClassGenerator addConstructor(String code) {
- if (mConstructors == null)
- mConstructors = new LinkedList<String>();
- mConstructors.add(code);
- return this;
- }
-
- public ClassGenerator addConstructor(int mod, Class<?>[] pts, String body) {
- return addConstructor(mod, pts, null, body);
- }
-
- public ClassGenerator addConstructor(int mod, Class<?>[] pts, Class<?>[] ets, String body) {
- StringBuilder sb = new StringBuilder();
- sb.append(modifier(mod)).append(' ').append(SIMPLE_NAME_TAG);
- sb.append('(');
- for (int i = 0; i < pts.length; i++) {
- if (i > 0)
- sb.append(',');
- sb.append(ReflectUtils.getName(pts[i]));
- sb.append(" arg").append(i);
- }
- sb.append(')');
- if (ets != null && ets.length > 0) {
- sb.append(" throws ");
- for (int i = 0; i < ets.length; i++) {
- if (i > 0)
- sb.append(',');
- sb.append(ReflectUtils.getName(ets[i]));
- }
- }
- sb.append('{').append(body).append('}');
- return addConstructor(sb.toString());
- }
-
- public ClassGenerator addConstructor(Constructor<?> c) {
- String desc = ReflectUtils.getDesc(c);
- addConstructor(":" + desc);
- if (mCopyConstructors == null)
- mCopyConstructors = new ConcurrentHashMap<String, Constructor<?>>(4);
- mCopyConstructors.put(desc, c);
- return this;
- }
-
- public ClassGenerator addDefaultConstructor() {
- mDefaultConstructor = true;
- return this;
- }
-
- public ClassPool getClassPool() {
- return mPool;
- }
-
- public Class<?> toClass() {
- return toClass(ClassHelper.getClassLoader(ClassGenerator.class), getClass().getProtectionDomain());
- }
-
- public Class<?> toClass(ClassLoader loader, ProtectionDomain pd) {
- if (mCtc != null)
- mCtc.detach();
- long id = CLASS_NAME_COUNTER.getAndIncrement();
- try {
- CtClass ctcs = mSuperClass == null ? null : mPool.get(mSuperClass);
- if (mClassName == null)
- mClassName = (mSuperClass == null || javassist.Modifier.isPublic(ctcs.getModifiers())
- ? ClassGenerator.class.getName() : mSuperClass + "$sc") + id;
- mCtc = mPool.makeClass(mClassName);
- if (mSuperClass != null)
- mCtc.setSuperclass(ctcs);
- mCtc.addInterface(mPool.get(DC.class.getName())); // add dynamic class tag.
- if (mInterfaces != null)
- for (String cl : mInterfaces) mCtc.addInterface(mPool.get(cl));
- if (mFields != null)
- for (String code : mFields) mCtc.addField(CtField.make(code, mCtc));
- if (mMethods != null) {
- for (String code : mMethods) {
- if (code.charAt(0) == ':')
- mCtc.addMethod(CtNewMethod.copy(getCtMethod(mCopyMethods.get(code.substring(1))), code.substring(1, code.indexOf('(')), mCtc, null));
- else
- mCtc.addMethod(CtNewMethod.make(code, mCtc));
- }
- }
- if (mDefaultConstructor)
- mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
- if (mConstructors != null) {
- for (String code : mConstructors) {
- if (code.charAt(0) == ':') {
- mCtc.addConstructor(CtNewConstructor.copy(getCtConstructor(mCopyConstructors.get(code.substring(1))), mCtc, null));
- } else {
- String[] sn = mCtc.getSimpleName().split("\\$+"); // inner class name include $.
- mCtc.addConstructor(CtNewConstructor.make(code.replaceFirst(SIMPLE_NAME_TAG, sn[sn.length - 1]), mCtc));
- }
- }
- }
- return mCtc.toClass(loader, pd);
- } catch (RuntimeException e) {
- throw e;
- } catch (NotFoundException e) {
- throw new RuntimeException(e.getMessage(), e);
- } catch (CannotCompileException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- public void release() {
- if (mCtc != null) mCtc.detach();
- if (mInterfaces != null) mInterfaces.clear();
- if (mFields != null) mFields.clear();
- if (mMethods != null) mMethods.clear();
- if (mConstructors != null) mConstructors.clear();
- if (mCopyMethods != null) mCopyMethods.clear();
- if (mCopyConstructors != null) mCopyConstructors.clear();
- }
-
- private CtClass getCtClass(Class<?> c) throws NotFoundException {
- return mPool.get(c.getName());
- }
-
- private CtMethod getCtMethod(Method m) throws NotFoundException {
- return getCtClass(m.getDeclaringClass()).getMethod(m.getName(), ReflectUtils.getDescWithoutMethodName(m));
- }
-
- private CtConstructor getCtConstructor(Constructor<?> c) throws NotFoundException {
- return getCtClass(c.getDeclaringClass()).getConstructor(ReflectUtils.getDesc(c));
- }
-
- public static interface DC {
- } // dynamic class tag interface.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+import javassist.CannotCompileException;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtConstructor;
+import javassist.CtField;
+import javassist.CtMethod;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+import javassist.LoaderClassPath;
+import javassist.NotFoundException;
+import org.apache.dubbo.common.utils.ClassHelper;
+import org.apache.dubbo.common.utils.ReflectUtils;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * ClassGenerator
+ */
+public final class ClassGenerator {
+ private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(0);
+ private static final String SIMPLE_NAME_TAG = "<init>";
+ private static final Map<ClassLoader, ClassPool> POOL_MAP = new ConcurrentHashMap<ClassLoader, ClassPool>(); //ClassLoader - ClassPool
+ private ClassPool mPool;
+ private CtClass mCtc;
+ private String mClassName, mSuperClass;
+ private Set<String> mInterfaces;
+ private List<String> mFields, mConstructors, mMethods;
+ private Map<String, Method> mCopyMethods; // <method desc,method instance>
+ private Map<String, Constructor<?>> mCopyConstructors; // <constructor desc,constructor instance>
+ private boolean mDefaultConstructor = false;
+
+ private ClassGenerator() {
+ }
+
+ private ClassGenerator(ClassPool pool) {
+ mPool = pool;
+ }
+
+ public static ClassGenerator newInstance() {
+ return new ClassGenerator(getClassPool(Thread.currentThread().getContextClassLoader()));
+ }
+
+ public static ClassGenerator newInstance(ClassLoader loader) {
+ return new ClassGenerator(getClassPool(loader));
+ }
+
+ public static boolean isDynamicClass(Class<?> cl) {
+ return ClassGenerator.DC.class.isAssignableFrom(cl);
+ }
+
+ public static ClassPool getClassPool(ClassLoader loader) {
+ if (loader == null)
+ return ClassPool.getDefault();
+
+ ClassPool pool = POOL_MAP.get(loader);
+ if (pool == null) {
+ pool = new ClassPool(true);
+ pool.appendClassPath(new LoaderClassPath(loader));
+ POOL_MAP.put(loader, pool);
+ }
+ return pool;
+ }
+
+ private static String modifier(int mod) {
+ StringBuilder modifier = new StringBuilder();
+ if (Modifier.isPublic(mod)) modifier.append("public");
+ if (Modifier.isProtected(mod)) modifier.append("protected");
+ if (Modifier.isPrivate(mod)) modifier.append("private");
+
+ if (Modifier.isStatic(mod)) modifier.append(" static");
+ if (Modifier.isVolatile(mod)) modifier.append(" volatile");
+
+ return modifier.toString();
+ }
+
+ public String getClassName() {
+ return mClassName;
+ }
+
+ public ClassGenerator setClassName(String name) {
+ mClassName = name;
+ return this;
+ }
+
+ public ClassGenerator addInterface(String cn) {
+ if (mInterfaces == null)
+ mInterfaces = new HashSet<String>();
+ mInterfaces.add(cn);
+ return this;
+ }
+
+ public ClassGenerator addInterface(Class<?> cl) {
+ return addInterface(cl.getName());
+ }
+
+ public ClassGenerator setSuperClass(String cn) {
+ mSuperClass = cn;
+ return this;
+ }
+
+ public ClassGenerator setSuperClass(Class<?> cl) {
+ mSuperClass = cl.getName();
+ return this;
+ }
+
+ public ClassGenerator addField(String code) {
+ if (mFields == null)
+ mFields = new ArrayList<String>();
+ mFields.add(code);
+ return this;
+ }
+
+ public ClassGenerator addField(String name, int mod, Class<?> type) {
+ return addField(name, mod, type, null);
+ }
+
+ public ClassGenerator addField(String name, int mod, Class<?> type, String def) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(type)).append(' ');
+ sb.append(name);
+ if (def != null && def.length() > 0) {
+ sb.append('=');
+ sb.append(def);
+ }
+ sb.append(';');
+ return addField(sb.toString());
+ }
+
+ public ClassGenerator addMethod(String code) {
+ if (mMethods == null)
+ mMethods = new ArrayList<String>();
+ mMethods.add(code);
+ return this;
+ }
+
+ public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, String body) {
+ return addMethod(name, mod, rt, pts, null, body);
+ }
+
+ public ClassGenerator addMethod(String name, int mod, Class<?> rt, Class<?>[] pts, Class<?>[] ets, String body) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(modifier(mod)).append(' ').append(ReflectUtils.getName(rt)).append(' ').append(name);
+ sb.append('(');
+ for (int i = 0; i < pts.length; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(ReflectUtils.getName(pts[i]));
+ sb.append(" arg").append(i);
+ }
+ sb.append(')');
+ if (ets != null && ets.length > 0) {
+ sb.append(" throws ");
+ for (int i = 0; i < ets.length; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(ReflectUtils.getName(ets[i]));
+ }
+ }
+ sb.append('{').append(body).append('}');
+ return addMethod(sb.toString());
+ }
+
+ public ClassGenerator addMethod(Method m) {
+ addMethod(m.getName(), m);
+ return this;
+ }
+
+ public ClassGenerator addMethod(String name, Method m) {
+ String desc = name + ReflectUtils.getDescWithoutMethodName(m);
+ addMethod(':' + desc);
+ if (mCopyMethods == null)
+ mCopyMethods = new ConcurrentHashMap<String, Method>(8);
+ mCopyMethods.put(desc, m);
+ return this;
+ }
+
+ public ClassGenerator addConstructor(String code) {
+ if (mConstructors == null)
+ mConstructors = new LinkedList<String>();
+ mConstructors.add(code);
+ return this;
+ }
+
+ public ClassGenerator addConstructor(int mod, Class<?>[] pts, String body) {
+ return addConstructor(mod, pts, null, body);
+ }
+
+ public ClassGenerator addConstructor(int mod, Class<?>[] pts, Class<?>[] ets, String body) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(modifier(mod)).append(' ').append(SIMPLE_NAME_TAG);
+ sb.append('(');
+ for (int i = 0; i < pts.length; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(ReflectUtils.getName(pts[i]));
+ sb.append(" arg").append(i);
+ }
+ sb.append(')');
+ if (ets != null && ets.length > 0) {
+ sb.append(" throws ");
+ for (int i = 0; i < ets.length; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(ReflectUtils.getName(ets[i]));
+ }
+ }
+ sb.append('{').append(body).append('}');
+ return addConstructor(sb.toString());
+ }
+
+ public ClassGenerator addConstructor(Constructor<?> c) {
+ String desc = ReflectUtils.getDesc(c);
+ addConstructor(":" + desc);
+ if (mCopyConstructors == null)
+ mCopyConstructors = new ConcurrentHashMap<String, Constructor<?>>(4);
+ mCopyConstructors.put(desc, c);
+ return this;
+ }
+
+ public ClassGenerator addDefaultConstructor() {
+ mDefaultConstructor = true;
+ return this;
+ }
+
+ public ClassPool getClassPool() {
+ return mPool;
+ }
+
+ public Class<?> toClass() {
+ return toClass(ClassHelper.getClassLoader(ClassGenerator.class), getClass().getProtectionDomain());
+ }
+
+ public Class<?> toClass(ClassLoader loader, ProtectionDomain pd) {
+ if (mCtc != null)
+ mCtc.detach();
+ long id = CLASS_NAME_COUNTER.getAndIncrement();
+ try {
+ CtClass ctcs = mSuperClass == null ? null : mPool.get(mSuperClass);
+ if (mClassName == null)
+ mClassName = (mSuperClass == null || javassist.Modifier.isPublic(ctcs.getModifiers())
+ ? ClassGenerator.class.getName() : mSuperClass + "$sc") + id;
+ mCtc = mPool.makeClass(mClassName);
+ if (mSuperClass != null)
+ mCtc.setSuperclass(ctcs);
+ mCtc.addInterface(mPool.get(DC.class.getName())); // add dynamic class tag.
+ if (mInterfaces != null)
+ for (String cl : mInterfaces) mCtc.addInterface(mPool.get(cl));
+ if (mFields != null)
+ for (String code : mFields) mCtc.addField(CtField.make(code, mCtc));
+ if (mMethods != null) {
+ for (String code : mMethods) {
+ if (code.charAt(0) == ':')
+ mCtc.addMethod(CtNewMethod.copy(getCtMethod(mCopyMethods.get(code.substring(1))), code.substring(1, code.indexOf('(')), mCtc, null));
+ else
+ mCtc.addMethod(CtNewMethod.make(code, mCtc));
+ }
+ }
+ if (mDefaultConstructor)
+ mCtc.addConstructor(CtNewConstructor.defaultConstructor(mCtc));
+ if (mConstructors != null) {
+ for (String code : mConstructors) {
+ if (code.charAt(0) == ':') {
+ mCtc.addConstructor(CtNewConstructor.copy(getCtConstructor(mCopyConstructors.get(code.substring(1))), mCtc, null));
+ } else {
+ String[] sn = mCtc.getSimpleName().split("\\$+"); // inner class name include $.
+ mCtc.addConstructor(CtNewConstructor.make(code.replaceFirst(SIMPLE_NAME_TAG, sn[sn.length - 1]), mCtc));
+ }
+ }
+ }
+ return mCtc.toClass(loader, pd);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (NotFoundException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } catch (CannotCompileException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+
+ public void release() {
+ if (mCtc != null) mCtc.detach();
+ if (mInterfaces != null) mInterfaces.clear();
+ if (mFields != null) mFields.clear();
+ if (mMethods != null) mMethods.clear();
+ if (mConstructors != null) mConstructors.clear();
+ if (mCopyMethods != null) mCopyMethods.clear();
+ if (mCopyConstructors != null) mCopyConstructors.clear();
+ }
+
+ private CtClass getCtClass(Class<?> c) throws NotFoundException {
+ return mPool.get(c.getName());
+ }
+
+ private CtMethod getCtMethod(Method m) throws NotFoundException {
+ return getCtClass(m.getDeclaringClass()).getMethod(m.getName(), ReflectUtils.getDescWithoutMethodName(m));
+ }
+
+ private CtConstructor getCtConstructor(Constructor<?> c) throws NotFoundException {
+ return getCtClass(c.getDeclaringClass()).getConstructor(ReflectUtils.getDesc(c));
+ }
+
+ public static interface DC {
+ } // dynamic class tag interface.
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
index fe37f2f031..2f7e14cc1b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Mixin.java
@@ -1,214 +1,214 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-import org.apache.dubbo.common.utils.ClassHelper;
-import org.apache.dubbo.common.utils.ReflectUtils;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Mixin
- */
-public abstract class Mixin {
- private static final String PACKAGE_NAME = Mixin.class.getPackage().getName();
- private static AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0);
-
- protected Mixin() {
- }
-
- /**
- * mixin interface and delegates.
- * all class must be public.
- *
- * @param ics interface class array.
- * @param dc delegate class.
- * @return Mixin instance.
- */
- public static Mixin mixin(Class<?>[] ics, Class<?> dc) {
- return mixin(ics, new Class[]{dc});
- }
-
- /**
- * mixin interface and delegates.
- * all class must be public.
- *
- * @param ics interface class array.
- * @param dc delegate class.
- * @param cl class loader.
- * @return Mixin instance.
- */
- public static Mixin mixin(Class<?>[] ics, Class<?> dc, ClassLoader cl) {
- return mixin(ics, new Class[]{dc}, cl);
- }
-
- /**
- * mixin interface and delegates.
- * all class must be public.
- *
- * @param ics interface class array.
- * @param dcs delegate class array.
- * @return Mixin instance.
- */
- public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs) {
- return mixin(ics, dcs, ClassHelper.getCallerClassLoader(Mixin.class));
- }
-
- /**
- * mixin interface and delegates.
- * all class must be public.
- *
- * @param ics interface class array.
- * @param dcs delegate class array.
- * @param cl class loader.
- * @return Mixin instance.
- */
- public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) {
- assertInterfaceArray(ics);
-
- long id = MIXIN_CLASS_COUNTER.getAndIncrement();
- String pkg = null;
- ClassGenerator ccp = null, ccm = null;
- try {
- ccp = ClassGenerator.newInstance(cl);
-
- // impl constructor
- StringBuilder code = new StringBuilder();
- for (int i = 0; i < dcs.length; i++) {
- if (!Modifier.isPublic(dcs[i].getModifiers())) {
- String npkg = dcs[i].getPackage().getName();
- if (pkg == null) {
- pkg = npkg;
- } else {
- if (!pkg.equals(npkg))
- throw new IllegalArgumentException("non-public interfaces class from different packages");
- }
- }
-
- ccp.addField("private " + dcs[i].getName() + " d" + i + ";");
-
- code.append("d").append(i).append(" = (").append(dcs[i].getName()).append(")$1[").append(i).append("];\n");
- if (MixinAware.class.isAssignableFrom(dcs[i]))
- code.append("d").append(i).append(".setMixinInstance(this);\n");
- }
- ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{Object[].class}, code.toString());
-
- // impl methods.
- Set<String> worked = new HashSet<String>();
- for (int i = 0; i < ics.length; i++) {
- if (!Modifier.isPublic(ics[i].getModifiers())) {
- String npkg = ics[i].getPackage().getName();
- if (pkg == null) {
- pkg = npkg;
- } else {
- if (!pkg.equals(npkg))
- throw new IllegalArgumentException("non-public delegate class from different packages");
- }
- }
-
- ccp.addInterface(ics[i]);
-
- for (Method method : ics[i].getMethods()) {
- if ("java.lang.Object".equals(method.getDeclaringClass().getName()))
- continue;
-
- String desc = ReflectUtils.getDesc(method);
- if (worked.contains(desc))
- continue;
- worked.add(desc);
-
- int ix = findMethod(dcs, desc);
- if (ix < 0)
- throw new RuntimeException("Missing method [" + desc + "] implement.");
-
- Class<?> rt = method.getReturnType();
- String mn = method.getName();
- if (Void.TYPE.equals(rt))
- ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
- "d" + ix + "." + mn + "($$);");
- else
- ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
- "return ($r)d" + ix + "." + mn + "($$);");
- }
- }
-
- if (pkg == null)
- pkg = PACKAGE_NAME;
-
- // create MixinInstance class.
- String micn = pkg + ".mixin" + id;
- ccp.setClassName(micn);
- ccp.toClass();
-
- // create Mixin class.
- String fcn = Mixin.class.getName() + id;
- ccm = ClassGenerator.newInstance(cl);
- ccm.setClassName(fcn);
- ccm.addDefaultConstructor();
- ccm.setSuperClass(Mixin.class.getName());
- ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
- Class<?> mixin = ccm.toClass();
- return (Mixin) mixin.newInstance();
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e.getMessage(), e);
- } finally {
- // release ClassGenerator
- if (ccp != null)
- ccp.release();
- if (ccm != null)
- ccm.release();
- }
- }
-
- private static int findMethod(Class<?>[] dcs, String desc) {
- Class<?> cl;
- Method[] methods;
- for (int i = 0; i < dcs.length; i++) {
- cl = dcs[i];
- methods = cl.getMethods();
- for (Method method : methods) {
- if (desc.equals(ReflectUtils.getDesc(method)))
- return i;
- }
- }
- return -1;
- }
-
- private static void assertInterfaceArray(Class<?>[] ics) {
- for (int i = 0; i < ics.length; i++)
- if (!ics[i].isInterface())
- throw new RuntimeException("Class " + ics[i].getName() + " is not a interface.");
- }
-
- /**
- * new Mixin instance.
- *
- * @param ds delegates instance.
- * @return instance.
- */
- abstract public Object newInstance(Object[] ds);
-
- public static interface MixinAware {
- void setMixinInstance(Object instance);
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+import org.apache.dubbo.common.utils.ClassHelper;
+import org.apache.dubbo.common.utils.ReflectUtils;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Mixin
+ */
+public abstract class Mixin {
+ private static final String PACKAGE_NAME = Mixin.class.getPackage().getName();
+ private static AtomicLong MIXIN_CLASS_COUNTER = new AtomicLong(0);
+
+ protected Mixin() {
+ }
+
+ /**
+ * mixin interface and delegates.
+ * all class must be public.
+ *
+ * @param ics interface class array.
+ * @param dc delegate class.
+ * @return Mixin instance.
+ */
+ public static Mixin mixin(Class<?>[] ics, Class<?> dc) {
+ return mixin(ics, new Class[]{dc});
+ }
+
+ /**
+ * mixin interface and delegates.
+ * all class must be public.
+ *
+ * @param ics interface class array.
+ * @param dc delegate class.
+ * @param cl class loader.
+ * @return Mixin instance.
+ */
+ public static Mixin mixin(Class<?>[] ics, Class<?> dc, ClassLoader cl) {
+ return mixin(ics, new Class[]{dc}, cl);
+ }
+
+ /**
+ * mixin interface and delegates.
+ * all class must be public.
+ *
+ * @param ics interface class array.
+ * @param dcs delegate class array.
+ * @return Mixin instance.
+ */
+ public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs) {
+ return mixin(ics, dcs, ClassHelper.getCallerClassLoader(Mixin.class));
+ }
+
+ /**
+ * mixin interface and delegates.
+ * all class must be public.
+ *
+ * @param ics interface class array.
+ * @param dcs delegate class array.
+ * @param cl class loader.
+ * @return Mixin instance.
+ */
+ public static Mixin mixin(Class<?>[] ics, Class<?>[] dcs, ClassLoader cl) {
+ assertInterfaceArray(ics);
+
+ long id = MIXIN_CLASS_COUNTER.getAndIncrement();
+ String pkg = null;
+ ClassGenerator ccp = null, ccm = null;
+ try {
+ ccp = ClassGenerator.newInstance(cl);
+
+ // impl constructor
+ StringBuilder code = new StringBuilder();
+ for (int i = 0; i < dcs.length; i++) {
+ if (!Modifier.isPublic(dcs[i].getModifiers())) {
+ String npkg = dcs[i].getPackage().getName();
+ if (pkg == null) {
+ pkg = npkg;
+ } else {
+ if (!pkg.equals(npkg))
+ throw new IllegalArgumentException("non-public interfaces class from different packages");
+ }
+ }
+
+ ccp.addField("private " + dcs[i].getName() + " d" + i + ";");
+
+ code.append("d").append(i).append(" = (").append(dcs[i].getName()).append(")$1[").append(i).append("];\n");
+ if (MixinAware.class.isAssignableFrom(dcs[i]))
+ code.append("d").append(i).append(".setMixinInstance(this);\n");
+ }
+ ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{Object[].class}, code.toString());
+
+ // impl methods.
+ Set<String> worked = new HashSet<String>();
+ for (int i = 0; i < ics.length; i++) {
+ if (!Modifier.isPublic(ics[i].getModifiers())) {
+ String npkg = ics[i].getPackage().getName();
+ if (pkg == null) {
+ pkg = npkg;
+ } else {
+ if (!pkg.equals(npkg))
+ throw new IllegalArgumentException("non-public delegate class from different packages");
+ }
+ }
+
+ ccp.addInterface(ics[i]);
+
+ for (Method method : ics[i].getMethods()) {
+ if ("java.lang.Object".equals(method.getDeclaringClass().getName()))
+ continue;
+
+ String desc = ReflectUtils.getDesc(method);
+ if (worked.contains(desc))
+ continue;
+ worked.add(desc);
+
+ int ix = findMethod(dcs, desc);
+ if (ix < 0)
+ throw new RuntimeException("Missing method [" + desc + "] implement.");
+
+ Class<?> rt = method.getReturnType();
+ String mn = method.getName();
+ if (Void.TYPE.equals(rt))
+ ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
+ "d" + ix + "." + mn + "($$);");
+ else
+ ccp.addMethod(mn, method.getModifiers(), rt, method.getParameterTypes(), method.getExceptionTypes(),
+ "return ($r)d" + ix + "." + mn + "($$);");
+ }
+ }
+
+ if (pkg == null)
+ pkg = PACKAGE_NAME;
+
+ // create MixinInstance class.
+ String micn = pkg + ".mixin" + id;
+ ccp.setClassName(micn);
+ ccp.toClass();
+
+ // create Mixin class.
+ String fcn = Mixin.class.getName() + id;
+ ccm = ClassGenerator.newInstance(cl);
+ ccm.setClassName(fcn);
+ ccm.addDefaultConstructor();
+ ccm.setSuperClass(Mixin.class.getName());
+ ccm.addMethod("public Object newInstance(Object[] delegates){ return new " + micn + "($1); }");
+ Class<?> mixin = ccm.toClass();
+ return (Mixin) mixin.newInstance();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ // release ClassGenerator
+ if (ccp != null)
+ ccp.release();
+ if (ccm != null)
+ ccm.release();
+ }
+ }
+
+ private static int findMethod(Class<?>[] dcs, String desc) {
+ Class<?> cl;
+ Method[] methods;
+ for (int i = 0; i < dcs.length; i++) {
+ cl = dcs[i];
+ methods = cl.getMethods();
+ for (Method method : methods) {
+ if (desc.equals(ReflectUtils.getDesc(method)))
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private static void assertInterfaceArray(Class<?>[] ics) {
+ for (int i = 0; i < ics.length; i++)
+ if (!ics[i].isInterface())
+ throw new RuntimeException("Class " + ics[i].getName() + " is not a interface.");
+ }
+
+ /**
+ * new Mixin instance.
+ *
+ * @param ds delegates instance.
+ * @return instance.
+ */
+ abstract public Object newInstance(Object[] ds);
+
+ public static interface MixinAware {
+ void setMixinInstance(Object instance);
+ }
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchMethodException.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchMethodException.java
index 56061a2baf..7f4a3cc93c 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchMethodException.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchMethodException.java
@@ -1,33 +1,33 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-/**
- * NoSuchMethodException.
- */
-
-public class NoSuchMethodException extends RuntimeException {
- private static final long serialVersionUID = -2725364246023268766L;
-
- public NoSuchMethodException() {
- super();
- }
-
- public NoSuchMethodException(String msg) {
- super(msg);
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+/**
+ * NoSuchMethodException.
+ */
+
+public class NoSuchMethodException extends RuntimeException {
+ private static final long serialVersionUID = -2725364246023268766L;
+
+ public NoSuchMethodException() {
+ super();
+ }
+
+ public NoSuchMethodException(String msg) {
+ super(msg);
+ }
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchPropertyException.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchPropertyException.java
index 0a2f21244e..55899f9453 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchPropertyException.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/NoSuchPropertyException.java
@@ -1,33 +1,33 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-/**
- * NoSuchPropertyException.
- */
-
-public class NoSuchPropertyException extends RuntimeException {
- private static final long serialVersionUID = -2725364246023268766L;
-
- public NoSuchPropertyException() {
- super();
- }
-
- public NoSuchPropertyException(String msg) {
- super(msg);
- }
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+/**
+ * NoSuchPropertyException.
+ */
+
+public class NoSuchPropertyException extends RuntimeException {
+ private static final long serialVersionUID = -2725364246023268766L;
+
+ public NoSuchPropertyException() {
+ super();
+ }
+
+ public NoSuchPropertyException(String msg) {
+ super(msg);
+ }
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
index 91c534f201..865b3bbbb6 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Proxy.java
@@ -1,261 +1,261 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-import org.apache.dubbo.common.utils.ClassHelper;
-import org.apache.dubbo.common.utils.ReflectUtils;
-
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.WeakHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Proxy.
- */
-
-public abstract class Proxy {
- public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) {
- return null;
- }
- };
- public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) {
- throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented.");
- }
- };
- private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
- private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
- private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
-
- private static final Object PendingGenerationMarker = new Object();
-
- protected Proxy() {
- }
-
- /**
- * Get proxy.
- *
- * @param ics interface class array.
- * @return Proxy instance.
- */
- public static Proxy getProxy(Class<?>... ics) {
- return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
- }
-
- /**
- * Get proxy.
- *
- * @param cl class loader.
- * @param ics interface class array.
- * @return Proxy instance.
- */
- public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
- if (ics.length > 65535)
- throw new IllegalArgumentException("interface limit exceeded");
-
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < ics.length; i++) {
- String itf = ics[i].getName();
- if (!ics[i].isInterface())
- throw new RuntimeException(itf + " is not a interface.");
-
- Class<?> tmp = null;
- try {
- tmp = Class.forName(itf, false, cl);
- } catch (ClassNotFoundException e) {
- }
-
- if (tmp != ics[i])
- throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
-
- sb.append(itf).append(';');
- }
-
- // use interface class name list as key.
- String key = sb.toString();
-
- // get cache by class loader.
- Map<String, Object> cache;
- synchronized (ProxyCacheMap) {
- cache = ProxyCacheMap.get(cl);
- if (cache == null) {
- cache = new HashMap<String, Object>();
- ProxyCacheMap.put(cl, cache);
- }
- }
-
- Proxy proxy = null;
- synchronized (cache) {
- do {
- Object value = cache.get(key);
- if (value instanceof Reference<?>) {
- proxy = (Proxy) ((Reference<?>) value).get();
- if (proxy != null)
- return proxy;
- }
-
- if (value == PendingGenerationMarker) {
- try {
- cache.wait();
- } catch (InterruptedException e) {
- }
- } else {
- cache.put(key, PendingGenerationMarker);
- break;
- }
- }
- while (true);
- }
-
- long id = PROXY_CLASS_COUNTER.getAndIncrement();
- String pkg = null;
- ClassGenerator ccp = null, ccm = null;
- try {
- ccp = ClassGenerator.newInstance(cl);
-
- Set<String> worked = new HashSet<String>();
- List<Method> methods = new ArrayList<Method>();
-
- for (int i = 0; i < ics.length; i++) {
- if (!Modifier.isPublic(ics[i].getModifiers())) {
- String npkg = ics[i].getPackage().getName();
- if (pkg == null) {
- pkg = npkg;
- } else {
- if (!pkg.equals(npkg))
- throw new IllegalArgumentException("non-public interfaces from different packages");
- }
- }
- ccp.addInterface(ics[i]);
-
- for (Method method : ics[i].getMethods()) {
- String desc = ReflectUtils.getDesc(method);
- if (worked.contains(desc))
- continue;
- worked.add(desc);
-
- int ix = methods.size();
- Class<?> rt = method.getReturnType();
- Class<?>[] pts = method.getParameterTypes();
-
- StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
- for (int j = 0; j < pts.length; j++)
- code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
- code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
- if (!Void.TYPE.equals(rt))
- code.append(" return ").append(asArgument(rt, "ret")).append(";");
-
- methods.add(method);
- ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
- }
- }
-
- if (pkg == null)
- pkg = PACKAGE_NAME;
-
- // create ProxyInstance class.
- String pcn = pkg + ".proxy" + id;
- ccp.setClassName(pcn);
- ccp.addField("public static java.lang.reflect.Method[] methods;");
- ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
- ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
- ccp.addDefaultConstructor();
- Class<?> clazz = ccp.toClass();
- clazz.getField("methods").set(null, methods.toArray(new Method[0]));
-
- // create Proxy class.
- String fcn = Proxy.class.getName() + id;
- ccm = ClassGenerator.newInstance(cl);
- ccm.setClassName(fcn);
- ccm.addDefaultConstructor();
- ccm.setSuperClass(Proxy.class);
- ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
- Class<?> pc = ccm.toClass();
- proxy = (Proxy) pc.newInstance();
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e.getMessage(), e);
- } finally {
- // release ClassGenerator
- if (ccp != null)
- ccp.release();
- if (ccm != null)
- ccm.release();
- synchronized (cache) {
- if (proxy == null)
- cache.remove(key);
- else
- cache.put(key, new WeakReference<Proxy>(proxy));
- cache.notifyAll();
- }
- }
- return proxy;
- }
-
- private static String asArgument(Class<?> cl, String name) {
- if (cl.isPrimitive()) {
- if (Boolean.TYPE == cl)
- return name + "==null?false:((Boolean)" + name + ").booleanValue()";
- if (Byte.TYPE == cl)
- return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
- if (Character.TYPE == cl)
- return name + "==null?(char)0:((Character)" + name + ").charValue()";
- if (Double.TYPE == cl)
- return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
- if (Float.TYPE == cl)
- return name + "==null?(float)0:((Float)" + name + ").floatValue()";
- if (Integer.TYPE == cl)
- return name + "==null?(int)0:((Integer)" + name + ").intValue()";
- if (Long.TYPE == cl)
- return name + "==null?(long)0:((Long)" + name + ").longValue()";
- if (Short.TYPE == cl)
- return name + "==null?(short)0:((Short)" + name + ").shortValue()";
- throw new RuntimeException(name + " is unknown primitive type.");
- }
- return "(" + ReflectUtils.getName(cl) + ")" + name;
- }
-
- /**
- * get instance with default handler.
- *
- * @return instance.
- */
- public Object newInstance() {
- return newInstance(THROW_UNSUPPORTED_INVOKER);
- }
-
- /**
- * get instance with special handler.
- *
- * @return instance.
- */
- abstract public Object newInstance(InvocationHandler handler);
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+import org.apache.dubbo.common.utils.ClassHelper;
+import org.apache.dubbo.common.utils.ReflectUtils;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Proxy.
+ */
+
+public abstract class Proxy {
+ public static final InvocationHandler RETURN_NULL_INVOKER = new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ return null;
+ }
+ };
+ public static final InvocationHandler THROW_UNSUPPORTED_INVOKER = new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ throw new UnsupportedOperationException("Method [" + ReflectUtils.getName(method) + "] unimplemented.");
+ }
+ };
+ private static final AtomicLong PROXY_CLASS_COUNTER = new AtomicLong(0);
+ private static final String PACKAGE_NAME = Proxy.class.getPackage().getName();
+ private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
+
+ private static final Object PendingGenerationMarker = new Object();
+
+ protected Proxy() {
+ }
+
+ /**
+ * Get proxy.
+ *
+ * @param ics interface class array.
+ * @return Proxy instance.
+ */
+ public static Proxy getProxy(Class<?>... ics) {
+ return getProxy(ClassHelper.getClassLoader(Proxy.class), ics);
+ }
+
+ /**
+ * Get proxy.
+ *
+ * @param cl class loader.
+ * @param ics interface class array.
+ * @return Proxy instance.
+ */
+ public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
+ if (ics.length > 65535)
+ throw new IllegalArgumentException("interface limit exceeded");
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < ics.length; i++) {
+ String itf = ics[i].getName();
+ if (!ics[i].isInterface())
+ throw new RuntimeException(itf + " is not a interface.");
+
+ Class<?> tmp = null;
+ try {
+ tmp = Class.forName(itf, false, cl);
+ } catch (ClassNotFoundException e) {
+ }
+
+ if (tmp != ics[i])
+ throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
+
+ sb.append(itf).append(';');
+ }
+
+ // use interface class name list as key.
+ String key = sb.toString();
+
+ // get cache by class loader.
+ Map<String, Object> cache;
+ synchronized (ProxyCacheMap) {
+ cache = ProxyCacheMap.get(cl);
+ if (cache == null) {
+ cache = new HashMap<String, Object>();
+ ProxyCacheMap.put(cl, cache);
+ }
+ }
+
+ Proxy proxy = null;
+ synchronized (cache) {
+ do {
+ Object value = cache.get(key);
+ if (value instanceof Reference<?>) {
+ proxy = (Proxy) ((Reference<?>) value).get();
+ if (proxy != null)
+ return proxy;
+ }
+
+ if (value == PendingGenerationMarker) {
+ try {
+ cache.wait();
+ } catch (InterruptedException e) {
+ }
+ } else {
+ cache.put(key, PendingGenerationMarker);
+ break;
+ }
+ }
+ while (true);
+ }
+
+ long id = PROXY_CLASS_COUNTER.getAndIncrement();
+ String pkg = null;
+ ClassGenerator ccp = null, ccm = null;
+ try {
+ ccp = ClassGenerator.newInstance(cl);
+
+ Set<String> worked = new HashSet<String>();
+ List<Method> methods = new ArrayList<Method>();
+
+ for (int i = 0; i < ics.length; i++) {
+ if (!Modifier.isPublic(ics[i].getModifiers())) {
+ String npkg = ics[i].getPackage().getName();
+ if (pkg == null) {
+ pkg = npkg;
+ } else {
+ if (!pkg.equals(npkg))
+ throw new IllegalArgumentException("non-public interfaces from different packages");
+ }
+ }
+ ccp.addInterface(ics[i]);
+
+ for (Method method : ics[i].getMethods()) {
+ String desc = ReflectUtils.getDesc(method);
+ if (worked.contains(desc))
+ continue;
+ worked.add(desc);
+
+ int ix = methods.size();
+ Class<?> rt = method.getReturnType();
+ Class<?>[] pts = method.getParameterTypes();
+
+ StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
+ for (int j = 0; j < pts.length; j++)
+ code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
+ code.append(" Object ret = handler.invoke(this, methods[" + ix + "], args);");
+ if (!Void.TYPE.equals(rt))
+ code.append(" return ").append(asArgument(rt, "ret")).append(";");
+
+ methods.add(method);
+ ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
+ }
+ }
+
+ if (pkg == null)
+ pkg = PACKAGE_NAME;
+
+ // create ProxyInstance class.
+ String pcn = pkg + ".proxy" + id;
+ ccp.setClassName(pcn);
+ ccp.addField("public static java.lang.reflect.Method[] methods;");
+ ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
+ ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
+ ccp.addDefaultConstructor();
+ Class<?> clazz = ccp.toClass();
+ clazz.getField("methods").set(null, methods.toArray(new Method[0]));
+
+ // create Proxy class.
+ String fcn = Proxy.class.getName() + id;
+ ccm = ClassGenerator.newInstance(cl);
+ ccm.setClassName(fcn);
+ ccm.addDefaultConstructor();
+ ccm.setSuperClass(Proxy.class);
+ ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
+ Class<?> pc = ccm.toClass();
+ proxy = (Proxy) pc.newInstance();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ // release ClassGenerator
+ if (ccp != null)
+ ccp.release();
+ if (ccm != null)
+ ccm.release();
+ synchronized (cache) {
+ if (proxy == null)
+ cache.remove(key);
+ else
+ cache.put(key, new WeakReference<Proxy>(proxy));
+ cache.notifyAll();
+ }
+ }
+ return proxy;
+ }
+
+ private static String asArgument(Class<?> cl, String name) {
+ if (cl.isPrimitive()) {
+ if (Boolean.TYPE == cl)
+ return name + "==null?false:((Boolean)" + name + ").booleanValue()";
+ if (Byte.TYPE == cl)
+ return name + "==null?(byte)0:((Byte)" + name + ").byteValue()";
+ if (Character.TYPE == cl)
+ return name + "==null?(char)0:((Character)" + name + ").charValue()";
+ if (Double.TYPE == cl)
+ return name + "==null?(double)0:((Double)" + name + ").doubleValue()";
+ if (Float.TYPE == cl)
+ return name + "==null?(float)0:((Float)" + name + ").floatValue()";
+ if (Integer.TYPE == cl)
+ return name + "==null?(int)0:((Integer)" + name + ").intValue()";
+ if (Long.TYPE == cl)
+ return name + "==null?(long)0:((Long)" + name + ").longValue()";
+ if (Short.TYPE == cl)
+ return name + "==null?(short)0:((Short)" + name + ").shortValue()";
+ throw new RuntimeException(name + " is unknown primitive type.");
+ }
+ return "(" + ReflectUtils.getName(cl) + ")" + name;
+ }
+
+ /**
+ * get instance with default handler.
+ *
+ * @return instance.
+ */
+ public Object newInstance() {
+ return newInstance(THROW_UNSUPPORTED_INVOKER);
+ }
+
+ /**
+ * get instance with special handler.
+ *
+ * @return instance.
+ */
+ abstract public Object newInstance(InvocationHandler handler);
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
index aebcda60a8..ddd47b17f9 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/bytecode/Wrapper.java
@@ -1,424 +1,424 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.bytecode;
-
-import org.apache.dubbo.common.utils.ClassHelper;
-import org.apache.dubbo.common.utils.ReflectUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.regex.Matcher;
-
-/**
- * Wrapper.
- */
-public abstract class Wrapper {
- private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
- private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
- private static final Wrapper OBJECT_WRAPPER = new Wrapper() {
- @Override
- public String[] getMethodNames() {
- return OBJECT_METHODS;
- }
-
- @Override
- public String[] getDeclaredMethodNames() {
- return OBJECT_METHODS;
- }
-
- @Override
- public String[] getPropertyNames() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Class<?> getPropertyType(String pn) {
- return null;
- }
-
- @Override
- public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException {
- throw new NoSuchPropertyException("Property [" + pn + "] not found.");
- }
-
- @Override
- public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException {
- throw new NoSuchPropertyException("Property [" + pn + "] not found.");
- }
-
- @Override
- public boolean hasProperty(String name) {
- return false;
- }
-
- @Override
- public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException {
- if ("getClass".equals(mn)) return instance.getClass();
- if ("hashCode".equals(mn)) return instance.hashCode();
- if ("toString".equals(mn)) return instance.toString();
- if ("equals".equals(mn)) {
- if (args.length == 1) return instance.equals(args[0]);
- throw new IllegalArgumentException("Invoke method [" + mn + "] argument number error.");
- }
- throw new NoSuchMethodException("Method [" + mn + "] not found.");
- }
- };
- private static AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);
-
- /**
- * get wrapper.
- *
- * @param c Class instance.
- * @return Wrapper instance(not null).
- */
- public static Wrapper getWrapper(Class<?> c) {
- while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
- c = c.getSuperclass();
-
- if (c == Object.class)
- return OBJECT_WRAPPER;
-
- Wrapper ret = WRAPPER_MAP.get(c);
- if (ret == null) {
- ret = makeWrapper(c);
- WRAPPER_MAP.put(c, ret);
- }
- return ret;
- }
-
- private static Wrapper makeWrapper(Class<?> c) {
- if (c.isPrimitive())
- throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
-
- String name = c.getName();
- ClassLoader cl = ClassHelper.getClassLoader(c);
-
- StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
- StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
- StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
-
- c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
- c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
- c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
-
- Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
- Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
- List<String> mns = new ArrayList<String>(); // method names.
- List<String> dmns = new ArrayList<String>(); // declaring method names.
-
- // get all public field.
- for (Field f : c.getFields()) {
- String fn = f.getName();
- Class<?> ft = f.getType();
- if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
- continue;
-
- c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
- c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
- pts.put(fn, ft);
- }
-
- Method[] methods = c.getMethods();
- // get all public method.
- boolean hasMethod = hasMethods(methods);
- if (hasMethod) {
- c3.append(" try{");
- }
- for (Method m : methods) {
- if (m.getDeclaringClass() == Object.class) //ignore Object's method.
- continue;
-
- String mn = m.getName();
- c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
- int len = m.getParameterTypes().length;
- c3.append(" && ").append(" $3.length == ").append(len);
-
- boolean override = false;
- for (Method m2 : methods) {
- if (m != m2 && m.getName().equals(m2.getName())) {
- override = true;
- break;
- }
- }
- if (override) {
- if (len > 0) {
- for (int l = 0; l < len; l++) {
- c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
- .append(m.getParameterTypes()[l].getName()).append("\")");
- }
- }
- }
-
- c3.append(" ) { ");
-
- if (m.getReturnType() == Void.TYPE)
- c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
- else
- c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
-
- c3.append(" }");
-
- mns.add(mn);
- if (m.getDeclaringClass() == c)
- dmns.add(mn);
- ms.put(ReflectUtils.getDesc(m), m);
- }
- if (hasMethod) {
- c3.append(" } catch(Throwable e) { ");
- c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
- c3.append(" }");
- }
-
- c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
-
- // deal with get/set method.
- Matcher matcher;
- for (Map.Entry<String, Method> entry : ms.entrySet()) {
- String md = entry.getKey();
- Method method = (Method) entry.getValue();
- if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
- String pn = propertyName(matcher.group(1));
- c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
- pts.put(pn, method.getReturnType());
- } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
- String pn = propertyName(matcher.group(1));
- c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
- pts.put(pn, method.getReturnType());
- } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
- Class<?> pt = method.getParameterTypes()[0];
- String pn = propertyName(matcher.group(1));
- c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
- pts.put(pn, pt);
- }
- }
- c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
- c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
-
- // make class
- long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
- ClassGenerator cc = ClassGenerator.newInstance(cl);
- cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
- cc.setSuperClass(Wrapper.class);
-
- cc.addDefaultConstructor();
- cc.addField("public static String[] pns;"); // property name array.
- cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
- cc.addField("public static String[] mns;"); // all method name array.
- cc.addField("public static String[] dmns;"); // declared method name array.
- for (int i = 0, len = ms.size(); i < len; i++)
- cc.addField("public static Class[] mts" + i + ";");
-
- cc.addMethod("public String[] getPropertyNames(){ return pns; }");
- cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
- cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
- cc.addMethod("public String[] getMethodNames(){ return mns; }");
- cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
- cc.addMethod(c1.toString());
- cc.addMethod(c2.toString());
- cc.addMethod(c3.toString());
-
- try {
- Class<?> wc = cc.toClass();
- // setup static field.
- wc.getField("pts").set(null, pts);
- wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
- wc.getField("mns").set(null, mns.toArray(new String[0]));
- wc.getField("dmns").set(null, dmns.toArray(new String[0]));
- int ix = 0;
- for (Method m : ms.values())
- wc.getField("mts" + ix++).set(null, m.getParameterTypes());
- return (Wrapper) wc.newInstance();
- } catch (RuntimeException e) {
- throw e;
- } catch (Throwable e) {
- throw new RuntimeException(e.getMessage(), e);
- } finally {
- cc.release();
- ms.clear();
- mns.clear();
- dmns.clear();
- }
- }
-
- private static String arg(Class<?> cl, String name) {
- if (cl.isPrimitive()) {
- if (cl == Boolean.TYPE)
- return "((Boolean)" + name + ").booleanValue()";
- if (cl == Byte.TYPE)
- return "((Byte)" + name + ").byteValue()";
- if (cl == Character.TYPE)
- return "((Character)" + name + ").charValue()";
- if (cl == Double.TYPE)
- return "((Number)" + name + ").doubleValue()";
- if (cl == Float.TYPE)
- return "((Number)" + name + ").floatValue()";
- if (cl == Integer.TYPE)
- return "((Number)" + name + ").intValue()";
- if (cl == Long.TYPE)
- return "((Number)" + name + ").longValue()";
- if (cl == Short.TYPE)
- return "((Number)" + name + ").shortValue()";
- throw new RuntimeException("Unknown primitive type: " + cl.getName());
- }
- return "(" + ReflectUtils.getName(cl) + ")" + name;
- }
-
- private static String args(Class<?>[] cs, String name) {
- int len = cs.length;
- if (len == 0) return "";
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < len; i++) {
- if (i > 0)
- sb.append(',');
- sb.append(arg(cs[i], name + "[" + i + "]"));
- }
- return sb.toString();
- }
-
- private static String propertyName(String pn) {
- return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1) : pn;
- }
-
- private static boolean hasMethods(Method[] methods) {
- if (methods == null || methods.length == 0) {
- return false;
- }
- for (Method m : methods) {
- if (m.getDeclaringClass() != Object.class) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * get property name array.
- *
- * @return property name array.
- */
- abstract public String[] getPropertyNames();
-
- /**
- * get property type.
- *
- * @param pn property name.
- * @return Property type or nul.
- */
- abstract public Class<?> getPropertyType(String pn);
-
- /**
- * has property.
- *
- * @param name property name.
- * @return has or has not.
- */
- abstract public boolean hasProperty(String name);
-
- /**
- * get property value.
- *
- * @param instance instance.
- * @param pn property name.
- * @return value.
- */
- abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException;
-
- /**
- * set property value.
- *
- * @param instance instance.
- * @param pn property name.
- * @param pv property value.
- */
- abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException;
-
- /**
- * get property value.
- *
- * @param instance instance.
- * @param pns property name array.
- * @return value array.
- */
- public Object[] getPropertyValues(Object instance, String[] pns) throws NoSuchPropertyException, IllegalArgumentException {
- Object[] ret = new Object[pns.length];
- for (int i = 0; i < ret.length; i++)
- ret[i] = getPropertyValue(instance, pns[i]);
- return ret;
- }
-
- /**
- * set property value.
- *
- * @param instance instance.
- * @param pns property name array.
- * @param pvs property value array.
- */
- public void setPropertyValues(Object instance, String[] pns, Object[] pvs) throws NoSuchPropertyException, IllegalArgumentException {
- if (pns.length != pvs.length)
- throw new IllegalArgumentException("pns.length != pvs.length");
-
- for (int i = 0; i < pns.length; i++)
- setPropertyValue(instance, pns[i], pvs[i]);
- }
-
- /**
- * get method name array.
- *
- * @return method name array.
- */
- abstract public String[] getMethodNames();
-
- /**
- * get method name array.
- *
- * @return method name array.
- */
- abstract public String[] getDeclaredMethodNames();
-
- /**
- * has method.
- *
- * @param name method name.
- * @return has or has not.
- */
- public boolean hasMethod(String name) {
- for (String mn : getMethodNames())
- if (mn.equals(name)) return true;
- return false;
- }
-
- /**
- * invoke method.
- *
- * @param instance instance.
- * @param mn method name.
- * @param types
- * @param args argument array.
- * @return return value.
- */
- abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.bytecode;
+
+import org.apache.dubbo.common.utils.ClassHelper;
+import org.apache.dubbo.common.utils.ReflectUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Matcher;
+
+/**
+ * Wrapper.
+ */
+public abstract class Wrapper {
+ private static final Map<Class<?>, Wrapper> WRAPPER_MAP = new ConcurrentHashMap<Class<?>, Wrapper>(); //class wrapper map
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final String[] OBJECT_METHODS = new String[]{"getClass", "hashCode", "toString", "equals"};
+ private static final Wrapper OBJECT_WRAPPER = new Wrapper() {
+ @Override
+ public String[] getMethodNames() {
+ return OBJECT_METHODS;
+ }
+
+ @Override
+ public String[] getDeclaredMethodNames() {
+ return OBJECT_METHODS;
+ }
+
+ @Override
+ public String[] getPropertyNames() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Class<?> getPropertyType(String pn) {
+ return null;
+ }
+
+ @Override
+ public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException {
+ throw new NoSuchPropertyException("Property [" + pn + "] not found.");
+ }
+
+ @Override
+ public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException {
+ throw new NoSuchPropertyException("Property [" + pn + "] not found.");
+ }
+
+ @Override
+ public boolean hasProperty(String name) {
+ return false;
+ }
+
+ @Override
+ public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException {
+ if ("getClass".equals(mn)) return instance.getClass();
+ if ("hashCode".equals(mn)) return instance.hashCode();
+ if ("toString".equals(mn)) return instance.toString();
+ if ("equals".equals(mn)) {
+ if (args.length == 1) return instance.equals(args[0]);
+ throw new IllegalArgumentException("Invoke method [" + mn + "] argument number error.");
+ }
+ throw new NoSuchMethodException("Method [" + mn + "] not found.");
+ }
+ };
+ private static AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);
+
+ /**
+ * get wrapper.
+ *
+ * @param c Class instance.
+ * @return Wrapper instance(not null).
+ */
+ public static Wrapper getWrapper(Class<?> c) {
+ while (ClassGenerator.isDynamicClass(c)) // can not wrapper on dynamic class.
+ c = c.getSuperclass();
+
+ if (c == Object.class)
+ return OBJECT_WRAPPER;
+
+ Wrapper ret = WRAPPER_MAP.get(c);
+ if (ret == null) {
+ ret = makeWrapper(c);
+ WRAPPER_MAP.put(c, ret);
+ }
+ return ret;
+ }
+
+ private static Wrapper makeWrapper(Class<?> c) {
+ if (c.isPrimitive())
+ throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
+
+ String name = c.getName();
+ ClassLoader cl = ClassHelper.getClassLoader(c);
+
+ StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
+ StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
+ StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
+
+ c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+ c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+ c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+
+ Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
+ Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
+ List<String> mns = new ArrayList<String>(); // method names.
+ List<String> dmns = new ArrayList<String>(); // declaring method names.
+
+ // get all public field.
+ for (Field f : c.getFields()) {
+ String fn = f.getName();
+ Class<?> ft = f.getType();
+ if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
+ continue;
+
+ c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
+ c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
+ pts.put(fn, ft);
+ }
+
+ Method[] methods = c.getMethods();
+ // get all public method.
+ boolean hasMethod = hasMethods(methods);
+ if (hasMethod) {
+ c3.append(" try{");
+ }
+ for (Method m : methods) {
+ if (m.getDeclaringClass() == Object.class) //ignore Object's method.
+ continue;
+
+ String mn = m.getName();
+ c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
+ int len = m.getParameterTypes().length;
+ c3.append(" && ").append(" $3.length == ").append(len);
+
+ boolean override = false;
+ for (Method m2 : methods) {
+ if (m != m2 && m.getName().equals(m2.getName())) {
+ override = true;
+ break;
+ }
+ }
+ if (override) {
+ if (len > 0) {
+ for (int l = 0; l < len; l++) {
+ c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
+ .append(m.getParameterTypes()[l].getName()).append("\")");
+ }
+ }
+ }
+
+ c3.append(" ) { ");
+
+ if (m.getReturnType() == Void.TYPE)
+ c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
+ else
+ c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
+
+ c3.append(" }");
+
+ mns.add(mn);
+ if (m.getDeclaringClass() == c)
+ dmns.add(mn);
+ ms.put(ReflectUtils.getDesc(m), m);
+ }
+ if (hasMethod) {
+ c3.append(" } catch(Throwable e) { ");
+ c3.append(" throw new java.lang.reflect.InvocationTargetException(e); ");
+ c3.append(" }");
+ }
+
+ c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
+
+ // deal with get/set method.
+ Matcher matcher;
+ for (Map.Entry<String, Method> entry : ms.entrySet()) {
+ String md = entry.getKey();
+ Method method = (Method) entry.getValue();
+ if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+ String pn = propertyName(matcher.group(1));
+ c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
+ pts.put(pn, method.getReturnType());
+ } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+ String pn = propertyName(matcher.group(1));
+ c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
+ pts.put(pn, method.getReturnType());
+ } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+ Class<?> pt = method.getParameterTypes()[0];
+ String pn = propertyName(matcher.group(1));
+ c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
+ pts.put(pn, pt);
+ }
+ }
+ c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
+ c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
+
+ // make class
+ long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
+ ClassGenerator cc = ClassGenerator.newInstance(cl);
+ cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() : c.getName() + "$sw") + id);
+ cc.setSuperClass(Wrapper.class);
+
+ cc.addDefaultConstructor();
+ cc.addField("public static String[] pns;"); // property name array.
+ cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
+ cc.addField("public static String[] mns;"); // all method name array.
+ cc.addField("public static String[] dmns;"); // declared method name array.
+ for (int i = 0, len = ms.size(); i < len; i++)
+ cc.addField("public static Class[] mts" + i + ";");
+
+ cc.addMethod("public String[] getPropertyNames(){ return pns; }");
+ cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
+ cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
+ cc.addMethod("public String[] getMethodNames(){ return mns; }");
+ cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
+ cc.addMethod(c1.toString());
+ cc.addMethod(c2.toString());
+ cc.addMethod(c3.toString());
+
+ try {
+ Class<?> wc = cc.toClass();
+ // setup static field.
+ wc.getField("pts").set(null, pts);
+ wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
+ wc.getField("mns").set(null, mns.toArray(new String[0]));
+ wc.getField("dmns").set(null, dmns.toArray(new String[0]));
+ int ix = 0;
+ for (Method m : ms.values())
+ wc.getField("mts" + ix++).set(null, m.getParameterTypes());
+ return (Wrapper) wc.newInstance();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ cc.release();
+ ms.clear();
+ mns.clear();
+ dmns.clear();
+ }
+ }
+
+ private static String arg(Class<?> cl, String name) {
+ if (cl.isPrimitive()) {
+ if (cl == Boolean.TYPE)
+ return "((Boolean)" + name + ").booleanValue()";
+ if (cl == Byte.TYPE)
+ return "((Byte)" + name + ").byteValue()";
+ if (cl == Character.TYPE)
+ return "((Character)" + name + ").charValue()";
+ if (cl == Double.TYPE)
+ return "((Number)" + name + ").doubleValue()";
+ if (cl == Float.TYPE)
+ return "((Number)" + name + ").floatValue()";
+ if (cl == Integer.TYPE)
+ return "((Number)" + name + ").intValue()";
+ if (cl == Long.TYPE)
+ return "((Number)" + name + ").longValue()";
+ if (cl == Short.TYPE)
+ return "((Number)" + name + ").shortValue()";
+ throw new RuntimeException("Unknown primitive type: " + cl.getName());
+ }
+ return "(" + ReflectUtils.getName(cl) + ")" + name;
+ }
+
+ private static String args(Class<?>[] cs, String name) {
+ int len = cs.length;
+ if (len == 0) return "";
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < len; i++) {
+ if (i > 0)
+ sb.append(',');
+ sb.append(arg(cs[i], name + "[" + i + "]"));
+ }
+ return sb.toString();
+ }
+
+ private static String propertyName(String pn) {
+ return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1) : pn;
+ }
+
+ private static boolean hasMethods(Method[] methods) {
+ if (methods == null || methods.length == 0) {
+ return false;
+ }
+ for (Method m : methods) {
+ if (m.getDeclaringClass() != Object.class) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * get property name array.
+ *
+ * @return property name array.
+ */
+ abstract public String[] getPropertyNames();
+
+ /**
+ * get property type.
+ *
+ * @param pn property name.
+ * @return Property type or nul.
+ */
+ abstract public Class<?> getPropertyType(String pn);
+
+ /**
+ * has property.
+ *
+ * @param name property name.
+ * @return has or has not.
+ */
+ abstract public boolean hasProperty(String name);
+
+ /**
+ * get property value.
+ *
+ * @param instance instance.
+ * @param pn property name.
+ * @return value.
+ */
+ abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException;
+
+ /**
+ * set property value.
+ *
+ * @param instance instance.
+ * @param pn property name.
+ * @param pv property value.
+ */
+ abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException;
+
+ /**
+ * get property value.
+ *
+ * @param instance instance.
+ * @param pns property name array.
+ * @return value array.
+ */
+ public Object[] getPropertyValues(Object instance, String[] pns) throws NoSuchPropertyException, IllegalArgumentException {
+ Object[] ret = new Object[pns.length];
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = getPropertyValue(instance, pns[i]);
+ return ret;
+ }
+
+ /**
+ * set property value.
+ *
+ * @param instance instance.
+ * @param pns property name array.
+ * @param pvs property value array.
+ */
+ public void setPropertyValues(Object instance, String[] pns, Object[] pvs) throws NoSuchPropertyException, IllegalArgumentException {
+ if (pns.length != pvs.length)
+ throw new IllegalArgumentException("pns.length != pvs.length");
+
+ for (int i = 0; i < pns.length; i++)
+ setPropertyValue(instance, pns[i], pvs[i]);
+ }
+
+ /**
+ * get method name array.
+ *
+ * @return method name array.
+ */
+ abstract public String[] getMethodNames();
+
+ /**
+ * get method name array.
+ *
+ * @return method name array.
+ */
+ abstract public String[] getDeclaredMethodNames();
+
+ /**
+ * has method.
+ *
+ * @param name method name.
+ * @return has or has not.
+ */
+ public boolean hasMethod(String name) {
+ for (String mn : getMethodNames())
+ if (mn.equals(name)) return true;
+ return false;
+ }
+
+ /**
+ * invoke method.
+ *
+ * @param instance instance.
+ * @param mn method name.
+ * @param types
+ * @param args argument array.
+ * @return return value.
+ */
+ abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/Compiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/Compiler.java
index 7c55a2910a..4d268d5c9a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/Compiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/Compiler.java
@@ -1,37 +1,37 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler;
-
-
-import org.apache.dubbo.common.extension.SPI;
-
-/**
- * Compiler. (SPI, Singleton, ThreadSafe)
- */
-@SPI("javassist")
-public interface Compiler {
-
- /**
- * Compile java source code.
- *
- * @param code Java source code
- * @param classLoader classloader
- * @return Compiled class
- */
- Class<?> compile(String code, ClassLoader classLoader);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler;
+
+
+import org.apache.dubbo.common.extension.SPI;
+
+/**
+ * Compiler. (SPI, Singleton, ThreadSafe)
+ */
+@SPI("javassist")
+public interface Compiler {
+
+ /**
+ * Compile java source code.
+ *
+ * @param code Java source code
+ * @param classLoader classloader
+ * @return Compiled class
+ */
+ Class<?> compile(String code, ClassLoader classLoader);
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AbstractCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AbstractCompiler.java
index 7323641284..d68f9f38ec 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AbstractCompiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AbstractCompiler.java
@@ -1,70 +1,70 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler.support;
-
-import org.apache.dubbo.common.compiler.Compiler;
-import org.apache.dubbo.common.utils.ClassHelper;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Abstract compiler. (SPI, Prototype, ThreadSafe)
- */
-public abstract class AbstractCompiler implements Compiler {
-
- private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");
-
- private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");
-
- @Override
- public Class<?> compile(String code, ClassLoader classLoader) {
- code = code.trim();
- Matcher matcher = PACKAGE_PATTERN.matcher(code);
- String pkg;
- if (matcher.find()) {
- pkg = matcher.group(1);
- } else {
- pkg = "";
- }
- matcher = CLASS_PATTERN.matcher(code);
- String cls;
- if (matcher.find()) {
- cls = matcher.group(1);
- } else {
- throw new IllegalArgumentException("No such class name in " + code);
- }
- String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
- try {
- return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
- } catch (ClassNotFoundException e) {
- if (!code.endsWith("}")) {
- throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
- }
- try {
- return doCompile(className, code);
- } catch (RuntimeException t) {
- throw t;
- } catch (Throwable t) {
- throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
- }
- }
- }
-
- protected abstract Class<?> doCompile(String name, String source) throws Throwable;
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler.support;
+
+import org.apache.dubbo.common.compiler.Compiler;
+import org.apache.dubbo.common.utils.ClassHelper;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Abstract compiler. (SPI, Prototype, ThreadSafe)
+ */
+public abstract class AbstractCompiler implements Compiler {
+
+ private static final Pattern PACKAGE_PATTERN = Pattern.compile("package\\s+([$_a-zA-Z][$_a-zA-Z0-9\\.]*);");
+
+ private static final Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s+");
+
+ @Override
+ public Class<?> compile(String code, ClassLoader classLoader) {
+ code = code.trim();
+ Matcher matcher = PACKAGE_PATTERN.matcher(code);
+ String pkg;
+ if (matcher.find()) {
+ pkg = matcher.group(1);
+ } else {
+ pkg = "";
+ }
+ matcher = CLASS_PATTERN.matcher(code);
+ String cls;
+ if (matcher.find()) {
+ cls = matcher.group(1);
+ } else {
+ throw new IllegalArgumentException("No such class name in " + code);
+ }
+ String className = pkg != null && pkg.length() > 0 ? pkg + "." + cls : cls;
+ try {
+ return Class.forName(className, true, ClassHelper.getCallerClassLoader(getClass()));
+ } catch (ClassNotFoundException e) {
+ if (!code.endsWith("}")) {
+ throw new IllegalStateException("The java code not endsWith \"}\", code: \n" + code + "\n");
+ }
+ try {
+ return doCompile(className, code);
+ } catch (RuntimeException t) {
+ throw t;
+ } catch (Throwable t) {
+ throw new IllegalStateException("Failed to compile class, cause: " + t.getMessage() + ", class: " + className + ", code: \n" + code + "\n, stack: " + ClassUtils.toString(t));
+ }
+ }
+ }
+
+ protected abstract Class<?> doCompile(String name, String source) throws Throwable;
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AdaptiveCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AdaptiveCompiler.java
index b47857c686..8414dc6554 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AdaptiveCompiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/AdaptiveCompiler.java
@@ -1,49 +1,49 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler.support;
-
-
-import org.apache.dubbo.common.compiler.Compiler;
-import org.apache.dubbo.common.extension.Adaptive;
-import org.apache.dubbo.common.extension.ExtensionLoader;
-
-/**
- * AdaptiveCompiler. (SPI, Singleton, ThreadSafe)
- */
-@Adaptive
-public class AdaptiveCompiler implements Compiler {
-
- private static volatile String DEFAULT_COMPILER;
-
- public static void setDefaultCompiler(String compiler) {
- DEFAULT_COMPILER = compiler;
- }
-
- @Override
- public Class<?> compile(String code, ClassLoader classLoader) {
- Compiler compiler;
- ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
- String name = DEFAULT_COMPILER; // copy reference
- if (name != null && name.length() > 0) {
- compiler = loader.getExtension(name);
- } else {
- compiler = loader.getDefaultExtension();
- }
- return compiler.compile(code, classLoader);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler.support;
+
+
+import org.apache.dubbo.common.compiler.Compiler;
+import org.apache.dubbo.common.extension.Adaptive;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+
+/**
+ * AdaptiveCompiler. (SPI, Singleton, ThreadSafe)
+ */
+@Adaptive
+public class AdaptiveCompiler implements Compiler {
+
+ private static volatile String DEFAULT_COMPILER;
+
+ public static void setDefaultCompiler(String compiler) {
+ DEFAULT_COMPILER = compiler;
+ }
+
+ @Override
+ public Class<?> compile(String code, ClassLoader classLoader) {
+ Compiler compiler;
+ ExtensionLoader<Compiler> loader = ExtensionLoader.getExtensionLoader(Compiler.class);
+ String name = DEFAULT_COMPILER; // copy reference
+ if (name != null && name.length() > 0) {
+ compiler = loader.getExtension(name);
+ } else {
+ compiler = loader.getDefaultExtension();
+ }
+ return compiler.compile(code, classLoader);
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
index 3d5235d63a..2e65c5f7bf 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/ClassUtils.java
@@ -1,430 +1,430 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler.support;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.lang.reflect.Array;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * ClassUtils. (Tool, Static, ThreadSafe)
- */
-public class ClassUtils {
-
- public static final String CLASS_EXTENSION = ".class";
-
- public static final String JAVA_EXTENSION = ".java";
- private static final int JIT_LIMIT = 5 * 1024;
-
- private ClassUtils() {
- }
-
- public static Object newInstance(String name) {
- try {
- return forName(name).newInstance();
- } catch (InstantiationException e) {
- throw new IllegalStateException(e.getMessage(), e);
- } catch (IllegalAccessException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- public static Class<?> forName(String[] packages, String className) {
- try {
- return _forName(className);
- } catch (ClassNotFoundException e) {
- if (packages != null && packages.length > 0) {
- for (String pkg : packages) {
- try {
- return _forName(pkg + "." + className);
- } catch (ClassNotFoundException e2) {
- }
- }
- }
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- public static Class<?> forName(String className) {
- try {
- return _forName(className);
- } catch (ClassNotFoundException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
-
- public static Class<?> _forName(String className) throws ClassNotFoundException {
- if ("boolean".equals(className))
- return boolean.class;
- if ("byte".equals(className))
- return byte.class;
- if ("char".equals(className))
- return char.class;
- if ("short".equals(className))
- return short.class;
- if ("int".equals(className))
- return int.class;
- if ("long".equals(className))
- return long.class;
- if ("float".equals(className))
- return float.class;
- if ("double".equals(className))
- return double.class;
- if ("boolean[]".equals(className))
- return boolean[].class;
- if ("byte[]".equals(className))
- return byte[].class;
- if ("char[]".equals(className))
- return char[].class;
- if ("short[]".equals(className))
- return short[].class;
- if ("int[]".equals(className))
- return int[].class;
- if ("long[]".equals(className))
- return long[].class;
- if ("float[]".equals(className))
- return float[].class;
- if ("double[]".equals(className))
- return double[].class;
- try {
- return arrayForName(className);
- } catch (ClassNotFoundException e) {
- // try to load from java.lang package
- if (className.indexOf('.') == -1) {
- try {
- return arrayForName("java.lang." + className);
- } catch (ClassNotFoundException e2) {
- // ignore, let the original exception be thrown
- }
- }
- throw e;
- }
- }
-
- private static Class<?> arrayForName(String className) throws ClassNotFoundException {
- return Class.forName(className.endsWith("[]")
- ? "[L" + className.substring(0, className.length() - 2) + ";"
- : className, true, Thread.currentThread().getContextClassLoader());
- }
-
- public static Class<?> getBoxedClass(Class<?> type) {
- if (type == boolean.class) {
- return Boolean.class;
- } else if (type == char.class) {
- return Character.class;
- } else if (type == byte.class) {
- return Byte.class;
- } else if (type == short.class) {
- return Short.class;
- } else if (type == int.class) {
- return Integer.class;
- } else if (type == long.class) {
- return Long.class;
- } else if (type == float.class) {
- return Float.class;
- } else if (type == double.class) {
- return Double.class;
- } else {
- return type;
- }
- }
-
- public static Boolean boxed(boolean v) {
- return Boolean.valueOf(v);
- }
-
- public static Character boxed(char v) {
- return Character.valueOf(v);
- }
-
- public static Byte boxed(byte v) {
- return Byte.valueOf(v);
- }
-
- public static Short boxed(short v) {
- return Short.valueOf(v);
- }
-
- public static Integer boxed(int v) {
- return Integer.valueOf(v);
- }
-
- public static Long boxed(long v) {
- return Long.valueOf(v);
- }
-
- public static Float boxed(float v) {
- return Float.valueOf(v);
- }
-
- public static Double boxed(double v) {
- return Double.valueOf(v);
- }
-
- public static Object boxed(Object v) {
- return v;
- }
-
- public static boolean unboxed(Boolean v) {
- return v == null ? false : v.booleanValue();
- }
-
- public static char unboxed(Character v) {
- return v == null ? '\0' : v.charValue();
- }
-
- public static byte unboxed(Byte v) {
- return v == null ? 0 : v.byteValue();
- }
-
- public static short unboxed(Short v) {
- return v == null ? 0 : v.shortValue();
- }
-
- public static int unboxed(Integer v) {
- return v == null ? 0 : v.intValue();
- }
-
- public static long unboxed(Long v) {
- return v == null ? 0 : v.longValue();
- }
-
- public static float unboxed(Float v) {
- return v == null ? 0 : v.floatValue();
- }
-
- public static double unboxed(Double v) {
- return v == null ? 0 : v.doubleValue();
- }
-
- public static Object unboxed(Object v) {
- return v;
- }
-
- public static boolean isNotEmpty(Object object) {
- return getSize(object) > 0;
- }
-
- public static int getSize(Object object) {
- if (object == null) {
- return 0;
- }
- if (object instanceof Collection<?>) {
- return ((Collection<?>) object).size();
- } else if (object instanceof Map<?, ?>) {
- return ((Map<?, ?>) object).size();
- } else if (object.getClass().isArray()) {
- return Array.getLength(object);
- } else {
- return -1;
- }
- }
-
- public static URI toURI(String name) {
- try {
- return new URI(name);
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
-
- public static Class<?> getGenericClass(Class<?> cls) {
- return getGenericClass(cls, 0);
- }
-
- public static Class<?> getGenericClass(Class<?> cls, int i) {
- try {
- ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
- Object genericClass = parameterizedType.getActualTypeArguments()[i];
- if (genericClass instanceof ParameterizedType) {
- return (Class<?>) ((ParameterizedType) genericClass).getRawType();
- } else if (genericClass instanceof GenericArrayType) {
- Type type = ((GenericArrayType) genericClass).getGenericComponentType();
- if (type instanceof TypeVariable) {
- return type.getClass();
- }
- return (((GenericArrayType) genericClass).getGenericComponentType() instanceof Class<?>)
- ? (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType()
- : ((GenericArrayType) genericClass).getGenericComponentType().getClass();
- } else if (genericClass != null) {
- if (genericClass instanceof TypeVariable) {
- return genericClass.getClass();
- }
- return (Class<?>) genericClass;
- }
- } catch (Throwable e) {
-
- }
- if (cls.getSuperclass() != null) {
- return getGenericClass(cls.getSuperclass(), i);
- } else {
- throw new IllegalArgumentException(cls.getName() + " generic type undefined!");
- }
- }
-
- public static boolean isBeforeJava5(String javaVersion) {
- return (javaVersion == null || javaVersion.length() == 0 || "1.0".equals(javaVersion)
- || "1.1".equals(javaVersion) || "1.2".equals(javaVersion)
- || "1.3".equals(javaVersion) || "1.4".equals(javaVersion));
- }
-
- public static boolean isBeforeJava6(String javaVersion) {
- return isBeforeJava5(javaVersion) || "1.5".equals(javaVersion);
- }
-
- public static String toString(Throwable e) {
- StringWriter w = new StringWriter();
- PrintWriter p = new PrintWriter(w);
- p.print(e.getClass().getName() + ": ");
- if (e.getMessage() != null) {
- p.print(e.getMessage() + "\n");
- }
- p.println();
- try {
- e.printStackTrace(p);
- return w.toString();
- } finally {
- p.close();
- }
- }
-
- public static void checkBytecode(String name, byte[] bytecode) {
- if (bytecode.length > JIT_LIMIT) {
- System.err.println("The template bytecode too long, may be affect the JIT compiler. template class: " + name);
- }
- }
-
- public static String getSizeMethod(Class<?> cls) {
- try {
- return cls.getMethod("size", new Class<?>[0]).getName() + "()";
- } catch (NoSuchMethodException e) {
- try {
- return cls.getMethod("length", new Class<?>[0]).getName() + "()";
- } catch (NoSuchMethodException e2) {
- try {
- return cls.getMethod("getSize", new Class<?>[0]).getName() + "()";
- } catch (NoSuchMethodException e3) {
- try {
- return cls.getMethod("getLength", new Class<?>[0]).getName() + "()";
- } catch (NoSuchMethodException e4) {
- return null;
- }
- }
- }
- }
- }
-
- public static String getMethodName(Method method, Class<?>[] parameterClasses, String rightCode) {
- if (method.getParameterTypes().length > parameterClasses.length) {
- Class<?>[] types = method.getParameterTypes();
- StringBuilder buf = new StringBuilder(rightCode);
- for (int i = parameterClasses.length; i < types.length; i++) {
- if (buf.length() > 0) {
- buf.append(",");
- }
- Class<?> type = types[i];
- String def;
- if (type == boolean.class) {
- def = "false";
- } else if (type == char.class) {
- def = "\'\\0\'";
- } else if (type == byte.class
- || type == short.class
- || type == int.class
- || type == long.class
- || type == float.class
- || type == double.class) {
- def = "0";
- } else {
- def = "null";
- }
- buf.append(def);
- }
- }
- return method.getName() + "(" + rightCode + ")";
- }
-
- public static Method searchMethod(Class<?> currentClass, String name, Class<?>[] parameterTypes) throws NoSuchMethodException {
- if (currentClass == null) {
- throw new NoSuchMethodException("class == null");
- }
- try {
- return currentClass.getMethod(name, parameterTypes);
- } catch (NoSuchMethodException e) {
- for (Method method : currentClass.getMethods()) {
- if (method.getName().equals(name)
- && parameterTypes.length == method.getParameterTypes().length
- && Modifier.isPublic(method.getModifiers())) {
- if (parameterTypes.length > 0) {
- Class<?>[] types = method.getParameterTypes();
- boolean match = true;
- for (int i = 0; i < parameterTypes.length; i++) {
- if (!types[i].isAssignableFrom(parameterTypes[i])) {
- match = false;
- break;
- }
- }
- if (!match) {
- continue;
- }
- }
- return method;
- }
- }
- throw e;
- }
- }
-
- public static String getInitCode(Class<?> type) {
- if (byte.class.equals(type)
- || short.class.equals(type)
- || int.class.equals(type)
- || long.class.equals(type)
- || float.class.equals(type)
- || double.class.equals(type)) {
- return "0";
- } else if (char.class.equals(type)) {
- return "'\\0'";
- } else if (boolean.class.equals(type)) {
- return "false";
- } else {
- return "null";
- }
- }
-
- public static <K, V> Map<K, V> toMap(Map.Entry<K, V>[] entries) {
- Map<K, V> map = new HashMap<K, V>();
- if (entries != null && entries.length > 0) {
- for (Map.Entry<K, V> enrty : entries) {
- map.put(enrty.getKey(), enrty.getValue());
- }
- }
- return map;
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler.support;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ClassUtils. (Tool, Static, ThreadSafe)
+ */
+public class ClassUtils {
+
+ public static final String CLASS_EXTENSION = ".class";
+
+ public static final String JAVA_EXTENSION = ".java";
+ private static final int JIT_LIMIT = 5 * 1024;
+
+ private ClassUtils() {
+ }
+
+ public static Object newInstance(String name) {
+ try {
+ return forName(name).newInstance();
+ } catch (InstantiationException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ public static Class<?> forName(String[] packages, String className) {
+ try {
+ return _forName(className);
+ } catch (ClassNotFoundException e) {
+ if (packages != null && packages.length > 0) {
+ for (String pkg : packages) {
+ try {
+ return _forName(pkg + "." + className);
+ } catch (ClassNotFoundException e2) {
+ }
+ }
+ }
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ public static Class<?> forName(String className) {
+ try {
+ return _forName(className);
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ public static Class<?> _forName(String className) throws ClassNotFoundException {
+ if ("boolean".equals(className))
+ return boolean.class;
+ if ("byte".equals(className))
+ return byte.class;
+ if ("char".equals(className))
+ return char.class;
+ if ("short".equals(className))
+ return short.class;
+ if ("int".equals(className))
+ return int.class;
+ if ("long".equals(className))
+ return long.class;
+ if ("float".equals(className))
+ return float.class;
+ if ("double".equals(className))
+ return double.class;
+ if ("boolean[]".equals(className))
+ return boolean[].class;
+ if ("byte[]".equals(className))
+ return byte[].class;
+ if ("char[]".equals(className))
+ return char[].class;
+ if ("short[]".equals(className))
+ return short[].class;
+ if ("int[]".equals(className))
+ return int[].class;
+ if ("long[]".equals(className))
+ return long[].class;
+ if ("float[]".equals(className))
+ return float[].class;
+ if ("double[]".equals(className))
+ return double[].class;
+ try {
+ return arrayForName(className);
+ } catch (ClassNotFoundException e) {
+ // try to load from java.lang package
+ if (className.indexOf('.') == -1) {
+ try {
+ return arrayForName("java.lang." + className);
+ } catch (ClassNotFoundException e2) {
+ // ignore, let the original exception be thrown
+ }
+ }
+ throw e;
+ }
+ }
+
+ private static Class<?> arrayForName(String className) throws ClassNotFoundException {
+ return Class.forName(className.endsWith("[]")
+ ? "[L" + className.substring(0, className.length() - 2) + ";"
+ : className, true, Thread.currentThread().getContextClassLoader());
+ }
+
+ public static Class<?> getBoxedClass(Class<?> type) {
+ if (type == boolean.class) {
+ return Boolean.class;
+ } else if (type == char.class) {
+ return Character.class;
+ } else if (type == byte.class) {
+ return Byte.class;
+ } else if (type == short.class) {
+ return Short.class;
+ } else if (type == int.class) {
+ return Integer.class;
+ } else if (type == long.class) {
+ return Long.class;
+ } else if (type == float.class) {
+ return Float.class;
+ } else if (type == double.class) {
+ return Double.class;
+ } else {
+ return type;
+ }
+ }
+
+ public static Boolean boxed(boolean v) {
+ return Boolean.valueOf(v);
+ }
+
+ public static Character boxed(char v) {
+ return Character.valueOf(v);
+ }
+
+ public static Byte boxed(byte v) {
+ return Byte.valueOf(v);
+ }
+
+ public static Short boxed(short v) {
+ return Short.valueOf(v);
+ }
+
+ public static Integer boxed(int v) {
+ return Integer.valueOf(v);
+ }
+
+ public static Long boxed(long v) {
+ return Long.valueOf(v);
+ }
+
+ public static Float boxed(float v) {
+ return Float.valueOf(v);
+ }
+
+ public static Double boxed(double v) {
+ return Double.valueOf(v);
+ }
+
+ public static Object boxed(Object v) {
+ return v;
+ }
+
+ public static boolean unboxed(Boolean v) {
+ return v == null ? false : v.booleanValue();
+ }
+
+ public static char unboxed(Character v) {
+ return v == null ? '\0' : v.charValue();
+ }
+
+ public static byte unboxed(Byte v) {
+ return v == null ? 0 : v.byteValue();
+ }
+
+ public static short unboxed(Short v) {
+ return v == null ? 0 : v.shortValue();
+ }
+
+ public static int unboxed(Integer v) {
+ return v == null ? 0 : v.intValue();
+ }
+
+ public static long unboxed(Long v) {
+ return v == null ? 0 : v.longValue();
+ }
+
+ public static float unboxed(Float v) {
+ return v == null ? 0 : v.floatValue();
+ }
+
+ public static double unboxed(Double v) {
+ return v == null ? 0 : v.doubleValue();
+ }
+
+ public static Object unboxed(Object v) {
+ return v;
+ }
+
+ public static boolean isNotEmpty(Object object) {
+ return getSize(object) > 0;
+ }
+
+ public static int getSize(Object object) {
+ if (object == null) {
+ return 0;
+ }
+ if (object instanceof Collection<?>) {
+ return ((Collection<?>) object).size();
+ } else if (object instanceof Map<?, ?>) {
+ return ((Map<?, ?>) object).size();
+ } else if (object.getClass().isArray()) {
+ return Array.getLength(object);
+ } else {
+ return -1;
+ }
+ }
+
+ public static URI toURI(String name) {
+ try {
+ return new URI(name);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static Class<?> getGenericClass(Class<?> cls) {
+ return getGenericClass(cls, 0);
+ }
+
+ public static Class<?> getGenericClass(Class<?> cls, int i) {
+ try {
+ ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
+ Object genericClass = parameterizedType.getActualTypeArguments()[i];
+ if (genericClass instanceof ParameterizedType) {
+ return (Class<?>) ((ParameterizedType) genericClass).getRawType();
+ } else if (genericClass instanceof GenericArrayType) {
+ Type type = ((GenericArrayType) genericClass).getGenericComponentType();
+ if (type instanceof TypeVariable) {
+ return type.getClass();
+ }
+ return (((GenericArrayType) genericClass).getGenericComponentType() instanceof Class<?>)
+ ? (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType()
+ : ((GenericArrayType) genericClass).getGenericComponentType().getClass();
+ } else if (genericClass != null) {
+ if (genericClass instanceof TypeVariable) {
+ return genericClass.getClass();
+ }
+ return (Class<?>) genericClass;
+ }
+ } catch (Throwable e) {
+
+ }
+ if (cls.getSuperclass() != null) {
+ return getGenericClass(cls.getSuperclass(), i);
+ } else {
+ throw new IllegalArgumentException(cls.getName() + " generic type undefined!");
+ }
+ }
+
+ public static boolean isBeforeJava5(String javaVersion) {
+ return (javaVersion == null || javaVersion.length() == 0 || "1.0".equals(javaVersion)
+ || "1.1".equals(javaVersion) || "1.2".equals(javaVersion)
+ || "1.3".equals(javaVersion) || "1.4".equals(javaVersion));
+ }
+
+ public static boolean isBeforeJava6(String javaVersion) {
+ return isBeforeJava5(javaVersion) || "1.5".equals(javaVersion);
+ }
+
+ public static String toString(Throwable e) {
+ StringWriter w = new StringWriter();
+ PrintWriter p = new PrintWriter(w);
+ p.print(e.getClass().getName() + ": ");
+ if (e.getMessage() != null) {
+ p.print(e.getMessage() + "\n");
+ }
+ p.println();
+ try {
+ e.printStackTrace(p);
+ return w.toString();
+ } finally {
+ p.close();
+ }
+ }
+
+ public static void checkBytecode(String name, byte[] bytecode) {
+ if (bytecode.length > JIT_LIMIT) {
+ System.err.println("The template bytecode too long, may be affect the JIT compiler. template class: " + name);
+ }
+ }
+
+ public static String getSizeMethod(Class<?> cls) {
+ try {
+ return cls.getMethod("size", new Class<?>[0]).getName() + "()";
+ } catch (NoSuchMethodException e) {
+ try {
+ return cls.getMethod("length", new Class<?>[0]).getName() + "()";
+ } catch (NoSuchMethodException e2) {
+ try {
+ return cls.getMethod("getSize", new Class<?>[0]).getName() + "()";
+ } catch (NoSuchMethodException e3) {
+ try {
+ return cls.getMethod("getLength", new Class<?>[0]).getName() + "()";
+ } catch (NoSuchMethodException e4) {
+ return null;
+ }
+ }
+ }
+ }
+ }
+
+ public static String getMethodName(Method method, Class<?>[] parameterClasses, String rightCode) {
+ if (method.getParameterTypes().length > parameterClasses.length) {
+ Class<?>[] types = method.getParameterTypes();
+ StringBuilder buf = new StringBuilder(rightCode);
+ for (int i = parameterClasses.length; i < types.length; i++) {
+ if (buf.length() > 0) {
+ buf.append(",");
+ }
+ Class<?> type = types[i];
+ String def;
+ if (type == boolean.class) {
+ def = "false";
+ } else if (type == char.class) {
+ def = "\'\\0\'";
+ } else if (type == byte.class
+ || type == short.class
+ || type == int.class
+ || type == long.class
+ || type == float.class
+ || type == double.class) {
+ def = "0";
+ } else {
+ def = "null";
+ }
+ buf.append(def);
+ }
+ }
+ return method.getName() + "(" + rightCode + ")";
+ }
+
+ public static Method searchMethod(Class<?> currentClass, String name, Class<?>[] parameterTypes) throws NoSuchMethodException {
+ if (currentClass == null) {
+ throw new NoSuchMethodException("class == null");
+ }
+ try {
+ return currentClass.getMethod(name, parameterTypes);
+ } catch (NoSuchMethodException e) {
+ for (Method method : currentClass.getMethods()) {
+ if (method.getName().equals(name)
+ && parameterTypes.length == method.getParameterTypes().length
+ && Modifier.isPublic(method.getModifiers())) {
+ if (parameterTypes.length > 0) {
+ Class<?>[] types = method.getParameterTypes();
+ boolean match = true;
+ for (int i = 0; i < parameterTypes.length; i++) {
+ if (!types[i].isAssignableFrom(parameterTypes[i])) {
+ match = false;
+ break;
+ }
+ }
+ if (!match) {
+ continue;
+ }
+ }
+ return method;
+ }
+ }
+ throw e;
+ }
+ }
+
+ public static String getInitCode(Class<?> type) {
+ if (byte.class.equals(type)
+ || short.class.equals(type)
+ || int.class.equals(type)
+ || long.class.equals(type)
+ || float.class.equals(type)
+ || double.class.equals(type)) {
+ return "0";
+ } else if (char.class.equals(type)) {
+ return "'\\0'";
+ } else if (boolean.class.equals(type)) {
+ return "false";
+ } else {
+ return "null";
+ }
+ }
+
+ public static <K, V> Map<K, V> toMap(Map.Entry<K, V>[] entries) {
+ Map<K, V> map = new HashMap<K, V>();
+ if (entries != null && entries.length > 0) {
+ for (Map.Entry<K, V> enrty : entries) {
+ map.put(enrty.getKey(), enrty.getValue());
+ }
+ }
+ return map;
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
index 5beb8e4ad9..9b44ed9567 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JavassistCompiler.java
@@ -1,125 +1,125 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler.support;
-
-import org.apache.dubbo.common.utils.ClassHelper;
-
-import javassist.ClassPool;
-import javassist.CtClass;
-import javassist.CtField;
-import javassist.CtNewConstructor;
-import javassist.CtNewMethod;
-import javassist.LoaderClassPath;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * JavassistCompiler. (SPI, Singleton, ThreadSafe)
- */
-public class JavassistCompiler extends AbstractCompiler {
-
- private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+([\\w\\.\\*]+);\n");
-
- private static final Pattern EXTENDS_PATTERN = Pattern.compile("\\s+extends\\s+([\\w\\.]+)[^\\{]*\\{\n");
-
- private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");
-
- private static final Pattern METHODS_PATTERN = Pattern.compile("\n(private|public|protected)\\s+");
-
- private static final Pattern FIELD_PATTERN = Pattern.compile("[^\n]+=[^\n]+;");
-
- @Override
- public Class<?> doCompile(String name, String source) throws Throwable {
- int i = name.lastIndexOf('.');
- String className = i < 0 ? name : name.substring(i + 1);
- ClassPool pool = new ClassPool(true);
- pool.appendClassPath(new LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));
- Matcher matcher = IMPORT_PATTERN.matcher(source);
- List<String> importPackages = new ArrayList<String>();
- Map<String, String> fullNames = new HashMap<String, String>();
- while (matcher.find()) {
- String pkg = matcher.group(1);
- if (pkg.endsWith(".*")) {
- String pkgName = pkg.substring(0, pkg.length() - 2);
- pool.importPackage(pkgName);
- importPackages.add(pkgName);
- } else {
- int pi = pkg.lastIndexOf('.');
- if (pi > 0) {
- String pkgName = pkg.substring(0, pi);
- pool.importPackage(pkgName);
- importPackages.add(pkgName);
- fullNames.put(pkg.substring(pi + 1), pkg);
- }
- }
- }
- String[] packages = importPackages.toArray(new String[0]);
- matcher = EXTENDS_PATTERN.matcher(source);
- CtClass cls;
- if (matcher.find()) {
- String extend = matcher.group(1).trim();
- String extendClass;
- if (extend.contains(".")) {
- extendClass = extend;
- } else if (fullNames.containsKey(extend)) {
- extendClass = fullNames.get(extend);
- } else {
- extendClass = ClassUtils.forName(packages, extend).getName();
- }
- cls = pool.makeClass(name, pool.get(extendClass));
- } else {
- cls = pool.makeClass(name);
- }
- matcher = IMPLEMENTS_PATTERN.matcher(source);
- if (matcher.find()) {
- String[] ifaces = matcher.group(1).trim().split("\\,");
- for (String iface : ifaces) {
- iface = iface.trim();
- String ifaceClass;
- if (iface.contains(".")) {
- ifaceClass = iface;
- } else if (fullNames.containsKey(iface)) {
- ifaceClass = fullNames.get(iface);
- } else {
- ifaceClass = ClassUtils.forName(packages, iface).getName();
- }
- cls.addInterface(pool.get(ifaceClass));
- }
- }
- String body = source.substring(source.indexOf("{") + 1, source.length() - 1);
- String[] methods = METHODS_PATTERN.split(body);
- for (String method : methods) {
- method = method.trim();
- if (method.length() > 0) {
- if (method.startsWith(className)) {
- cls.addConstructor(CtNewConstructor.make("public " + method, cls));
- } else if (FIELD_PATTERN.matcher(method).matches()) {
- cls.addField(CtField.make("private " + method, cls));
- } else {
- cls.addMethod(CtNewMethod.make("public " + method, cls));
- }
- }
- }
- return cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler.support;
+
+import org.apache.dubbo.common.utils.ClassHelper;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtNewConstructor;
+import javassist.CtNewMethod;
+import javassist.LoaderClassPath;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * JavassistCompiler. (SPI, Singleton, ThreadSafe)
+ */
+public class JavassistCompiler extends AbstractCompiler {
+
+ private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+([\\w\\.\\*]+);\n");
+
+ private static final Pattern EXTENDS_PATTERN = Pattern.compile("\\s+extends\\s+([\\w\\.]+)[^\\{]*\\{\n");
+
+ private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");
+
+ private static final Pattern METHODS_PATTERN = Pattern.compile("\n(private|public|protected)\\s+");
+
+ private static final Pattern FIELD_PATTERN = Pattern.compile("[^\n]+=[^\n]+;");
+
+ @Override
+ public Class<?> doCompile(String name, String source) throws Throwable {
+ int i = name.lastIndexOf('.');
+ String className = i < 0 ? name : name.substring(i + 1);
+ ClassPool pool = new ClassPool(true);
+ pool.appendClassPath(new LoaderClassPath(ClassHelper.getCallerClassLoader(getClass())));
+ Matcher matcher = IMPORT_PATTERN.matcher(source);
+ List<String> importPackages = new ArrayList<String>();
+ Map<String, String> fullNames = new HashMap<String, String>();
+ while (matcher.find()) {
+ String pkg = matcher.group(1);
+ if (pkg.endsWith(".*")) {
+ String pkgName = pkg.substring(0, pkg.length() - 2);
+ pool.importPackage(pkgName);
+ importPackages.add(pkgName);
+ } else {
+ int pi = pkg.lastIndexOf('.');
+ if (pi > 0) {
+ String pkgName = pkg.substring(0, pi);
+ pool.importPackage(pkgName);
+ importPackages.add(pkgName);
+ fullNames.put(pkg.substring(pi + 1), pkg);
+ }
+ }
+ }
+ String[] packages = importPackages.toArray(new String[0]);
+ matcher = EXTENDS_PATTERN.matcher(source);
+ CtClass cls;
+ if (matcher.find()) {
+ String extend = matcher.group(1).trim();
+ String extendClass;
+ if (extend.contains(".")) {
+ extendClass = extend;
+ } else if (fullNames.containsKey(extend)) {
+ extendClass = fullNames.get(extend);
+ } else {
+ extendClass = ClassUtils.forName(packages, extend).getName();
+ }
+ cls = pool.makeClass(name, pool.get(extendClass));
+ } else {
+ cls = pool.makeClass(name);
+ }
+ matcher = IMPLEMENTS_PATTERN.matcher(source);
+ if (matcher.find()) {
+ String[] ifaces = matcher.group(1).trim().split("\\,");
+ for (String iface : ifaces) {
+ iface = iface.trim();
+ String ifaceClass;
+ if (iface.contains(".")) {
+ ifaceClass = iface;
+ } else if (fullNames.containsKey(iface)) {
+ ifaceClass = fullNames.get(iface);
+ } else {
+ ifaceClass = ClassUtils.forName(packages, iface).getName();
+ }
+ cls.addInterface(pool.get(ifaceClass));
+ }
+ }
+ String body = source.substring(source.indexOf("{") + 1, source.length() - 1);
+ String[] methods = METHODS_PATTERN.split(body);
+ for (String method : methods) {
+ method = method.trim();
+ if (method.length() > 0) {
+ if (method.startsWith(className)) {
+ cls.addConstructor(CtNewConstructor.make("public " + method, cls));
+ } else if (FIELD_PATTERN.matcher(method).matches()) {
+ cls.addField(CtField.make("private " + method, cls));
+ } else {
+ cls.addMethod(CtNewMethod.make("public " + method, cls));
+ }
+ }
+ }
+ return cls.toClass(ClassHelper.getCallerClassLoader(getClass()), JavassistCompiler.class.getProtectionDomain());
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
index 8a8580d03d..e1cca52540 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java
@@ -1,291 +1,291 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.compiler.support;
-
-import org.apache.dubbo.common.utils.ClassHelper;
-
-import javax.tools.DiagnosticCollector;
-import javax.tools.FileObject;
-import javax.tools.ForwardingJavaFileManager;
-import javax.tools.JavaCompiler;
-import javax.tools.JavaFileManager;
-import javax.tools.JavaFileObject;
-import javax.tools.JavaFileObject.Kind;
-import javax.tools.SimpleJavaFileObject;
-import javax.tools.StandardJavaFileManager;
-import javax.tools.StandardLocation;
-import javax.tools.ToolProvider;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.URI;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * JdkCompiler. (SPI, Singleton, ThreadSafe)
- */
-public class JdkCompiler extends AbstractCompiler {
-
- private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-
- private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
-
- private final ClassLoaderImpl classLoader;
-
- private final JavaFileManagerImpl javaFileManager;
-
- private volatile List<String> options;
-
- public JdkCompiler() {
- options = new ArrayList<String>();
- options.add("-source");
- options.add("1.6");
- options.add("-target");
- options.add("1.6");
- StandardJavaFileManager manager = compiler.getStandardFileManager(diagnosticCollector, null, null);
- final ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if (loader instanceof URLClassLoader
- && (!loader.getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))) {
- try {
- URLClassLoader urlClassLoader = (URLClassLoader) loader;
- List<File> files = new ArrayList<File>();
- for (URL url : urlClassLoader.getURLs()) {
- files.add(new File(url.getFile()));
- }
- manager.setLocation(StandardLocation.CLASS_PATH, files);
- } catch (IOException e) {
- throw new IllegalStateException(e.getMessage(), e);
- }
- }
- classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoaderImpl>() {
- @Override
- public ClassLoaderImpl run() {
- return new ClassLoaderImpl(loader);
- }
- });
- javaFileManager = new JavaFileManagerImpl(manager, classLoader);
- }
-
- @Override
- public Class<?> doCompile(String name, String sourceCode) throws Throwable {
- int i = name.lastIndexOf('.');
- String packageName = i < 0 ? "" : name.substring(0, i);
- String className = i < 0 ? name : name.substring(i + 1);
- JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);
- javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName,
- className + ClassUtils.JAVA_EXTENSION, javaFileObject);
- Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options,
- null, Arrays.asList(javaFileObject)).call();
- if (result == null || !result) {
- throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector);
- }
- return classLoader.loadClass(name);
- }
-
- private static final class JavaFileObjectImpl extends SimpleJavaFileObject {
-
- private final CharSequence source;
- private ByteArrayOutputStream bytecode;
-
- public JavaFileObjectImpl(final String baseName, final CharSequence source) {
- super(ClassUtils.toURI(baseName + ClassUtils.JAVA_EXTENSION), Kind.SOURCE);
- this.source = source;
- }
-
- JavaFileObjectImpl(final String name, final Kind kind) {
- super(ClassUtils.toURI(name), kind);
- source = null;
- }
-
- public JavaFileObjectImpl(URI uri, Kind kind) {
- super(uri, kind);
- source = null;
- }
-
- @Override
- public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {
- if (source == null) {
- throw new UnsupportedOperationException("source == null");
- }
- return source;
- }
-
- @Override
- public InputStream openInputStream() {
- return new ByteArrayInputStream(getByteCode());
- }
-
- @Override
- public OutputStream openOutputStream() {
- return bytecode = new ByteArrayOutputStream();
- }
-
- public byte[] getByteCode() {
- return bytecode.toByteArray();
- }
- }
-
- private static final class JavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
-
- private final ClassLoaderImpl classLoader;
-
- private final Map<URI, JavaFileObject> fileObjects = new HashMap<URI, JavaFileObject>();
-
- public JavaFileManagerImpl(JavaFileManager fileManager, ClassLoaderImpl classLoader) {
- super(fileManager);
- this.classLoader = classLoader;
- }
-
- @Override
- public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
- FileObject o = fileObjects.get(uri(location, packageName, relativeName));
- if (o != null)
- return o;
- return super.getFileForInput(location, packageName, relativeName);
- }
-
- public void putFileForInput(StandardLocation location, String packageName, String relativeName, JavaFileObject file) {
- fileObjects.put(uri(location, packageName, relativeName), file);
- }
-
- private URI uri(Location location, String packageName, String relativeName) {
- return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);
- }
-
- @Override
- public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, Kind kind, FileObject outputFile)
- throws IOException {
- JavaFileObject file = new JavaFileObjectImpl(qualifiedName, kind);
- classLoader.add(qualifiedName, file);
- return file;
- }
-
- @Override
- public ClassLoader getClassLoader(JavaFileManager.Location location) {
- return classLoader;
- }
-
- @Override
- public String inferBinaryName(Location loc, JavaFileObject file) {
- if (file instanceof JavaFileObjectImpl)
- return file.getName();
- return super.inferBinaryName(loc, file);
- }
-
- @Override
- public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse)
- throws IOException {
- Iterable<JavaFileObject> result = super.list(location, packageName, kinds, recurse);
-
- ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
- List<URL> urlList = new ArrayList<URL>();
- Enumeration<URL> e = contextClassLoader.getResources("com");
- while (e.hasMoreElements()) {
- urlList.add(e.nextElement());
- }
-
- ArrayList<JavaFileObject> files = new ArrayList<JavaFileObject>();
-
- if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
- for (JavaFileObject file : fileObjects.values()) {
- if (file.getKind() == Kind.CLASS && file.getName().startsWith(packageName)) {
- files.add(file);
- }
- }
-
- files.addAll(classLoader.files());
- } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(JavaFileObject.Kind.SOURCE)) {
- for (JavaFileObject file : fileObjects.values()) {
- if (file.getKind() == Kind.SOURCE && file.getName().startsWith(packageName)) {
- files.add(file);
- }
- }
- }
-
- for (JavaFileObject file : result) {
- files.add(file);
- }
-
- return files;
- }
- }
-
- private final class ClassLoaderImpl extends ClassLoader {
-
- private final Map<String, JavaFileObject> classes = new HashMap<String, JavaFileObject>();
-
- ClassLoaderImpl(final ClassLoader parentClassLoader) {
- super(parentClassLoader);
- }
-
- Collection<JavaFileObject> files() {
- return Collections.unmodifiableCollection(classes.values());
- }
-
- @Override
- protected Class<?> findClass(final String qualifiedClassName) throws ClassNotFoundException {
- JavaFileObject file = classes.get(qualifiedClassName);
- if (file != null) {
- byte[] bytes = ((JavaFileObjectImpl) file).getByteCode();
- return defineClass(qualifiedClassName, bytes, 0, bytes.length);
- }
- try {
- return ClassHelper.forNameWithCallerClassLoader(qualifiedClassName, getClass());
- } catch (ClassNotFoundException nf) {
- return super.findClass(qualifiedClassName);
- }
- }
-
- void add(final String qualifiedClassName, final JavaFileObject javaFile) {
- classes.put(qualifiedClassName, javaFile);
- }
-
- @Override
- protected synchronized Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
- return super.loadClass(name, resolve);
- }
-
- @Override
- public InputStream getResourceAsStream(final String name) {
- if (name.endsWith(ClassUtils.CLASS_EXTENSION)) {
- String qualifiedClassName = name.substring(0, name.length() - ClassUtils.CLASS_EXTENSION.length()).replace('/', '.');
- JavaFileObjectImpl file = (JavaFileObjectImpl) classes.get(qualifiedClassName);
- if (file != null) {
- return new ByteArrayInputStream(file.getByteCode());
- }
- }
- return super.getResourceAsStream(name);
- }
- }
-
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.compiler.support;
+
+import org.apache.dubbo.common.utils.ClassHelper;
+
+import javax.tools.DiagnosticCollector;
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * JdkCompiler. (SPI, Singleton, ThreadSafe)
+ */
+public class JdkCompiler extends AbstractCompiler {
+
+ private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+ private final DiagnosticCollector<JavaFileObject> diagnosticCollector = new DiagnosticCollector<JavaFileObject>();
+
+ private final ClassLoaderImpl classLoader;
+
+ private final JavaFileManagerImpl javaFileManager;
+
+ private volatile List<String> options;
+
+ public JdkCompiler() {
+ options = new ArrayList<String>();
+ options.add("-source");
+ options.add("1.6");
+ options.add("-target");
+ options.add("1.6");
+ StandardJavaFileManager manager = compiler.getStandardFileManager(diagnosticCollector, null, null);
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader instanceof URLClassLoader
+ && (!loader.getClass().getName().equals("sun.misc.Launcher$AppClassLoader"))) {
+ try {
+ URLClassLoader urlClassLoader = (URLClassLoader) loader;
+ List<File> files = new ArrayList<File>();
+ for (URL url : urlClassLoader.getURLs()) {
+ files.add(new File(url.getFile()));
+ }
+ manager.setLocation(StandardLocation.CLASS_PATH, files);
+ } catch (IOException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+ classLoader = AccessController.doPrivileged(new PrivilegedAction<ClassLoaderImpl>() {
+ @Override
+ public ClassLoaderImpl run() {
+ return new ClassLoaderImpl(loader);
+ }
+ });
+ javaFileManager = new JavaFileManagerImpl(manager, classLoader);
+ }
+
+ @Override
+ public Class<?> doCompile(String name, String sourceCode) throws Throwable {
+ int i = name.lastIndexOf('.');
+ String packageName = i < 0 ? "" : name.substring(0, i);
+ String className = i < 0 ? name : name.substring(i + 1);
+ JavaFileObjectImpl javaFileObject = new JavaFileObjectImpl(className, sourceCode);
+ javaFileManager.putFileForInput(StandardLocation.SOURCE_PATH, packageName,
+ className + ClassUtils.JAVA_EXTENSION, javaFileObject);
+ Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options,
+ null, Arrays.asList(javaFileObject)).call();
+ if (result == null || !result) {
+ throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector);
+ }
+ return classLoader.loadClass(name);
+ }
+
+ private static final class JavaFileObjectImpl extends SimpleJavaFileObject {
+
+ private final CharSequence source;
+ private ByteArrayOutputStream bytecode;
+
+ public JavaFileObjectImpl(final String baseName, final CharSequence source) {
+ super(ClassUtils.toURI(baseName + ClassUtils.JAVA_EXTENSION), Kind.SOURCE);
+ this.source = source;
+ }
+
+ JavaFileObjectImpl(final String name, final Kind kind) {
+ super(ClassUtils.toURI(name), kind);
+ source = null;
+ }
+
+ public JavaFileObjectImpl(URI uri, Kind kind) {
+ super(uri, kind);
+ source = null;
+ }
+
+ @Override
+ public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws UnsupportedOperationException {
+ if (source == null) {
+ throw new UnsupportedOperationException("source == null");
+ }
+ return source;
+ }
+
+ @Override
+ public InputStream openInputStream() {
+ return new ByteArrayInputStream(getByteCode());
+ }
+
+ @Override
+ public OutputStream openOutputStream() {
+ return bytecode = new ByteArrayOutputStream();
+ }
+
+ public byte[] getByteCode() {
+ return bytecode.toByteArray();
+ }
+ }
+
+ private static final class JavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
+
+ private final ClassLoaderImpl classLoader;
+
+ private final Map<URI, JavaFileObject> fileObjects = new HashMap<URI, JavaFileObject>();
+
+ public JavaFileManagerImpl(JavaFileManager fileManager, ClassLoaderImpl classLoader) {
+ super(fileManager);
+ this.classLoader = classLoader;
+ }
+
+ @Override
+ public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
+ FileObject o = fileObjects.get(uri(location, packageName, relativeName));
+ if (o != null)
+ return o;
+ return super.getFileForInput(location, packageName, relativeName);
+ }
+
+ public void putFileForInput(StandardLocation location, String packageName, String relativeName, JavaFileObject file) {
+ fileObjects.put(uri(location, packageName, relativeName), file);
+ }
+
+ private URI uri(Location location, String packageName, String relativeName) {
+ return ClassUtils.toURI(location.getName() + '/' + packageName + '/' + relativeName);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String qualifiedName, Kind kind, FileObject outputFile)
+ throws IOException {
+ JavaFileObject file = new JavaFileObjectImpl(qualifiedName, kind);
+ classLoader.add(qualifiedName, file);
+ return file;
+ }
+
+ @Override
+ public ClassLoader getClassLoader(JavaFileManager.Location location) {
+ return classLoader;
+ }
+
+ @Override
+ public String inferBinaryName(Location loc, JavaFileObject file) {
+ if (file instanceof JavaFileObjectImpl)
+ return file.getName();
+ return super.inferBinaryName(loc, file);
+ }
+
+ @Override
+ public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse)
+ throws IOException {
+ Iterable<JavaFileObject> result = super.list(location, packageName, kinds, recurse);
+
+ ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+ List<URL> urlList = new ArrayList<URL>();
+ Enumeration<URL> e = contextClassLoader.getResources("com");
+ while (e.hasMoreElements()) {
+ urlList.add(e.nextElement());
+ }
+
+ ArrayList<JavaFileObject> files = new ArrayList<JavaFileObject>();
+
+ if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
+ for (JavaFileObject file : fileObjects.values()) {
+ if (file.getKind() == Kind.CLASS && file.getName().startsWith(packageName)) {
+ files.add(file);
+ }
+ }
+
+ files.addAll(classLoader.files());
+ } else if (location == StandardLocation.SOURCE_PATH && kinds.contains(JavaFileObject.Kind.SOURCE)) {
+ for (JavaFileObject file : fileObjects.values()) {
+ if (file.getKind() == Kind.SOURCE && file.getName().startsWith(packageName)) {
+ files.add(file);
+ }
+ }
+ }
+
+ for (JavaFileObject file : result) {
+ files.add(file);
+ }
+
+ return files;
+ }
+ }
+
+ private final class ClassLoaderImpl extends ClassLoader {
+
+ private final Map<String, JavaFileObject> classes = new HashMap<String, JavaFileObject>();
+
+ ClassLoaderImpl(final ClassLoader parentClassLoader) {
+ super(parentClassLoader);
+ }
+
+ Collection<JavaFileObject> files() {
+ return Collections.unmodifiableCollection(classes.values());
+ }
+
+ @Override
+ protected Class<?> findClass(final String qualifiedClassName) throws ClassNotFoundException {
+ JavaFileObject file = classes.get(qualifiedClassName);
+ if (file != null) {
+ byte[] bytes = ((JavaFileObjectImpl) file).getByteCode();
+ return defineClass(qualifiedClassName, bytes, 0, bytes.length);
+ }
+ try {
+ return ClassHelper.forNameWithCallerClassLoader(qualifiedClassName, getClass());
+ } catch (ClassNotFoundException nf) {
+ return super.findClass(qualifiedClassName);
+ }
+ }
+
+ void add(final String qualifiedClassName, final JavaFileObject javaFile) {
+ classes.put(qualifiedClassName, javaFile);
+ }
+
+ @Override
+ protected synchronized Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
+ return super.loadClass(name, resolve);
+ }
+
+ @Override
+ public InputStream getResourceAsStream(final String name) {
+ if (name.endsWith(ClassUtils.CLASS_EXTENSION)) {
+ String qualifiedClassName = name.substring(0, name.length() - ClassUtils.CLASS_EXTENSION.length()).replace('/', '.');
+ JavaFileObjectImpl file = (JavaFileObjectImpl) classes.get(qualifiedClassName);
+ if (file != null) {
+ return new ByteArrayInputStream(file.getByteCode());
+ }
+ }
+ return super.getResourceAsStream(name);
+ }
+ }
+
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Activate.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Activate.java
index 52e9305347..36e8fff1c4 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Activate.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/Activate.java
@@ -1,88 +1,88 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.extension;
-
-import org.apache.dubbo.common.URL;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Activate. This annotation is useful for automatically activate certain extensions with the given criteria,
- * for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are
- * multiple implementations.
- * <ol>
- * <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.
- * <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.
- * </ol>
- * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated
- * extensions with the given criteria.
- *
- * @see SPI
- * @see URL
- * @see ExtensionLoader
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE, ElementType.METHOD})
-public @interface Activate {
- /**
- * Activate the current extension when one of the groups matches. The group passed into
- * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
- *
- * @return group names to match
- * @see ExtensionLoader#getActivateExtension(URL, String, String)
- */
- String[] group() default {};
-
- /**
- * Activate the current extension when the specified keys appear in the URL's parameters.
- * <p>
- * For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
- * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
- * </p>
- *
- * @return URL parameter keys
- * @see ExtensionLoader#getActivateExtension(URL, String)
- * @see ExtensionLoader#getActivateExtension(URL, String, String)
- */
- String[] value() default {};
-
- /**
- * Relative ordering info, optional
- *
- * @return extension list which should be put before the current one
- */
- String[] before() default {};
-
- /**
- * Relative ordering info, optional
- *
- * @return extension list which should be put after the current one
- */
- String[] after() default {};
-
- /**
- * Absolute ordering info, optional
- *
- * @return absolute ordering info
- */
- int order() default 0;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+import org.apache.dubbo.common.URL;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Activate. This annotation is useful for automatically activate certain extensions with the given criteria,
+ * for examples: <code>@Activate</code> can be used to load certain <code>Filter</code> extension when there are
+ * multiple implementations.
+ * <ol>
+ * <li>{@link Activate#group()} specifies group criteria. Framework SPI defines the valid group values.
+ * <li>{@link Activate#value()} specifies parameter key in {@link URL} criteria.
+ * </ol>
+ * SPI provider can call {@link ExtensionLoader#getActivateExtension(URL, String, String)} to find out all activated
+ * extensions with the given criteria.
+ *
+ * @see SPI
+ * @see URL
+ * @see ExtensionLoader
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface Activate {
+ /**
+ * Activate the current extension when one of the groups matches. The group passed into
+ * {@link ExtensionLoader#getActivateExtension(URL, String, String)} will be used for matching.
+ *
+ * @return group names to match
+ * @see ExtensionLoader#getActivateExtension(URL, String, String)
+ */
+ String[] group() default {};
+
+ /**
+ * Activate the current extension when the specified keys appear in the URL's parameters.
+ * <p>
+ * For example, given <code>@Activate("cache, validation")</code>, the current extension will be return only when
+ * there's either <code>cache</code> or <code>validation</code> key appeared in the URL's parameters.
+ * </p>
+ *
+ * @return URL parameter keys
+ * @see ExtensionLoader#getActivateExtension(URL, String)
+ * @see ExtensionLoader#getActivateExtension(URL, String, String)
+ */
+ String[] value() default {};
+
+ /**
+ * Relative ordering info, optional
+ *
+ * @return extension list which should be put before the current one
+ */
+ String[] before() default {};
+
+ /**
+ * Relative ordering info, optional
+ *
+ * @return extension list which should be put after the current one
+ */
+ String[] after() default {};
+
+ /**
+ * Absolute ordering info, optional
+ *
+ * @return absolute ordering info
+ */
+ int order() default 0;
}
\ No newline at end of file
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionFactory.java
index 35cee53399..32bb8465d9 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionFactory.java
@@ -1,34 +1,34 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.extension;
-
-/**
- * ExtensionFactory
- */
-@SPI
-public interface ExtensionFactory {
-
- /**
- * Get extension.
- *
- * @param type object type.
- * @param name object name.
- * @return object instance.
- */
- <T> T getExtension(Class<T> type, String name);
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+/**
+ * ExtensionFactory
+ */
+@SPI
+public interface ExtensionFactory {
+
+ /**
+ * Get extension.
+ *
+ * @param type object type.
+ * @param name object name.
+ * @return object instance.
+ */
+ <T> T getExtension(Class<T> type, String name);
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index b8e7bbf974..f57e343783 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -1,950 +1,950 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.dubbo.common.extension;
-
-import org.apache.dubbo.common.Constants;
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.support.ActivateComparator;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.ConcurrentHashSet;
-import org.apache.dubbo.common.utils.ConfigUtils;
-import org.apache.dubbo.common.utils.Holder;
-import org.apache.dubbo.common.utils.StringUtils;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Pattern;
-
-/**
- * Load dubbo extensions
- * <ul>
- * <li>auto inject dependency extension </li>
- * <li>auto wrap extension in wrapper </li>
- * <li>default extension is an adaptive instance</li>
- * </ul>
- *
- * @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">Service Provider in Java 5</a>
- * @see org.apache.dubbo.common.extension.SPI
- * @see org.apache.dubbo.common.extension.Adaptive
- * @see org.apache.dubbo.common.extension.Activate
- */
-public class ExtensionLoader<T> {
-
- private static final Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
-
- private static final String SERVICES_DIRECTORY = "META-INF/services/";
-
- private static final String DUBBO_DIRECTORY = "META-INF/dubbo/";
-
- private static final String DUBBO_INTERNAL_DIRECTORY = DUBBO_DIRECTORY + "internal/";
-
- private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
-
- private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<Class<?>, ExtensionLoader<?>>();
-
- private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
-
- // ==============================
-
- private final Class<?> type;
-
- private final ExtensionFactory objectFactory;
-
- private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();
-
- private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();
-
- private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
- private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();
- private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
- private volatile Class<?> cachedAdaptiveClass = null;
- private String cachedDefaultName;
- private volatile Throwable createAdaptiveInstanceError;
-
- private Set<Class<?>> cachedWrapperClasses;
-
- private Map<String, IllegalStateException> exceptions = new ConcurrentHashMap<String, IllegalStateException>();
-
- private ExtensionLoader(Class<?> type) {
- this.type = type;
- objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
- }
-
- private static <T> boolean withExtensionAnnotation(Class<T> type) {
- return type.isAnnotationPresent(SPI.class);
- }
-
- @SuppressWarnings("unchecked")
- public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
- if (type == null)
- throw new IllegalArgumentException("Extension type == null");
- if (!type.isInterface()) {
- throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
- }
- if (!withExtensionAnnotation(type)) {
- throw new IllegalArgumentException("Extension type(" + type +
- ") is not extension, because WITHOUT @" + SPI.class.getSimpleName() + " Annotation!");
- }
-
- ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
- if (loader == null) {
- EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
- loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
- }
- return loader;
- }
-
- private static ClassLoader findClassLoader() {
- return ExtensionLoader.class.getClassLoader();
- }
-
- public String getExtensionName(T extensionInstance) {
- return getExtensionName(extensionInstance.getClass());
- }
-
- public String getExtensionName(Class<?> extensionClass) {
- getExtensionClasses();// load class
- return cachedNames.get(extensionClass);
- }
-
- /**
- * This is equivalent to {@code getActivateExtension(url, key, null)}
- *
- * @param url url
- * @param key url parameter key which used to get extension point names
- * @return extension list which are activated.
- * @see #getActivateExtension(org.apache.dubbo.common.URL, String, String)
- */
- public List<T> getActivateExtension(URL url, String key) {
- return getActivateExtension(url, key, null);
- }
-
- /**
- * This is equivalent to {@code getActivateExtension(url, values, null)}
- *
- * @param url url
- * @param values extension point names
- * @return extension list which are activated
- * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)
- */
- public List<T> getActivateExtension(URL url, String[] values) {
- return getActivateExtension(url, values, null);
- }
-
- /**
- * This is equivalent to {@code getActivateExtension(url, url.getParameter(key).split(","), null)}
- *
- * @param url url
- * @param key url parameter key which used to get extension point names
- * @param group group
- * @return extension list which are activated.
- * @see #getActivateExtension(org.apache.dubbo.common.URL, String[], String)
- */
- public List<T> getActivateExtension(URL url, String key, String group) {
- String value = url.getParameter(key);
- return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
- }
-
- /**
- * Get activate extensions.
- *
- * @param url url
- * @param values extension point names
- * @param group group
- * @return extension list which are activated
- * @see org.apache.dubbo.common.extension.Activate
- */
- public List<T> getActivateExtension(URL url, String[] values, String group) {
- List<T> exts = new ArrayList<T>();
- List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
- if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
- getExtensionClasses();
- for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
- String name = entry.getKey();
- Activate activate = entry.getValue();
- if (isMatchGroup(group, activate.group())) {
- T ext = getExtension(name);
- if (!names.contains(name)
- && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)
- && isActive(activate, url)) {
- exts.add(ext);
- }
- }
- }
- Collections.sort(exts, ActivateComparator.COMPARATOR);
- }
- List<T> usrs = new ArrayList<T>();
- for (int i = 0; i < names.size(); i++) {
- String name = names.get(i);
- if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX)
- && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) {
- if (Constants.DEFAULT_KEY.equals(name)) {
- if (!usrs.isEmpty()) {
- exts.addAll(0, usrs);
- usrs.clear();
- }
- } else {
- T ext = getExtension(name);
- usrs.add(ext);
- }
- }
- }
- if (!usrs.isEmpty()) {
- exts.addAll(usrs);
- }
- return exts;
- }
-
- private boolean isMatchGroup(String group, String[] groups) {
- if (group == null || group.length() == 0) {
- return true;
- }
- if (groups != null && groups.length > 0) {
- for (String g : groups) {
- if (group.equals(g)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean isActive(Activate activate, URL url) {
- String[] keys = activate.value();
- if (keys.length == 0) {
- return true;
- }
- for (String key : keys) {
- for (Map.Entry<String, String> entry : url.getParameters().entrySet()) {
- String k = entry.getKey();
- String v = entry.getValue();
- if ((k.equals(key) || k.endsWith("." + key))
- && ConfigUtils.isNotEmpty(v)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Get extension's instance. Return <code>null</code> if extension is not found or is not initialized. Pls. note
- * that this method will not trigger extension load.
- * <p>
- * In order to trigger extension load, call {@link #getExtension(String)} instead.
- *
- * @see #getExtension(String)
- */
- @SuppressWarnings("unchecked")
- public T getLoadedExtension(String name) {
- if (name == null || name.length() == 0)
- throw new IllegalArgumentException("Extension name == null");
- Holder<Object> holder = cachedInstances.get(name);
- if (holder == null) {
- cachedInstances.putIfAbsent(name, new Holder<Object>());
- holder = cachedInstances.get(name);
- }
- return (T) holder.get();
- }
-
- /**
- * Return the list of extensions which are already loaded.
- * <p>
- * Usually {@link #getSupportedExtensions()} should be called in order to get all extensions.
- *
- * @see #getSupportedExtensions()
- */
- public Set<String> getLoadedExtensions() {
- return Collections.unmodifiableSet(new TreeSet<String>(cachedInstances.keySet()));
- }
-
- /**
- * Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException}
- * will be thrown.
- */
- @SuppressWarnings("unchecked")
- public T getExtension(String name) {
- if (name == null || name.length() == 0)
- throw new IllegalArgumentException("Extension name == null");
- if ("true".equals(name)) {
- return getDefaultExtension();
- }
- Holder<Object> holder = cachedInstances.get(name);
- if (holder == null) {
- cachedInstances.putIfAbsent(name, new Holder<Object>());
- holder = cachedInstances.get(name);
- }
- Object instance = holder.get();
- if (instance == null) {
- synchronized (holder) {
- instance = holder.get();
- if (instance == null) {
- instance = createExtension(name);
- holder.set(instance);
- }
- }
- }
- return (T) instance;
- }
-
- /**
- * Return default extension, return <code>null</code> if it's not configured.
- */
- public T getDefaultExtension() {
- getExtensionClasses();
- if (null == cachedDefaultName || cachedDefaultName.length() == 0
- || "true".equals(cachedDefaultName)) {
- return null;
- }
- return getExtension(cachedDefaultName);
- }
-
- public boolean hasExtension(String name) {
- if (name == null || name.length() == 0)
- throw new IllegalArgumentException("Extension name == null");
- try {
- this.getExtensionClass(name);
- return true;
- } catch (Throwable t) {
- return false;
- }
- }
-
- public Set<String> getSupportedExtensions() {
- Map<String, Class<?>> clazzes = getExtensionClasses();
- return Collections.unmodifiableSet(new TreeSet<String>(clazzes.keySet()));
- }
-
- /**
- * Return default extension name, return <code>null</code> if not configured.
- */
- public String getDefaultExtensionName() {
- getExtensionClasses();
- return cachedDefaultName;
- }
-
- /**
- * Register new extension via API
- *
- * @param name extension name
- * @param clazz extension class
- * @throws IllegalStateException when extension with the same name has already been registered.
- */
- public void addExtension(String name, Class<?> clazz) {
- getExtensionClasses(); // load classes
-
- if (!type.isAssignableFrom(clazz)) {
- throw new IllegalStateException("Input type " +
- clazz + "not implement Extension " + type);
- }
- if (clazz.isInterface()) {
- throw new IllegalStateException("Input type " +
- clazz + "can not be interface!");
- }
-
- if (!clazz.isAnnotationPresent(Adaptive.class)) {
- if (StringUtils.isBlank(name)) {
- throw new IllegalStateException("Extension name is blank (Extension " + type + ")!");
- }
- if (cachedClasses.get().containsKey(name)) {
- throw new IllegalStateException("Extension name " +
- name + " already existed(Extension " + type + ")!");
- }
-
- cachedNames.put(clazz, name);
- cachedClasses.get().put(name, clazz);
- } else {
- if (cachedAdaptiveClass != null) {
- throw new IllegalStateException("Adaptive Extension already existed(Extension " + type + ")!");
- }
-
- cachedAdaptiveClass = clazz;
- }
- }
-
- /**
- * Replace the existing extension via API
- *
- * @param name extension name
- * @param clazz extension class
- * @throws IllegalStateException when extension to be placed doesn't exist
- * @deprecated not recommended any longer, and use only when test
- */
- @Deprecated
- public void replaceExtension(String name, Class<?> clazz) {
- getExtensionClasses(); // load classes
-
- if (!type.isAssignableFrom(clazz)) {
- throw new IllegalStateException("Input type " +
- clazz + "not implement Extension " + type);
- }
- if (clazz.isInterface()) {
- throw new IllegalStateException("Input type " +
- clazz + "can not be interface!");
- }
-
- if (!clazz.isAnnotationPresent(Adaptive.class)) {
- if (StringUtils.isBlank(name)) {
- throw new IllegalStateException("Extension name is blank (Extension " + type + ")!");
- }
- if (!cachedClasses.get().containsKey(name)) {
- throw new IllegalStateException("Extension name " +
- name + " not existed(Extension " + type + ")!");
- }
-
- cachedNames.put(clazz, name);
- cachedClasses.get().put(name, clazz);
- cachedInstances.remove(name);
- } else {
- if (cachedAdaptiveClass == null) {
- throw new IllegalStateException("Adaptive Extension not existed(Extension " + type + ")!");
- }
-
- cachedAdaptiveClass = clazz;
- cachedAdaptiveInstance.set(null);
- }
- }
-
- @SuppressWarnings("unchecked")
- public T getAdaptiveExtension() {
- Object instance = cachedAdaptiveInstance.get();
- if (instance == null) {
- if (createAdaptiveInstanceError == null) {
- synchronized (cachedAdaptiveInstance) {
- instance = cachedAdaptiveInstance.get();
- if (instance == null) {
- try {
- instance = createAdaptiveExtension();
- cachedAdaptiveInstance.set(instance);
- } catch (Throwable t) {
- createAdaptiveInstanceError = t;
- throw new IllegalStateException("fail to create adaptive instance: " + t.toString(), t);
- }
- }
- }
- } else {
- throw new IllegalStateException("fail to create adaptive instance: " + createAdaptiveInstanceError.toString(), createAdaptiveInstanceError);
- }
- }
-
- return (T) instance;
- }
-
- private IllegalStateException findException(String name) {
- for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
- if (entry.getKey().toLowerCase().contains(name.toLowerCase())) {
- return entry.getValue();
- }
- }
- StringBuilder buf = new StringBuilder("No such extension " + type.getName() + " by name " + name);
-
-
- int i = 1;
- for (Map.Entry<String, IllegalStateException> entry : exceptions.entrySet()) {
- if (i == 1) {
- buf.append(", possible causes: ");
- }
-
- buf.append("\r\n(");
- buf.append(i++);
- buf.append(") ");
- buf.append(entry.getKey());
- buf.append(":\r\n");
- buf.append(StringUtils.toString(entry.getValue()));
- }
- return new IllegalStateException(buf.toString());
- }
-
- @SuppressWarnings("unchecked")
- private T createExtension(String name) {
- Class<?> clazz = getExtensionClasses().get(name);
- if (clazz == null) {
- throw findException(name);
- }
- try {
- T instance = (T) EXTENSION_INSTANCES.get(clazz);
- if (instance == null) {
- EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
- instance = (T) EXTENSION_INSTANCES.get(clazz);
- }
- injectExtension(instance);
- Set<Class<?>> wrapperClasses = cachedWrapperClasses;
- if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
- for (Class<?> wrapperClass : wrapperClasses) {
- instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
- }
- }
- return instance;
- } catch (Throwable t) {
- throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
- type + ") could not be instantiated: " + t.getMessage(), t);
- }
- }
-
- private T injectExtension(T instance) {
- try {
- if (objectFactory != null) {
- for (Method method : instance.getClass().getMethods()) {
- if (method.getName().startsWith("set")
- && method.getParameterTypes().length == 1
- && Modifier.isPublic(method.getModifiers())) {
- Class<?> pt = method.getParameterTypes()[0];
- try {
- String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
- Object object = objectFactory.getExtension(pt, property);
- if (object != null) {
- method.invoke(instance, object);
- }
- } catch (Exception e) {
- logger.error("fail to inject via method " + method.getName()
- + " of interface " + type.getName() + ": " + e.getMessage(), e);
- }
- }
- }
- }
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- return instance;
- }
-
- private Class<?> getExtensionClass(String name) {
- if (type == null)
- throw new IllegalArgumentException("Extension type == null");
- if (name == null)
- throw new IllegalArgumentException("Extension name == null");
- Class<?> clazz = getExtensionClasses().get(name);
- if (clazz == null)
- throw new IllegalStateException("No such extension \"" + name + "\" for " + type.getName() + "!");
- return clazz;
- }
-
- private Map<String, Class<?>> getExtensionClasses() {
- Map<String, Class<?>> classes = cachedClasses.get();
- if (classes == null) {
- synchronized (cachedClasses) {
- classes = cachedClasses.get();
- if (classes == null) {
- classes = loadExtensionClasses();
- cachedClasses.set(classes);
- }
- }
- }
- return classes;
- }
-
- // synchronized in getExtensionClasses
- private Map<String, Class<?>> loadExtensionClasses() {
- final SPI defaultAnnotation = type.getAnnotation(SPI.class);
- if (defaultAnnotation != null) {
- String value = defaultAnnotation.value();
- if ((value = value.trim()).length() > 0) {
- String[] names = NAME_SEPARATOR.split(value);
- if (names.length > 1) {
- throw new IllegalStateException("more than 1 default extension name on extension " + type.getName()
- + ": " + Arrays.toString(names));
- }
- if (names.length == 1) cachedDefaultName = names[0];
- }
- }
-
- Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
- loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName());
- loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
- loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName());
- loadDirectory(extensionClasses, DUBBO_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
- loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName());
- loadDirectory(extensionClasses, SERVICES_DIRECTORY, type.getName().replace("org.apache", "com.alibaba"));
- return extensionClasses;
- }
-
- private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir, String type) {
- String fileName = dir + type;
- try {
- Enumeration<java.net.URL> urls;
- ClassLoader classLoader = findClassLoader();
- if (classLoader != null) {
- urls = classLoader.getResources(fileName);
- } else {
- urls = ClassLoader.getSystemResources(fileName);
- }
- if (urls != null) {
- while (urls.hasMoreElements()) {
- java.net.URL resourceURL = urls.nextElement();
- loadResource(extensionClasses, classLoader, resourceURL);
- }
- }
- } catch (Throwable t) {
- logger.error("Exception when load extension class(interface: " +
- type + ", description file: " + fileName + ").", t);
- }
- }
-
- private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, java.net.URL resourceURL) {
- try {
- BufferedReader reader = new BufferedReader(new InputStreamReader(resourceURL.openStream(), "utf-8"));
- try {
- String line;
- while ((line = reader.readLine()) != null) {
- final int ci = line.indexOf('#');
- if (ci >= 0) line = line.substring(0, ci);
- line = line.trim();
- if (line.length() > 0) {
- try {
- String name = null;
- int i = line.indexOf('=');
- if (i > 0) {
- name = line.substring(0, i).trim();
- line = line.substring(i + 1).trim();
- }
- if (line.length() > 0) {
- loadClass(extensionClasses, resourceURL, Class.forName(line, true, classLoader), name);
- }
- } catch (Throwable t) {
- IllegalStateException e = new IllegalStateException("Failed to load extension class(interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
- exceptions.put(line, e);
- }
- }
- }
- } finally {
- reader.close();
- }
- } catch (Throwable t) {
- logger.error("Exception when load extension class(interface: " +
- type + ", class file: " + resourceURL + ") in " + resourceURL, t);
- }
- }
-
- private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
- if (!type.isAssignableFrom(clazz)) {
- throw new IllegalStateException("Error when load extension class(interface: " +
- type + ", class line: " + clazz.getName() + "), class "
- + clazz.getName() + "is not subtype of interface.");
- }
- if (clazz.isAnnotationPresent(Adaptive.class)) {
- if (cachedAdaptiveClass == null) {
- cachedAdaptiveClass = clazz;
- } else if (!cachedAdaptiveClass.equals(clazz)) {
- throw new IllegalStateException("More than 1 adaptive class found: "
- + cachedAdaptiveClass.getClass().getName()
- + ", " + clazz.getClass().getName());
- }
- } else if (isWrapperClass(clazz)) {
- Set<Class<?>> wrappers = cachedWrapperClasses;
- if (wrappers == null) {
- cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
- wrappers = cachedWrapperClasses;
- }
- wrappers.add(clazz);
- } else {
- clazz.getConstructor();
- if (name == null || name.length() == 0) {
- name = findAnnotationName(clazz);
- if (name.length() == 0) {
- throw new IllegalStateException("No such extension name for the class " + clazz.getName() + " in the config " + resourceURL);
- }
- }
- String[] names = NAME_SEPARATOR.split(name);
- if (names != null && names.length > 0) {
- Activate activate = clazz.getAnnotation(Activate.class);
- if (activate != null) {
- cachedActivates.put(names[0], activate);
- }
- for (String n : names) {
- if (!cachedNames.containsKey(clazz)) {
- cachedNames.put(clazz, n);
- }
- Class<?> c = extensionClasses.get(n);
- if (c == null) {
- extensionClasses.put(n, clazz);
- } else if (c != clazz) {
- throw new IllegalStateException("Duplicate extension " + type.getName() + " name " + n + " on " + c.getName() + " and " + clazz.getName());
- }
- }
- }
- }
- }
-
- private boolean isWrapperClass(Class<?> clazz) {
- try {
- clazz.getConstructor(type);
- return true;
- } catch (NoSuchMethodException e) {
- return false;
- }
- }
-
- @SuppressWarnings("deprecation")
- private String findAnnotationName(Class<?> clazz) {
- org.apache.dubbo.common.Extension extension = clazz.getAnnotation(org.apache.dubbo.common.Extension.class);
- if (extension == null) {
- String name = clazz.getSimpleName();
- if (name.endsWith(type.getSimpleName())) {
- name = name.substring(0, name.length() - type.getSimpleName().length());
- }
- return name.toLowerCase();
- }
- return extension.value();
- }
-
- @SuppressWarnings("unchecked")
- private T createAdaptiveExtension() {
- try {
- return injectExtension((T) getAdaptiveExtensionClass().newInstance());
- } catch (Exception e) {
- throw new IllegalStateException("Can not create adaptive extension " + type + ", cause: " + e.getMessage(), e);
- }
- }
-
- private Class<?> getAdaptiveExtensionClass() {
- getExtensionClasses();
- if (cachedAdaptiveClass != null) {
- return cachedAdaptiveClass;
- }
- return cachedAdaptiveClass = createAdaptiveExtensionClass();
- }
-
- private Class<?> createAdaptiveExtensionClass() {
- String code = createAdaptiveExtensionClassCode();
- ClassLoader classLoader = findClassLoader();
- org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
- return compiler.compile(code, classLoader);
- }
-
- private String createAdaptiveExtensionClassCode() {
- StringBuilder codeBuilder = new StringBuilder();
- Method[] methods = type.getMethods();
- boolean hasAdaptiveAnnotation = false;
- for (Method m : methods) {
- if (m.isAnnotationPresent(Adaptive.class)) {
- hasAdaptiveAnnotation = true;
- break;
- }
- }
- // no need to generate adaptive class since there's no adaptive method found.
- if (!hasAdaptiveAnnotation)
- throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");
-
- codeBuilder.append("package ").append(type.getPackage().getName()).append(";");
- codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");
- codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");
-
- for (Method method : methods) {
- Class<?> rt = method.getReturnType();
- Class<?>[] pts = method.getParameterTypes();
- Class<?>[] ets = method.getExceptionTypes();
-
- Adaptive adaptiveAnnotation = method.getAnnotation(Adaptive.class);
- StringBuilder code = new StringBuilder(512);
- if (adaptiveAnnotation == null) {
- code.append("throw new UnsupportedOperationException(\"method ")
- .append(method.toString()).append(" of interface ")
- .append(type.getName()).append(" is not adaptive method!\");");
- } else {
- int urlTypeIndex = -1;
- for (int i = 0; i < pts.length; ++i) {
- if (pts[i].equals(URL.class)) {
- urlTypeIndex = i;
- break;
- }
- }
- // found parameter in URL type
- if (urlTypeIndex != -1) {
- // Null Point check
- String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"url == null\");",
- urlTypeIndex);
- code.append(s);
-
- s = String.format("\n%s url = arg%d;", URL.class.getName(), urlTypeIndex);
- code.append(s);
- }
- // did not find parameter in URL type
- else {
- String attribMethod = null;
-
- // find URL getter method
- LBL_PTS:
- for (int i = 0; i < pts.length; ++i) {
- Method[] ms = pts[i].getMethods();
- for (Method m : ms) {
- String name = m.getName();
- if ((name.startsWith("get") || name.length() > 3)
- && Modifier.isPublic(m.getModifiers())
- && !Modifier.isStatic(m.getModifiers())
- && m.getParameterTypes().length == 0
- && m.getReturnType() == URL.class) {
- urlTypeIndex = i;
- attribMethod = name;
- break LBL_PTS;
- }
- }
- }
- if (attribMethod == null) {
- throw new IllegalStateException("fail to create adaptive class for interface " + type.getName()
- + ": not found url parameter or url attribute in parameters of method " + method.getName());
- }
-
- // Null point check
- String s = String.format("\nif (arg%d == null) throw new IllegalArgumentException(\"%s argument == null\");",
- urlTypeIndex, pts[urlTypeIndex].getName());
- code.append(s);
- s = String.format("\nif (arg%d.%s() == null) throw new IllegalArgumentException(\"%s argument %s() == null\");",
- urlTypeIndex, attribMethod, pts[urlTypeIndex].getName(), attribMethod);
- code.append(s);
-
- s = String.format("%s url = arg%d.%s();", URL.class.getName(), urlTypeIndex, attribMethod);
- code.append(s);
- }
-
- String[] value = adaptiveAnnotation.value();
- // value is not set, use the value generated from class name as the key
- if (value.length == 0) {
- char[] charArray = type.getSimpleName().toCharArray();
- StringBuilder sb = new StringBuilder(128);
- for (int i = 0; i < charArray.length; i++) {
- if (Character.isUpperCase(charArray[i])) {
(This diff was longer than 20,000 lines, and has been truncated...)
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org