diff --git a/.travis.yml b/.travis.yml index 7f30febe7bbd95ffbf1c25abce997408c7681074..1b46f5d872932b7ed307ceaf802c95997b2800e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: go os: - linux - - osx go: - "1.13" @@ -14,6 +13,9 @@ install: true script: - go fmt ./... && [[ -z `git status -s` ]] + - sh before_validate_license.sh + - chmod u+x /tmp/tools/license/license-header-checker + - /tmp/tools/license/license-header-checker -v -a -r -i vendor /tmp/tools/license/license.txt . go && [[ -z `git status -s` ]] - chmod u+x before_ut.sh && ./before_ut.sh - go mod vendor && go test ./... -coverprofile=coverage.txt -covermode=atomic @@ -21,4 +23,4 @@ after_success: - bash <(curl -s https://codecov.io/bash) notifications: - webhooks: https://oapi.dingtalk.com/robot/send?access_token=f5d6237f2c79db584e75604f7f88db1ce1673c8c0e98451217b28fde791e1d4f \ No newline at end of file + webhooks: https://oapi.dingtalk.com/robot/send?access_token=f5d6237f2c79db584e75604f7f88db1ce1673c8c0e98451217b28fde791e1d4f diff --git a/CHANGE.md b/CHANGE.md index ad8bc594cd92ea0c72a284a262cc0cb3630cbeac..00b074d284971d779c84792951262879098fc18b 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -8,6 +8,7 @@ - [Context support](https://github.com/apache/dubbo-go/pull/330) - [Opentracing & transfer context end to end for jsonrpc protocol](https://github.com/apache/dubbo-go/pull/335) - [Opentracing & transfer context end to end for dubbo protocol](https://github.com/apache/dubbo-go/pull/344) +- [Grpc tracing for client and server](https://github.com/apache/dubbo-go/pull/397) - [Nacos config center](https://github.com/apache/dubbo-go/pull/357) - [Prometheus support](https://github.com/apache/dubbo-go/pull/342) - [Support sign and auth for request](https://github.com/apache/dubbo-go/pull/323) diff --git a/README.md b/README.md index e43b1e9aed6b82b2e367edf43728aee24a521d68..5c4de0559d534e03b23d136da5f5f23ff6768d55 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ Apache License, Version 2.0 ## Release note ## +[v1.4.0-rc1 - Mar 12, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1) + [v1.3.0 - Mar 1, 2020](https://github.com/apache/dubbo-go/releases/tag/v1.3.0) [v1.2.0 - Nov 15, 2019](https://github.com/apache/dubbo-go/releases/tag/v1.2.0) @@ -28,7 +30,7 @@ Apache License, Version 2.0 Both extension module and layered project architecture is according to Apache Dubbo (including protocol layer, registry layer, cluster layer, config layer and so on), the advantage of this arch is as following: you can implement these layered interfaces in your own way, override the default implementation of dubbo-go by calling 'extension.SetXXX' of extension, complete your special needs without modifying the source code. At the same time, you are welcome to contribute implementation of useful extension to the community. - + If you wanna know more about dubbo-go, please visit this reference [Project Architeture design](https://github.com/apache/dubbo-go/wiki/dubbo-go-V1.0-design) @@ -56,6 +58,7 @@ Finished List: - Router * [Condition router](https://github.com/apache/dubbo-go/pull/294) + * [Health check router](https://github.com/apache/dubbo-go/pull/389) - Registry * ZooKeeper @@ -91,13 +94,21 @@ Finished List: * [TpsLimitFilter](https://github.com/apache/dubbo-go/pull/237) * [ExecuteLimitFilter](https://github.com/apache/dubbo-go/pull/246) * [GenericServiceFilter](https://github.com/apache/dubbo-go/pull/291) + * [Auth/Sign](https://github.com/apache/dubbo-go/pull/323) + * [Metrics filter](https://github.com/apache/dubbo-go/pull/342) + * [Tracing filter](https://github.com/apache/dubbo-go/pull/335) - Invoke * [generic invoke](https://github.com/apache/dubbo-go/pull/122) - Monitor * Opentracing API - * Prometheus + * [Prometheus](https://github.com/apache/dubbo-go/pull/342) + +- Tracing + * [For jsonrpc](https://github.com/apache/dubbo-go/pull/335) + * [For dubbo](https://github.com/apache/dubbo-go/pull/344) + * [For grpc](https://github.com/apache/dubbo-go/pull/397) - Others: * start check diff --git a/README_CN.md b/README_CN.md index e70e6786313d6a012f377f2e349880740b30c50b..5dec68fd6134fc58bf265ea382473d724332ecc6 100644 --- a/README_CN.md +++ b/README_CN.md @@ -15,6 +15,8 @@ Apache License, Version 2.0 ## 鍙戝竷鏃ュ織 ## +[v1.4.0-rc1 - 2020骞�3鏈�12鏃(https://github.com/apache/dubbo-go/releases/tag/v1.4.0-rc1) + [v1.3.0 - 2020骞�3鏈�1鏃(https://github.com/apache/dubbo-go/releases/tag/v1.3.0) [v1.2.0 - 2019骞�11鏈�15鏃(https://github.com/apache/dubbo-go/releases/tag/v1.2.0) @@ -27,7 +29,7 @@ Apache License, Version 2.0 鍩轰簬dubbo鐨別xtension妯″潡鍜屽垎灞傜殑浠g爜璁捐(鍖呮嫭 protocol layer, registry layer, cluster layer, config 绛夌瓑)銆傛垜浠殑鐩爣鏄細浣犲彲浠ュ杩欎簺鍒嗗眰鎺ュ彛杩涜鏂扮殑瀹炵幇锛屽苟閫氳繃璋冪敤 extension 妯″潡鐨勨€� extension.SetXXX 鈥濇柟娉曟潵瑕嗙洊 dubbo-go [鍚� go-for-apache-dubbo ]鐨勯粯璁ゅ疄鐜帮紝浠ュ畬鎴愯嚜宸辩殑鐗规畩闇€姹傝€屾棤闇€淇敼婧愪唬鐮併€傚悓鏃讹紝娆㈣繋浣犱负绀惧尯璐$尞鏈夌敤鐨勬嫇灞曞疄鐜般€� - + 鍏充簬璇︾粏璁捐璇烽槄璇� [code layered design](https://github.com/apache/dubbo-go/wiki/dubbo-go-V1.0-design) @@ -55,6 +57,7 @@ Apache License, Version 2.0 - 璺敱鍣� * [Condition router](https://github.com/apache/dubbo-go/pull/294) + * [Health check router](https://github.com/apache/dubbo-go/pull/389) - 娉ㄥ唽涓績 * ZooKeeper @@ -89,13 +92,22 @@ Apache License, Version 2.0 * [AccessLogFilter](https://github.com/apache/dubbo-go/pull/214) * [TpsLimitFilter](https://github.com/apache/dubbo-go/pull/237) * [ExecuteLimitFilter](https://github.com/apache/dubbo-go/pull/246) + * [Auth/Sign](https://github.com/apache/dubbo-go/pull/323) + * [Metrics filter](https://github.com/apache/dubbo-go/pull/342) + * [Tracing filter](https://github.com/apache/dubbo-go/pull/335) - 璋冪敤 * [娉涘寲璋冪敤](https://github.com/apache/dubbo-go/pull/122) - 鐩戞帶 * Opentracing API - * Prometheus + * [Prometheus](https://github.com/apache/dubbo-go/pull/342) + +- Tracing + * [For jsonrpc](https://github.com/apache/dubbo-go/pull/335) + * [For dubbo](https://github.com/apache/dubbo-go/pull/344) + * [For grpc](https://github.com/apache/dubbo-go/pull/397) + - 鍏朵粬鍔熻兘鏀寔: * 鍚姩鏃舵鏌� diff --git a/before_validate_license.sh b/before_validate_license.sh new file mode 100644 index 0000000000000000000000000000000000000000..8fa6e381c7a4cd44835d107ba9213f685f899a10 --- /dev/null +++ b/before_validate_license.sh @@ -0,0 +1,26 @@ +# +# 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. + +remoteLicenseCheckerPath="https://github.com/dubbogo/resources/raw/master/tools/license" +remoteLicenseCheckerName="license-header-checker" +remoteLicenseCheckerURL="${remoteLicenseCheckerPath}/${remoteLicenseCheckerName}" +remoteLicenseName="license.txt" +remoteLicenseURL="${remoteLicenseCheckerPath}/${remoteLicenseName}" + +licensePath="/tmp/tools/license" +mkdir -p ${licensePath} +wget -P "${licensePath}" ${remoteLicenseCheckerURL} +wget -P "${licensePath}" ${remoteLicenseURL} diff --git a/cluster/cluster_impl/available_cluster.go b/cluster/cluster_impl/available_cluster.go index 2ad140b93e15b97d1517119b07b1080a68a0503f..e041d91edb969c8a9b6f0309d1146f1ea874b42a 100644 --- a/cluster/cluster_impl/available_cluster.go +++ b/cluster/cluster_impl/available_cluster.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/available_cluster_invoker.go b/cluster/cluster_impl/available_cluster_invoker.go index 6f6d2dffbbbf2f6c758097b11713ae0c1b6bd387..e69f8b9f471d2aa6241b34bd01990d5d003feb3e 100644 --- a/cluster/cluster_impl/available_cluster_invoker.go +++ b/cluster/cluster_impl/available_cluster_invoker.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/available_cluster_invoker_test.go b/cluster/cluster_impl/available_cluster_invoker_test.go index dc0666d5afa633c86fdfaa48b93a334c19bb0248..c2cebd3843d453a2d46d031e711e0efebd240fda 100644 --- a/cluster/cluster_impl/available_cluster_invoker_test.go +++ b/cluster/cluster_impl/available_cluster_invoker_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/broadcast_cluster.go b/cluster/cluster_impl/broadcast_cluster.go index 9b27a4ce37bc73e42b55e4e20deb9593fd837444..a1692e96c5b68bc01adeab6600e99dff16a1bea1 100644 --- a/cluster/cluster_impl/broadcast_cluster.go +++ b/cluster/cluster_impl/broadcast_cluster.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/broadcast_cluster_invoker.go b/cluster/cluster_impl/broadcast_cluster_invoker.go index 1b49e9a115252d4eca94bedd557ebcc21fee4cc7..3a97d3d9b499c011ac90cb88b6692565388411a7 100644 --- a/cluster/cluster_impl/broadcast_cluster_invoker.go +++ b/cluster/cluster_impl/broadcast_cluster_invoker.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/broadcast_cluster_invoker_test.go b/cluster/cluster_impl/broadcast_cluster_invoker_test.go index 1de5270265a79b4d1d62317730bd06927d939acd..9b5733e98b142759c3317f9cb3e3d3f08eea81e4 100644 --- a/cluster/cluster_impl/broadcast_cluster_invoker_test.go +++ b/cluster/cluster_impl/broadcast_cluster_invoker_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/failback_cluster_test.go b/cluster/cluster_impl/failback_cluster_test.go index 4571fccec59a2f995009f57c35b56ec5e1cb3ea6..69418bc3b876f7c9375a2164d78bac2fcbb05043 100644 --- a/cluster/cluster_impl/failback_cluster_test.go +++ b/cluster/cluster_impl/failback_cluster_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/failfast_cluster.go b/cluster/cluster_impl/failfast_cluster.go index e0b80ded041cd30b379857ff00d307811e53765d..1e85485f7144f27a1994b18ba9419d9537d93ca1 100644 --- a/cluster/cluster_impl/failfast_cluster.go +++ b/cluster/cluster_impl/failfast_cluster.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/failfast_cluster_invoker.go b/cluster/cluster_impl/failfast_cluster_invoker.go index 49e7c7689f5a19a36154e092a6a83cc39da604ba..3b4dc9b721720948cf635f57191d1e6bce023a1e 100644 --- a/cluster/cluster_impl/failfast_cluster_invoker.go +++ b/cluster/cluster_impl/failfast_cluster_invoker.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/failfast_cluster_test.go b/cluster/cluster_impl/failfast_cluster_test.go index 38e258199e05c396e22118337bbdb3ae2b955bd0..c5ab7cd5410ea312e082f8064c13b2356c9b4bb4 100644 --- a/cluster/cluster_impl/failfast_cluster_test.go +++ b/cluster/cluster_impl/failfast_cluster_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/failsafe_cluster_test.go b/cluster/cluster_impl/failsafe_cluster_test.go index 2e35de8da91cc78730b6380bf039f0626ca75ec0..0bfeb576bd095508ef122c55c1345208c50eb339 100644 --- a/cluster/cluster_impl/failsafe_cluster_test.go +++ b/cluster/cluster_impl/failsafe_cluster_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/forking_cluster.go b/cluster/cluster_impl/forking_cluster.go index 6b0572b15088e86870b3d9fd911a1d0b022378be..a6f7a7b45475f8a26b9b2027a8b4a2fa4f95d509 100644 --- a/cluster/cluster_impl/forking_cluster.go +++ b/cluster/cluster_impl/forking_cluster.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/forking_cluster_invoker.go b/cluster/cluster_impl/forking_cluster_invoker.go index 058d7fefd6edf6c43e5eda4b8f2f6a9c161189e2..732569416daea8f878569db143271139b791ceca 100644 --- a/cluster/cluster_impl/forking_cluster_invoker.go +++ b/cluster/cluster_impl/forking_cluster_invoker.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/cluster_impl/forking_cluster_test.go b/cluster/cluster_impl/forking_cluster_test.go index 9797ecbd041ae2e09c3d0566f88d08b7246b900f..526b137d71c46c166367ac3b3308f9ad5b941538 100644 --- a/cluster/cluster_impl/forking_cluster_test.go +++ b/cluster/cluster_impl/forking_cluster_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 cluster_impl diff --git a/cluster/router/condition/app_router_test.go b/cluster/router/condition/app_router_test.go index bd817af36c8c144295479fb07ada9411f4115bbc..e99307625baf34fa6b744f168ff4e6cb8e042502 100644 --- a/cluster/router/condition/app_router_test.go +++ b/cluster/router/condition/app_router_test.go @@ -113,7 +113,7 @@ conditions: assert.Nil(t, err) assert.NotNil(t, appRouter) - rule, err := Parse(testYML) + rule, err := getRule(testYML) assert.Nil(t, err) appRouter.generateConditions(rule) diff --git a/cluster/router/condition/file.go b/cluster/router/condition/file.go index efeec53efc840d93c4b6906adfd19820a57b36fd..b2c876690043d18a1a9e746fee13f06c77a0de03 100644 --- a/cluster/router/condition/file.go +++ b/cluster/router/condition/file.go @@ -44,7 +44,7 @@ type FileConditionRouter struct { // NewFileConditionRouter Create file condition router instance with content ( from config file) func NewFileConditionRouter(content []byte) (*FileConditionRouter, error) { fileRouter := &FileConditionRouter{} - rule, err := Parse(string(content)) + rule, err := getRule(string(content)) if err != nil { return nil, perrors.Errorf("yaml.Unmarshal() failed , error:%v", perrors.WithStack(err)) } diff --git a/cluster/router/condition/listenable_router.go b/cluster/router/condition/listenable_router.go index ba2fbb0eb2f482dfde215c1b078ecad60e66bc14..4ccc19e95521d03ae1f663ec276646cf30926533 100644 --- a/cluster/router/condition/listenable_router.go +++ b/cluster/router/condition/listenable_router.go @@ -102,7 +102,7 @@ func (l *listenableRouter) Process(event *config_center.ConfigChangeEvent) { return } - routerRule, err := Parse(content) + routerRule, err := getRule(content) if err != nil { logger.Errorf("Parse condition router rule fail,error:[%s] ", err) return diff --git a/cluster/router/condition/router.go b/cluster/router/condition/router.go index c5d46444bde921386d14a8be7eb0a89d855f8ece..0267a3c7a462acb43f84ccb4701247147699804a 100644 --- a/cluster/router/condition/router.go +++ b/cluster/router/condition/router.go @@ -27,7 +27,6 @@ import ( ) import ( - matcher "github.com/apache/dubbo-go/cluster/router/match" "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/logger" @@ -301,7 +300,7 @@ func (pair MatchPair) isMatch(value string, param *common.URL) bool { if !pair.Matches.Empty() && pair.Mismatches.Empty() { for match := range pair.Matches.Items { - if matcher.IsMatchGlobalPattern(match.(string), value, param) { + if isMatchGlobalPattern(match.(string), value, param) { return true } } @@ -310,7 +309,7 @@ func (pair MatchPair) isMatch(value string, param *common.URL) bool { if !pair.Mismatches.Empty() && pair.Matches.Empty() { for mismatch := range pair.Mismatches.Items { - if matcher.IsMatchGlobalPattern(mismatch.(string), value, param) { + if isMatchGlobalPattern(mismatch.(string), value, param) { return false } } @@ -319,12 +318,12 @@ func (pair MatchPair) isMatch(value string, param *common.URL) bool { if !pair.Mismatches.Empty() && !pair.Matches.Empty() { //when both mismatches and matches contain the same value, then using mismatches first for mismatch := range pair.Mismatches.Items { - if matcher.IsMatchGlobalPattern(mismatch.(string), value, param) { + if isMatchGlobalPattern(mismatch.(string), value, param) { return false } } for match := range pair.Matches.Items { - if matcher.IsMatchGlobalPattern(match.(string), value, param) { + if isMatchGlobalPattern(match.(string), value, param) { return true } } diff --git a/cluster/router/condition/router_rule.go b/cluster/router/condition/router_rule.go index 1374cf9de2585f78a27e3de99f356c6900268927..ce397d6cc0f51519123dd427709e8dba42d72a20 100644 --- a/cluster/router/condition/router_rule.go +++ b/cluster/router/condition/router_rule.go @@ -18,11 +18,17 @@ package condition import ( - "gopkg.in/yaml.v2" + "strings" +) + +import ( + gxstrings "github.com/dubbogo/gost/strings" ) import ( "github.com/apache/dubbo-go/cluster/router" + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/yaml" ) // RouterRule RouterRule config read from config file or config center @@ -44,9 +50,9 @@ type RouterRule struct { * => * 1.1.1.1 */ -func Parse(rawRule string) (*RouterRule, error) { +func getRule(rawRule string) (*RouterRule, error) { r := &RouterRule{} - err := yaml.Unmarshal([]byte(rawRule), r) + err := yaml.UnmarshalYML([]byte(rawRule), r) if err != nil { return r, err } @@ -57,3 +63,11 @@ func Parse(rawRule string) (*RouterRule, error) { return r, nil } + +// isMatchGlobalPattern Match value to param content by pattern +func isMatchGlobalPattern(pattern string, value string, param *common.URL) bool { + if param != nil && strings.HasPrefix(pattern, "$") { + pattern = param.GetRawParam(pattern[1:]) + } + return gxstrings.IsMatchPattern(pattern, value) +} diff --git a/cluster/router/condition/router_rule_test.go b/cluster/router/condition/router_rule_test.go index 5acc7283917a7aa662b60cd90daba89d312db0cd..675acaec912b413d8fa3d1a25463b1fd4813a7f5 100644 --- a/cluster/router/condition/router_rule_test.go +++ b/cluster/router/condition/router_rule_test.go @@ -20,11 +20,16 @@ package condition import ( "testing" ) + import ( "github.com/stretchr/testify/assert" ) -func TestParse(t *testing.T) { +import ( + "github.com/apache/dubbo-go/common" +) + +func TestGetRule(t *testing.T) { testyml := ` scope: application runtime: true @@ -36,7 +41,7 @@ conditions: ip=127.0.0.1 => 1.1.1.1` - rule, e := Parse(testyml) + rule, e := getRule(testyml) assert.Nil(t, e) assert.NotNil(t, rule) @@ -50,3 +55,8 @@ conditions: assert.Equal(t, false, rule.Dynamic) assert.Equal(t, "", rule.Key) } + +func TestIsMatchGlobPattern(t *testing.T) { + url, _ := common.NewURL("dubbo://localhost:8080/Foo?key=v*e") + assert.Equal(t, true, isMatchGlobalPattern("$key", "value", &url)) +} diff --git a/cluster/router/match/match_utils.go b/cluster/router/match/match_utils.go deleted file mode 100644 index 28fe7151c5126c41fbadf9f4d54da2b9df74a7fe..0000000000000000000000000000000000000000 --- a/cluster/router/match/match_utils.go +++ /dev/null @@ -1,63 +0,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 match - -import ( - "strings" -) - -import ( - "github.com/apache/dubbo-go/common" -) - -// IsMatchGlobalPattern Match value to param content by pattern -func IsMatchGlobalPattern(pattern string, value string, param *common.URL) bool { - if param != nil && strings.HasPrefix(pattern, "$") { - pattern = param.GetRawParam(pattern[1:]) - } - return isMatchInternalPattern(pattern, value) -} - -func isMatchInternalPattern(pattern string, value string) bool { - if "*" == pattern { - return true - } - if len(pattern) == 0 && len(value) == 0 { - return true - } - if len(pattern) == 0 || len(value) == 0 { - return false - } - i := strings.LastIndex(pattern, "*") - switch i { - case -1: - // doesn't find "*" - return value == pattern - case len(pattern) - 1: - // "*" is at the end - return strings.HasPrefix(value, pattern[0:i]) - case 0: - // "*" is at the beginning - return strings.HasSuffix(value, pattern[i+1:]) - default: - // "*" is in the middle - prefix := pattern[0:1] - suffix := pattern[i+1:] - return strings.HasPrefix(value, prefix) && strings.HasSuffix(value, suffix) - } -} diff --git a/cluster/router/router.go b/cluster/router/router.go index a28002a09e3b7217549b896d452f70997504ac8f..9ee1154437e6fd205f08098deabb1ca260c3c040 100644 --- a/cluster/router/router.go +++ b/cluster/router/router.go @@ -31,7 +31,7 @@ type RouterFactory interface { } // RouterFactory Router create factory use for parse config file -type FIleRouterFactory interface { +type FileRouterFactory interface { // NewFileRouters Create file router with config file NewFileRouter([]byte) (Router, error) } diff --git a/cluster/router/tag/factory.go b/cluster/router/tag/factory.go new file mode 100644 index 0000000000000000000000000000000000000000..d74924c89862ae4f4cd85b59c7008880298c0c99 --- /dev/null +++ b/cluster/router/tag/factory.go @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tag + +import ( + "github.com/apache/dubbo-go/cluster/router" + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/common/extension" +) + +func init() { + extension.SetRouterFactory(constant.TagRouterName, NewTagRouterFactory) +} + +type tagRouterFactory struct{} + +// NewTagRouterFactory create a tagRouterFactory +func NewTagRouterFactory() router.RouterFactory { + return &tagRouterFactory{} +} + +// NewRouter create a tagRouter by tagRouterFactory with a url +// The url contains router configuration information +func (c *tagRouterFactory) NewRouter(url *common.URL) (router.Router, error) { + return NewTagRouter(url) +} + +// NewFileRouter create a tagRouter by profile content +func (c *tagRouterFactory) NewFileRouter(content []byte) (router.Router, error) { + return NewFileTagRouter(content) +} diff --git a/cluster/router/match/match_utils_test.go b/cluster/router/tag/factory_test.go similarity index 55% rename from cluster/router/match/match_utils_test.go rename to cluster/router/tag/factory_test.go index f16480f1d3b7dd5ca820c81d5d04d837c129687f..58bff5b18113d69f97ec513e393aa6759a3cf050 100644 --- a/cluster/router/match/match_utils_test.go +++ b/cluster/router/tag/factory_test.go @@ -15,7 +15,7 @@ * limitations under the License. */ -package match +package tag import ( "testing" @@ -29,18 +29,11 @@ import ( "github.com/apache/dubbo-go/common" ) -func TestIsMatchInternalPattern(t *testing.T) { - assert.Equal(t, true, isMatchInternalPattern("*", "value")) - assert.Equal(t, true, isMatchInternalPattern("", "")) - assert.Equal(t, false, isMatchInternalPattern("", "value")) - assert.Equal(t, true, isMatchInternalPattern("value", "value")) - assert.Equal(t, true, isMatchInternalPattern("v*", "value")) - assert.Equal(t, true, isMatchInternalPattern("*ue", "value")) - assert.Equal(t, true, isMatchInternalPattern("*e", "value")) - assert.Equal(t, true, isMatchInternalPattern("v*e", "value")) -} - -func TestIsMatchGlobPattern(t *testing.T) { - url, _ := common.NewURL("dubbo://localhost:8080/Foo?key=v*e") - assert.Equal(t, true, IsMatchGlobalPattern("$key", "value", &url)) +func TestTagRouterFactory_NewRouter(t *testing.T) { + u1, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true") + assert.Nil(t, err) + factory := NewTagRouterFactory() + tagRouter, e := factory.NewRouter(&u1) + assert.Nil(t, e) + assert.NotNil(t, tagRouter) } diff --git a/cluster/router/tag/file.go b/cluster/router/tag/file.go new file mode 100644 index 0000000000000000000000000000000000000000..8144c83203dbe98778dd6bb8dcdb9888be664b3b --- /dev/null +++ b/cluster/router/tag/file.go @@ -0,0 +1,82 @@ +/* + * 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 tag + +import ( + "net/url" + "strconv" + "sync" +) + +import ( + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol" +) + +// FileTagRouter Use for parse config file of Tag router +type FileTagRouter struct { + parseOnce sync.Once + router *tagRouter + routerRule *RouterRule + url *common.URL + force bool +} + +// NewFileTagRouter Create file tag router instance with content ( from config file) +func NewFileTagRouter(content []byte) (*FileTagRouter, error) { + fileRouter := &FileTagRouter{} + rule, err := getRule(string(content)) + if err != nil { + return nil, perrors.Errorf("yaml.Unmarshal() failed , error:%v", perrors.WithStack(err)) + } + fileRouter.routerRule = rule + url := fileRouter.URL() + fileRouter.router, err = NewTagRouter(&url) + return fileRouter, err +} + +// URL Return URL in file tag router n +func (f *FileTagRouter) URL() common.URL { + f.parseOnce.Do(func() { + routerRule := f.routerRule + f.url = common.NewURLWithOptions( + common.WithProtocol(constant.TAG_ROUTE_PROTOCOL), + common.WithParams(url.Values{}), + common.WithParamsValue(constant.ForceUseTag, strconv.FormatBool(routerRule.Force)), + common.WithParamsValue(constant.RouterPriority, strconv.Itoa(routerRule.Priority)), + common.WithParamsValue(constant.ROUTER_KEY, constant.TAG_ROUTE_PROTOCOL)) + }) + return *f.url +} + +// Priority Return Priority in listenable router +func (f *FileTagRouter) Priority() int64 { + return f.router.priority +} + +func (f *FileTagRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { + if len(invokers) == 0 { + return invokers + } + return f.Route(invokers, url, invocation) +} diff --git a/cluster/router/tag/file_test.go b/cluster/router/tag/file_test.go new file mode 100644 index 0000000000000000000000000000000000000000..94fcf9e0e0fabed2445417d14b711f91b65b9e5e --- /dev/null +++ b/cluster/router/tag/file_test.go @@ -0,0 +1,62 @@ +/* + * 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 tag + +import ( + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common/constant" +) + +func TestNewFileTagRouter(t *testing.T) { + router, e := NewFileTagRouter([]byte(`priority: 100 +force: true`)) + assert.Nil(t, e) + assert.NotNil(t, router) + assert.Equal(t, 100, router.routerRule.Priority) + assert.Equal(t, true, router.routerRule.Force) +} + +func TestFileTagRouter_URL(t *testing.T) { + router, e := NewFileTagRouter([]byte(`priority: 100 +force: true`)) + assert.Nil(t, e) + assert.NotNil(t, router) + url := router.URL() + assert.NotNil(t, url) + force := url.GetParam(constant.ForceUseTag, "false") + priority := url.GetParam(constant.RouterPriority, "0") + assert.Equal(t, "true", force) + assert.Equal(t, "100", priority) + +} + +func TestFileTagRouter_Priority(t *testing.T) { + router, e := NewFileTagRouter([]byte(`priority: 100 +force: true`)) + assert.Nil(t, e) + assert.NotNil(t, router) + priority := router.Priority() + assert.Equal(t, int64(100), priority) +} diff --git a/cluster/router/tag/router_rule.go b/cluster/router/tag/router_rule.go new file mode 100644 index 0000000000000000000000000000000000000000..926446dcb2f18fa2fd4639a9246a85f435d75d45 --- /dev/null +++ b/cluster/router/tag/router_rule.go @@ -0,0 +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. + */ + +package tag + +import ( + "github.com/apache/dubbo-go/cluster/router" + "github.com/apache/dubbo-go/common/yaml" +) + +// RouterRule RouterRule config read from config file or config center +type RouterRule struct { + router.BaseRouterRule `yaml:",inline""` +} + +func getRule(rawRule string) (*RouterRule, error) { + r := &RouterRule{} + err := yaml.UnmarshalYML([]byte(rawRule), r) + if err != nil { + return r, err + } + r.RawRule = rawRule + return r, nil +} diff --git a/cluster/router/tag/router_rule_test.go b/cluster/router/tag/router_rule_test.go new file mode 100644 index 0000000000000000000000000000000000000000..2df65193f9d0cf607258f3080e22b42cd6e9b16a --- /dev/null +++ b/cluster/router/tag/router_rule_test.go @@ -0,0 +1,40 @@ +/* + * 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 tag + +import ( + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestGetRule(t *testing.T) { + yml := ` +scope: application +runtime: true +force: true +` + rule, e := getRule(yml) + assert.Nil(t, e) + assert.NotNil(t, rule) + assert.Equal(t, true, rule.Force) + assert.Equal(t, true, rule.Runtime) + assert.Equal(t, "application", rule.Scope) +} diff --git a/cluster/router/tag/tag_router.go b/cluster/router/tag/tag_router.go new file mode 100644 index 0000000000000000000000000000000000000000..87da418943e90c63a905f35260ada7880d6f51b9 --- /dev/null +++ b/cluster/router/tag/tag_router.go @@ -0,0 +1,94 @@ +/* + * 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 tag + +import ( + "strconv" +) + +import ( + perrors "github.com/pkg/errors" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/protocol" +) + +type tagRouter struct { + url *common.URL + enabled bool + priority int64 +} + +func NewTagRouter(url *common.URL) (*tagRouter, error) { + if url == nil { + return nil, perrors.Errorf("Illegal route URL!") + } + return &tagRouter{ + url: url, + enabled: url.GetParamBool(constant.RouterEnabled, true), + priority: url.GetParamInt(constant.RouterPriority, 0), + }, nil +} + +func (c *tagRouter) isEnabled() bool { + return c.enabled +} + +func (c *tagRouter) Route(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { + if !c.isEnabled() { + return invokers + } + if len(invokers) == 0 { + return invokers + } + return filterUsingStaticTag(invokers, url, invocation) +} + +func (c *tagRouter) URL() common.URL { + return *c.url +} + +func (c *tagRouter) Priority() int64 { + return c.priority +} + +func filterUsingStaticTag(invokers []protocol.Invoker, url *common.URL, invocation protocol.Invocation) []protocol.Invoker { + if tag, ok := invocation.Attachments()[constant.Tagkey]; ok { + result := make([]protocol.Invoker, 0, 8) + for _, v := range invokers { + if v.GetUrl().GetParam(constant.Tagkey, "") == tag { + result = append(result, v) + } + } + if len(result) == 0 && !isForceUseTag(url, invocation) { + return invokers + } + return result + } + return invokers +} + +func isForceUseTag(url *common.URL, invocation protocol.Invocation) bool { + if b, e := strconv.ParseBool(invocation.AttachmentsByKey(constant.ForceUseTag, url.GetParam(constant.ForceUseTag, "false"))); e == nil { + return b + } + return false +} diff --git a/cluster/router/tag/tag_router_test.go b/cluster/router/tag/tag_router_test.go new file mode 100644 index 0000000000000000000000000000000000000000..280b56c8ccb69eb5d32dae2369bdc862adb8e6fd --- /dev/null +++ b/cluster/router/tag/tag_router_test.go @@ -0,0 +1,147 @@ +/* + * 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 tag + +import ( + "context" + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/protocol" + "github.com/apache/dubbo-go/protocol/invocation" +) + +// MockInvoker is only mock the Invoker to support test tagRouter +type MockInvoker struct { + url common.URL + available bool + destroyed bool + successCount int +} + +func NewMockInvoker(url common.URL) *MockInvoker { + return &MockInvoker{ + url: url, + available: true, + destroyed: false, + successCount: 0, + } +} + +func (bi *MockInvoker) GetUrl() common.URL { + return bi.url +} + +func (bi *MockInvoker) IsAvailable() bool { + return bi.available +} + +func (bi *MockInvoker) IsDestroyed() bool { + return bi.destroyed +} + +func (bi *MockInvoker) Invoke(_ context.Context, _ protocol.Invocation) protocol.Result { + bi.successCount++ + + result := &protocol.RPCResult{Err: nil} + return result +} + +func (bi *MockInvoker) Destroy() { + bi.destroyed = true + bi.available = false +} + +func TestTagRouter_Priority(t *testing.T) { + u1, err := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true&dubbo.force.tag=true") + assert.Nil(t, err) + tagRouter, e := NewTagRouter(&u1) + assert.Nil(t, e) + p := tagRouter.Priority() + assert.Equal(t, int64(0), p) +} + +func TestTagRouter_Route_force(t *testing.T) { + u1, e1 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true&dubbo.force.tag=true") + assert.Nil(t, e1) + tagRouter, e := NewTagRouter(&u1) + assert.Nil(t, e) + + u2, e2 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=hangzhou") + u3, e3 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=shanghai") + u4, e4 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=beijing") + assert.Nil(t, e2) + assert.Nil(t, e3) + assert.Nil(t, e4) + inv2 := NewMockInvoker(u2) + inv3 := NewMockInvoker(u3) + inv4 := NewMockInvoker(u4) + var invokers []protocol.Invoker + invokers = append(invokers, inv2, inv3, inv4) + inv := &invocation.RPCInvocation{} + inv.SetAttachments("dubbo.tag", "hangzhou") + invRst1 := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 1, len(invRst1)) + assert.Equal(t, "hangzhou", invRst1[0].GetUrl().GetParam("dubbo.tag", "")) + + inv.SetAttachments("dubbo.tag", "guangzhou") + invRst2 := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 0, len(invRst2)) + inv.SetAttachments("dubbo.force.tag", "false") + inv.SetAttachments("dubbo.tag", "guangzhou") + invRst3 := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 3, len(invRst3)) +} + +func TestTagRouter_Route_noForce(t *testing.T) { + u1, e1 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserConsumer?interface=com.ikurento.user.UserConsumer&group=&version=2.6.0&enabled=true") + assert.Nil(t, e1) + tagRouter, e := NewTagRouter(&u1) + assert.Nil(t, e) + + u2, e2 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=hangzhou") + u3, e3 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=shanghai") + u4, e4 := common.NewURL("dubbo://127.0.0.1:20000/com.ikurento.user.UserProvider?interface=com.ikurento.user.UserProvider&group=&version=2.6.0&enabled=true&dubbo.tag=beijing") + assert.Nil(t, e2) + assert.Nil(t, e3) + assert.Nil(t, e4) + inv2 := NewMockInvoker(u2) + inv3 := NewMockInvoker(u3) + inv4 := NewMockInvoker(u4) + var invokers []protocol.Invoker + invokers = append(invokers, inv2, inv3, inv4) + inv := &invocation.RPCInvocation{} + inv.SetAttachments("dubbo.tag", "hangzhou") + invRst := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 1, len(invRst)) + assert.Equal(t, "hangzhou", invRst[0].GetUrl().GetParam("dubbo.tag", "")) + + inv.SetAttachments("dubbo.tag", "guangzhou") + inv.SetAttachments("dubbo.force.tag", "true") + invRst1 := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 0, len(invRst1)) + inv.SetAttachments("dubbo.force.tag", "false") + invRst2 := tagRouter.Route(invokers, &u1, inv) + assert.Equal(t, 3, len(invRst2)) +} diff --git a/common/constant/key.go b/common/constant/key.go index d353573e78e9bd9ab1e54b614b0523bfbee901d4..16986c7421345318d3477adca59de800b9d9c415 100644 --- a/common/constant/key.go +++ b/common/constant/key.go @@ -41,6 +41,9 @@ const ( LOCAL_ADDR = "local-addr" REMOTE_ADDR = "remote-addr" PATH_SEPARATOR = "/" + DUBBO_KEY = "dubbo" + RELEASE_KEY = "release" + ANYHOST_KEY = "anyhost" ) const ( @@ -105,6 +108,7 @@ const ( ROUTERS_CATEGORY = "routers" ROUTE_PROTOCOL = "route" CONDITION_ROUTE_PROTOCOL = "condition" + TAG_ROUTE_PROTOCOL = "tag" PROVIDERS_CATEGORY = "providers" ROUTER_KEY = "router" ) @@ -162,7 +166,8 @@ const ( ListenableRouterName = "listenable" // HealthCheckRouterName Specify the name of HealthCheckRouter HealthCheckRouterName = "health_check" - + // TagRouterName Specify the name of TagRouter + TagRouterName = "tag" // ConditionRouterRuleSuffix Specify condition router suffix ConditionRouterRuleSuffix = ".condition-router" @@ -172,6 +177,10 @@ const ( RouterEnabled = "enabled" // Priority Priority key in router module RouterPriority = "priority" + + // ForceUseTag is the tag in attachment + ForceUseTag = "dubbo.force.tag" + Tagkey = "dubbo.tag" ) const ( diff --git a/common/extension/auth.go b/common/extension/auth.go index a35fc509dae5b77a4e80fdd04171f90f337c668b..d7900045d3f7db9e2587e4e92e377325c74971b3 100644 --- a/common/extension/auth.go +++ b/common/extension/auth.go @@ -1,3 +1,20 @@ +/* + * 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 extension import ( diff --git a/common/extension/event_dispatcher.go b/common/extension/event_dispatcher.go new file mode 100644 index 0000000000000000000000000000000000000000..2d33528259e85f50a0784aceba37ecd87be61620 --- /dev/null +++ b/common/extension/event_dispatcher.go @@ -0,0 +1,62 @@ +/* + * 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 extension + +import ( + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/common/observer" +) + +var ( + globalEventDispatcher observer.EventDispatcher + initEventListeners []observer.EventListener +) + +var ( + dispatchers = make(map[string]func() observer.EventDispatcher, 8) +) + +// SetEventDispatcher by name +func SetEventDispatcher(name string, v func() observer.EventDispatcher) { + dispatchers[name] = v +} + +// SetAndInitGlobalDispatcher +func SetAndInitGlobalDispatcher(name string) { + if len(name) == 0 { + name = "direct" + } + if globalEventDispatcher != nil { + logger.Warnf("EventDispatcher already init. It will be replaced") + } + if dp, ok := dispatchers[name]; !ok || dp == nil { + panic("EventDispatcher for " + name + " is not existing, make sure you have import the package.") + } + globalEventDispatcher = dispatchers[name]() + globalEventDispatcher.AddEventListeners(initEventListeners) +} + +// GetGlobalDispatcher +func GetGlobalDispatcher() observer.EventDispatcher { + return globalEventDispatcher +} + +// AddEventListener it will be added in global event dispatcher +func AddEventListener(listener observer.EventListener) { + initEventListeners = append(initEventListeners, listener) +} diff --git a/common/extension/router_factory.go b/common/extension/router_factory.go index 70d71dfa859b996030c865775a588da20039f9a5..1339228618def41ccebc8d54cdebb5a623e605fa 100644 --- a/common/extension/router_factory.go +++ b/common/extension/router_factory.go @@ -28,7 +28,7 @@ import ( var ( routers = make(map[string]func() router.RouterFactory) fileRouterFactoryOnce sync.Once - fileRouterFactories = make(map[string]router.FIleRouterFactory) + fileRouterFactories = make(map[string]router.FileRouterFactory) ) // SetRouterFactory Set create router factory function by name @@ -50,7 +50,7 @@ func GetRouterFactories() map[string]func() router.RouterFactory { } // GetFileRouterFactories Get all create file router factory instance -func GetFileRouterFactories() map[string]router.FIleRouterFactory { +func GetFileRouterFactories() map[string]router.FileRouterFactory { l := len(routers) if l == 0 { return nil @@ -58,7 +58,7 @@ func GetFileRouterFactories() map[string]router.FIleRouterFactory { fileRouterFactoryOnce.Do(func() { for k := range routers { factory := GetRouterFactory(k) - if fr, ok := factory.(router.FIleRouterFactory); ok { + if fr, ok := factory.(router.FileRouterFactory); ok { fileRouterFactories[k] = fr } } diff --git a/common/observer/dispatcher/direct_event_dispatcher.go b/common/observer/dispatcher/direct_event_dispatcher.go new file mode 100644 index 0000000000000000000000000000000000000000..2b7567b47ed40caa8867901ff0a05e0a2497cd31 --- /dev/null +++ b/common/observer/dispatcher/direct_event_dispatcher.go @@ -0,0 +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 dispatcher + +import ( + "reflect" +) + +import ( + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/common/logger" + "github.com/apache/dubbo-go/common/observer" +) + +func init() { + extension.SetEventDispatcher("direct", NewDirectEventDispatcher) +} + +// DirectEventDispatcher is align with DirectEventDispatcher interface in Java. +// it's the top abstraction +// Align with 2.7.5 +// Dispatcher event to listener direct +type DirectEventDispatcher struct { + observer.BaseListenable +} + +// NewDirectEventDispatcher ac constructor of DirectEventDispatcher +func NewDirectEventDispatcher() observer.EventDispatcher { + return &DirectEventDispatcher{} +} + +// Dispatch event directly +func (ded *DirectEventDispatcher) Dispatch(event observer.Event) { + if event == nil { + logger.Warnf("[DirectEventDispatcher] dispatch event nil") + return + } + eventType := reflect.TypeOf(event).Elem() + value, loaded := ded.ListenersCache.Load(eventType) + if !loaded { + return + } + listenersSlice := value.([]observer.EventListener) + for _, listener := range listenersSlice { + if err := listener.OnEvent(event); err != nil { + logger.Warnf("[DirectEventDispatcher] dispatch event error:%v", err) + } + } +} diff --git a/common/observer/dispatcher/direct_event_dispatcher_test.go b/common/observer/dispatcher/direct_event_dispatcher_test.go new file mode 100644 index 0000000000000000000000000000000000000000..355c930a9e86dbe6e82adc2795f8590c15a473c2 --- /dev/null +++ b/common/observer/dispatcher/direct_event_dispatcher_test.go @@ -0,0 +1,75 @@ +/* + * 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 dispatcher + +import ( + "fmt" + "reflect" + "testing" +) + +import ( + "github.com/apache/dubbo-go/common/observer" +) + +func TestDirectEventDispatcher_Dispatch(t *testing.T) { + ded := NewDirectEventDispatcher() + ded.AddEventListener(&TestEventListener{}) + ded.AddEventListener(&TestEventListener1{}) + ded.Dispatch(&TestEvent{}) + ded.Dispatch(nil) +} + +type TestEvent struct { + observer.BaseEvent +} + +type TestEventListener struct { + observer.BaseListenable + observer.EventListener +} + +func (tel *TestEventListener) OnEvent(e observer.Event) error { + fmt.Println("TestEventListener") + return nil +} + +func (tel *TestEventListener) GetPriority() int { + return -1 +} + +func (tel *TestEventListener) GetEventType() reflect.Type { + return reflect.TypeOf(&TestEvent{}) +} + +type TestEventListener1 struct { + observer.EventListener +} + +func (tel *TestEventListener1) OnEvent(e observer.Event) error { + fmt.Println("TestEventListener1") + return nil +} + +func (tel *TestEventListener1) GetPriority() int { + return 1 +} + +func (tel *TestEventListener1) GetEventType() reflect.Type { + return reflect.TypeOf(TestEvent{}) +} diff --git a/common/observer/event.go b/common/observer/event.go new file mode 100644 index 0000000000000000000000000000000000000000..8c3362feeee3d62315eb734460f486dcdbfe2f36 --- /dev/null +++ b/common/observer/event.go @@ -0,0 +1,66 @@ +/* + * 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 observer + +import ( + "fmt" + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// Event is align with Event interface in Java. +// it's the top abstraction +// Align with 2.7.5 +type Event interface { + fmt.Stringer + GetSource() interface{} + GetTimestamp() time.Time +} + +// BaseEvent is the base implementation of Event +// You should never use it directly +type BaseEvent struct { + Source interface{} + Timestamp time.Time +} + +// GetSource return the source +func (b *BaseEvent) GetSource() interface{} { + return b.Source +} + +// GetTimestamp return the Timestamp when the event is created +func (b *BaseEvent) GetTimestamp() time.Time { + return b.Timestamp +} + +// String return a human readable string representing this event +func (b *BaseEvent) String() string { + return fmt.Sprintf("BaseEvent[source = %#v]", b.Source) +} + +func newBaseEvent(source interface{}) *BaseEvent { + return &BaseEvent{ + Source: source, + Timestamp: time.Now(), + } +} diff --git a/common/observer/event_dispatcher.go b/common/observer/event_dispatcher.go new file mode 100644 index 0000000000000000000000000000000000000000..17745e68c07065f954d456914fb276fadf6d975d --- /dev/null +++ b/common/observer/event_dispatcher.go @@ -0,0 +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 observer + +// EventDispatcher is align with EventDispatcher interface in Java. +// it's the top abstraction +// Align with 2.7.5 +type EventDispatcher interface { + Listenable + // Dispatch event + Dispatch(event Event) +} diff --git a/common/observer/event_listener.go b/common/observer/event_listener.go new file mode 100644 index 0000000000000000000000000000000000000000..8db60d8475da49262947329fc71fd8e364d8d0af --- /dev/null +++ b/common/observer/event_listener.go @@ -0,0 +1,48 @@ +/* + * 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 observer + +import ( + "reflect" +) + +import ( + gxsort "github.com/dubbogo/gost/sort" +) + +// EventListener is an new interface used to align with dubbo 2.7.5 +// It contains the Prioritized means that the listener has its priority +type EventListener interface { + gxsort.Prioritizer + // OnEvent handle this event + OnEvent(e Event) error + // GetEventType listen which event type + GetEventType() reflect.Type +} + +// ConditionalEventListener only handle the event which it can handle +type ConditionalEventListener interface { + EventListener + // Accept will make the decision whether it should handle this event + Accept(e Event) bool +} + +// TODO (implement ConditionalEventListener) +type ServiceInstancesChangedListener struct { + ServiceName string +} diff --git a/common/observer/listenable.go b/common/observer/listenable.go new file mode 100644 index 0000000000000000000000000000000000000000..7b64aa8f2d263793c7aa4dc5e294466c48cd7b36 --- /dev/null +++ b/common/observer/listenable.go @@ -0,0 +1,133 @@ +/* + * 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 observer + +import ( + "reflect" + "sort" + "sync" +) + +// Listenable could add and remove the event listener +type Listenable interface { + AddEventListener(listener EventListener) + AddEventListeners(listenersSlice []EventListener) + RemoveEventListener(listener EventListener) + RemoveEventListeners(listenersSlice []EventListener) + GetAllEventListeners() []EventListener + RemoveAllEventListeners() +} + +// BaseListenable base listenable +type BaseListenable struct { + Listenable + ListenersCache sync.Map + Mutex sync.Mutex +} + +// NewBaseListenable a constructor of base listenable +func NewBaseListenable() Listenable { + return &BaseListenable{} +} + +// AddEventListener add event listener +func (bl *BaseListenable) AddEventListener(listener EventListener) { + eventType := listener.GetEventType() + if eventType.Kind() == reflect.Ptr { + eventType = eventType.Elem() + } + bl.Mutex.Lock() + defer bl.Mutex.Unlock() + value, loaded := bl.ListenersCache.LoadOrStore(eventType, make([]EventListener, 0, 8)) + listenersSlice := value.([]EventListener) + // return if listenersSlice already has this listener + if loaded && containListener(listenersSlice, listener) { + return + } + listenersSlice = append(listenersSlice, listener) + sort.Slice(listenersSlice, func(i, j int) bool { + return listenersSlice[i].GetPriority() < listenersSlice[j].GetPriority() + }) + bl.ListenersCache.Store(eventType, listenersSlice) +} + +// AddEventListeners add the slice of event listener +func (bl *BaseListenable) AddEventListeners(listenersSlice []EventListener) { + for _, listener := range listenersSlice { + bl.AddEventListener(listener) + } +} + +// RemoveEventListener remove the event listener +func (bl *BaseListenable) RemoveEventListener(listener EventListener) { + eventType := listener.GetEventType() + if eventType.Kind() == reflect.Ptr { + eventType = eventType.Elem() + } + bl.Mutex.Lock() + defer bl.Mutex.Unlock() + value, loaded := bl.ListenersCache.Load(eventType) + if !loaded { + return + } + listenersSlice := value.([]EventListener) + for i, l := range listenersSlice { + if l == listener { + listenersSlice = append(listenersSlice[:i], listenersSlice[i+1:]...) + } + } + bl.ListenersCache.Store(eventType, listenersSlice) +} + +// RemoveEventListeners remove the slice of event listener +func (bl *BaseListenable) RemoveEventListeners(listenersSlice []EventListener) { + for _, listener := range listenersSlice { + bl.RemoveEventListener(listener) + } +} + +// RemoveAllEventListeners remove all +func (bl *BaseListenable) RemoveAllEventListeners() { + bl.Mutex.Lock() + defer bl.Mutex.Unlock() + bl.ListenersCache = sync.Map{} +} + +// GetAllEventListeners get all +func (bl *BaseListenable) GetAllEventListeners() []EventListener { + allListenersSlice := make([]EventListener, 0, 16) + bl.ListenersCache.Range(func(_, value interface{}) bool { + listenersSlice := value.([]EventListener) + allListenersSlice = append(allListenersSlice, listenersSlice...) + return true + }) + sort.Slice(allListenersSlice, func(i, j int) bool { + return allListenersSlice[i].GetPriority() < allListenersSlice[j].GetPriority() + }) + return allListenersSlice +} + +// containListener true if contain listener +func containListener(listenersSlice []EventListener, listener EventListener) bool { + for _, loadListener := range listenersSlice { + if loadListener == listener { + return true + } + } + return false +} diff --git a/common/observer/listenable_test.go b/common/observer/listenable_test.go new file mode 100644 index 0000000000000000000000000000000000000000..df46bfc2ba47f6e447074b44208a809949f7ae3d --- /dev/null +++ b/common/observer/listenable_test.go @@ -0,0 +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 observer + +import ( + "reflect" + "testing" +) + +import ( + "github.com/stretchr/testify/assert" +) + +func TestListenable(t *testing.T) { + el := &TestEventListener{} + b := &BaseListenable{} + b.AddEventListener(el) + b.AddEventListener(el) + al := b.GetAllEventListeners() + assert.Equal(t, len(al), 1) + assert.Equal(t, al[0].GetEventType(), reflect.TypeOf(TestEvent{})) + b.RemoveEventListener(el) + assert.Equal(t, len(b.GetAllEventListeners()), 0) + var ts []EventListener + ts = append(ts, el) + b.AddEventListeners(ts) + assert.Equal(t, len(al), 1) + +} + +type TestEvent struct { + BaseEvent +} + +type TestEventListener struct { + EventListener +} + +func (tel *TestEventListener) OnEvent(e Event) error { + return nil +} + +func (tel *TestEventListener) GetPriority() int { + return -1 +} + +func (tel *TestEventListener) GetEventType() reflect.Type { + return reflect.TypeOf(TestEvent{}) +} diff --git a/common/rpc_service.go b/common/rpc_service.go index b235c32abc9a971d7144605c8b4b82953ac8f3c4..ebd1d02f843bc339c3a37d977e2138798307475d 100644 --- a/common/rpc_service.go +++ b/common/rpc_service.go @@ -71,7 +71,8 @@ var ( // ServiceMap ... // todo: lowerecas? ServiceMap = &serviceMap{ - serviceMap: make(map[string]map[string]*Service), + serviceMap: make(map[string]map[string]*Service), + interfaceMap: make(map[string][]*Service), } ) @@ -147,10 +148,12 @@ func (s *Service) Rcvr() reflect.Value { ////////////////////////// type serviceMap struct { - mutex sync.RWMutex // protects the serviceMap - serviceMap map[string]map[string]*Service // protocol -> service name -> service + mutex sync.RWMutex // protects the serviceMap + serviceMap map[string]map[string]*Service // protocol -> service name -> service + interfaceMap map[string][]*Service // interface -> service } +// GetService get a service defination by protocol and name func (sm *serviceMap) GetService(protocol, name string) *Service { sm.mutex.RLock() defer sm.mutex.RUnlock() @@ -163,10 +166,24 @@ func (sm *serviceMap) GetService(protocol, name string) *Service { return nil } -func (sm *serviceMap) Register(protocol string, rcvr RPCService) (string, error) { +// GetInterface get an interface defination by interface name +func (sm *serviceMap) GetInterface(interfaceName string) []*Service { + sm.mutex.RLock() + defer sm.mutex.RUnlock() + if s, ok := sm.interfaceMap[interfaceName]; ok { + return s + } + return nil +} + +// Register register a service by @interfaceName and @protocol +func (sm *serviceMap) Register(interfaceName, protocol string, rcvr RPCService) (string, error) { if sm.serviceMap[protocol] == nil { sm.serviceMap[protocol] = make(map[string]*Service) } + if sm.interfaceMap[interfaceName] == nil { + sm.interfaceMap[interfaceName] = make([]*Service, 0, 16) + } s := new(Service) s.rcvrType = reflect.TypeOf(rcvr) @@ -201,32 +218,65 @@ func (sm *serviceMap) Register(protocol string, rcvr RPCService) (string, error) } sm.mutex.Lock() sm.serviceMap[protocol][s.name] = s + sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], s) sm.mutex.Unlock() return strings.TrimSuffix(methods, ","), nil } -func (sm *serviceMap) UnRegister(protocol, serviceId string) error { +// UnRegister cancel a service by @interfaceName, @protocol and @serviceId +func (sm *serviceMap) UnRegister(interfaceName, protocol, serviceId string) error { if protocol == "" || serviceId == "" { return perrors.New("protocol or serviceName is nil") } - sm.mutex.RLock() - svcs, ok := sm.serviceMap[protocol] - if !ok { - sm.mutex.RUnlock() - return perrors.New("no services for " + protocol) + + var ( + err error + index = -1 + svcs map[string]*Service + svrs []*Service + ok bool + ) + + f := func() error { + sm.mutex.RLock() + defer sm.mutex.RUnlock() + svcs, ok = sm.serviceMap[protocol] + if !ok { + return perrors.New("no services for " + protocol) + } + s, ok := svcs[serviceId] + if !ok { + return perrors.New("no service for " + serviceId) + } + svrs, ok = sm.interfaceMap[interfaceName] + if !ok { + return perrors.New("no service for " + interfaceName) + } + for i, svr := range svrs { + if svr == s { + index = i + } + } + return nil } - _, ok = svcs[serviceId] - if !ok { - sm.mutex.RUnlock() - return perrors.New("no service for " + serviceId) + + if err = f(); err != nil { + return err } - sm.mutex.RUnlock() sm.mutex.Lock() defer sm.mutex.Unlock() + sm.interfaceMap[interfaceName] = make([]*Service, 0, len(svrs)) + for i, _ := range svrs { + if i != index { + sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], svrs[i]) + } + } delete(svcs, serviceId) - delete(sm.serviceMap, protocol) + if len(sm.serviceMap) == 0 { + delete(sm.serviceMap, protocol) + } return nil } diff --git a/common/rpc_service_test.go b/common/rpc_service_test.go index 8c9b9d15cdd4061dbe2f445b5fff7a868e5ae67e..2311205d0ec0c2fd4642a4d8639c0bf871fe1d17 100644 --- a/common/rpc_service_test.go +++ b/common/rpc_service_test.go @@ -77,46 +77,48 @@ func TestServiceMap_Register(t *testing.T) { // lowercase s0 := &testService{} // methods, err := ServiceMap.Register("testporotocol", s0) - _, err := ServiceMap.Register("testporotocol", s0) + _, err := ServiceMap.Register("testService", "testporotocol", s0) assert.EqualError(t, err, "type testService is not exported") // succ s := &TestService{} - methods, err := ServiceMap.Register("testporotocol", s) + methods, err := ServiceMap.Register("testService", "testporotocol", s) assert.NoError(t, err) assert.Equal(t, "MethodOne,MethodThree,methodTwo", methods) // repeat - _, err = ServiceMap.Register("testporotocol", s) + _, err = ServiceMap.Register("testService", "testporotocol", s) assert.EqualError(t, err, "service already defined: com.test.Path") // no method s1 := &TestService1{} - _, err = ServiceMap.Register("testporotocol", s1) + _, err = ServiceMap.Register("testService", "testporotocol", s1) assert.EqualError(t, err, "type com.test.Path1 has no exported methods of suitable type") ServiceMap = &serviceMap{ - serviceMap: make(map[string]map[string]*Service), + serviceMap: make(map[string]map[string]*Service), + interfaceMap: make(map[string][]*Service), } } func TestServiceMap_UnRegister(t *testing.T) { s := &TestService{} - _, err := ServiceMap.Register("testprotocol", s) + _, err := ServiceMap.Register("TestService", "testprotocol", s) assert.NoError(t, err) assert.NotNil(t, ServiceMap.GetService("testprotocol", "com.test.Path")) + assert.Equal(t, 1, len(ServiceMap.GetInterface("TestService"))) - err = ServiceMap.UnRegister("", "com.test.Path") + err = ServiceMap.UnRegister("", "", "com.test.Path") assert.EqualError(t, err, "protocol or serviceName is nil") - err = ServiceMap.UnRegister("protocol", "com.test.Path") + err = ServiceMap.UnRegister("", "protocol", "com.test.Path") assert.EqualError(t, err, "no services for protocol") - err = ServiceMap.UnRegister("testprotocol", "com.test.Path1") + err = ServiceMap.UnRegister("", "testprotocol", "com.test.Path1") assert.EqualError(t, err, "no service for com.test.Path1") // succ - err = ServiceMap.UnRegister("testprotocol", "com.test.Path") + err = ServiceMap.UnRegister("TestService", "testprotocol", "com.test.Path") assert.NoError(t, err) } diff --git a/common/yaml/yaml.go b/common/yaml/yaml.go index 7c31d71c35fff547d2ed0a765e8245717148a451..93ebb166144510236aff27a67422a6377ccb5c9f 100644 --- a/common/yaml/yaml.go +++ b/common/yaml/yaml.go @@ -48,3 +48,7 @@ func UnmarshalYMLConfig(confProFile string, out interface{}) ([]byte, error) { } return confFileStream, yaml.Unmarshal(confFileStream, out) } + +func UnmarshalYML(data []byte, out interface{}) error { + return yaml.Unmarshal(data, out) +} diff --git a/common/yaml/yaml_test.go b/common/yaml/yaml_test.go index 45eee59048c1c074b9c386e26cc7a2252896e6ea..c8b8258a68951a1437ac2e617c13ee5af4b3a5ee 100644 --- a/common/yaml/yaml_test.go +++ b/common/yaml/yaml_test.go @@ -46,6 +46,18 @@ func TestUnmarshalYMLConfig_Error(t *testing.T) { assert.Error(t, err) } +func TestUnmarshalYML(t *testing.T) { + c := &Config{} + b, err := LoadYMLConfig("./testdata/config.yml") + assert.NoError(t, err) + err = UnmarshalYML(b, c) + assert.NoError(t, err) + assert.Equal(t, "strTest", c.StrTest) + assert.Equal(t, 11, c.IntTest) + assert.Equal(t, false, c.BooleanTest) + assert.Equal(t, "childStrTest", c.ChildConfig.StrTest) +} + type Config struct { StrTest string `yaml:"strTest" default:"default" json:"strTest,omitempty" property:"strTest"` IntTest int `default:"109" yaml:"intTest" json:"intTest,omitempty" property:"intTest"` diff --git a/config/base_config.go b/config/base_config.go index 93c0ce6a6692193e7ea7b1b9f2f74e9eaed0c858..f58138d2e58a1b3da06894d3afa4728ea2ecf8fb 100644 --- a/config/base_config.go +++ b/config/base_config.go @@ -42,14 +42,13 @@ type multiConfiger interface { // BaseConfig is the common configuration for provider and consumer type BaseConfig struct { - ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` - configCenterUrl *common.URL - prefix string - fatherConfig interface{} - - MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"` - - fileStream *bytes.Buffer + ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` + configCenterUrl *common.URL + prefix string + fatherConfig interface{} + eventDispatcherType string `default:"direct" yaml:"event_dispatcher_type" json:"event_dispatcher_type,omitempty"` + MetricConfig *MetricConfig `yaml:"metrics" json:"metrics,omitempty"` + fileStream *bytes.Buffer } // startConfigCenter will start the config center. diff --git a/config/config_loader.go b/config/config_loader.go index c0687d8fc162331afc5098e347d4bbba6a1750c6..11107e83e1c6660c5265bdbe31851e2380dfdd00 100644 --- a/config/config_loader.go +++ b/config/config_loader.go @@ -33,6 +33,7 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" + _ "github.com/apache/dubbo-go/common/observer/dispatcher" ) var ( @@ -91,6 +92,17 @@ func Load() { } } + var eventDispatcherType string + if consumerConfig != nil { + eventDispatcherType = consumerConfig.eventDispatcherType + } + // notice consumerConfig.eventDispatcherType will be replaced + if providerConfig != nil { + eventDispatcherType = providerConfig.eventDispatcherType + } + // init EventDispatcher should before everything + extension.SetAndInitGlobalDispatcher(eventDispatcherType) + // reference config if consumerConfig == nil { logger.Warnf("consumerConfig is nil!") @@ -199,7 +211,7 @@ func Load() { svs.id = key svs.Implement(rpcService) if err := svs.Export(); err != nil { - panic(fmt.Sprintf("service %s export failed! ", key)) + panic(fmt.Sprintf("service %s export failed! err: %#v", key, err)) } } } diff --git a/config/config_loader_test.go b/config/config_loader_test.go index 498f82678070d194e3ffe1539064be7aec19f719..6368fcbd2c7bc675231e7b7835750f26743708af 100644 --- a/config/config_loader_test.go +++ b/config/config_loader_test.go @@ -82,7 +82,8 @@ func TestLoad(t *testing.T) { conServices = map[string]common.RPCService{} proServices = map[string]common.RPCService{} - common.ServiceMap.UnRegister("mock", "MockService") + err := common.ServiceMap.UnRegister("com.MockService", "mock", "MockService") + assert.Nil(t, err) consumerConfig = nil providerConfig = nil } @@ -110,7 +111,7 @@ func TestLoadWithSingleReg(t *testing.T) { conServices = map[string]common.RPCService{} proServices = map[string]common.RPCService{} - common.ServiceMap.UnRegister("mock", "MockService") + common.ServiceMap.UnRegister("com.MockService", "mock", "MockService") consumerConfig = nil providerConfig = nil } @@ -139,7 +140,7 @@ func TestWithNoRegLoad(t *testing.T) { conServices = map[string]common.RPCService{} proServices = map[string]common.RPCService{} - common.ServiceMap.UnRegister("mock", "MockService") + common.ServiceMap.UnRegister("com.MockService", "mock", "MockService") consumerConfig = nil providerConfig = nil } diff --git a/config/interfaces/config_reader.go b/config/interfaces/config_reader.go index 23f2225e1bd670d43065f3b6eca08385a5c964a2..8b79a17d8903ffe888204875c12feed669cb2f9b 100644 --- a/config/interfaces/config_reader.go +++ b/config/interfaces/config_reader.go @@ -1,3 +1,20 @@ +/* + * 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 interfaces import "bytes" diff --git a/config/metadata_report_config_test.go b/config/metadata_report_config_test.go index d6b08d5fb0c51495940d4dc021a0796c1d577923..635feecc2d433366534566d184e058eb54a881ed 100644 --- a/config/metadata_report_config_test.go +++ b/config/metadata_report_config_test.go @@ -1,3 +1,20 @@ +/* + * 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 config import "testing" diff --git a/config/reference_config.go b/config/reference_config.go index 7ce0013194f5c1a1d09e014a858433833aa07f0e..3710cbc4bc62a01a014e91bcb978742c4a93c5cb 100644 --- a/config/reference_config.go +++ b/config/reference_config.go @@ -63,6 +63,7 @@ type ReferenceConfig struct { Generic bool `yaml:"generic" json:"generic,omitempty" property:"generic"` Sticky bool `yaml:"sticky" json:"sticky,omitempty" property:"sticky"` RequestTimeout string `yaml:"timeout" json:"timeout,omitempty" property:"timeout"` + ForceTag bool `yaml:"force.tag" json:"force.tag,omitempty" property:"force.tag"` } // Prefix ... @@ -99,7 +100,9 @@ func (c *ReferenceConfig) Refer(_ interface{}) { common.WithParams(c.getUrlMap()), common.WithParamsValue(constant.BEAN_NAME_KEY, c.id), ) - + if c.ForceTag { + cfgURL.AddParam(constant.ForceUseTag, "true") + } if c.Url != "" { // 1. user specified URL, could be peer-to-peer address, or register center's address. urlStrings := gxstrings.RegSplit(c.Url, "\\s*[;]+\\s*") @@ -185,6 +188,10 @@ func (c *ReferenceConfig) getUrlMap() url.Values { urlMap.Set(constant.VERSION_KEY, c.Version) urlMap.Set(constant.GENERIC_KEY, strconv.FormatBool(c.Generic)) urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.CONSUMER)) + + urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version) + urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.CONSUMER)).Role()) + if len(c.RequestTimeout) != 0 { urlMap.Set(constant.TIMEOUT_KEY, c.RequestTimeout) } diff --git a/config/condition_router_config.go b/config/router_config.go similarity index 89% rename from config/condition_router_config.go rename to config/router_config.go index 87e835108efd2ccac4f829386ec44a3916339f85..0670ee9c20f618021d1d574344a0df85d837bd66 100644 --- a/config/condition_router_config.go +++ b/config/router_config.go @@ -28,13 +28,14 @@ import ( "github.com/apache/dubbo-go/common/yaml" ) -//RouterInit Load config file to init router config +// RouterInit Load config file to init router config func RouterInit(confRouterFile string) error { fileRouterFactories := extension.GetFileRouterFactories() bytes, err := yaml.LoadYMLConfig(confRouterFile) if err != nil { return perrors.Errorf("ioutil.ReadFile(file:%s) = error:%v", confRouterFile, perrors.WithStack(err)) } + logger.Warnf("get fileRouterFactories len{%+v})", len(fileRouterFactories)) for k, factory := range fileRouterFactories { r, e := factory.NewFileRouter(bytes) if e == nil { @@ -42,7 +43,7 @@ func RouterInit(confRouterFile string) error { directory.AddRouterURLSet(&url) return nil } - logger.Warnf("router config type %s create fail \n", k) + logger.Warnf("router config type %s create fail {%v}\n", k, e) } return perrors.Errorf("no file router exists for parse %s , implement router.FIleRouterFactory please.", confRouterFile) } diff --git a/config/condition_router_config_test.go b/config/router_config_test.go similarity index 100% rename from config/condition_router_config_test.go rename to config/router_config_test.go diff --git a/config/service_config.go b/config/service_config.go index 7d97fa4d1e95bd79e051f77deaeafa1afcc58b0f..50bf5e12c3247340f177a84c72446383ec5c3450 100644 --- a/config/service_config.go +++ b/config/service_config.go @@ -69,6 +69,7 @@ type ServiceConfig struct { ExecuteLimitRejectedHandler string `yaml:"execute.limit.rejected.handler" json:"execute.limit.rejected.handler,omitempty" property:"execute.limit.rejected.handler"` Auth string `yaml:"auth" json:"auth,omitempty" property:"auth"` ParamSign string `yaml:"param.sign" json:"param.sign,omitempty" property:"param.sign"` + Tag string `yaml:"tag" json:"tag,omitempty" property:"tag"` unexported *atomic.Bool exported *atomic.Bool @@ -128,7 +129,7 @@ func (c *ServiceConfig) Export() error { } for _, proto := range protocolConfigs { // registry the service reflect - methods, err := common.ServiceMap.Register(proto.Name, c.rpcService) + methods, err := common.ServiceMap.Register(c.InterfaceName, proto.Name, c.rpcService) if err != nil { err := perrors.Errorf("The service %v export the protocol %v error! Error message is %v .", c.InterfaceName, proto.Name, err.Error()) logger.Errorf(err.Error()) @@ -144,7 +145,9 @@ func (c *ServiceConfig) Export() error { common.WithMethods(strings.Split(methods, ",")), common.WithToken(c.Token), ) - + if len(c.Tag) > 0 { + ivkURL.AddParam(constant.Tagkey, c.Tag) + } if len(regUrls) > 0 { for _, regUrl := range regUrls { regUrl.SubURL = ivkURL @@ -193,6 +196,9 @@ func (c *ServiceConfig) getUrlMap() url.Values { urlMap.Set(constant.GROUP_KEY, c.Group) urlMap.Set(constant.VERSION_KEY, c.Version) urlMap.Set(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)) + urlMap.Set(constant.RELEASE_KEY, "dubbo-golang-"+constant.Version) + urlMap.Set(constant.SIDE_KEY, (common.RoleType(common.PROVIDER)).Role()) + // application info urlMap.Set(constant.APPLICATION_KEY, providerConfig.ApplicationConfig.Name) urlMap.Set(constant.ORGANIZATION_KEY, providerConfig.ApplicationConfig.Organization) diff --git a/config_center/apollo/factory.go b/config_center/apollo/factory.go index a5a69e121598bea4194398423775a99f04b61ced..f975ce13d8e5832f03051c42f92157532347d283 100644 --- a/config_center/apollo/factory.go +++ b/config_center/apollo/factory.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 apollo diff --git a/config_center/apollo/impl.go b/config_center/apollo/impl.go index 9045c2864933fcfc79d5be32d160324805605595..b049d334bca7e5191caaf9674734e731bc709ba2 100644 --- a/config_center/apollo/impl.go +++ b/config_center/apollo/impl.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 apollo diff --git a/config_center/apollo/listener.go b/config_center/apollo/listener.go index 820d02fb48e2204c3f1eb74fd5624132a63d367e..fb257a4828aed077f61568685ee7823e9c215cf9 100644 --- a/config_center/apollo/listener.go +++ b/config_center/apollo/listener.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 apollo diff --git a/config_center/zookeeper/impl.go b/config_center/zookeeper/impl.go index 937c56eef0b29f6fee52717f7a43c37ec35c7e95..0a1ce35306dab98363ca475cd5d1b0648e924b90 100644 --- a/config_center/zookeeper/impl.go +++ b/config_center/zookeeper/impl.go @@ -76,7 +76,7 @@ func newZookeeperDynamicConfiguration(url *common.URL) (*zookeeperDynamicConfigu c.cacheListener = NewCacheListener(c.rootPath) err = c.client.Create(c.rootPath) - c.listener.ListenServiceEvent(c.rootPath, c.cacheListener) + c.listener.ListenServiceEvent(url, c.rootPath, c.cacheListener) return c, err } @@ -102,7 +102,7 @@ func newMockZookeeperDynamicConfiguration(url *common.URL, opts ...zookeeper.Opt c.cacheListener = NewCacheListener(c.rootPath) err = c.client.Create(c.rootPath) - go c.listener.ListenServiceEvent(c.rootPath, c.cacheListener) + go c.listener.ListenServiceEvent(url, c.rootPath, c.cacheListener) return tc, c, err } diff --git a/doc/pic/arch/dubbo-go-arch.png b/doc/pic/arch/dubbo-go-arch.png index 87726d88484c23d6395023bb10e86009d59a1fd7..e5f192715216257929cf4a550a1adf3588ab0e0f 100644 Binary files a/doc/pic/arch/dubbo-go-arch.png and b/doc/pic/arch/dubbo-go-arch.png differ diff --git a/doc/pic/arch/dubbo-go-ext.png b/doc/pic/arch/dubbo-go-ext.png new file mode 100644 index 0000000000000000000000000000000000000000..a5285c95570afa13212f7ee6eac5510f20243c3c Binary files /dev/null and b/doc/pic/arch/dubbo-go-ext.png differ diff --git a/filter/filter_impl/active_filter_test.go b/filter/filter_impl/active_filter_test.go index 8917e9141cad4f22ea201a9a07c2873b584c1f92..d5a51d50d93bd9769001964fbb0ae7905eb24980 100644 --- a/filter/filter_impl/active_filter_test.go +++ b/filter/filter_impl/active_filter_test.go @@ -1,3 +1,20 @@ +/* + * 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 filter_impl import ( diff --git a/filter/filter_impl/generic_service_filter_test.go b/filter/filter_impl/generic_service_filter_test.go index 37c6af7450a75449fce51182684be2f619eda9d8..2a911659f068b53836b87af5caf5773d8ac5f119 100644 --- a/filter/filter_impl/generic_service_filter_test.go +++ b/filter/filter_impl/generic_service_filter_test.go @@ -96,7 +96,7 @@ func TestGenericServiceFilter_Invoke(t *testing.T) { hessian.Object("222")}, } s := &TestService{} - _, _ = common.ServiceMap.Register("testprotocol", s) + _, _ = common.ServiceMap.Register("TestService", "testprotocol", s) rpcInvocation := invocation.NewRPCInvocation(methodName, aurguments, nil) filter := GetGenericServiceFilter() url, _ := common.NewURL("testprotocol://127.0.0.1:20000/com.test.Path") diff --git a/filter/filter_impl/token_filter.go b/filter/filter_impl/token_filter.go index 4605416c40a616361868c313881ae784257e6742..8ec3929b6ddc8dcfa430204cd22d2f6d297c59d3 100644 --- a/filter/filter_impl/token_filter.go +++ b/filter/filter_impl/token_filter.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 filter_impl diff --git a/filter/filter_impl/token_filter_test.go b/filter/filter_impl/token_filter_test.go index 672082c729bc371a40573a66d13bc57a7024186b..d7a7f20a5d7648f6ee18fd26f041acb313dd97fe 100644 --- a/filter/filter_impl/token_filter_test.go +++ b/filter/filter_impl/token_filter_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 filter_impl diff --git a/filter/filter_impl/tps/tps_limit_strategy_mock.go b/filter/filter_impl/tps/tps_limit_strategy_mock.go index 72c658fb9a5d48b6080900a4645d318dfd2b0c21..c228c7349ce6ad305051e0ba9b26dddee8c12c71 100644 --- a/filter/filter_impl/tps/tps_limit_strategy_mock.go +++ b/filter/filter_impl/tps/tps_limit_strategy_mock.go @@ -1,18 +1,19 @@ -// 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. -// +/* + * 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. + */ // Code generated by MockGen. DO NOT EDIT. // Source: tps_limit_strategy.go diff --git a/filter/filter_impl/tps/tps_limiter_mock.go b/filter/filter_impl/tps/tps_limiter_mock.go index 463b0988acbeb17a967c9803337a61c4914bce42..b49084f28e7d4b62d64762170b6dfbbec4a4de96 100644 --- a/filter/filter_impl/tps/tps_limiter_mock.go +++ b/filter/filter_impl/tps/tps_limiter_mock.go @@ -1,18 +1,19 @@ -// 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. -// +/* + * 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. + */ // Code generated by MockGen. DO NOT EDIT. // Source: tps_limiter.go diff --git a/filter/handler/rejected_execution_handler_mock.go b/filter/handler/rejected_execution_handler_mock.go index a5bef63b3729a7b04d911c9844320aa778ac357a..bff54769cb007ed2fce5a7623c96edc370e63903 100644 --- a/filter/handler/rejected_execution_handler_mock.go +++ b/filter/handler/rejected_execution_handler_mock.go @@ -1,18 +1,19 @@ -// 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. -// +/* + * 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. + */ // Code generated by MockGen. DO NOT EDIT. // Source: rejected_execution_handler.go diff --git a/metadata/identifier/subscribe_metadata_identifier.go b/metadata/identifier/subscribe_metadata_identifier.go index fd3a290b41e870674366943e12a396c3dae7e238..321a216a3e3ad3f2390ab832782924a81e226160 100644 --- a/metadata/identifier/subscribe_metadata_identifier.go +++ b/metadata/identifier/subscribe_metadata_identifier.go @@ -1,3 +1,20 @@ +/* + * 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 identifier type SubscriberMetadataIdentifier struct { diff --git a/protocol/dubbo/client_test.go b/protocol/dubbo/client_test.go index 1e0a73fac1a6cf6d4d102e5f4f6f1ba60fc4102a..744ffa80d6bc65e8526201b8cd327bb12b43caef 100644 --- a/protocol/dubbo/client_test.go +++ b/protocol/dubbo/client_test.go @@ -162,7 +162,7 @@ func InitTest(t *testing.T) (protocol.Protocol, common.URL) { hessian.RegisterPOJO(&User{}) - methods, err := common.ServiceMap.Register("dubbo", &UserProvider{}) + methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "dubbo", &UserProvider{}) assert.NoError(t, err) assert.Equal(t, "GetBigPkg,GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4,GetUser5,GetUser6", methods) diff --git a/protocol/dubbo/dubbo_exporter.go b/protocol/dubbo/dubbo_exporter.go index f4cd0cc1234f71bdcf6ce746f01ff3618d820fc5..1c45c40056f7690ba64838f641fe0b13a1554727 100644 --- a/protocol/dubbo/dubbo_exporter.go +++ b/protocol/dubbo/dubbo_exporter.go @@ -43,8 +43,9 @@ func NewDubboExporter(key string, invoker protocol.Invoker, exporterMap *sync.Ma // Unexport ... func (de *DubboExporter) Unexport() { serviceId := de.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "") + interfaceName := de.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "") de.BaseExporter.Unexport() - err := common.ServiceMap.UnRegister(DUBBO, serviceId) + err := common.ServiceMap.UnRegister(interfaceName, DUBBO, serviceId) if err != nil { logger.Errorf("[DubboExporter.Unexport] error: %v", err) } diff --git a/protocol/grpc/client.go b/protocol/grpc/client.go index 6026f0991b926fd38de8aef3774e46b001820edd..0c7499a179571d623eccc607dd4cc8f1950f3239 100644 --- a/protocol/grpc/client.go +++ b/protocol/grpc/client.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/client_test.go b/protocol/grpc/client_test.go index 56ec766f70da93bcddbcff13667a34c39deffe06..099f03e429ec83dd01941f6add68c751cf6dd7b0 100644 --- a/protocol/grpc/client_test.go +++ b/protocol/grpc/client_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/common_test.go b/protocol/grpc/common_test.go index 3d0823b1061a61cfa391358e270c8b9081e9031c..33c2fc617d52795d13d9b4fc02054ef5a79d0934 100644 --- a/protocol/grpc/common_test.go +++ b/protocol/grpc/common_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/grpc_exporter.go b/protocol/grpc/grpc_exporter.go index 3c38ef974ca22a582ce83102718d01a8edd4258f..0296ad8b5b06b693fd5e0972f18be77a69cd21ed 100644 --- a/protocol/grpc/grpc_exporter.go +++ b/protocol/grpc/grpc_exporter.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc @@ -43,8 +43,9 @@ func NewGrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map // Unexport ... func (gg *GrpcExporter) Unexport() { serviceId := gg.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "") + interfaceName := gg.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "") gg.BaseExporter.Unexport() - err := common.ServiceMap.UnRegister(GRPC, serviceId) + err := common.ServiceMap.UnRegister(interfaceName, GRPC, serviceId) if err != nil { logger.Errorf("[GrpcExporter.Unexport] error: %v", err) } diff --git a/protocol/grpc/grpc_invoker.go b/protocol/grpc/grpc_invoker.go index 26bc86f3aa46c8048b16284bd61cb5d9fb4664f9..78439fcd9b7f7d3b845f326bf432ea486855965e 100644 --- a/protocol/grpc/grpc_invoker.go +++ b/protocol/grpc/grpc_invoker.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/grpc_invoker_test.go b/protocol/grpc/grpc_invoker_test.go index 368c1392ec03af310f93e8fc2173b8354975c99e..3054ada13340a9c9cc038a63d89c45ced9ec7ac7 100644 --- a/protocol/grpc/grpc_invoker_test.go +++ b/protocol/grpc/grpc_invoker_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/grpc_protocol.go b/protocol/grpc/grpc_protocol.go index 0f5625c152cc366289143b8a29d11cafb513b2f2..cc4aba10bf69f5e80d761649b9830fd61c4084cd 100644 --- a/protocol/grpc/grpc_protocol.go +++ b/protocol/grpc/grpc_protocol.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/grpc_protocol_test.go b/protocol/grpc/grpc_protocol_test.go index d0206a0fd953e40a478c26a2298f4889d8f72771..d028f8ef4285b0183e6e0b5b32deede59ce5c531 100644 --- a/protocol/grpc/grpc_protocol_test.go +++ b/protocol/grpc/grpc_protocol_test.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/grpc/internal/client.go b/protocol/grpc/internal/client.go index d236e3046a90e9179fba07a0be5edb07f8c2a3e8..3ce0f570b7eb3424fa85a868931b1b3cebe362eb 100644 --- a/protocol/grpc/internal/client.go +++ b/protocol/grpc/internal/client.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 internal diff --git a/protocol/grpc/internal/doc.go b/protocol/grpc/internal/doc.go index f2ef2ebd5e41980e1e1f1b0071ca7bb3885539f7..b70fc24e728acb85364a8c314f65a7ec997cda58 100644 --- a/protocol/grpc/internal/doc.go +++ b/protocol/grpc/internal/doc.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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. + */ // just for test, never use internal for production. package internal diff --git a/protocol/grpc/internal/helloworld.pb.go b/protocol/grpc/internal/helloworld.pb.go index 79b74ac65011208ae74f989cf86e4e6f9f446015..82537f553bdd8ed74970627c217091b6a9de637b 100644 --- a/protocol/grpc/internal/helloworld.pb.go +++ b/protocol/grpc/internal/helloworld.pb.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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. + */ // Code generated by protoc-gen-go. DO NOT EDIT. // source: helloworld.proto diff --git a/protocol/grpc/internal/server.go b/protocol/grpc/internal/server.go index a0759f757dc44153e7f09b726db5e66176796c96..a6b861cac6ccb73f8bdf894f462f380123fa9ae3 100644 --- a/protocol/grpc/internal/server.go +++ b/protocol/grpc/internal/server.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 internal diff --git a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go index f5d3a49b0916050fc6b2e6373fde0b70df0a1c31..702391b299402cf7f1cefbcc785fd10ea9f1634d 100644 --- a/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go +++ b/protocol/grpc/protoc-gen-dubbo/examples/helloworld.pb.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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. + */ // Code generated by protoc-gen-go. DO NOT EDIT. // source: helloworld.proto diff --git a/protocol/grpc/protoc-gen-dubbo/main.go b/protocol/grpc/protoc-gen-dubbo/main.go index b2f0e82f74a4d3c1a7013714cd18d83562baff71..fbcfa6f9d492afa8bc7848c733358b3cf7223e99 100644 --- a/protocol/grpc/protoc-gen-dubbo/main.go +++ b/protocol/grpc/protoc-gen-dubbo/main.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 main diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go index 064c738a53d2200223b0ca81aca77358afad032b..76fbf647249c57464204867398299b51c65bb846 100644 --- a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go +++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/doc.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 dubbo plugin for protobuf. package dubbo diff --git a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go index e84a7d0cc96887cf728f499c28c26f061ed1ccdf..83d28519f6f8e28bf471ce2ea6807603c1324911 100644 --- a/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go +++ b/protocol/grpc/protoc-gen-dubbo/plugin/dubbo/dubbo.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 dubbo diff --git a/protocol/grpc/server.go b/protocol/grpc/server.go index cc184bf3cff83e6ed57bc41cba49c184860233dd..63783040f9840c26dbd0cc843e9d49cdc981e64a 100644 --- a/protocol/grpc/server.go +++ b/protocol/grpc/server.go @@ -1,19 +1,19 @@ /* -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. -*/ + * 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 grpc diff --git a/protocol/jsonrpc/http_test.go b/protocol/jsonrpc/http_test.go index 0cb88b36a8f330059906eb70417b6d4841020c38..f8480bf32e15ad428209eedb72757a299455eb20 100644 --- a/protocol/jsonrpc/http_test.go +++ b/protocol/jsonrpc/http_test.go @@ -50,7 +50,7 @@ type ( func TestHTTPClient_Call(t *testing.T) { - methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{}) + methods, err := common.ServiceMap.Register("com.ikurento.user.UserProvider", "jsonrpc", &UserProvider{}) assert.NoError(t, err) assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods) diff --git a/protocol/jsonrpc/jsonrpc_exporter.go b/protocol/jsonrpc/jsonrpc_exporter.go index 7f8fd491854f1ab25e63410a22ef5664db92f614..c61cf9adaebe9105a87ece1dcbae4dbe706cb3fc 100644 --- a/protocol/jsonrpc/jsonrpc_exporter.go +++ b/protocol/jsonrpc/jsonrpc_exporter.go @@ -43,8 +43,9 @@ func NewJsonrpcExporter(key string, invoker protocol.Invoker, exporterMap *sync. // Unexport ... func (je *JsonrpcExporter) Unexport() { serviceId := je.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "") + interfaceName := je.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "") je.BaseExporter.Unexport() - err := common.ServiceMap.UnRegister(JSONRPC, serviceId) + err := common.ServiceMap.UnRegister(interfaceName, JSONRPC, serviceId) if err != nil { logger.Errorf("[JsonrpcExporter.Unexport] error: %v", err) } diff --git a/protocol/jsonrpc/jsonrpc_invoker_test.go b/protocol/jsonrpc/jsonrpc_invoker_test.go index 9e08eed2b4c61e686073a9039a605c4f73aa08c5..0f14ba11e2dec18bbd4d63e87e8c0fb2727f3755 100644 --- a/protocol/jsonrpc/jsonrpc_invoker_test.go +++ b/protocol/jsonrpc/jsonrpc_invoker_test.go @@ -36,7 +36,7 @@ import ( func TestJsonrpcInvoker_Invoke(t *testing.T) { - methods, err := common.ServiceMap.Register("jsonrpc", &UserProvider{}) + methods, err := common.ServiceMap.Register("UserProvider", "jsonrpc", &UserProvider{}) assert.NoError(t, err) assert.Equal(t, "GetUser,GetUser0,GetUser1,GetUser2,GetUser3,GetUser4", methods) diff --git a/protocol/mock/mock_invoker.go b/protocol/mock/mock_invoker.go index 5c5b476b7b07f6c41a74a7ec8f51648aff84b1a3..0c88b47e36122dc1a9bc9345d7e93f62cd76f13b 100644 --- a/protocol/mock/mock_invoker.go +++ b/protocol/mock/mock_invoker.go @@ -1,18 +1,19 @@ -// 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. -// +/* + * 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. + */ // Code generated by MockGen. DO NOT EDIT. // Source: invoker.go diff --git a/protocol/rest/client/client_impl/resty_client.go b/protocol/rest/client/client_impl/resty_client.go index aa6c23137dc68492948b85a85555a5340572ac49..b60f50a5a70cde01a051dbb2a4490cbb792e0116 100644 --- a/protocol/rest/client/client_impl/resty_client.go +++ b/protocol/rest/client/client_impl/resty_client.go @@ -40,10 +40,12 @@ func init() { extension.SetRestClient(constant.DEFAULT_REST_CLIENT, NewRestyClient) } +// RestyClient a rest client implement by Resty type RestyClient struct { client *resty.Client } +// NewRestyClient a constructor of RestyClient func NewRestyClient(restOption *client.RestOptions) client.RestClient { client := resty.New() client.SetTransport( @@ -65,21 +67,21 @@ func NewRestyClient(restOption *client.RestOptions) client.RestClient { } } -func (rc *RestyClient) Do(restRequest *client.RestRequest, res interface{}) error { - r, err := rc.client.R(). - SetHeader("Content-Type", restRequest.Consumes). - SetHeader("Accept", restRequest.Produces). +// Do send request by RestyClient +func (rc *RestyClient) Do(restRequest *client.RestClientRequest, res interface{}) error { + req := rc.client.R() + req.Header = restRequest.Header + resp, err := req. SetPathParams(restRequest.PathParams). SetQueryParams(restRequest.QueryParams). - SetHeaders(restRequest.Headers). SetBody(restRequest.Body). SetResult(res). Execute(restRequest.Method, "http://"+path.Join(restRequest.Location, restRequest.Path)) if err != nil { return perrors.WithStack(err) } - if r.IsError() { - return perrors.New(r.String()) + if resp.IsError() { + return perrors.New(resp.String()) } return nil } diff --git a/protocol/rest/client/rest_client.go b/protocol/rest/client/rest_client.go index 7d020abc81c2bd44473ed25ffec4b2b657e7bcc0..d63c5e0bd0c7e6392eb5b0efc50bb0a585f4192d 100644 --- a/protocol/rest/client/rest_client.go +++ b/protocol/rest/client/rest_client.go @@ -18,26 +18,28 @@ package client import ( + "net/http" "time" ) +// RestOptions type RestOptions struct { RequestTimeout time.Duration ConnectTimeout time.Duration } -type RestRequest struct { +// RestClientRequest +type RestClientRequest struct { + Header http.Header Location string Path string - Produces string - Consumes string Method string PathParams map[string]string QueryParams map[string]string Body interface{} - Headers map[string]string } +// RestClient user can implement this client interface to send request type RestClient interface { - Do(request *RestRequest, res interface{}) error + Do(request *RestClientRequest, res interface{}) error } diff --git a/protocol/rest/rest_exporter.go b/protocol/rest/rest_exporter.go index 470d525ad806687e7a732ce5681eb372eb431a63..1ee208615ea07e3f2850920492ab9e9821e7ffef 100644 --- a/protocol/rest/rest_exporter.go +++ b/protocol/rest/rest_exporter.go @@ -40,8 +40,9 @@ func NewRestExporter(key string, invoker protocol.Invoker, exporterMap *sync.Map func (re *RestExporter) Unexport() { serviceId := re.GetInvoker().GetUrl().GetParam(constant.BEAN_NAME_KEY, "") + interfaceName := re.GetInvoker().GetUrl().GetParam(constant.INTERFACE_KEY, "") re.BaseExporter.Unexport() - err := common.ServiceMap.UnRegister(REST, serviceId) + err := common.ServiceMap.UnRegister(interfaceName, REST, serviceId) if err != nil { logger.Errorf("[RestExporter.Unexport] error: %v", err) } diff --git a/protocol/rest/rest_invoker.go b/protocol/rest/rest_invoker.go index 0c82035ac5eb9a52ab188baa971dbdf1b864e970..121d1217efd3baea0f961b67e243e9a0450aefc2 100644 --- a/protocol/rest/rest_invoker.go +++ b/protocol/rest/rest_invoker.go @@ -20,6 +20,7 @@ package rest import ( "context" "fmt" + "net/http" ) import ( @@ -56,7 +57,7 @@ func (ri *RestInvoker) Invoke(ctx context.Context, invocation protocol.Invocatio body interface{} pathParams map[string]string queryParams map[string]string - headers map[string]string + header http.Header err error ) if methodConfig == nil { @@ -71,24 +72,21 @@ func (ri *RestInvoker) Invoke(ctx context.Context, invocation protocol.Invocatio result.Err = err return &result } - if headers, err = restStringMapTransform(methodConfig.HeadersMap, inv.Arguments()); err != nil { + if header, err = getRestHttpHeader(methodConfig, inv.Arguments()); err != nil { result.Err = err return &result } if len(inv.Arguments()) > methodConfig.Body && methodConfig.Body >= 0 { body = inv.Arguments()[methodConfig.Body] } - - req := &client.RestRequest{ + req := &client.RestClientRequest{ Location: ri.GetUrl().Location, - Produces: methodConfig.Produces, - Consumes: methodConfig.Consumes, Method: methodConfig.MethodType, Path: methodConfig.Path, PathParams: pathParams, QueryParams: queryParams, Body: body, - Headers: headers, + Header: header, } result.Err = ri.client.Do(req, inv.Reply()) if result.Err == nil { @@ -107,3 +105,17 @@ func restStringMapTransform(paramsMap map[int]string, args []interface{}) (map[s } return resMap, nil } + +func getRestHttpHeader(methodConfig *config.RestMethodConfig, args []interface{}) (http.Header, error) { + header := http.Header{} + headersMap := methodConfig.HeadersMap + header.Set("Content-Type", methodConfig.Consumes) + header.Set("Accept", methodConfig.Produces) + for k, v := range headersMap { + if k >= len(args) || k < 0 { + return nil, perrors.Errorf("[Rest Invoke] Index %v is out of bundle", k) + } + header.Set(v, fmt.Sprint(args[k])) + } + return header, nil +} diff --git a/protocol/rest/rest_invoker_test.go b/protocol/rest/rest_invoker_test.go index e44c5d9a21026992178bd432676c99bc837c361b..2ea260c58d03c27a691e48b953ce6d64f75040a2 100644 --- a/protocol/rest/rest_invoker_test.go +++ b/protocol/rest/rest_invoker_test.go @@ -61,7 +61,7 @@ func TestRestInvoker_Invoke(t *testing.T) { "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) - _, err = common.ServiceMap.Register(url.Protocol, &UserProvider{}) + _, err = common.ServiceMap.Register("UserProvider", url.Protocol, &UserProvider{}) assert.NoError(t, err) con := config.ProviderConfig{} config.SetProviderConfig(con) @@ -206,6 +206,6 @@ func TestRestInvoker_Invoke(t *testing.T) { assert.Error(t, res.Error(), "test error") assert.Equal(t, filterNum, 12) - err = common.ServiceMap.UnRegister(url.Protocol, "com.ikurento.user.UserProvider") + err = common.ServiceMap.UnRegister("UserProvider", url.Protocol, "com.ikurento.user.UserProvider") assert.NoError(t, err) } diff --git a/protocol/rest/rest_protocol.go b/protocol/rest/rest_protocol.go index 47ecb6093b4cfa12a1d3397fa45d59b1e173a93a..e15eeb39d72212eb9f1d0235313eba231d3b0a36 100644 --- a/protocol/rest/rest_protocol.go +++ b/protocol/rest/rest_protocol.go @@ -75,7 +75,9 @@ func (rp *RestProtocol) Export(invoker protocol.Invoker) protocol.Exporter { } rp.SetExporterMap(serviceKey, exporter) restServer := rp.getServer(url, restServiceConfig.Server) - restServer.Deploy(invoker, restServiceConfig.RestMethodConfigsMap) + for _, methodConfig := range restServiceConfig.RestMethodConfigsMap { + restServer.Deploy(methodConfig, server.GetRouteFunc(invoker, methodConfig)) + } return exporter } diff --git a/protocol/rest/rest_protocol_test.go b/protocol/rest/rest_protocol_test.go index 8af73a1839c159fdf58c64d12e039c20bb3221c6..9117148777ca868cb7d2672236e800c836d3de84 100644 --- a/protocol/rest/rest_protocol_test.go +++ b/protocol/rest/rest_protocol_test.go @@ -80,7 +80,7 @@ func TestRestProtocol_Export(t *testing.T) { "module=dubbogo+user-info+server&org=ikurento.com&owner=ZX&pid=1447&revision=0.0.1&" + "side=provider&timeout=3000×tamp=1556509797245") assert.NoError(t, err) - _, err = common.ServiceMap.Register(url.Protocol, &UserProvider{}) + _, err = common.ServiceMap.Register("UserProvider", url.Protocol, &UserProvider{}) assert.NoError(t, err) con := config.ProviderConfig{} config.SetProviderConfig(con) @@ -128,7 +128,7 @@ func TestRestProtocol_Export(t *testing.T) { proto.Destroy() _, ok = proto.(*RestProtocol).serverMap[url.Location] assert.False(t, ok) - err = common.ServiceMap.UnRegister(url.Protocol, "com.ikurento.user.UserProvider") + err = common.ServiceMap.UnRegister("UserProvider", url.Protocol, "com.ikurento.user.UserProvider") assert.NoError(t, err) } diff --git a/protocol/rest/server/rest_server.go b/protocol/rest/server/rest_server.go index c10c98a7b677d47c43b64643a69d5b3768a6c663..fbd6fb7ad9dd81f043e4d45ee94a54e12ef89cdd 100644 --- a/protocol/rest/server/rest_server.go +++ b/protocol/rest/server/rest_server.go @@ -17,15 +17,306 @@ package server +import ( + "context" + "errors" + "net/http" + "reflect" + "strconv" + "strings" +) + +import ( + perrors "github.com/pkg/errors" +) + import ( "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/logger" "github.com/apache/dubbo-go/protocol" - "github.com/apache/dubbo-go/protocol/rest/config" + "github.com/apache/dubbo-go/protocol/invocation" + rest_config "github.com/apache/dubbo-go/protocol/rest/config" ) +const parseParameterErrorStr = "An error occurred while parsing parameters on the server" + +// RestServer user can implement this server interface type RestServer interface { + // Start rest server Start(url common.URL) - Deploy(invoker protocol.Invoker, restMethodConfig map[string]*config.RestMethodConfig) - UnDeploy(restMethodConfig map[string]*config.RestMethodConfig) + // Deploy a http api + Deploy(restMethodConfig *rest_config.RestMethodConfig, routeFunc func(request RestServerRequest, response RestServerResponse)) + // UnDeploy a http api + UnDeploy(restMethodConfig *rest_config.RestMethodConfig) + // Destroy rest server Destroy() } + +// RestServerRequest interface +type RestServerRequest interface { + // RawRequest get the Ptr of http.Request + RawRequest() *http.Request + // PathParameter get the path parameter by name + PathParameter(name string) string + // PathParameters get the map of the path parameters + PathParameters() map[string]string + // QueryParameter get the query parameter by name + QueryParameter(name string) string + // QueryParameters get the map of query parameters + QueryParameters(name string) []string + // BodyParameter get the body parameter of name + BodyParameter(name string) (string, error) + // HeaderParameter get the header parameter of name + HeaderParameter(name string) string + // ReadEntity checks the Accept header and reads the content into the entityPointer. + ReadEntity(entityPointer interface{}) error +} + +// RestServerResponse interface +type RestServerResponse interface { + http.ResponseWriter + // WriteError writes the http status and the error string on the response. err can be nil. + // Return an error if writing was not successful. + WriteError(httpStatus int, err error) (writeErr error) + // WriteEntity marshals the value using the representation denoted by the Accept Header. + WriteEntity(value interface{}) error +} + +// GetRouteFunc +// A route function will be invoked by http server +func GetRouteFunc(invoker protocol.Invoker, methodConfig *rest_config.RestMethodConfig) func(req RestServerRequest, resp RestServerResponse) { + return func(req RestServerRequest, resp RestServerResponse) { + var ( + err error + args []interface{} + ) + svc := common.ServiceMap.GetService(invoker.GetUrl().Protocol, strings.TrimPrefix(invoker.GetUrl().Path, "/")) + // get method + method := svc.Method()[methodConfig.MethodName] + argsTypes := method.ArgsType() + replyType := method.ReplyType() + // two ways to prepare arguments + // if method like this 'func1(req []interface{}, rsp *User) error' + // we don't have arguments type + if (len(argsTypes) == 1 || len(argsTypes) == 2 && replyType == nil) && + argsTypes[0].String() == "[]interface {}" { + args, err = getArgsInterfaceFromRequest(req, methodConfig) + } else { + args, err = getArgsFromRequest(req, argsTypes, methodConfig) + } + if err != nil { + logger.Errorf("[Go Restful] parsing http parameters error:%v", err) + err = resp.WriteError(http.StatusInternalServerError, errors.New(parseParameterErrorStr)) + if err != nil { + logger.Errorf("[Go Restful] WriteErrorString error:%v", err) + } + } + result := invoker.Invoke(context.Background(), invocation.NewRPCInvocation(methodConfig.MethodName, args, make(map[string]string))) + if result.Error() != nil { + err = resp.WriteError(http.StatusInternalServerError, result.Error()) + if err != nil { + logger.Errorf("[Go Restful] WriteError error:%v", err) + } + return + } + err = resp.WriteEntity(result.Result()) + if err != nil { + logger.Errorf("[Go Restful] WriteEntity error:%v", err) + } + } +} + +// getArgsInterfaceFromRequest when service function like GetUser(req []interface{}, rsp *User) error +// use this method to get arguments +func getArgsInterfaceFromRequest(req RestServerRequest, methodConfig *rest_config.RestMethodConfig) ([]interface{}, error) { + argsMap := make(map[int]interface{}, 8) + maxKey := 0 + for k, v := range methodConfig.PathParamsMap { + if maxKey < k { + maxKey = k + } + argsMap[k] = req.PathParameter(v) + } + for k, v := range methodConfig.QueryParamsMap { + if maxKey < k { + maxKey = k + } + params := req.QueryParameters(v) + if len(params) == 1 { + argsMap[k] = params[0] + } else { + argsMap[k] = params + } + } + for k, v := range methodConfig.HeadersMap { + if maxKey < k { + maxKey = k + } + argsMap[k] = req.HeaderParameter(v) + } + if methodConfig.Body >= 0 { + if maxKey < methodConfig.Body { + maxKey = methodConfig.Body + } + m := make(map[string]interface{}) + // TODO read as a slice + if err := req.ReadEntity(&m); err != nil { + return nil, perrors.Errorf("[Go restful] Read body entity as map[string]interface{} error:%v", err) + } + argsMap[methodConfig.Body] = m + } + args := make([]interface{}, maxKey+1) + for k, v := range argsMap { + if k >= 0 { + args[k] = v + } + } + return args, nil +} + +// getArgsFromRequest get arguments from server.RestServerRequest +func getArgsFromRequest(req RestServerRequest, argsTypes []reflect.Type, methodConfig *rest_config.RestMethodConfig) ([]interface{}, error) { + argsLength := len(argsTypes) + args := make([]interface{}, argsLength) + for i, t := range argsTypes { + args[i] = reflect.Zero(t).Interface() + } + if err := assembleArgsFromPathParams(methodConfig, argsLength, argsTypes, req, args); err != nil { + return nil, err + } + if err := assembleArgsFromQueryParams(methodConfig, argsLength, argsTypes, req, args); err != nil { + return nil, err + } + if err := assembleArgsFromBody(methodConfig, argsTypes, req, args); err != nil { + return nil, err + } + if err := assembleArgsFromHeaders(methodConfig, req, argsLength, argsTypes, args); err != nil { + return nil, err + } + return args, nil +} + +// assembleArgsFromHeaders assemble arguments from headers +func assembleArgsFromHeaders(methodConfig *rest_config.RestMethodConfig, req RestServerRequest, argsLength int, argsTypes []reflect.Type, args []interface{}) error { + for k, v := range methodConfig.HeadersMap { + param := req.HeaderParameter(v) + if k < 0 || k >= argsLength { + return perrors.Errorf("[Go restful] Header param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) + } + t := argsTypes[k] + if t.Kind() == reflect.Ptr { + t = t.Elem() + } + if t.Kind() == reflect.String { + args[k] = param + } else { + return perrors.Errorf("[Go restful] Header param parse error, the index %v args's type isn't string", k) + } + } + return nil +} + +// assembleArgsFromBody assemble arguments from body +func assembleArgsFromBody(methodConfig *rest_config.RestMethodConfig, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { + if methodConfig.Body >= 0 && methodConfig.Body < len(argsTypes) { + t := argsTypes[methodConfig.Body] + kind := t.Kind() + if kind == reflect.Ptr { + t = t.Elem() + } + var ni interface{} + if t.String() == "[]interface {}" { + ni = make([]map[string]interface{}, 0) + } else if t.String() == "interface {}" { + ni = make(map[string]interface{}) + } else { + n := reflect.New(t) + if n.CanInterface() { + ni = n.Interface() + } + } + if err := req.ReadEntity(&ni); err != nil { + return perrors.Errorf("[Go restful] Read body entity error, error is %v", perrors.WithStack(err)) + } + args[methodConfig.Body] = ni + } + return nil +} + +// assembleArgsFromQueryParams assemble arguments from query params +func assembleArgsFromQueryParams(methodConfig *rest_config.RestMethodConfig, argsLength int, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { + var ( + err error + param interface{} + i64 int64 + ) + for k, v := range methodConfig.QueryParamsMap { + if k < 0 || k >= argsLength { + return perrors.Errorf("[Go restful] Query param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) + } + t := argsTypes[k] + kind := t.Kind() + if kind == reflect.Ptr { + t = t.Elem() + } + if kind == reflect.Slice { + param = req.QueryParameters(v) + } else if kind == reflect.String { + param = req.QueryParameter(v) + } else if kind == reflect.Int { + param, err = strconv.Atoi(req.QueryParameter(v)) + } else if kind == reflect.Int32 { + i64, err = strconv.ParseInt(req.QueryParameter(v), 10, 32) + if err == nil { + param = int32(i64) + } + } else if kind == reflect.Int64 { + param, err = strconv.ParseInt(req.QueryParameter(v), 10, 64) + } else { + return perrors.Errorf("[Go restful] Query param parse error, the index %v args's type isn't int or string or slice", k) + } + if err != nil { + return perrors.Errorf("[Go restful] Query param parse error, error:%v", perrors.WithStack(err)) + } + args[k] = param + } + return nil +} + +// assembleArgsFromPathParams assemble arguments from path params +func assembleArgsFromPathParams(methodConfig *rest_config.RestMethodConfig, argsLength int, argsTypes []reflect.Type, req RestServerRequest, args []interface{}) error { + var ( + err error + param interface{} + i64 int64 + ) + for k, v := range methodConfig.PathParamsMap { + if k < 0 || k >= argsLength { + return perrors.Errorf("[Go restful] Path param parse error, the index %v args of method:%v doesn't exist", k, methodConfig.MethodName) + } + t := argsTypes[k] + kind := t.Kind() + if kind == reflect.Ptr { + t = t.Elem() + } + if kind == reflect.Int { + param, err = strconv.Atoi(req.PathParameter(v)) + } else if kind == reflect.Int32 { + i64, err = strconv.ParseInt(req.PathParameter(v), 10, 32) + if err == nil { + param = int32(i64) + } + } else if kind == reflect.Int64 { + param, err = strconv.ParseInt(req.PathParameter(v), 10, 64) + } else if kind == reflect.String { + param = req.PathParameter(v) + } else { + return perrors.Errorf("[Go restful] Path param parse error, the index %v args's type isn't int or string", k) + } + if err != nil { + return perrors.Errorf("[Go restful] Path param parse error, error is %v", perrors.WithStack(err)) + } + args[k] = param + } + return nil +} diff --git a/protocol/rest/server/server_impl/go_restful_server.go b/protocol/rest/server/server_impl/go_restful_server.go index 69f36a5c80aa51f52dfcfabc5a1bd4003f4cd727..c7d971fcaa5ada0ba02cc436b5ae6705793887ef 100644 --- a/protocol/rest/server/server_impl/go_restful_server.go +++ b/protocol/rest/server/server_impl/go_restful_server.go @@ -22,8 +22,6 @@ import ( "fmt" "net" "net/http" - "reflect" - "strconv" "strings" "time" ) @@ -38,27 +36,29 @@ import ( "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/common/logger" - "github.com/apache/dubbo-go/protocol" - "github.com/apache/dubbo-go/protocol/invocation" "github.com/apache/dubbo-go/protocol/rest/config" "github.com/apache/dubbo-go/protocol/rest/server" ) func init() { - extension.SetRestServer(constant.DEFAULT_REST_SERVER, GetNewGoRestfulServer) + extension.SetRestServer(constant.DEFAULT_REST_SERVER, NewGoRestfulServer) } var filterSlice []restful.FilterFunction +// GoRestfulServer a rest server implement by go-restful type GoRestfulServer struct { srv *http.Server container *restful.Container } -func NewGoRestfulServer() *GoRestfulServer { +// NewGoRestfulServer a constructor of GoRestfulServer +func NewGoRestfulServer() server.RestServer { return &GoRestfulServer{} } +// Start go-restful server +// It will add all go-restful filters func (grs *GoRestfulServer) Start(url common.URL) { grs.container = restful.NewContainer() for _, filter := range filterSlice { @@ -80,61 +80,32 @@ func (grs *GoRestfulServer) Start(url common.URL) { }() } -func (grs *GoRestfulServer) Deploy(invoker protocol.Invoker, restMethodConfig map[string]*config.RestMethodConfig) { - svc := common.ServiceMap.GetService(invoker.GetUrl().Protocol, strings.TrimPrefix(invoker.GetUrl().Path, "/")) - for methodName, config := range restMethodConfig { - // get method - method := svc.Method()[methodName] - argsTypes := method.ArgsType() - replyType := method.ReplyType() - ws := new(restful.WebService) - ws.Path(config.Path). - Produces(strings.Split(config.Produces, ",")...). - Consumes(strings.Split(config.Consumes, ",")...). - Route(ws.Method(config.MethodType).To(getFunc(methodName, invoker, argsTypes, replyType, config))) - grs.container.Add(ws) +// Publish a http api in go-restful server +// The routeFunc should be invoked when the server receive a request +func (grs *GoRestfulServer) Deploy(restMethodConfig *config.RestMethodConfig, routeFunc func(request server.RestServerRequest, response server.RestServerResponse)) { + ws := &restful.WebService{} + rf := func(req *restful.Request, resp *restful.Response) { + routeFunc(NewGoRestfulRequestAdapter(req), resp) } + ws.Path(restMethodConfig.Path). + Produces(strings.Split(restMethodConfig.Produces, ",")...). + Consumes(strings.Split(restMethodConfig.Consumes, ",")...). + Route(ws.Method(restMethodConfig.MethodType).To(rf)) + grs.container.Add(ws) } -func getFunc(methodName string, invoker protocol.Invoker, argsTypes []reflect.Type, - replyType reflect.Type, config *config.RestMethodConfig) func(req *restful.Request, resp *restful.Response) { - return func(req *restful.Request, resp *restful.Response) { - var ( - err error - args []interface{} - ) - if (len(argsTypes) == 1 || len(argsTypes) == 2 && replyType == nil) && - argsTypes[0].String() == "[]interface {}" { - args = getArgsInterfaceFromRequest(req, config) - } else { - args = getArgsFromRequest(req, argsTypes, config) - } - result := invoker.Invoke(context.Background(), invocation.NewRPCInvocation(methodName, args, make(map[string]string))) - if result.Error() != nil { - err = resp.WriteError(http.StatusInternalServerError, result.Error()) - if err != nil { - logger.Errorf("[Go Restful] WriteError error:%v", err) - } - return - } - err = resp.WriteEntity(result.Result()) - if err != nil { - logger.Error("[Go Restful] WriteEntity error:%v", err) - } - } -} -func (grs *GoRestfulServer) UnDeploy(restMethodConfig map[string]*config.RestMethodConfig) { - for _, config := range restMethodConfig { - ws := new(restful.WebService) - ws.Path(config.Path) - err := grs.container.Remove(ws) - if err != nil { - logger.Warnf("[Go restful] Remove web service error:%v", err) - } +// Delete a http api in go-restful server +func (grs *GoRestfulServer) UnDeploy(restMethodConfig *config.RestMethodConfig) { + ws := new(restful.WebService) + ws.Path(restMethodConfig.Path) + err := grs.container.Remove(ws) + if err != nil { + logger.Warnf("[Go restful] Remove web service error:%v", err) } } +// Destroy the go-restful server func (grs *GoRestfulServer) Destroy() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -144,179 +115,59 @@ func (grs *GoRestfulServer) Destroy() { logger.Infof("[Go Restful] Server exiting") } -func getArgsInterfaceFromRequest(req *restful.Request, config *config.RestMethodConfig) []interface{} { - argsMap := make(map[int]interface{}, 8) - maxKey := 0 - for k, v := range config.PathParamsMap { - if maxKey < k { - maxKey = k - } - argsMap[k] = req.PathParameter(v) - } - for k, v := range config.QueryParamsMap { - if maxKey < k { - maxKey = k - } - params := req.QueryParameters(v) - if len(params) == 1 { - argsMap[k] = params[0] - } else { - argsMap[k] = params - } - } - for k, v := range config.HeadersMap { - if maxKey < k { - maxKey = k - } - argsMap[k] = req.HeaderParameter(v) - } - if config.Body >= 0 { - if maxKey < config.Body { - maxKey = config.Body - } - m := make(map[string]interface{}) - // TODO read as a slice - if err := req.ReadEntity(&m); err != nil { - logger.Warnf("[Go restful] Read body entity as map[string]interface{} error:%v", perrors.WithStack(err)) - } else { - argsMap[config.Body] = m - } - } - args := make([]interface{}, maxKey+1) - for k, v := range argsMap { - if k >= 0 { - args[k] = v - } - } - return args +// AddGoRestfulServerFilter let user add the http server of go-restful +// addFilter should before config.Load() +func AddGoRestfulServerFilter(filterFuc restful.FilterFunction) { + filterSlice = append(filterSlice, filterFuc) } -func getArgsFromRequest(req *restful.Request, argsTypes []reflect.Type, config *config.RestMethodConfig) []interface{} { - argsLength := len(argsTypes) - args := make([]interface{}, argsLength) - for i, t := range argsTypes { - args[i] = reflect.Zero(t).Interface() - } - var ( - err error - param interface{} - i64 int64 - ) - for k, v := range config.PathParamsMap { - if k < 0 || k >= argsLength { - logger.Errorf("[Go restful] Path param parse error, the args:%v doesn't exist", k) - continue - } - t := argsTypes[k] - kind := t.Kind() - if kind == reflect.Ptr { - t = t.Elem() - } - if kind == reflect.Int { - param, err = strconv.Atoi(req.PathParameter(v)) - } else if kind == reflect.Int32 { - i64, err = strconv.ParseInt(req.PathParameter(v), 10, 32) - if err == nil { - param = int32(i64) - } - } else if kind == reflect.Int64 { - param, err = strconv.ParseInt(req.PathParameter(v), 10, 64) - } else if kind == reflect.String { - param = req.PathParameter(v) - } else { - logger.Warnf("[Go restful] Path param parse error, the args:%v of type isn't int or string", k) - continue - } - if err != nil { - logger.Errorf("[Go restful] Path param parse error, error is %v", err) - continue - } - args[k] = param - } - for k, v := range config.QueryParamsMap { - if k < 0 || k >= argsLength { - logger.Errorf("[Go restful] Query param parse error, the args:%v doesn't exist", k) - continue - } - t := argsTypes[k] - kind := t.Kind() - if kind == reflect.Ptr { - t = t.Elem() - } - if kind == reflect.Slice { - param = req.QueryParameters(v) - } else if kind == reflect.String { - param = req.QueryParameter(v) - } else if kind == reflect.Int { - param, err = strconv.Atoi(req.QueryParameter(v)) - } else if kind == reflect.Int32 { - i64, err = strconv.ParseInt(req.QueryParameter(v), 10, 32) - if err == nil { - param = int32(i64) - } - } else if kind == reflect.Int64 { - param, err = strconv.ParseInt(req.QueryParameter(v), 10, 64) - } else { - logger.Errorf("[Go restful] Query param parse error, the args:%v of type isn't int or string or slice", k) - continue - } - if err != nil { - logger.Errorf("[Go restful] Query param parse error, error is %v", err) - continue - } - args[k] = param - } +// GoRestfulRequestAdapter a adapter struct about RestServerRequest +type GoRestfulRequestAdapter struct { + server.RestServerRequest + request *restful.Request +} - if config.Body >= 0 && config.Body < len(argsTypes) { - t := argsTypes[config.Body] - kind := t.Kind() - if kind == reflect.Ptr { - t = t.Elem() - } - var ni interface{} - if t.String() == "[]interface {}" { - ni = make([]map[string]interface{}, 0) - } else if t.String() == "interface {}" { - ni = make(map[string]interface{}) - } else { - n := reflect.New(t) - if n.CanInterface() { - ni = n.Interface() - } - } - if err := req.ReadEntity(&ni); err != nil { - logger.Errorf("[Go restful] Read body entity error:%v", err) - } else { - args[config.Body] = ni - } - } +// NewGoRestfulRequestAdapter a constructor of GoRestfulRequestAdapter +func NewGoRestfulRequestAdapter(request *restful.Request) *GoRestfulRequestAdapter { + return &GoRestfulRequestAdapter{request: request} +} - for k, v := range config.HeadersMap { - param := req.HeaderParameter(v) - if k < 0 || k >= argsLength { - logger.Errorf("[Go restful] Header param parse error, the args:%v doesn't exist", k) - continue - } - t := argsTypes[k] - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - if t.Kind() == reflect.String { - args[k] = param - } else { - logger.Errorf("[Go restful] Header param parse error, the args:%v of type isn't string", k) - } - } +// RawRequest a adapter function of server.RestServerRequest's RawRequest +func (grra *GoRestfulRequestAdapter) RawRequest() *http.Request { + return grra.request.Request +} - return args +// PathParameter a adapter function of server.RestServerRequest's PathParameter +func (grra *GoRestfulRequestAdapter) PathParameter(name string) string { + return grra.request.PathParameter(name) } -func GetNewGoRestfulServer() server.RestServer { - return NewGoRestfulServer() +// PathParameters a adapter function of server.RestServerRequest's QueryParameter +func (grra *GoRestfulRequestAdapter) PathParameters() map[string]string { + return grra.request.PathParameters() } -// Let user addFilter -// addFilter should before config.Load() -func AddGoRestfulServerFilter(filterFuc restful.FilterFunction) { - filterSlice = append(filterSlice, filterFuc) +// QueryParameter a adapter function of server.RestServerRequest's QueryParameters +func (grra *GoRestfulRequestAdapter) QueryParameter(name string) string { + return grra.request.QueryParameter(name) +} + +// QueryParameters a adapter function of server.RestServerRequest's QueryParameters +func (grra *GoRestfulRequestAdapter) QueryParameters(name string) []string { + return grra.request.QueryParameters(name) +} + +// BodyParameter a adapter function of server.RestServerRequest's BodyParameter +func (grra *GoRestfulRequestAdapter) BodyParameter(name string) (string, error) { + return grra.request.BodyParameter(name) +} + +// HeaderParameter a adapter function of server.RestServerRequest's HeaderParameter +func (grra *GoRestfulRequestAdapter) HeaderParameter(name string) string { + return grra.request.HeaderParameter(name) +} + +// ReadEntity a adapter func of server.RestServerRequest's ReadEntity +func (grra *GoRestfulRequestAdapter) ReadEntity(entityPointer interface{}) error { + return grra.request.ReadEntity(entityPointer) } diff --git a/protocol/rpc_status_test.go b/protocol/rpc_status_test.go index 5a07f44eab0db60ba65a155d6c6190ab4ce2d716..611b7cba6e453cdf00624b4414d468278fd62cb1 100644 --- a/protocol/rpc_status_test.go +++ b/protocol/rpc_status_test.go @@ -1,3 +1,20 @@ +/* + * 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 protocol import ( diff --git a/registry/base_registry.go b/registry/base_registry.go index 3b64e93e2f6b5b58a70650f589dec3ca092376c1..3e1bddf233310871182544b6415c10c8df27e622 100644 --- a/registry/base_registry.go +++ b/registry/base_registry.go @@ -121,6 +121,7 @@ func (r *BaseRegistry) Destroy() { close(r.done) // wait waitgroup done (wait listeners outside close over) r.wg.Wait() + //close registry client r.closeRegisters() } @@ -178,7 +179,10 @@ func (r *BaseRegistry) RestartCallBack() bool { } logger.Infof("success to re-register service :%v", confIf.Key()) } - r.facadeBasedRegistry.InitListeners() + + if flag { + r.facadeBasedRegistry.InitListeners() + } return flag } @@ -245,19 +249,13 @@ func (r *BaseRegistry) providerRegistry(c common.URL, params url.Values) (string logger.Errorf("facadeBasedRegistry.CreatePath(path{%s}) = error{%#v}", dubboPath, perrors.WithStack(err)) return "", "", perrors.WithMessagef(err, "facadeBasedRegistry.CreatePath(path:%s)", dubboPath) } - params.Add("anyhost", "true") + params.Add(constant.ANYHOST_KEY, "true") // Dubbo java consumer to start looking for the provider url,because the category does not match, // the provider will not find, causing the consumer can not start, so we use consumers. - // DubboRole = [...]string{"consumer", "", "", "provider"} - // params.Add("category", (RoleType(PROVIDER)).Role()) - params.Add("category", (common.RoleType(common.PROVIDER)).String()) - params.Add("dubbo", "dubbo-provider-golang-"+constant.Version) - - params.Add("side", (common.RoleType(common.PROVIDER)).Role()) if len(c.Methods) == 0 { - params.Add("methods", strings.Join(c.Methods, ",")) + params.Add(constant.METHODS_KEY, strings.Join(c.Methods, ",")) } logger.Debugf("provider url params:%#v", params) var host string @@ -308,9 +306,6 @@ func (r *BaseRegistry) consumerRegistry(c common.URL, params url.Values) (string } params.Add("protocol", c.Protocol) - params.Add("category", (common.RoleType(common.CONSUMER)).String()) - params.Add("dubbo", "dubbogo-consumer-"+constant.Version) - rawURL = fmt.Sprintf("consumer://%s%s?%s", localIP, c.Path, params.Encode()) dubboPath = fmt.Sprintf("/dubbo/%s/%s", r.service(c), (common.RoleType(common.CONSUMER)).String()) diff --git a/registry/directory/directory.go b/registry/directory/directory.go index a6d2cdf49b0935b2402e03208d1ff5f702e1cc52..20be268d7401976ef1b7884f2a7bd40eeacb8158 100644 --- a/registry/directory/directory.go +++ b/registry/directory/directory.go @@ -127,12 +127,13 @@ func (dir *registryDirectory) refreshInvokers(res *registry.ServiceEvent) { } else if url.Protocol == constant.ROUTER_PROTOCOL || //2.for router url.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY) == constant.ROUTER_CATEGORY { url = nil + } switch res.Action { case remoting.EventTypeAdd, remoting.EventTypeUpdate: logger.Infof("selector add service url{%s}", res.Service) - var urls []*common.URL + var urls []*common.URL for _, v := range directory.GetRouterURLSet().Values() { urls = append(urls, v.(*common.URL)) } @@ -140,8 +141,6 @@ func (dir *registryDirectory) refreshInvokers(res *registry.ServiceEvent) { if len(urls) > 0 { dir.SetRouters(urls) } - - //dir.cacheService.EventTypeAdd(res.Path, dir.serviceTTL) oldInvoker = dir.cacheInvoker(url) case remoting.EventTypeDel: oldInvoker = dir.uncacheInvoker(url) diff --git a/registry/etcdv3/registry.go b/registry/etcdv3/registry.go index e1c25768119ea7d7122b9aa22a5f881db44bafd9..5d389c36374fe9de5561418bc90d44a7d780fd48 100644 --- a/registry/etcdv3/registry.go +++ b/registry/etcdv3/registry.go @@ -164,9 +164,7 @@ func (r *etcdV3Registry) DoSubscribe(svc *common.URL) (registry.Listener, error) //register the svc to dataListener r.dataListener.AddInterestedURL(svc) - for _, v := range strings.Split(svc.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), ",") { - go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+v, svc.Service()), r.dataListener) - } + go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+constant.DEFAULT_CATEGORY, svc.Service()), r.dataListener) return configListener, nil } diff --git a/registry/etcdv3/registry_test.go b/registry/etcdv3/registry_test.go index dc4e382979d910e4f42453fa0a409afbcb0ecabc..164fe9ca61793614e3d9d2f77f49cdfaebdd7317 100644 --- a/registry/etcdv3/registry_test.go +++ b/registry/etcdv3/registry_test.go @@ -63,7 +63,7 @@ func (suite *RegistryTestSuite) TestRegister() { if err != nil { t.Fatal(err) } - assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-1.3.0%26.*provider", children) + assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26cluster%3Dmock", children) assert.NoError(t, err) } diff --git a/registry/event.go b/registry/event.go index be9f11d00bb5a70b0d787d15bcdc98471aad0a4b..6f647185cc213b80b9ab25b4702f91b36aa8ad4b 100644 --- a/registry/event.go +++ b/registry/event.go @@ -25,6 +25,7 @@ import ( import ( "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/observer" "github.com/apache/dubbo-go/remoting" ) @@ -47,47 +48,9 @@ func (e ServiceEvent) String() string { return fmt.Sprintf("ServiceEvent{Action{%s}, Path{%s}}", e.Action, e.Service) } -// Event is align with Event interface in Java. -// it's the top abstraction -// Align with 2.7.5 -type Event interface { - fmt.Stringer - GetSource() interface{} - GetTimestamp() time.Time -} - -// baseEvent is the base implementation of Event -// You should never use it directly -type baseEvent struct { - source interface{} - timestamp time.Time -} - -// GetSource return the source -func (b *baseEvent) GetSource() interface{} { - return b.source -} - -// GetTimestamp return the timestamp when the event is created -func (b *baseEvent) GetTimestamp() time.Time { - return b.timestamp -} - -// String return a human readable string representing this event -func (b *baseEvent) String() string { - return fmt.Sprintf("baseEvent[source = %#v]", b.source) -} - -func newBaseEvent(source interface{}) *baseEvent { - return &baseEvent{ - source: source, - timestamp: time.Now(), - } -} - // ServiceInstancesChangedEvent represents service instances make some changing type ServiceInstancesChangedEvent struct { - baseEvent + observer.BaseEvent ServiceName string Instances []ServiceInstance } @@ -100,9 +63,9 @@ func (s *ServiceInstancesChangedEvent) String() string { // NewServiceInstancesChangedEvent will create the ServiceInstanceChangedEvent instance func NewServiceInstancesChangedEvent(serviceName string, instances []ServiceInstance) *ServiceInstancesChangedEvent { return &ServiceInstancesChangedEvent{ - baseEvent: baseEvent{ - source: serviceName, - timestamp: time.Now(), + BaseEvent: observer.BaseEvent{ + Source: serviceName, + Timestamp: time.Now(), }, ServiceName: serviceName, Instances: instances, diff --git a/registry/event_listener.go b/registry/event_listener.go index b8d6148442d9e10e210958dead690c4a95b33fb6..0aaa081a4488de5c291485277cdc0fc14ef4e380 100644 --- a/registry/event_listener.go +++ b/registry/event_listener.go @@ -18,25 +18,27 @@ package registry import ( - gxsort "github.com/dubbogo/gost/sort" + "reflect" ) -// EventListener is an new interface used to align with dubbo 2.7.5 -// It contains the Prioritized means that the listener has its priority -type EventListener interface { - gxsort.Prioritizer - // OnEvent handle this event - OnEvent(e Event) error -} - -// ConditionalEventListener only handle the event which it can handle -type ConditionalEventListener interface { - EventListener - // Accept will make the decision whether it should handle this event - Accept(e Event) bool -} +import ( + "github.com/apache/dubbo-go/common/observer" +) // TODO (implement ConditionalEventListener) type ServiceInstancesChangedListener struct { ServiceName string + observer.EventListener +} + +func (sicl *ServiceInstancesChangedListener) OnEvent(e observer.Event) error { + return nil +} + +func (sicl *ServiceInstancesChangedListener) GetPriority() int { + return -1 +} + +func (sicl *ServiceInstancesChangedListener) GetEventType() reflect.Type { + return reflect.TypeOf(&ServiceInstancesChangedEvent{}) } diff --git a/registry/kubernetes/registry.go b/registry/kubernetes/registry.go index 7212a83d63b34cc08f193994f004efccf9e21a0c..8a02d0e3e693b58946a97e7b47238e0be4272dcf 100644 --- a/registry/kubernetes/registry.go +++ b/registry/kubernetes/registry.go @@ -21,7 +21,6 @@ import ( "fmt" "os" "path" - "strings" "sync" "time" ) @@ -135,9 +134,7 @@ func (r *kubernetesRegistry) DoSubscribe(svc *common.URL) (registry.Listener, er //register the svc to dataListener r.dataListener.AddInterestedURL(svc) - for _, v := range strings.Split(svc.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), ",") { - go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+v, svc.Service()), r.dataListener) - } + go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+constant.DEFAULT_CATEGORY, svc.Service()), r.dataListener) return configListener, nil } diff --git a/registry/nacos/base_registry.go b/registry/nacos/base_registry.go index bd5dc86b4376a4cc81644df332c60009379a24ec..63f4999675470853d0f48d1a22b709efdc1c9d26 100644 --- a/registry/nacos/base_registry.go +++ b/registry/nacos/base_registry.go @@ -38,22 +38,22 @@ import ( // baseRegistry is the parent of both interface-level registry // and service discovery(related to application-level registry) -type baseRegistry struct { +type nacosBaseRegistry struct { *common.URL namingClient naming_client.INamingClient } // newBaseRegistry will create new instance -func newBaseRegistry(url *common.URL) (baseRegistry, error) { +func newBaseRegistry(url *common.URL) (nacosBaseRegistry, error) { nacosConfig, err := getNacosConfig(url) if err != nil { - return baseRegistry{}, err + return nacosBaseRegistry{}, err } client, err := clients.CreateNamingClient(nacosConfig) if err != nil { - return baseRegistry{}, err + return nacosBaseRegistry{}, err } - registry := baseRegistry{ + registry := nacosBaseRegistry{ URL: url, namingClient: client, } diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go index b0f399862af6fff64b4db346648d1486ad9fafc7..a436b85064829b9f42c9dcc45545e5bf2fd2fefe 100644 --- a/registry/nacos/registry.go +++ b/registry/nacos/registry.go @@ -53,7 +53,7 @@ func init() { } type nacosRegistry struct { - baseRegistry + nacosBaseRegistry } // newNacosRegistry will create an instance diff --git a/registry/nacos/service_discovery.go b/registry/nacos/service_discovery.go index b89d4f611bd4193085164225cf1271e037ed7548..8ef72c1b11dca257103c155534b68cbd522d358f 100644 --- a/registry/nacos/service_discovery.go +++ b/registry/nacos/service_discovery.go @@ -47,7 +47,7 @@ func init() { // There is a problem, the go client for nacos does not support the id field. // we will use the metadata to store the id of ServiceInstance type nacosServiceDiscovery struct { - baseRegistry + nacosBaseRegistry group string } @@ -279,7 +279,7 @@ func newNacosServiceDiscovery(url *common.URL) (registry.ServiceDiscovery, error return nil, perrors.WithStack(err) } return &nacosServiceDiscovery{ - baseRegistry: base, + nacosBaseRegistry: base, group: url.GetParam(constant.NACOS_GROUP, defaultGroup), }, nil } diff --git a/registry/protocol/protocol.go b/registry/protocol/protocol.go index a7678ba4e2f38cfeb77f202103e03066a7efdbef..b47b9f372da8948d1add97c7b354503e18e23511 100644 --- a/registry/protocol/protocol.go +++ b/registry/protocol/protocol.go @@ -45,6 +45,7 @@ import ( var ( regProtocol *registryProtocol + once sync.Once ) type registryProtocol struct { @@ -346,12 +347,12 @@ func setProviderUrl(regURL *common.URL, providerURL *common.URL) { regURL.SubURL = providerURL } -// GetProtocol ... +// GetProtocol return the singleton RegistryProtocol func GetProtocol() protocol.Protocol { - if regProtocol != nil { - return regProtocol - } - return newRegistryProtocol() + once.Do(func() { + regProtocol = newRegistryProtocol() + }) + return regProtocol } type wrappedInvoker struct { diff --git a/registry/zookeeper/listener.go b/registry/zookeeper/listener.go index bef1760e04fd6597721fd19b5d19820f45ed2bf0..c5b2f33c6107e82aa172c818c0d8aca1483248c6 100644 --- a/registry/zookeeper/listener.go +++ b/registry/zookeeper/listener.go @@ -35,23 +35,28 @@ import ( zk "github.com/apache/dubbo-go/remoting/zookeeper" ) -// RegistryDataListener ... +// RegistryDataListener contains all URL information subscribed by zookeeper registry type RegistryDataListener struct { - interestedURL []*common.URL - listener config_center.ConfigurationListener + subscribed map[*common.URL]config_center.ConfigurationListener + mutex sync.Mutex + closed bool } -// NewRegistryDataListener ... -func NewRegistryDataListener(listener config_center.ConfigurationListener) *RegistryDataListener { - return &RegistryDataListener{listener: listener} +// NewRegistryDataListener constructs a new RegistryDataListener +func NewRegistryDataListener() *RegistryDataListener { + return &RegistryDataListener{ + subscribed: make(map[*common.URL]config_center.ConfigurationListener)} } -// AddInterestedURL ... -func (l *RegistryDataListener) AddInterestedURL(url *common.URL) { - l.interestedURL = append(l.interestedURL, url) +// SubscribeURL is used to set a watch listener for url +func (l *RegistryDataListener) SubscribeURL(url *common.URL, listener config_center.ConfigurationListener) { + if l.closed { + return + } + l.subscribed[url] = listener } -// DataChange ... +// DataChange accepts all events sent from the zookeeper server and trigger the corresponding listener for processing func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool { // Intercept the last bit index := strings.Index(eventType.Path, "/providers/") @@ -65,10 +70,14 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool { logger.Errorf("Listen NewURL(r{%s}) = error{%v} eventType.Path={%v}", url, err, eventType.Path) return false } - - for _, v := range l.interestedURL { - if serviceURL.URLEqual(*v) { - l.listener.Process( + l.mutex.Lock() + defer l.mutex.Unlock() + if l.closed { + return false + } + for url, listener := range l.subscribed { + if serviceURL.URLEqual(*url) { + listener.Process( &config_center.ConfigChangeEvent{ Key: eventType.Path, Value: serviceURL, @@ -81,38 +90,48 @@ func (l *RegistryDataListener) DataChange(eventType remoting.Event) bool { return false } -// RegistryConfigurationListener ... +// Close all RegistryConfigurationListener in subscribed +func (l *RegistryDataListener) Close() { + l.mutex.Lock() + defer l.mutex.Unlock() + for _, listener := range l.subscribed { + listener.(*RegistryConfigurationListener).Close() + } +} + +// RegistryConfigurationListener represent the processor of zookeeper watcher type RegistryConfigurationListener struct { client *zk.ZookeeperClient registry *zkRegistry events chan *config_center.ConfigChangeEvent isClosed bool + close chan struct{} closeOnce sync.Once } // NewRegistryConfigurationListener for listening the event of zk. func NewRegistryConfigurationListener(client *zk.ZookeeperClient, reg *zkRegistry) *RegistryConfigurationListener { reg.WaitGroup().Add(1) - return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32), isClosed: false} + return &RegistryConfigurationListener{client: client, registry: reg, events: make(chan *config_center.ConfigChangeEvent, 32), isClosed: false, close: make(chan struct{}, 1)} } -// Process ... +// Process submit the ConfigChangeEvent to the event chan to notify all observer func (l *RegistryConfigurationListener) Process(configType *config_center.ConfigChangeEvent) { l.events <- configType } -// Next ... +// Next will observe the registry state and events chan func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) { for { select { case <-l.client.Done(): - logger.Warnf("listener's zk client connection is broken, so zk event listener exit now.") - return nil, perrors.New("listener stopped") - + logger.Warnf("listener's zk client connection (address {%s}) is broken, so zk event listener exit now.", l.client.ZkAddrs) + return nil, perrors.New("zookeeper client stopped") + case <-l.close: + return nil, perrors.New("listener have been closed") case <-l.registry.Done(): - logger.Warnf("zk consumer register has quit, so zk event listener exit now.") - return nil, perrors.New("listener stopped") - + logger.Warnf("zk consumer register has quit, so zk event listener exit now. (registry url {%v}", l.registry.BaseRegistry.URL) + return nil, perrors.New("zookeeper registry, (registry url{%v}) stopped") case e := <-l.events: logger.Debugf("got zk event %s", e) if e.ConfigType == remoting.EventTypeDel && !l.valid() { @@ -127,15 +146,17 @@ func (l *RegistryConfigurationListener) Next() (*registry.ServiceEvent, error) { } } -// Close ... +// Close RegistryConfigurationListener only once func (l *RegistryConfigurationListener) Close() { // ensure that the listener will be closed at most once. l.closeOnce.Do(func() { l.isClosed = true + l.close <- struct{}{} l.registry.WaitGroup().Done() }) } +// valid return the true if the client conn isn't nil func (l *RegistryConfigurationListener) valid() bool { return l.client.ZkConnValid() } diff --git a/registry/zookeeper/listener_test.go b/registry/zookeeper/listener_test.go index 1a76b29a6f64e0329b289ce50218032a25f6f5cd..a0e9147a9e0ee8767efcf78d5e2aa536140f6a8b 100644 --- a/registry/zookeeper/listener_test.go +++ b/registry/zookeeper/listener_test.go @@ -32,15 +32,15 @@ import ( ) func Test_DataChange(t *testing.T) { - listener := NewRegistryDataListener(&MockDataListener{}) + listener := NewRegistryDataListener() url, _ := common.NewURL("jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100") - listener.AddInterestedURL(&url) + listener.SubscribeURL(&url, &MockConfigurationListener{}) int := listener.DataChange(remoting.Event{Path: "/dubbo/com.ikurento.user.UserProvider/providers/jsonrpc%3A%2F%2F127.0.0.1%3A20001%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26app.version%3D0.0.1%26application%3DBDTService%26category%3Dproviders%26cluster%3Dfailover%26dubbo%3Ddubbo-provider-golang-1.3.0%26environment%3Ddev%26group%3D%26interface%3Dcom.ikurento.user.UserProvider%26ip%3D10.32.20.124%26loadbalance%3Drandom%26methods.GetUser.loadbalance%3Drandom%26methods.GetUser.retries%3D1%26methods.GetUser.weight%3D0%26module%3Ddubbogo%2Buser-info%2Bserver%26name%3DBDTService%26organization%3Dikurento.com%26owner%3DZX%26pid%3D74500%26retries%3D0%26service.filter%3Decho%26side%3Dprovider%26timestamp%3D1560155407%26version%3D%26warmup%3D100"}) assert.Equal(t, true, int) } -type MockDataListener struct { +type MockConfigurationListener struct { } -func (*MockDataListener) Process(configType *config_center.ConfigChangeEvent) { +func (*MockConfigurationListener) Process(configType *config_center.ConfigChangeEvent) { } diff --git a/registry/zookeeper/registry.go b/registry/zookeeper/registry.go index e13443d57d7dae9fb5d50b2e1c28f618780fd850..88d5d6221b4bc7136ba4c3e7c95fb53ba35a9a58 100644 --- a/registry/zookeeper/registry.go +++ b/registry/zookeeper/registry.go @@ -20,7 +20,6 @@ package zookeeper import ( "fmt" "net/url" - "strings" "sync" "time" ) @@ -54,12 +53,11 @@ func init() { type zkRegistry struct { registry.BaseRegistry - client *zookeeper.ZookeeperClient - listenerLock sync.Mutex - listener *zookeeper.ZkEventListener - dataListener *RegistryDataListener - configListener *RegistryConfigurationListener - cltLock sync.Mutex + client *zookeeper.ZookeeperClient + listenerLock sync.Mutex + listener *zookeeper.ZkEventListener + dataListener *RegistryDataListener + cltLock sync.Mutex //for provider zkPath map[string]int // key = protocol://ip:port/interface } @@ -78,13 +76,12 @@ func newZkRegistry(url *common.URL) (registry.Registry, error) { if err != nil { return nil, err } - r.WaitGroup().Add(1) //zk client start successful, then wg +1 go zookeeper.HandleClientRestart(r) r.listener = zookeeper.NewZkEventListener(r.client) - r.configListener = NewRegistryConfigurationListener(r.client, r) - r.dataListener = NewRegistryDataListener(r.configListener) + + r.dataListener = NewRegistryDataListener() return r, nil } @@ -121,8 +118,27 @@ func newMockZkRegistry(url *common.URL, opts ...zookeeper.Option) (*zk.TestClust func (r *zkRegistry) InitListeners() { r.listener = zookeeper.NewZkEventListener(r.client) - r.configListener = NewRegistryConfigurationListener(r.client, r) - r.dataListener = NewRegistryDataListener(r.configListener) + newDataListener := NewRegistryDataListener() + // should recover if dataListener isn't nil before + if r.dataListener != nil { + // close all old listener + oldDataListener := r.dataListener + oldDataListener.mutex.Lock() + defer oldDataListener.mutex.Unlock() + recoverd := r.dataListener.subscribed + if recoverd != nil && len(recoverd) > 0 { + // recover all subscribed url + for conf, oldListener := range recoverd { + if regConfigListener, ok := oldListener.(*RegistryConfigurationListener); ok { + regConfigListener.Close() + } + newDataListener.SubscribeURL(conf, NewRegistryConfigurationListener(r.client, r)) + go r.listener.ListenServiceEvent(conf, fmt.Sprintf("/dubbo/%s/"+constant.DEFAULT_CATEGORY, url.QueryEscape(conf.Service())), newDataListener) + + } + } + } + r.dataListener = newDataListener } func (r *zkRegistry) CreatePath(path string) error { @@ -155,8 +171,8 @@ func (r *zkRegistry) ZkClientLock() *sync.Mutex { } func (r *zkRegistry) CloseListener() { - if r.configListener != nil { - r.configListener.Close() + if r.dataListener != nil { + r.dataListener.Close() } } @@ -173,32 +189,49 @@ func (r *zkRegistry) registerTempZookeeperNode(root string, node string) error { logger.Errorf("zk.Create(root{%s}) = err{%v}", root, perrors.WithStack(err)) return perrors.WithStack(err) } + + // try to register the node zkPath, err = r.client.RegisterTemp(root, node) if err != nil { - if err == zk.ErrNodeExists { - logger.Warnf("RegisterTempNode(root{%s}, node{%s}) = error{%v}", root, node, perrors.WithStack(err)) - } else { - logger.Errorf("RegisterTempNode(root{%s}, node{%s}) = error{%v}", root, node, perrors.WithStack(err)) + logger.Errorf("Register temp node(root{%s}, node{%s}) = error{%v}", root, node, perrors.WithStack(err)) + if perrors.Cause(err) == zk.ErrNodeExists { + // should delete the old node + logger.Info("Register temp node failed, try to delete the old and recreate (root{%s}, node{%s}) , ignore!", root, node) + if err = r.client.Delete(zkPath); err == nil { + _, err = r.client.RegisterTemp(root, node) + } + if err != nil { + logger.Errorf("Recreate the temp node failed, (root{%s}, node{%s}) = error{%v}", root, node, perrors.WithStack(err)) + } } return perrors.WithMessagef(err, "RegisterTempNode(root{%s}, node{%s})", root, node) } - logger.Debugf("create a zookeeper node:%s", zkPath) + logger.Debugf("Create a zookeeper node:%s", zkPath) return nil } func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListener, error) { - var ( - zkListener *RegistryConfigurationListener - ) - r.listenerLock.Lock() - if r.configListener.isClosed { - r.listenerLock.Unlock() - return nil, perrors.New("configListener already been closed") + var zkListener *RegistryConfigurationListener + dataListener := r.dataListener + dataListener.mutex.Lock() + defer dataListener.mutex.Unlock() + if r.dataListener.subscribed[conf] != nil { + + zkListener, _ := r.dataListener.subscribed[conf].(*RegistryConfigurationListener) + if zkListener != nil { + r.listenerLock.Lock() + defer r.listenerLock.Unlock() + if zkListener.isClosed { + return nil, perrors.New("configListener already been closed") + } else { + return zkListener, nil + } + } } - zkListener = r.configListener - r.listenerLock.Unlock() + + zkListener = NewRegistryConfigurationListener(r.client, r) if r.listener == nil { r.cltLock.Lock() client := r.client @@ -216,10 +249,9 @@ func (r *zkRegistry) getListener(conf *common.URL) (*RegistryConfigurationListen } //Interested register to dataconfig. - r.dataListener.AddInterestedURL(conf) - for _, v := range strings.Split(conf.GetParam(constant.CATEGORY_KEY, constant.DEFAULT_CATEGORY), ",") { - go r.listener.ListenServiceEvent(fmt.Sprintf("/dubbo/%s/"+v, url.QueryEscape(conf.Service())), r.dataListener) - } + r.dataListener.SubscribeURL(conf, zkListener) + + go r.listener.ListenServiceEvent(conf, fmt.Sprintf("/dubbo/%s/"+constant.DEFAULT_CATEGORY, url.QueryEscape(conf.Service())), r.dataListener) return zkListener, nil } diff --git a/registry/zookeeper/registry_test.go b/registry/zookeeper/registry_test.go index 0d7623ca12a9b4e49f84ec988c796f2e913d537f..688deccfbec67771c4071f6307802a16e4e0fc8b 100644 --- a/registry/zookeeper/registry_test.go +++ b/registry/zookeeper/registry_test.go @@ -41,7 +41,7 @@ func Test_Register(t *testing.T) { defer ts.Stop() err := reg.Register(url) children, _ := reg.client.GetChildren("/dubbo/com.ikurento.user.UserProvider/providers") - assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26category%3Dproviders%26cluster%3Dmock%26dubbo%3Ddubbo-provider-golang-1.3.0%26.*.serviceid%3Dsoa.mock%26.*provider", children) + assert.Regexp(t, ".*dubbo%3A%2F%2F127.0.0.1%3A20000%2Fcom.ikurento.user.UserProvider%3Fanyhost%3Dtrue%26cluster%3Dmock%26.*.serviceid%3Dsoa.mock", children) assert.NoError(t, err) } diff --git a/remoting/zookeeper/client.go b/remoting/zookeeper/client.go index 7dac6146fa2aab88771ef5b7cb0205736e6478a9..bd1da547766abb12dc742234787262212e3db314 100644 --- a/remoting/zookeeper/client.go +++ b/remoting/zookeeper/client.go @@ -118,7 +118,7 @@ func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error { for _, opt := range opts { opt(opions) } - + connected := false err = nil lock := container.ZkClientLock() @@ -143,6 +143,7 @@ func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error { return perrors.WithMessagef(err, "newZookeeperClient(address:%+v)", url.Location) } container.SetZkClient(newClient) + connected = true } if container.ZkClient().Conn == nil { @@ -150,10 +151,16 @@ func ValidateZookeeperClient(container zkClientFacade, opts ...Option) error { container.ZkClient().Conn, event, err = zk.Connect(container.ZkClient().ZkAddrs, container.ZkClient().Timeout) if err == nil { container.ZkClient().Wait.Add(1) + connected = true go container.ZkClient().HandleZkEvent(event) } } + if connected { + logger.Info("Connect to zookeeper successfully, name{%s}, zk address{%v}", opions.zkName, url.Location) + container.WaitGroup().Add(1) //zk client start successful, then registry wg +1 + } + return perrors.WithMessagef(err, "newZookeeperClient(address:%+v)", url.PrimitiveURL) } @@ -386,6 +393,7 @@ func (z *ZookeeperClient) Close() { z.Conn = nil z.Unlock() if conn != nil { + logger.Warnf("zkClient Conn{name:%s, zk addr:%s} exit now.", z.name, conn.SessionID()) conn.Close() } @@ -470,7 +478,7 @@ func (z *ZookeeperClient) RegisterTemp(basePath string, node string) (string, er //if err != nil && err != zk.ErrNodeExists { if err != nil { logger.Warnf("conn.Create(\"%s\", zk.FlagEphemeral) = error(%v)\n", zkPath, perrors.WithStack(err)) - return "", perrors.WithStack(err) + return zkPath, perrors.WithStack(err) } logger.Debugf("zkClient{%s} create a temp zookeeper node:%s\n", z.name, tmpPath) diff --git a/remoting/zookeeper/facade.go b/remoting/zookeeper/facade.go index 055db4f716a914354d1bada653fbc0a850b615b5..4e3945388ff402f60a02150615a8914f9cba2435 100644 --- a/remoting/zookeeper/facade.go +++ b/remoting/zookeeper/facade.go @@ -48,11 +48,11 @@ func HandleClientRestart(r zkClientFacade) { failTimes int ) - defer r.WaitGroup().Done() LOOP: for { select { case <-r.Done(): + r.WaitGroup().Done() // dec the wg when registry is closed logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") break LOOP // re-register all services @@ -63,12 +63,14 @@ LOOP: zkAddress := r.ZkClient().ZkAddrs r.SetZkClient(nil) r.ZkClientLock().Unlock() + r.WaitGroup().Done() // dec the wg when zk client is closed // Connect zk until success. failTimes = 0 for { select { case <-r.Done(): + r.WaitGroup().Done() // dec the wg when registry is closed logger.Warnf("(ZkProviderRegistry)reconnectZkRegistry goroutine exit now...") break LOOP case <-getty.GetTimeWheel().After(timeSecondDuration(failTimes * ConnDelay)): // Prevent crazy reconnection zk. diff --git a/remoting/zookeeper/facade_test.go b/remoting/zookeeper/facade_test.go index a41f6cd3230700332519ce1c2d3489bfcc4b6ef0..01d46da6cc1abae90210a323d32ac84bad80249b 100644 --- a/remoting/zookeeper/facade_test.go +++ b/remoting/zookeeper/facade_test.go @@ -38,6 +38,16 @@ type mockFacade struct { done chan struct{} } +func newMockFacade(client *ZookeeperClient, url *common.URL) zkClientFacade { + mock := &mockFacade{ + client: client, + URL: url, + } + + mock.wg.Add(1) + return mock +} + func (r *mockFacade) ZkClient() *ZookeeperClient { return r.client } @@ -80,7 +90,7 @@ func Test_Facade(t *testing.T) { assert.NoError(t, err) defer ts.Stop() url, _ := common.NewURL("mock://127.0.0.1") - mock := &mockFacade{client: z, URL: &url} + mock := newMockFacade(z, &url) go HandleClientRestart(mock) states := []zk.State{zk.StateConnecting, zk.StateConnected, zk.StateHasSession} verifyEventStateOrder(t, event, states, "event channel") diff --git a/remoting/zookeeper/listener.go b/remoting/zookeeper/listener.go index eaf259f4417201c95172e95d7a87476575e004d5..84877667763ce870e76202844e9dc9dc1c3f008c 100644 --- a/remoting/zookeeper/listener.go +++ b/remoting/zookeeper/listener.go @@ -18,6 +18,7 @@ package zookeeper import ( + "github.com/apache/dubbo-go/common" "path" "strings" "sync" @@ -173,7 +174,7 @@ func (l *ZkEventListener) handleZkNodeEvent(zkPath string, children []string, li } } -func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataListener) { +func (l *ZkEventListener) listenDirEvent(conf *common.URL, zkPath string, listener remoting.DataListener) { defer l.wg.Done() var ( @@ -224,7 +225,16 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi } failTimes = 0 for _, c := range children { - // listen l service node + + // Only need to compare Path when subscribing to provider + if strings.LastIndex(zkPath, constant.PROVIDER_CATEGORY) != -1 { + provider, _ := common.NewURL(c) + if provider.Path != conf.Path { + continue + } + } + + //listen l service node dubboPath := path.Join(zkPath, c) //Save the path to avoid listen repeatedly @@ -232,7 +242,7 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi _, ok := l.pathMap[dubboPath] l.pathMapLock.Unlock() if ok { - logger.Warnf("@zkPath %s has already been listened.", zkPath) + logger.Warnf("@zkPath %s has already been listened.", dubboPath) continue } @@ -263,7 +273,7 @@ func (l *ZkEventListener) listenDirEvent(zkPath string, listener remoting.DataLi strings.LastIndex(zkPath, constant.CONSUMER_CATEGORY) == -1 { l.wg.Add(1) go func(zkPath string, listener remoting.DataListener) { - l.listenDirEvent(zkPath, listener) + l.listenDirEvent(conf, zkPath, listener) logger.Warnf("listenDirEvent(zkPath{%s}) goroutine exit now", zkPath) }(dubboPath, listener) } @@ -291,11 +301,11 @@ func timeSecondDuration(sec int) time.Duration { // registry.go:Listen -> listenServiceEvent -> listenDirEvent -> ListenServiceNodeEvent // | // --------> ListenServiceNodeEvent -func (l *ZkEventListener) ListenServiceEvent(zkPath string, listener remoting.DataListener) { +func (l *ZkEventListener) ListenServiceEvent(conf *common.URL, zkPath string, listener remoting.DataListener) { logger.Infof("listen dubbo path{%s}", zkPath) l.wg.Add(1) go func(zkPath string, listener remoting.DataListener) { - l.listenDirEvent(zkPath, listener) + l.listenDirEvent(conf, zkPath, listener) logger.Warnf("listenDirEvent(zkPath{%s}) goroutine exit now", zkPath) }(zkPath, listener) } diff --git a/remoting/zookeeper/listener_test.go b/remoting/zookeeper/listener_test.go index 7301cd52c392b6950b3a49f78e8124eae532b083..ba7d6ba81b6af97dc5ad3788e8399d08cbe5b2bb 100644 --- a/remoting/zookeeper/listener_test.go +++ b/remoting/zookeeper/listener_test.go @@ -97,7 +97,7 @@ func TestListener(t *testing.T) { go client.HandleZkEvent(event) listener := NewZkEventListener(client) dataListener := &mockDataListener{client: client, changedData: changedData, wait: &wait} - listener.ListenServiceEvent("/dubbo", dataListener) + listener.ListenServiceEvent(nil, "/dubbo", dataListener) time.Sleep(1 * time.Second) _, err := client.Conn.Set("/dubbo/dubbo.properties", []byte(changedData), 1) assert.NoError(t, err)